ultimecia

A ps1 emulator in c
Log | Files | Refs

commit 8ee9b6f53a75c3b79409347d2a584363590f7728
parent 65dcc262b854e3dad76cfcce9d8a9c041b43f888
Author: noone <vazkats@gmail.com>
Date:   Sat, 11 Oct 2025 19:45:41 +0300

Tidying up. Fixed compiler warnings. Following ansi c philosophy.
Still compiling with c99 though.
Gonna see if integrating lua will help me through my debugging journey

Diffstat:
Dlib/include/MiniFB.h | 107-------------------------------------------------------------------------------
Dlib/include/MiniFB_cpp.h | 186-------------------------------------------------------------------------------
Dlib/include/MiniFB_enums.h | 186-------------------------------------------------------------------------------
Dlib/include/MiniFB_ios.h | 7-------
Dlib/libminifb.a | 0
Mmakefile | 8++++----
Dntani.txt | 4----
Rtest.cc -> playground/test.cc | 0
Msrc/cdrom.c | 6++++--
Msrc/cdrom.h | 11++++-------
Msrc/cpu.c | 64++++++++++++++++++++++++++++++++--------------------------------
Dsrc/defs.h | 26--------------------------
Msrc/gpu.c | 594++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/interconnect.c | 942++++++++++++++++++++++++++++++++++++++-----------------------------------------
Msrc/irq.h | 2+-
Asrc/log.c | 168+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/log.h | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/main.c | 99+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/mem.c | 3++-
Msrc/sr.c | 119+++++++++++++++++++++++++++++++++++++------------------------------------------
Msrc/sr.h | 3+--
Msrc/time.c | 6++++++
22 files changed, 1132 insertions(+), 1458 deletions(-)

diff --git a/lib/include/MiniFB.h b/lib/include/MiniFB.h @@ -1,107 +0,0 @@ -#ifndef _MINIFB_H_ -#define _MINIFB_H_ - -#include "MiniFB_enums.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#ifndef __ANDROID__ -#define MFB_RGB(r, g, b) (((uint32_t) r) << 16) | (((uint32_t) g) << 8) | ((uint32_t) b) -#define MFB_ARGB(a, r, g, b) (((uint32_t) a) << 24) | (((uint32_t) r) << 16) | (((uint32_t) g) << 8) | ((uint32_t) b) -#else - #ifdef HOST_WORDS_BIGENDIAN - #define MFB_RGB(r, g, b) (((uint32_t) r) << 16) | (((uint32_t) g) << 8) | ((uint32_t) b) - #define MFB_ARGB(a, r, g, b) (((uint32_t) a) << 24) | (((uint32_t) r) << 16) | (((uint32_t) g) << 8) | ((uint32_t) b) - #else - #define MFB_ARGB(r, g, b) (((uint32_t) a) << 24) | (((uint32_t) b) << 16) | (((uint32_t) g) << 8) | ((uint32_t) r) - #define MFB_RGB(r, g, b) (((uint32_t) b) << 16) | (((uint32_t) g) << 8) | ((uint32_t) r) - #endif -#endif - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// Create a window that is used to display the buffer sent into the mfb_update function, returns 0 if fails -struct mfb_window * mfb_open(const char *title, unsigned width, unsigned height); -struct mfb_window * mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags); - -// Update the display -// Input buffer is assumed to be a 32-bit buffer of the size given in the open call -// Will return a negative status if something went wrong or the user want to exit -// Also updates the window events -mfb_update_state mfb_update(struct mfb_window *window, void *buffer); - -mfb_update_state mfb_update_ex(struct mfb_window *window, void *buffer, unsigned width, unsigned height); - -// Only updates the window events -mfb_update_state mfb_update_events(struct mfb_window *window); - -// Close the window -void mfb_close(struct mfb_window *window); - -// Set user data -void mfb_set_user_data(struct mfb_window *window, void *user_data); -void * mfb_get_user_data(struct mfb_window *window); - -// Set viewport (useful when resize) -bool mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height); -// Let mfb to calculate the best fit from your framebuffer original size -bool mfb_set_viewport_best_fit(struct mfb_window *window, unsigned old_width, unsigned old_height); - -// DPI -// [Deprecated]: Probably a better name will be mfb_get_monitor_scale -void mfb_get_monitor_dpi(struct mfb_window *window, float *dpi_x, float *dpi_y); -// Use this instead -void mfb_get_monitor_scale(struct mfb_window *window, float *scale_x, float *scale_y); - -// Callbacks -void mfb_set_active_callback(struct mfb_window *window, mfb_active_func callback); -void mfb_set_resize_callback(struct mfb_window *window, mfb_resize_func callback); -void mfb_set_close_callback(struct mfb_window* window, mfb_close_func callback); -void mfb_set_keyboard_callback(struct mfb_window *window, mfb_keyboard_func callback); -void mfb_set_char_input_callback(struct mfb_window *window, mfb_char_input_func callback); -void mfb_set_mouse_button_callback(struct mfb_window *window, mfb_mouse_button_func callback); -void mfb_set_mouse_move_callback(struct mfb_window *window, mfb_mouse_move_func callback); -void mfb_set_mouse_scroll_callback(struct mfb_window *window, mfb_mouse_scroll_func callback); - -// Getters -const char * mfb_get_key_name(mfb_key key); - -bool mfb_is_window_active(struct mfb_window *window); -unsigned mfb_get_window_width(struct mfb_window *window); -unsigned mfb_get_window_height(struct mfb_window *window); -int mfb_get_mouse_x(struct mfb_window *window); // Last mouse pos X -int mfb_get_mouse_y(struct mfb_window *window); // Last mouse pos Y -float mfb_get_mouse_scroll_x(struct mfb_window *window); // Mouse wheel X as a sum. When you call this function it resets. -float mfb_get_mouse_scroll_y(struct mfb_window *window); // Mouse wheel Y as a sum. When you call this function it resets. -const uint8_t * mfb_get_mouse_button_buffer(struct mfb_window *window); // One byte for every button. Press (1), Release 0. (up to 8 buttons) -const uint8_t * mfb_get_key_buffer(struct mfb_window *window); // One byte for every key. Press (1), Release 0. - -// FPS -void mfb_set_target_fps(uint32_t fps); -unsigned mfb_get_target_fps(void); -bool mfb_wait_sync(struct mfb_window *window); - -// Timer -struct mfb_timer * mfb_timer_create(void); -void mfb_timer_destroy(struct mfb_timer *tmr); -void mfb_timer_reset(struct mfb_timer *tmr); -double mfb_timer_now(struct mfb_timer *tmr); -double mfb_timer_delta(struct mfb_timer *tmr); -double mfb_timer_get_frequency(void); -double mfb_timer_get_resolution(void); - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#ifdef __cplusplus -} - -#if !defined(MINIFB_AVOID_CPP_HEADERS) - #include "MiniFB_cpp.h" -#endif - -#endif - -#endif diff --git a/lib/include/MiniFB_cpp.h b/lib/include/MiniFB_cpp.h @@ -1,186 +0,0 @@ -#pragma once - -#if defined(__cplusplus) - -#include <functional> -#include "MiniFB.h" - -//------------------------------------- -// To be able to distinguish these C++ functions, using std::function, from C functions, using raw function pointers, we need to reverse params order. -// -// Note that FROM the compiler point of view -// mfb_set_XXX_callback(window, &my_c_func) -// and -// mfb_set_XXX_callback(window, [](...) {}) -// have the same parameters. -//------------------------------------- -void mfb_set_active_callback (std::function<void(struct mfb_window *, bool)> func, struct mfb_window *window); -void mfb_set_resize_callback (std::function<void(struct mfb_window *, int, int)> func, struct mfb_window *window); -void mfb_set_close_callback (std::function<bool(struct mfb_window *)> func, struct mfb_window *window); -void mfb_set_keyboard_callback (std::function<void(struct mfb_window *, mfb_key, mfb_key_mod, bool)> func, struct mfb_window *window); -void mfb_set_char_input_callback (std::function<void(struct mfb_window *, unsigned int)> func, struct mfb_window *window); -void mfb_set_mouse_button_callback(std::function<void(struct mfb_window *, mfb_mouse_button, mfb_key_mod, bool)> func, struct mfb_window *window); -void mfb_set_mouse_move_callback (std::function<void(struct mfb_window *, int, int)> func, struct mfb_window *window); -void mfb_set_mouse_scroll_callback(std::function<void(struct mfb_window *, mfb_key_mod, float, float)> func, struct mfb_window *window); -//------------------------------------- - -//------------------------------------- -template <class T> -void mfb_set_active_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, bool)); - -template <class T> -void mfb_set_resize_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, int, int)); - -template <class T> -void mfb_set_keyboard_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_key, mfb_key_mod, bool)); - -template <class T> -void mfb_set_char_input_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, unsigned int)); - -template <class T> -void mfb_set_mouse_button_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_mouse_button, mfb_key_mod, bool)); - -template <class T> -void mfb_set_mouse_move_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, int, int)); - -template <class T> -void mfb_set_mouse_scroll_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_key_mod, float, float)); -//------------------------------------- - -//------------------------------------- -// To avoid clumsy hands -//------------------------------------- -class mfb_stub { - mfb_stub() : m_window(0x0) {} - - friend void mfb_set_active_callback (std::function<void(struct mfb_window *window, bool)> func, struct mfb_window *window); - friend void mfb_set_resize_callback (std::function<void(struct mfb_window *, int, int)> func, struct mfb_window *window); - friend void mfb_set_close_callback (std::function<bool(struct mfb_window *)> func, struct mfb_window *window); - friend void mfb_set_keyboard_callback (std::function<void(struct mfb_window *, mfb_key, mfb_key_mod, bool)> func, struct mfb_window *window); - friend void mfb_set_char_input_callback (std::function<void(struct mfb_window *, unsigned int)> func, struct mfb_window *window); - friend void mfb_set_mouse_button_callback(std::function<void(struct mfb_window *, mfb_mouse_button, mfb_key_mod, bool)> func, struct mfb_window *window); - friend void mfb_set_mouse_move_callback (std::function<void(struct mfb_window *, int, int)> func, struct mfb_window *window); - friend void mfb_set_mouse_scroll_callback(std::function<void(struct mfb_window *, mfb_key_mod, float, float)> func, struct mfb_window *window); - - template <class T> - friend void mfb_set_active_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, bool)); - template <class T> - friend void mfb_set_resize_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, int, int)); - template <class T> - friend void mfb_set_close_callback(struct mfb_window *window, T *obj, bool (T::*method)(struct mfb_window *)); - template <class T> - friend void mfb_set_mouse_button_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_mouse_button, mfb_key_mod, bool)); - template <class T> - friend void mfb_set_keyboard_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_key, mfb_key_mod, bool)); - template <class T> - friend void mfb_set_char_input_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, unsigned int)); - template <class T> - friend void mfb_set_mouse_button_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_mouse_button, mfb_key_mod, bool)); - template <class T> - friend void mfb_set_mouse_move_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, int, int)); - template <class T> - friend void mfb_set_mouse_scroll_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_key_mod, float, float)); - - static mfb_stub *GetInstance(struct mfb_window *window); - - static void active_stub(struct mfb_window *window, bool isActive); - static void resize_stub(struct mfb_window *window, int width, int height); - static bool close_stub(struct mfb_window *window); - static void keyboard_stub(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed); - static void char_input_stub(struct mfb_window *window, unsigned int); - static void mouse_btn_stub(struct mfb_window *window, mfb_mouse_button button, mfb_key_mod mod, bool isPressed); - static void mouse_move_stub(struct mfb_window *window, int x, int y); - static void scroll_stub(struct mfb_window *window, mfb_key_mod mod, float deltaX, float deltaY); - - struct mfb_window *m_window; - std::function<void(struct mfb_window *window, bool)> m_active; - std::function<void(struct mfb_window *window, int, int)> m_resize; - std::function<bool(struct mfb_window *window)> m_close; - std::function<void(struct mfb_window *window, mfb_key, mfb_key_mod, bool)> m_keyboard; - std::function<void(struct mfb_window *window, unsigned int)> m_char_input; - std::function<void(struct mfb_window *window, mfb_mouse_button, mfb_key_mod, bool)> m_mouse_btn; - std::function<void(struct mfb_window *window, int, int)> m_mouse_move; - std::function<void(struct mfb_window *window, mfb_key_mod, float, float)> m_scroll; -}; - -//------------------------------------- -template <class T> -inline void mfb_set_active_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, bool)) { - using namespace std::placeholders; - - mfb_stub *stub = mfb_stub::GetInstance(window); - stub->m_active = std::bind(method, obj, _1, _2); - mfb_set_active_callback(window, mfb_stub::active_stub); -} - -//------------------------------------- -template <class T> -inline void mfb_set_resize_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, int, int)) { - using namespace std::placeholders; - - mfb_stub *stub = mfb_stub::GetInstance(window); - stub->m_resize = std::bind(method, obj, _1, _2, _3); - mfb_set_resize_callback(window, mfb_stub::resize_stub); -} - -//------------------------------------- -template <class T> -inline void mfb_set_close_callback(struct mfb_window *window, T *obj, bool (T::*method)(struct mfb_window *window)) { - using namespace std::placeholders; - - mfb_stub *stub = mfb_stub::GetInstance(window); - stub->m_close = std::bind(method, obj, _1); - mfb_set_close_callback(window, mfb_stub::close_stub); -} - -//------------------------------------- -template <class T> -inline void mfb_set_keyboard_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, mfb_key, mfb_key_mod, bool)) { - using namespace std::placeholders; - - mfb_stub *stub = mfb_stub::GetInstance(window); - stub->m_keyboard = std::bind(method, obj, _1, _2, _3, _4); - mfb_set_keyboard_callback(window, mfb_stub::keyboard_stub); -} - -//------------------------------------- -template <class T> -inline void mfb_set_char_input_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, unsigned int)) { - using namespace std::placeholders; - - mfb_stub *stub = mfb_stub::GetInstance(window); - stub->m_char_input = std::bind(method, obj, _1, _2); - mfb_set_char_input_callback(window, mfb_stub::char_input_stub); -} - -//------------------------------------- -template <class T> -inline void mfb_set_mouse_button_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, mfb_mouse_button, mfb_key_mod, bool)) { - using namespace std::placeholders; - - mfb_stub *stub = mfb_stub::GetInstance(window); - stub->m_mouse_btn = std::bind(method, obj, _1, _2, _3, _4); - mfb_set_mouse_button_callback(window, mfb_stub::mouse_btn_stub); -} - -//------------------------------------- -template <class T> -inline void mfb_set_mouse_move_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, int, int)) { - using namespace std::placeholders; - - mfb_stub *stub = mfb_stub::GetInstance(window); - stub->m_mouse_move = std::bind(method, obj, _1, _2, _3); - mfb_set_mouse_move_callback(window, mfb_stub::mouse_move_stub); -} - -//------------------------------------- -template <class T> -inline void mfb_set_mouse_scroll_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, mfb_key_mod, float, float)) { - using namespace std::placeholders; - - mfb_stub *stub = mfb_stub::GetInstance(window); - stub->m_scroll = std::bind(method, obj, _1, _2, _3, _4); - mfb_set_mouse_scroll_callback(window, mfb_stub::scroll_stub); -} - -#endif diff --git a/lib/include/MiniFB_enums.h b/lib/include/MiniFB_enums.h @@ -1,186 +0,0 @@ -#pragma once - -#include <stdint.h> -#include <stdbool.h> - -// Enums -typedef enum { - STATE_OK = 0, - STATE_EXIT = -1, - STATE_INVALID_WINDOW = -2, - STATE_INVALID_BUFFER = -3, - STATE_INTERNAL_ERROR = -4, -} mfb_update_state; - -typedef enum { - MOUSE_BTN_0, // No mouse button - MOUSE_BTN_1, - MOUSE_BTN_2, - MOUSE_BTN_3, - MOUSE_BTN_4, - MOUSE_BTN_5, - MOUSE_BTN_6, - MOUSE_BTN_7, -} mfb_mouse_button; -#define MOUSE_LEFT MOUSE_BTN_1 -#define MOUSE_RIGHT MOUSE_BTN_2 -#define MOUSE_MIDDLE MOUSE_BTN_3 - -typedef enum { - KB_KEY_UNKNOWN = -1, - - KB_KEY_SPACE = 32, - KB_KEY_APOSTROPHE = 39, - KB_KEY_COMMA = 44, - KB_KEY_MINUS = 45, - KB_KEY_PERIOD = 46, - KB_KEY_SLASH = 47, - KB_KEY_0 = 48, - KB_KEY_1 = 49, - KB_KEY_2 = 50, - KB_KEY_3 = 51, - KB_KEY_4 = 52, - KB_KEY_5 = 53, - KB_KEY_6 = 54, - KB_KEY_7 = 55, - KB_KEY_8 = 56, - KB_KEY_9 = 57, - KB_KEY_SEMICOLON = 59, - KB_KEY_EQUAL = 61, - KB_KEY_A = 65, - KB_KEY_B = 66, - KB_KEY_C = 67, - KB_KEY_D = 68, - KB_KEY_E = 69, - KB_KEY_F = 70, - KB_KEY_G = 71, - KB_KEY_H = 72, - KB_KEY_I = 73, - KB_KEY_J = 74, - KB_KEY_K = 75, - KB_KEY_L = 76, - KB_KEY_M = 77, - KB_KEY_N = 78, - KB_KEY_O = 79, - KB_KEY_P = 80, - KB_KEY_Q = 81, - KB_KEY_R = 82, - KB_KEY_S = 83, - KB_KEY_T = 84, - KB_KEY_U = 85, - KB_KEY_V = 86, - KB_KEY_W = 87, - KB_KEY_X = 88, - KB_KEY_Y = 89, - KB_KEY_Z = 90, - KB_KEY_LEFT_BRACKET = 91, - KB_KEY_BACKSLASH = 92, - KB_KEY_RIGHT_BRACKET = 93, - KB_KEY_GRAVE_ACCENT = 96, - KB_KEY_WORLD_1 = 161, - KB_KEY_WORLD_2 = 162, - - KB_KEY_ESCAPE = 256, - KB_KEY_ENTER = 257, - KB_KEY_TAB = 258, - KB_KEY_BACKSPACE = 259, - KB_KEY_INSERT = 260, - KB_KEY_DELETE = 261, - KB_KEY_RIGHT = 262, - KB_KEY_LEFT = 263, - KB_KEY_DOWN = 264, - KB_KEY_UP = 265, - KB_KEY_PAGE_UP = 266, - KB_KEY_PAGE_DOWN = 267, - KB_KEY_HOME = 268, - KB_KEY_END = 269, - KB_KEY_CAPS_LOCK = 280, - KB_KEY_SCROLL_LOCK = 281, - KB_KEY_NUM_LOCK = 282, - KB_KEY_PRINT_SCREEN = 283, - KB_KEY_PAUSE = 284, - KB_KEY_F1 = 290, - KB_KEY_F2 = 291, - KB_KEY_F3 = 292, - KB_KEY_F4 = 293, - KB_KEY_F5 = 294, - KB_KEY_F6 = 295, - KB_KEY_F7 = 296, - KB_KEY_F8 = 297, - KB_KEY_F9 = 298, - KB_KEY_F10 = 299, - KB_KEY_F11 = 300, - KB_KEY_F12 = 301, - KB_KEY_F13 = 302, - KB_KEY_F14 = 303, - KB_KEY_F15 = 304, - KB_KEY_F16 = 305, - KB_KEY_F17 = 306, - KB_KEY_F18 = 307, - KB_KEY_F19 = 308, - KB_KEY_F20 = 309, - KB_KEY_F21 = 310, - KB_KEY_F22 = 311, - KB_KEY_F23 = 312, - KB_KEY_F24 = 313, - KB_KEY_F25 = 314, - KB_KEY_KP_0 = 320, - KB_KEY_KP_1 = 321, - KB_KEY_KP_2 = 322, - KB_KEY_KP_3 = 323, - KB_KEY_KP_4 = 324, - KB_KEY_KP_5 = 325, - KB_KEY_KP_6 = 326, - KB_KEY_KP_7 = 327, - KB_KEY_KP_8 = 328, - KB_KEY_KP_9 = 329, - KB_KEY_KP_DECIMAL = 330, - KB_KEY_KP_DIVIDE = 331, - KB_KEY_KP_MULTIPLY = 332, - KB_KEY_KP_SUBTRACT = 333, - KB_KEY_KP_ADD = 334, - KB_KEY_KP_ENTER = 335, - KB_KEY_KP_EQUAL = 336, - KB_KEY_LEFT_SHIFT = 340, - KB_KEY_LEFT_CONTROL = 341, - KB_KEY_LEFT_ALT = 342, - KB_KEY_LEFT_SUPER = 343, - KB_KEY_RIGHT_SHIFT = 344, - KB_KEY_RIGHT_CONTROL = 345, - KB_KEY_RIGHT_ALT = 346, - KB_KEY_RIGHT_SUPER = 347, - KB_KEY_MENU = 348 -} mfb_key; -#define KB_KEY_LAST KB_KEY_MENU - -typedef enum { - KB_MOD_SHIFT = 0x0001, - KB_MOD_CONTROL = 0x0002, - KB_MOD_ALT = 0x0004, - KB_MOD_SUPER = 0x0008, - KB_MOD_CAPS_LOCK = 0x0010, - KB_MOD_NUM_LOCK = 0x0020 -} mfb_key_mod; - -typedef enum { - WF_RESIZABLE = 0x01, - WF_FULLSCREEN = 0x02, - WF_FULLSCREEN_DESKTOP = 0x04, - WF_BORDERLESS = 0x08, - WF_ALWAYS_ON_TOP = 0x10, -} mfb_window_flags; - -// Opaque pointer -struct mfb_window; -struct mfb_timer; - -// Event callbacks -typedef void(*mfb_active_func)(struct mfb_window *window, bool isActive); -typedef void(*mfb_resize_func)(struct mfb_window *window, int width, int height); -typedef bool(*mfb_close_func)(struct mfb_window* window); -typedef void(*mfb_keyboard_func)(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed); -typedef void(*mfb_char_input_func)(struct mfb_window *window, unsigned int code); -typedef void(*mfb_mouse_button_func)(struct mfb_window *window, mfb_mouse_button button, mfb_key_mod mod, bool isPressed); -typedef void(*mfb_mouse_move_func)(struct mfb_window *window, int x, int y); -typedef void(*mfb_mouse_scroll_func)(struct mfb_window *window, mfb_key_mod mod, float deltaX, float deltaY); - diff --git a/lib/include/MiniFB_ios.h b/lib/include/MiniFB_ios.h @@ -1,7 +0,0 @@ -#pragma once - -#include "MiniFB_enums.h" - -void user_implemented_init(struct mfb_window *window); - -void user_implemented_update(struct mfb_window *window); diff --git a/lib/libminifb.a b/lib/libminifb.a Binary files differ. diff --git a/makefile b/makefile @@ -1,9 +1,9 @@ # Ultimecia PSX Emulator Makefile CC := clang -CFLAGS := -Wall -Wpedantic -g -Ilib/include $(shell /opt/homebrew/bin/pkg-config --cflags sdl2 lua) -LDFLAGS := $(shell /opt/homebrew/bin/pkg-config --libs sdl2 lua) -framework Cocoa -framework Metal -framework MetalKit -LIBS := lib/libminifb.a +CFLAGS := -std=c99 -g -Wall -Wextra -Werror -pedantic -Icommon $(shell /opt/homebrew/bin/pkg-config --cflags sdl2 lua) -DLOG_USE_COLOR +LDFLAGS := $(shell /opt/homebrew/bin/pkg-config --libs sdl2 lua) -framework Cocoa -framework Metal -framework MetalKit -lcurses +#LIBS := lib/libminifb.a SRC := $(wildcard src/*.c) OBJ := $(SRC:.c=.o) @@ -13,7 +13,7 @@ all: $(BIN) $(BIN): $(OBJ) @mkdir -p bin - $(CC) $(OBJ) -o $@ $(LDFLAGS) $(LIBS) + $(CC) $(OBJ) -o $@ $(LDFLAGS) #$(LIBS) # Compile .c to .o %.o: %.c diff --git a/ntani.txt b/ntani.txt @@ -1,4 +0,0 @@ -ηθελα να σου πω οτι οτι ειπα δεν ηταν αληθεια και δεν το εννουσα -αλιμονο αν κατι τετοιο δεν το λαχταρουσα -συγγνωμη μονο μπορω να πω και σε παρακαλω πιστεψε με μετανοω -σε περιμενω την παρασκευη σαν τρελος να σε ειδω diff --git a/test.cc b/playground/test.cc diff --git a/src/cdrom.c b/src/cdrom.c @@ -29,11 +29,12 @@ cdrom_fifo_full(fifo fifo) return fifo.write_idx == (fifo.read_idx ^ 0x10); } -void +/*void cdrom_store8(cdrom* cd, u32 off, u8 val) { off &= 0x3; -} + +}*/ void cdrom_write(cdrom* cd, u32 offset, u8 val) @@ -102,6 +103,7 @@ cdrom_exec_cmd(cdrom* cd, u8 cmd) switch ((cdrom_cmd)cmd) { case CDROM_CMD_GETSTAT: + fprintf(stderr, "Not implemented TEST COMMAND"); cd->status = cdrom_status(cd); break; case CDROM_CMD_TEST: diff --git a/src/cdrom.h b/src/cdrom.h @@ -8,23 +8,20 @@ enum { cdrom_sector_header_size = 4, cdrom_mode1_header_size = 4, cdrom_mode2_header_size = 12, - cdrom_mode2_data_sector_size = 2336, // header + edc - cdrom_frames_per_second = 75, // "sectors", or "timecode frames" (not "channel frames") + cdrom_mode2_data_sector_size = 2336, + cdrom_frames_per_second = 75, cdrom_seconds_per_minute = 60, cdrom_frames_per_minute = cdrom_frames_per_second * cdrom_seconds_per_minute, cdrom_subchannel_bytes_per_frame = 12, cdrom_lead_out_sector_count = 6750, cdrom_all_subcode_size = 96, cdrom_audio_sample_rate = 44100, - cdrom_audio_channels = 2, + cdrom_audio_channels = 2 }; typedef struct { - // Data buffer u8 buffer[16]; - // Write pointer (4bits + carry) u8 write_idx; - // Read pointer (4bits + carry) u8 read_idx; } fifo; @@ -33,7 +30,7 @@ typedef enum { CDROM_CMD_GETSTAT = 0x01, CDROM_CMD_SETLOC = 0x02, CDROM_CMD_TEST = 0x19, - CDROM_CMD_INIT = 0xA, + CDROM_CMD_INIT = 0xA } cdrom_cmd; #define STATUS_INDEX_MASK 0x03 diff --git a/src/cpu.c b/src/cpu.c @@ -4,8 +4,8 @@ #include "interconnect.h" #include "cpu.h" #include "types.h" -#include "defs.h" #include "util.h" +#include "log.h" CPU* new_cpu(Interconnect* inter) { @@ -124,9 +124,7 @@ op_sw(CPU* cpu, instruction* i) if ((cpu->sr & 0x10000) != 0) { -#ifndef DEBUG - printf("ignoring store while cache is isolated!\n"); -#endif + log_debug("ignoring store while cache is isolated!"); return; } @@ -162,7 +160,7 @@ op_swl(CPU* cpu, instruction* i) case 1: mem = (cur_mem & 0xffff0000) | (v >> 16); break; case 2: mem = (cur_mem & 0xff000000) | (v >> 8); break; case 3: mem = (cur_mem & 0x00000000) | (v >> 0); break; - default: fprintf(stderr, "* STORE WORD LEFT.. WHAT ARE YOU DOING *\n"); exit(EXIT_FAILURE); + default: log_fatal("* STORE WORD LEFT.. WHAT ARE YOU DOING *"); exit(EXIT_FAILURE); } CPU_store32(cpu, addr, mem); @@ -184,7 +182,7 @@ op_swr(CPU* cpu, instruction* i) case 1: mem = (cur_mem & 0x000000ff) | (v << 8); break; case 2: mem = (cur_mem & 0x0000ffff) | (v << 16); break; case 3: mem = (cur_mem & 0x00ffffff) | (v << 24); break; - default: fprintf(stderr, "* STORE WORD RIGHT.. WHAT ARE YOU DOING *\n"); exit(EXIT_FAILURE); + default: log_fatal("* STORE WORD RIGHT.. WHAT ARE YOU DOING *"); exit(EXIT_FAILURE); } CPU_store32(cpu, addr, mem); @@ -197,9 +195,7 @@ op_sh(CPU* cpu, instruction* i) if ((cpu->sr & 0x10000) != 0) { -#ifndef DEBUG - printf("ignoring store while cache is isolated!\n"); -#endif + log_info("ignoring store while cache is isolated!"); return; } @@ -227,9 +223,7 @@ op_sb(CPU* cpu, instruction* i) if ((cpu->sr & 0x10000) != 0) { -#ifndef DEBUG - printf("ignoring store while cache is isolated!\n"); -#endif + log_info("ignoring store while cache is isolated!"); return; } @@ -338,7 +332,7 @@ op_mtc0(CPU* cpu, instruction* i) case 3: case 5: case 6: case 7: case 9: case 11: if (v != 0) { - fprintf(stderr, "Unhandled cop0r%d", cop_r); + log_fatal("Unhandled cop0r%d", cop_r); exit(EXIT_FAILURE); } break; @@ -348,12 +342,12 @@ op_mtc0(CPU* cpu, instruction* i) case 13: if (v != 0) { - fprintf(stderr, "Unhandled write to CAUSE register\n"); + log_fatal("Unhandled write to CAUSE register"); exit(EXIT_FAILURE); } break; default: - fprintf(stderr, "Unhandled cop0 register %d\n", cop_r); + log_fatal("Unhandled cop0 register %d", cop_r); exit(EXIT_FAILURE); } } @@ -379,7 +373,7 @@ op_mfc0(CPU* cpu, instruction* i) cpu->load._1 = cpu->epc; break; default: - fprintf(stderr, "Unhandled read from cop0r%d\n", cop_r); + log_fatal("Unhandled read from cop0r%d", cop_r); exit(EXIT_FAILURE); } } @@ -391,7 +385,7 @@ op_rfe(CPU* cpu, instruction* i) if ((i->_0 & 0x3f) != 0x10) { - fprintf(stderr, "Invalid cop0 instruction %08X\n", i->_0); + log_fatal("Invalid cop0 instruction %08X", i->_0); exit(EXIT_FAILURE); } @@ -407,13 +401,14 @@ op_cop0(CPU* cpu, instruction* i) case 0x00: op_mfc0(cpu, i); break; case 0x04: op_mtc0(cpu, i); break; case 0x10: op_rfe(cpu, i); break; - default: printf("Unhandled cop0 instruction %08X\n", i->_0); exit(EXIT_FAILURE); + default: log_fatal("Unhandled cop0 instruction %08X", i->_0); exit(EXIT_FAILURE); } } void op_cop1(CPU* cpu, instruction* i) { + (void)i; exception(cpu, E_COPROCESSOR_ERROR); } @@ -421,7 +416,8 @@ op_cop1(CPU* cpu, instruction* i) void op_cop2(CPU* cpu, instruction* i) { - fprintf(stderr, "Unhandle GTE Instruction: %08X\n", i->_0); + (void)i;(void)cpu; + log_fatal("Unhandle GTE Instruction: %08X", i->_0); exit(EXIT_FAILURE); /* exception(cpu, E_COPROCESSOR_ERROR); */ } @@ -429,6 +425,7 @@ op_cop2(CPU* cpu, instruction* i) void op_cop3(CPU* cpu, instruction* i) { + (void)i; exception(cpu, E_COPROCESSOR_ERROR); } @@ -536,7 +533,7 @@ op_lwl(CPU* cpu, instruction* i) case 1: v = (cur_v & 0x0000ffff) | (aligned_word << 16); break; case 2: v = (cur_v & 0x000000ff) | (aligned_word << 8); break; case 3: v = (cur_v & 0x00000000) | (aligned_word << 0); break; - default: fprintf(stderr, "* LOAD WORD LEFT.. WHAT ARE YOU DOING *\n"); exit(EXIT_FAILURE); + default: log_fatal("* LOAD WORD LEFT.. WHAT ARE YOU DOING *"); exit(EXIT_FAILURE); } cpu->load._0 = i->t; @@ -561,7 +558,7 @@ op_lwr(CPU* cpu, instruction* i) case 1: v = (cur_v & 0xff000000) | (aligned_word >> 8); break; case 2: v = (cur_v & 0xffff0000) | (aligned_word >> 16); break; case 3: v = (cur_v & 0xffffff00) | (aligned_word >> 24); break; - default: fprintf(stderr, "* LOAD WORD RIGHT.. WHAT ARE YOU DOING *\n"); exit(EXIT_FAILURE); + default: log_fatal("* LOAD WORD RIGHT.. WHAT ARE YOU DOING *"); exit(EXIT_FAILURE); } cpu->load._0 = i->t; @@ -856,29 +853,32 @@ op_mthi(CPU* cpu, instruction* i) void op_syscall(CPU* cpu, instruction* i) { + (void)i; exception(cpu, E_SYSCALL); } void op_break(CPU* cpu, instruction* i) { + (void)i; exception(cpu, E_BREAK); } -void op_lwc0(CPU* cpu, instruction* i) { exception(cpu, E_COPROCESSOR_ERROR); } -void op_lwc1(CPU* cpu, instruction* i) { exception(cpu, E_COPROCESSOR_ERROR); } -void op_lwc2(CPU* cpu, instruction* i) { fprintf(stderr, "Unhandled GTE LWC: %08X\n", i->_0); exit(EXIT_FAILURE); } -void op_lwc3(CPU* cpu, instruction* i) { exception(cpu, E_COPROCESSOR_ERROR); } +void op_lwc0(CPU* cpu, instruction* i) { (void)i; exception(cpu, E_COPROCESSOR_ERROR); } +void op_lwc1(CPU* cpu, instruction* i) { (void)i; exception(cpu, E_COPROCESSOR_ERROR); } +void op_lwc2(CPU* cpu, instruction* i) { (void)i; (void)cpu; log_fatal("Unhandled GTE LWC: %08X", i->_0); exit(EXIT_FAILURE); } +void op_lwc3(CPU* cpu, instruction* i) { (void)i; exception(cpu, E_COPROCESSOR_ERROR); } -void op_swc0(CPU* cpu, instruction* i) { exception(cpu, E_COPROCESSOR_ERROR); } -void op_swc1(CPU* cpu, instruction* i) { exception(cpu, E_COPROCESSOR_ERROR); } -void op_swc2(CPU* cpu, instruction* i) { fprintf(stderr, "Unhandled GTE SWC: %08X\n", i->_0); exit(EXIT_FAILURE); } -void op_swc3(CPU* cpu, instruction* i) { exception(cpu, E_COPROCESSOR_ERROR); } +void op_swc0(CPU* cpu, instruction* i) { (void)i; exception(cpu, E_COPROCESSOR_ERROR); } +void op_swc1(CPU* cpu, instruction* i) { (void)i; exception(cpu, E_COPROCESSOR_ERROR); } +void op_swc2(CPU* cpu, instruction* i) { (void)i; (void)cpu; log_fatal("Unhandled GTE SWC: %08X", i->_0); exit(EXIT_FAILURE); } +void op_swc3(CPU* cpu, instruction* i) { (void)i; exception(cpu, E_COPROCESSOR_ERROR); } void op_illegal(CPU* cpu, instruction* i) { - printf("Illegal instruction %08X\n", i->_0); + (void)i; + log_warn("Illegal instruction %08X", i->_0); exception(cpu, E_ILLEGAL_INSTRUCTION); } @@ -893,7 +893,7 @@ CPU_decode_and_execute(CPU* cpu, instruction* i) case 0x0: op_sll(cpu, i); break; case 0x02: op_srl(cpu, i); break; case 0x03: op_sra(cpu, i); break; - case 0x0d: op_break(cpu, i); break; + case 0x0d: op_break(cpu, i); break; case 0x07: op_srav(cpu, i); break; case 0x04: op_sllv(cpu, i); break; case 0x06: op_srlv(cpu, i); break; @@ -917,7 +917,7 @@ CPU_decode_and_execute(CPU* cpu, instruction* i) case 0x13: op_mtlo(cpu, i); break; case 0x18: op_mult(cpu, i); break; case 0x19: op_multu(cpu, i); break; - case 0x0C: op_syscall(cpu, i); break; + case 0x0C: op_syscall(cpu, i); break; default: op_illegal(cpu, i); break; } break; diff --git a/src/defs.h b/src/defs.h @@ -1,26 +0,0 @@ -#pragma once - -static const int debug = 0; // Set to 0 to disable debug prints - -#include <assert.h> - -#define LOG_ERR(x) fprintf(stderr, (x)) - -/* #define PANIC(...) do { fprintf(stderr, __VA_ARGS__); exit(EXIT_FAILURE); } while(0) */ - -/* We should get rid of this */ -#define DEBUG 0; - -#define LOG_NONE 0 -#define LOG_DEBUG 1 -#define LOG_INFO 2 -#define LOG_WARN 3 -#define LOG_ERROR 4 - -// Set the current log level -#define CURRENT_LOG_LEVEL LOG_ERROR - -#define LOG(level, fmt, ...) \ - do { if (level >= CURRENT_LOG_LEVEL) fprintf(stderr, fmt, __VA_ARGS__); } while (0) -#define GPU_LOG(fmt, ...) \ - do { fprintf(stderr, fmt, __VA_ARGS__); } while (0) diff --git a/src/gpu.c b/src/gpu.c @@ -3,8 +3,8 @@ #include <string.h> #include "gpu.h" #include "types.h" -#include "defs.h" #include "sr.h" +#include "log.h" u8 HOR_RES_from_fields(u8 hr1, u8 hr2) { return (hr2 & 1) | ((hr1 & 3) << 1); } u32 HOR_RES_into_status(u8 hr) {return ((u32)hr) << 16; } @@ -12,452 +12,458 @@ u32 HOR_RES_into_status(u8 hr) {return ((u32)hr) << 16; } GPU* GPU_new(void) { - GPU* gpu; + GPU* gpu; - gpu = (GPU*)malloc(sizeof(GPU)); - memset(gpu, 0, sizeof(GPU)); - gpu->display_disabled = 1; - gpu->ren = REN_new(); + gpu = (GPU*)malloc(sizeof(GPU)); + memset(gpu, 0, sizeof(GPU)); + gpu->display_disabled = 1; + gpu->ren = REN_new(); - return gpu; + return gpu; } u32 GPU_read(GPU* gpu) { - return 0; + (void)gpu; + return 0; } u32 GPU_status(GPU* gpu) { - u32 r; - u32 dma_req; - - dma_req = 0; - r = 0; - - r |= ((u32)gpu->page_base_x) << 0; - r |= ((u32)gpu->page_base_y) << 4; - r |= ((u32)gpu->semi_transparency) << 5; - r |= ((u32)gpu->texture_depth) << 7; - r |= ((u32)gpu->dithering) << 9; - r |= ((u32)gpu->draw_to_display) << 10; - r |= ((u32)gpu->force_set_mask_bit) << 11; - r |= ((u32)gpu->preserve_masked_pixels) << 12; - r |= ((u32)gpu->field) << 13; - /* Bit 14 not supported */ - r |= ((u32)gpu->texture_disable) << 15; - r |= HOR_RES_into_status(gpu->hres); - /* If we don't emulate bit 31 correctly setting vres to 1 - locks the BIOS. 4.17 on the guide. - */ - //r |= ((u32)gpu->vres) << 19; - r |= ((u32)gpu->vmode) << 20; - r |= ((u32)gpu->display_depth) << 21; - r |= ((u32)gpu->interlaced) << 22; - r |= ((u32)gpu->display_disabled) << 23; - r |= ((u32)gpu->interrupt) << 24; - - /* Always GPU is ready */ - r |= 1 << 26; - r |= 1 << 27; - r |= 1 << 28; - - r |= ((u32) gpu->dma_direction) << 29; - - /* Ignore odd lines for now */ - r |= 0 << 31; - - switch(gpu->dma_direction) - { - case DMA_DIR_OFF: dma_req = 0; break; - case DMA_DIR_FIFO: dma_req = 1; break; - case DMA_DIR_CPUTOGP0: dma_req = (r >> 28) & 1; break; - case DMA_DIR_VRAMTOCPU: dma_req = (r >> 27) & 1; break; - default: fprintf(stderr, "UNREACHABLE"); exit(1); - } - - r |= dma_req << 25; - - return r; + u32 r; + u32 dma_req; + + dma_req = 0; + r = 0; + + r |= ((u32)gpu->page_base_x) << 0; + r |= ((u32)gpu->page_base_y) << 4; + r |= ((u32)gpu->semi_transparency) << 5; + r |= ((u32)gpu->texture_depth) << 7; + r |= ((u32)gpu->dithering) << 9; + r |= ((u32)gpu->draw_to_display) << 10; + r |= ((u32)gpu->force_set_mask_bit) << 11; + r |= ((u32)gpu->preserve_masked_pixels) << 12; + r |= ((u32)gpu->field) << 13; + /* Bit 14 not supported */ + r |= ((u32)gpu->texture_disable) << 15; + r |= HOR_RES_into_status(gpu->hres); + /* If we don't emulate bit 31 correctly setting vres to 1 + locks the BIOS. 4.17 on the guide. + */ + /*r |= ((u32)gpu->vres) << 19;*/ + r |= ((u32)gpu->vmode) << 20; + r |= ((u32)gpu->display_depth) << 21; + r |= ((u32)gpu->interlaced) << 22; + r |= ((u32)gpu->display_disabled) << 23; + r |= ((u32)gpu->interrupt) << 24; + + /* Always GPU is ready */ + r |= 1 << 26; + r |= 1 << 27; + r |= 1 << 28; + + r |= ((u32) gpu->dma_direction) << 29; + + /* Ignore odd lines for now */ + r |= 0 << 31; + + switch(gpu->dma_direction) + { + case DMA_DIR_OFF: dma_req = 0; break; + case DMA_DIR_FIFO: dma_req = 1; break; + case DMA_DIR_CPUTOGP0: dma_req = (r >> 28) & 1; break; + case DMA_DIR_VRAMTOCPU: dma_req = (r >> 27) & 1; break; + default: log_fatal("UNREACHABLE"); exit(1); + } + + r |= dma_req << 25; + + return r; } void GPU_gp1(GPU* gpu, u32 val) { - u32 opcode; + u32 opcode; - opcode = (val >> 24) & 0xff; + opcode = (val >> 24) & 0xff; - switch (opcode) - { - case 0x00: GPU_gp1_reset(gpu, val); break; - case 0x01: GPU_gp1_reset_command_buffer(gpu, val); break; - case 0x02: GPU_gp1_acknowledge_irq(gpu, val); break; - case 0x03: GPU_gp1_display_enable(gpu, val); break; - case 0x04: GPU_gp1_dma_direction(gpu, val); break; - case 0x05: GPU_gp1_display_vram_start(gpu, val); break; - case 0x06: GPU_gp1_display_horizontal_range(gpu, val); break; - case 0x07: GPU_gp1_display_vertical_range(gpu, val); break; - case 0x08: GPU_gp1_display_mode(gpu, val); break; - default: fprintf(stderr, "OP: %08X: Unhandled GP1 command %08X\n", opcode, val); exit(1); - } + switch (opcode) + { + case 0x00: GPU_gp1_reset(gpu, val); break; + case 0x01: GPU_gp1_reset_command_buffer(gpu, val); break; + case 0x02: GPU_gp1_acknowledge_irq(gpu, val); break; + case 0x03: GPU_gp1_display_enable(gpu, val); break; + case 0x04: GPU_gp1_dma_direction(gpu, val); break; + case 0x05: GPU_gp1_display_vram_start(gpu, val); break; + case 0x06: GPU_gp1_display_horizontal_range(gpu, val); break; + case 0x07: GPU_gp1_display_vertical_range(gpu, val); break; + case 0x08: GPU_gp1_display_mode(gpu, val); break; + default: log_fatal("OP: %08X: Unhandled GP1 command %08X", opcode, val); exit(1); + } } void GPU_gp1_reset(GPU* gpu, u32 val) { - REN* tmp = gpu->ren; - memset(gpu, 0, sizeof(GPU)); - /* Fill out the rest of the fields with no$cash spec reset values*/ - gpu->display_disabled = 1; - gpu->interlaced = 1; - gpu->display_horiz_start = 0x200; - gpu->display_horiz_end = 0xc00; - gpu->display_line_start = 0x10; - gpu->display_line_end = 0x100; - gpu->ren = tmp; + (void)val; + REN* tmp = gpu->ren; + memset(gpu, 0, sizeof(GPU)); + /* Fill out the rest of the fields with no$cash spec reset values*/ + gpu->display_disabled = 1; + gpu->interlaced = 1; + gpu->display_horiz_start = 0x200; + gpu->display_horiz_end = 0xc00; + gpu->display_line_start = 0x10; + gpu->display_line_end = 0x100; + gpu->ren = tmp; } void GPU_gp1_display_enable(GPU* gpu, u32 val) { - gpu->display_disabled = (val & 1) != 0; + gpu->display_disabled = (val & 1) != 0; } void GPU_gp1_acknowledge_irq(GPU* gpu, u32 val) { - gpu->interrupt = 0; + (void)val; + gpu->interrupt = 0; } void GPU_gp1_reset_command_buffer(GPU* gpu, u32 val) { - GPU_CMD_BUFFER_clear(&gpu->gp0_command); - gpu->gp0_words_remaining = 0; - gpu->gp0_mode = GP0_MODE_COMMAND; + (void)val; + GPU_CMD_BUFFER_clear(&gpu->gp0_command); + gpu->gp0_words_remaining = 0; + gpu->gp0_mode = GP0_MODE_COMMAND; - // XXX Should also clear the command FIFO when we implement it + /* XXX Should also clear the command FIFO when we implement it*/ } -void + void GPU_gp1_display_horizontal_range(GPU* gpu, u32 val) { - gpu->display_horiz_start = (u16)(val & 0xfff); - gpu->display_horiz_end = (u16)((val >> 12) & 0xfff); + gpu->display_horiz_start = (u16)(val & 0xfff); + gpu->display_horiz_end = (u16)((val >> 12) & 0xfff); } -void + void GPU_gp1_display_vertical_range(GPU* gpu, u32 val) { - gpu->display_line_start = (u16)(val & 0x3ff); - gpu->display_line_end = (u16)((val >> 10) & 0x3ff); + gpu->display_line_start = (u16)(val & 0x3ff); + gpu->display_line_end = (u16)((val >> 10) & 0x3ff); } -void + void GPU_gp1_display_vram_start(GPU* gpu, u32 val) { - gpu->display_vram_x_start = (u16)(val & 0x3fe); - gpu->display_vram_y_start = (u16)((val >> 10) & 0x1ff); + gpu->display_vram_x_start = (u16)(val & 0x3fe); + gpu->display_vram_y_start = (u16)((val >> 10) & 0x1ff); } -void + void GPU_gp1_dma_direction(GPU* gpu, u32 val) { - switch (val & 3) { - case 0: gpu->dma_direction = DMA_DIR_OFF; break; - case 1: gpu->dma_direction = DMA_DIR_FIFO; break; - case 2: gpu->dma_direction = DMA_DIR_CPUTOGP0; break; - case 3: gpu->dma_direction = DMA_DIR_VRAMTOCPU; break; - default: fprintf(stderr, "UNREACHABLE"); exit(EXIT_FAILURE); - } + switch (val & 3) { + case 0: gpu->dma_direction = DMA_DIR_OFF; break; + case 1: gpu->dma_direction = DMA_DIR_FIFO; break; + case 2: gpu->dma_direction = DMA_DIR_CPUTOGP0; break; + case 3: gpu->dma_direction = DMA_DIR_VRAMTOCPU; break; + default: log_fatal("UNREACHABLE"); exit(EXIT_FAILURE); + } } -void + void GPU_gp1_display_mode(GPU* gpu, u32 val) { - u8 hr1, hr2; + u8 hr1, hr2; - hr1 = (u8)(val & 3); - hr2 = (u8)((val >> 6) & 1); + hr1 = (u8)(val & 3); + hr2 = (u8)((val >> 6) & 1); - gpu->hres = HOR_RES_from_fields(hr1, hr2); - gpu->vres = (val & 0x4) != 0; - gpu->vmode = (val & 0x8) != 0 ? VMODE_NTSC : VMODE_PAL; - gpu->display_depth = (val & 0x10) != 0 ? DISP_DEPTH_D24BITS : DISP_DEPTH_D15BITS; - gpu->interlaced = (val & 0x20) != 0; + gpu->hres = HOR_RES_from_fields(hr1, hr2); + gpu->vres = (val & 0x4) != 0; + gpu->vmode = (val & 0x8) != 0 ? VMODE_NTSC : VMODE_PAL; + gpu->display_depth = (val & 0x10) != 0 ? DISP_DEPTH_D24BITS : DISP_DEPTH_D15BITS; + gpu->interlaced = (val & 0x20) != 0; - if (val & 0x80) - fprintf(stderr, "Unsupported display mode %08X\n", val), exit(EXIT_FAILURE); + if (val & 0x80) + log_fatal("Unsupported display mode %08X", val), exit(EXIT_FAILURE); } -void + void GPU_gp0(GPU* gpu, u32 val) { - if (gpu->gp0_words_remaining == 0) { - u32 opcode, len; - void (*method)(GPU*); - - opcode = (val >> 24) & 0xff; - - switch (opcode) { - case 0x00: len = 1; method = GPU_gp0_nop; break; - case 0x01: len = 1; method = GPU_gp0_clear_cache; break; - case 0xa0: len = 3; method = GPU_gp0_image_load; break; - case 0xe1: len = 1; method = GPU_gp0_draw_mode; break; - case 0xe2: len = 1; method = GPU_gp0_texture_window; break; - case 0xe3: len = 1; method = GPU_gp0_drawing_area_top_left; break; - case 0xe4: len = 1; method = GPU_gp0_drawing_area_bottom_right; break; - case 0xe5: len = 1; method = GPU_gp0_drawing_offset; break; - case 0xe6: len = 1; method = GPU_gp0_mask_bit_setting; break; - case 0x28: len = 5; method = GPU_gp0_quad_mono_opaque; break; - case 0x2c: len = 9; method = GPU_gp0_quad_texture_blend_opaque; break; - case 0x30: len = 6; method = GPU_gp0_triangle_shaded_opaque; break; - case 0x38: len = 8; method = GPU_gp0_quad_shaded_opaque; break; - case 0xc0: len = 3; method = GPU_gp0_image_store; break; - default: fprintf(stderr, "OP: %08X: Unhandled GP0 command %08X\n", opcode, val); exit(1); + if (gpu->gp0_words_remaining == 0) { + u32 opcode, len; + void (*method)(GPU*); + + opcode = (val >> 24) & 0xff; + + switch (opcode) { + case 0x00: len = 1; method = GPU_gp0_nop; break; + case 0x01: len = 1; method = GPU_gp0_clear_cache; break; + case 0xa0: len = 3; method = GPU_gp0_image_load; break; + case 0xe1: len = 1; method = GPU_gp0_draw_mode; break; + case 0xe2: len = 1; method = GPU_gp0_texture_window; break; + case 0xe3: len = 1; method = GPU_gp0_drawing_area_top_left; break; + case 0xe4: len = 1; method = GPU_gp0_drawing_area_bottom_right; break; + case 0xe5: len = 1; method = GPU_gp0_drawing_offset; break; + case 0xe6: len = 1; method = GPU_gp0_mask_bit_setting; break; + case 0x28: len = 5; method = GPU_gp0_quad_mono_opaque; break; + case 0x2c: len = 9; method = GPU_gp0_quad_texture_blend_opaque; break; + case 0x30: len = 6; method = GPU_gp0_triangle_shaded_opaque; break; + case 0x38: len = 8; method = GPU_gp0_quad_shaded_opaque; break; + case 0xc0: len = 3; method = GPU_gp0_image_store; break; + default: log_fatal("OP: %08X: Unhandled GP0 command %08X", opcode, val); exit(1); + } + + gpu->gp0_words_remaining = len; + gpu->gp0_command_method = method; + GPU_CMD_BUFFER_clear(&gpu->gp0_command); } - gpu->gp0_words_remaining = len; - gpu->gp0_command_method = method; - GPU_CMD_BUFFER_clear(&gpu->gp0_command); - } - - gpu->gp0_words_remaining -= 1; - - switch (gpu->gp0_mode) { - case GP0_MODE_COMMAND: - GPU_CMD_BUFFER_push_word(&gpu->gp0_command, val); - if (gpu->gp0_words_remaining == 0) - gpu->gp0_command_method(gpu); - break; - case GP0_MODE_IMAGE_LOAD: - if (gpu->gp0_words_remaining == 0) - gpu->gp0_mode = GP0_MODE_COMMAND; - break; - } + gpu->gp0_words_remaining -= 1; + + switch (gpu->gp0_mode) { + case GP0_MODE_COMMAND: + GPU_CMD_BUFFER_push_word(&gpu->gp0_command, val); + if (gpu->gp0_words_remaining == 0) + gpu->gp0_command_method(gpu); + break; + case GP0_MODE_IMAGE_LOAD: + if (gpu->gp0_words_remaining == 0) + gpu->gp0_mode = GP0_MODE_COMMAND; + break; + } } -void GPU_gp0_nop(GPU* gpu) {} +void GPU_gp0_nop(GPU* gpu) {(void)gpu;} -void GPU_gp0_clear_cache(GPU* gpu) { /* Not implemented */} +void GPU_gp0_clear_cache(GPU* gpu) {(void)gpu;} -void + void GPU_gp0_image_load(GPU* gpu) { - u32 res, width, height, imgsize; - - res = gpu->gp0_command.buffer[2]; - width = res & 0xffff; - height = res >> 16; - imgsize = width * height; - imgsize = (imgsize + 1) & ~1; - gpu->gp0_words_remaining = imgsize / 2; - gpu->gp0_mode = GP0_MODE_IMAGE_LOAD; + u32 res, width, height, imgsize; + + res = gpu->gp0_command.buffer[2]; + width = res & 0xffff; + height = res >> 16; + imgsize = width * height; + imgsize = (imgsize + 1) & ~1; + gpu->gp0_words_remaining = imgsize / 2; + gpu->gp0_mode = GP0_MODE_IMAGE_LOAD; } -void + void GPU_gp0_draw_mode(GPU* gpu) { - u32 val; - val = gpu->gp0_command.buffer[0]; - - gpu->page_base_x = (u8)(val & 0xf); - gpu->page_base_y = (u8)((val >> 4) & 1); - gpu->semi_transparency = (u8)((val >> 5) & 3); - - switch ((val >> 7) & 3) - { - case 0: gpu->texture_depth = TD_T4BIT; break; - case 1: gpu->texture_depth = TD_T8BIT; break; - case 2: gpu->texture_depth = TD_T15BIT; break; - default: fprintf(stderr, "Unhandled texture depth %d\n", (val >> 7) & 3); exit(1); - } - - gpu->dithering = ((val >> 9) & 1); - gpu->draw_to_display = ((val >> 10) & 1); - gpu->texture_disable = ((val >> 11) & 1); - gpu->rectangle_texture_x_flip = ((val >> 12) & 1); - gpu->rectangle_texture_y_flip = ((val >> 13) & 1); + u32 val; + val = gpu->gp0_command.buffer[0]; + + gpu->page_base_x = (u8)(val & 0xf); + gpu->page_base_y = (u8)((val >> 4) & 1); + gpu->semi_transparency = (u8)((val >> 5) & 3); + + switch ((val >> 7) & 3) + { + case 0: gpu->texture_depth = TD_T4BIT; break; + case 1: gpu->texture_depth = TD_T8BIT; break; + case 2: gpu->texture_depth = TD_T15BIT; break; + default: log_fatal("Unhandled texture depth %d", (val >> 7) & 3); exit(1); + } + + gpu->dithering = ((val >> 9) & 1); + gpu->draw_to_display = ((val >> 10) & 1); + gpu->texture_disable = ((val >> 11) & 1); + gpu->rectangle_texture_x_flip = ((val >> 12) & 1); + gpu->rectangle_texture_y_flip = ((val >> 13) & 1); } -void + void GPU_gp0_drawing_area_top_left(GPU* gpu) { - u32 val; - val = gpu->gp0_command.buffer[0]; - gpu->drawing_area_top = (u16)((val >> 10) & 0x3ff); - gpu->drawing_area_left = (u16)(val & 0x3ff); + u32 val; + val = gpu->gp0_command.buffer[0]; + gpu->drawing_area_top = (u16)((val >> 10) & 0x3ff); + gpu->drawing_area_left = (u16)(val & 0x3ff); } -void + void GPU_gp0_drawing_area_bottom_right(GPU* gpu) { - u32 val; - val = gpu->gp0_command.buffer[0]; + u32 val; + val = gpu->gp0_command.buffer[0]; - gpu->drawing_area_bottom = (u16)((val >> 10) & 0x3ff); - gpu->drawing_area_right = (u16)(val & 0x3ff); + gpu->drawing_area_bottom = (u16)((val >> 10) & 0x3ff); + gpu->drawing_area_right = (u16)(val & 0x3ff); } -void + void GPU_gp0_drawing_offset(GPU* gpu) { - u16 x, y; - u32 val; - - val = gpu->gp0_command.buffer[0]; - x = (u16)(val & 0x7ff); - y = (u16)((val >> 11) & 0x7ff); - - /* Values here are 11bit 2s complement signed values, we need to force sign extension */ - gpu->drawing_x_offset = ((i16)(x << 5)) >> 5; - gpu->drawing_y_offset = ((i16)(y << 5)) >> 5; - - /* - This is a hack because I haven't implemented gpu timings yet. - But gp0_drawing_offset is called every frame apparently. - */ - REN_display(gpu->ren); - + u16 x, y; + u32 val; + + val = gpu->gp0_command.buffer[0]; + x = (u16)(val & 0x7ff); + y = (u16)((val >> 11) & 0x7ff); + + /* Values here are 11bit 2s complement signed values, we need to force sign extension */ + gpu->drawing_x_offset = ((i16)(x << 5)) >> 5; + gpu->drawing_y_offset = ((i16)(y << 5)) >> 5; + + /* + This is a hack because I haven't implemented gpu timings yet. + But gp0_drawing_offset is called every frame apparently. + */ + REN_display(gpu->ren); + } -void + void GPU_gp0_texture_window(GPU* gpu) { - u32 val; - val = gpu->gp0_command.buffer[0]; + u32 val; + val = gpu->gp0_command.buffer[0]; - gpu->texture_window_x_mask = (u8)(val & 0x1f); - gpu->texture_window_y_mask = (u8)((val >> 5) & 0x1f); - gpu->texture_window_x_offset = (u8)((val >> 10) & 0x1f); - gpu->texture_window_y_offset = (u8)((val >> 15) & 0x1f); + gpu->texture_window_x_mask = (u8)(val & 0x1f); + gpu->texture_window_y_mask = (u8)((val >> 5) & 0x1f); + gpu->texture_window_x_offset = (u8)((val >> 10) & 0x1f); + gpu->texture_window_y_offset = (u8)((val >> 15) & 0x1f); } -void + void GPU_gp0_mask_bit_setting(GPU* gpu) { - u32 val; - val = gpu->gp0_command.buffer[0]; + u32 val; + val = gpu->gp0_command.buffer[0]; - gpu->force_set_mask_bit = (val & 1) != 0; - gpu->preserve_masked_pixels = (val & 2) != 0; + gpu->force_set_mask_bit = (val & 1) != 0; + gpu->preserve_masked_pixels = (val & 2) != 0; } -void + void GPU_gp0_quad_mono_opaque(GPU* gpu) { - ivec2 positions[4]; - C colors[4]; + ivec2 positions[4]; + C colors[4]; - positions[0] = POSITION_from_gp0(gpu->gp0_command.buffer[1]); - positions[1] = POSITION_from_gp0(gpu->gp0_command.buffer[2]); - positions[2] = POSITION_from_gp0(gpu->gp0_command.buffer[3]); - positions[3] = POSITION_from_gp0(gpu->gp0_command.buffer[4]); + positions[0] = POSITION_from_gp0(gpu->gp0_command.buffer[1]); + positions[1] = POSITION_from_gp0(gpu->gp0_command.buffer[2]); + positions[2] = POSITION_from_gp0(gpu->gp0_command.buffer[3]); + positions[3] = POSITION_from_gp0(gpu->gp0_command.buffer[4]); - colors[0] = colors[1] = colors[2] = colors[3] = COLOR_from_gp0(gpu->gp0_command.buffer[0]); + colors[0] = colors[1] = colors[2] = colors[3] = COLOR_from_gp0(gpu->gp0_command.buffer[0]); - //GPU_LOG("Draw quad mono opaque at x: %d, y: %d\n", positions[0].x, positions[0].y, NULL); - //GPU_LOG("Draw quad mono opaque with R: %d, G: %d, B: %d\n", colors[0].r, colors[0].g, colors[0].b, NULL); + /*GPU_LOG("Draw quad mono opaque at x: %d, y: %d\n", positions[0].x, positions[0].y, NULL);*/ + /*GPU_LOG("Draw quad mono opaque with R: %d, G: %d, B: %d\n", colors[0].r, colors[0].g, colors[0].b, NULL);*/ - REN_push_quad(gpu->ren, positions, colors); + REN_push_quad(gpu->ren, positions, colors); } -void + void GPU_gp0_triangle_shaded_opaque(GPU* gpu) { - ivec2 positions[3]; - C colors[3]; + ivec2 positions[3]; + C colors[3]; - positions[0] = POSITION_from_gp0(gpu->gp0_command.buffer[1]); - positions[1] = POSITION_from_gp0(gpu->gp0_command.buffer[3]); - positions[2] = POSITION_from_gp0(gpu->gp0_command.buffer[5]); + positions[0] = POSITION_from_gp0(gpu->gp0_command.buffer[1]); + positions[1] = POSITION_from_gp0(gpu->gp0_command.buffer[3]); + positions[2] = POSITION_from_gp0(gpu->gp0_command.buffer[5]); - colors[0] = COLOR_from_gp0(gpu->gp0_command.buffer[0]); - colors[1] = COLOR_from_gp0(gpu->gp0_command.buffer[2]); - colors[2] = COLOR_from_gp0(gpu->gp0_command.buffer[4]); + colors[0] = COLOR_from_gp0(gpu->gp0_command.buffer[0]); + colors[1] = COLOR_from_gp0(gpu->gp0_command.buffer[2]); + colors[2] = COLOR_from_gp0(gpu->gp0_command.buffer[4]); - REN_push_triangle(gpu->ren, positions, colors); + REN_push_triangle(gpu->ren, positions, colors); - //GPU_LOG("Draw triangle shaded at x: %d, y: %d\n", positions[0].x, positions[0].y, NULL); + /*GPU_LOG("Draw triangle shaded at x: %d, y: %d\n", positions[0].x, positions[0].y, NULL);*/ } -void + void GPU_gp0_quad_texture_blend_opaque(GPU* gpu) { - ivec2 positions[4]; - C colors[4]; + ivec2 positions[4]; + C colors[4]; + C tmp = {0x80, 0x00, 0x00}; + - positions[0] = POSITION_from_gp0(gpu->gp0_command.buffer[1]); - positions[1] = POSITION_from_gp0(gpu->gp0_command.buffer[3]); - positions[2] = POSITION_from_gp0(gpu->gp0_command.buffer[5]); - positions[3] = POSITION_from_gp0(gpu->gp0_command.buffer[7]); + positions[0] = POSITION_from_gp0(gpu->gp0_command.buffer[1]); + positions[1] = POSITION_from_gp0(gpu->gp0_command.buffer[3]); + positions[2] = POSITION_from_gp0(gpu->gp0_command.buffer[5]); + positions[3] = POSITION_from_gp0(gpu->gp0_command.buffer[7]); - colors[0] = colors[1] = colors[2] = colors[3] = (C){0x80, 0x00, 0x00}; + colors[0] = colors[1] = colors[2] = colors[3] = tmp; - REN_push_quad(gpu->ren, positions, colors); + REN_push_quad(gpu->ren, positions, colors); } -void + void GPU_gp0_quad_shaded_opaque(GPU* gpu) { - ivec2 positions[4]; - C colors[4]; + ivec2 positions[4]; + C colors[4]; - positions[0] = POSITION_from_gp0(gpu->gp0_command.buffer[1]); - positions[1] = POSITION_from_gp0(gpu->gp0_command.buffer[3]); - positions[2] = POSITION_from_gp0(gpu->gp0_command.buffer[5]); - positions[3] = POSITION_from_gp0(gpu->gp0_command.buffer[7]); + positions[0] = POSITION_from_gp0(gpu->gp0_command.buffer[1]); + positions[1] = POSITION_from_gp0(gpu->gp0_command.buffer[3]); + positions[2] = POSITION_from_gp0(gpu->gp0_command.buffer[5]); + positions[3] = POSITION_from_gp0(gpu->gp0_command.buffer[7]); - colors[0] = COLOR_from_gp0(gpu->gp0_command.buffer[0]); - colors[1] = COLOR_from_gp0(gpu->gp0_command.buffer[2]); - colors[2] = COLOR_from_gp0(gpu->gp0_command.buffer[4]); - colors[3] = COLOR_from_gp0(gpu->gp0_command.buffer[6]); + colors[0] = COLOR_from_gp0(gpu->gp0_command.buffer[0]); + colors[1] = COLOR_from_gp0(gpu->gp0_command.buffer[2]); + colors[2] = COLOR_from_gp0(gpu->gp0_command.buffer[4]); + colors[3] = COLOR_from_gp0(gpu->gp0_command.buffer[6]); - //GPU_LOG("I GOT CALLED\n", NULL); - REN_push_quad(gpu->ren, positions, colors); + /*GPU_LOG("I GOT CALLED\n", NULL);*/ + REN_push_quad(gpu->ren, positions, colors); } -void + void GPU_gp0_image_store(GPU* gpu) { - u32 res, width, height; + u32 res, width, height; - res = gpu->gp0_command.buffer[2]; - width = res & 0xffff; - height = res >> 16; + res = gpu->gp0_command.buffer[2]; + width = res & 0xffff; + height = res >> 16; - fprintf(stdout, "Unhandled image store: %dx%d\n", width, height); + log_debug("Unhandled image store: %dx%d", width, height); } -GPU_CMD_BUFFER* + GPU_CMD_BUFFER* GPU_CMD_BUFFER_new(void) { - GPU_CMD_BUFFER* buffer; + GPU_CMD_BUFFER* buffer; - buffer = (GPU_CMD_BUFFER*)malloc(sizeof(GPU_CMD_BUFFER)); - memset(buffer, 0, sizeof(GPU_CMD_BUFFER)); + buffer = (GPU_CMD_BUFFER*)malloc(sizeof(GPU_CMD_BUFFER)); + memset(buffer, 0, sizeof(GPU_CMD_BUFFER)); - return buffer; + return buffer; } -void + void GPU_CMD_BUFFER_clear(GPU_CMD_BUFFER* cmd_buffer) { - cmd_buffer->len = 0; - memset(cmd_buffer->buffer, 413, 12 * sizeof(u32)); + cmd_buffer->len = 0; + memset(cmd_buffer->buffer, 413, 12 * sizeof(u32)); } -void + void GPU_CMD_BUFFER_push_word(GPU_CMD_BUFFER* cmd_buffer, u32 word) { - if (cmd_buffer->len > 12) - fprintf(stderr, "OUT OF BOUNDS GPU_CMD_BUFFER"), exit(EXIT_FAILURE); + if (cmd_buffer->len > 12) + log_fatal("OUT OF BOUNDS GPU_CMD_BUFFER"), exit(EXIT_FAILURE); - cmd_buffer->buffer[cmd_buffer->len] = word; - cmd_buffer->len++; + cmd_buffer->buffer[cmd_buffer->len] = word; + cmd_buffer->len++; } diff --git a/src/interconnect.c b/src/interconnect.c @@ -6,580 +6,542 @@ #include "mem.h" #include "util.h" #include "types.h" -#include "defs.h" #include "gpu.h" #include "cdrom.h" +#include "log.h" Interconnect* new_interconnect(void) { - Interconnect* inter = (Interconnect*)malloc(sizeof(Interconnect)); - inter->bios = BIOS_new("roms/scph1001.bin"); - inter->ram = RAM_new(); - inter->dma = DMA_new(); - inter->gpu = GPU_new(); - inter->cdrom = cdrom_new(); - inter->irq = irq_new(); - return inter; + Interconnect* inter = (Interconnect*)malloc(sizeof(Interconnect)); + inter->bios = BIOS_new("roms/scph1001.bin"); + inter->ram = RAM_new(); + inter->dma = DMA_new(); + inter->gpu = GPU_new(); + inter->cdrom = cdrom_new(); + inter->irq = irq_new(); + return inter; } u8 INTER_load8(Interconnect* inter, u32 addr) { - u32 offset; - u32 abs_addr; - u32 contains; - - offset = 0; - contains = 0; - abs_addr = mask_region(addr); - - /* Assert abs_address Mappings */ - contains = UTIL_contains(BIOS_START, BIOS_SIZE, abs_addr, &offset); - if (contains) - return BIOS_load8(inter->bios, offset); - - contains = UTIL_contains(EXPANSION1_START, EXPANSION1_SIZE, abs_addr, &offset); - if (contains) - return 0xff; - - contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); - if (contains) - return RAM_load8(inter->ram, offset); - - contains = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr, &offset); - if (contains) - { -#ifndef DEBUG - printf("IRQ CONTROL read %08X\n", offset); -#endif - return 0; - } - - contains = UTIL_contains(CDROM_START, CDROM_SIZE, abs_addr, &offset); - if (contains) - { - return cdrom_load(inter->cdrom, offset); - } - - fprintf(stderr, "Unhandled Load8 At Address %08X\n", addr); - exit(EXIT_FAILURE); + u32 offset; + u32 abs_addr; + u32 contains; + + offset = 0; + contains = 0; + abs_addr = mask_region(addr); + + /* Assert abs_address Mappings */ + contains = UTIL_contains(BIOS_START, BIOS_SIZE, abs_addr, &offset); + if (contains) + return BIOS_load8(inter->bios, offset); + + contains = UTIL_contains(EXPANSION1_START, EXPANSION1_SIZE, abs_addr, &offset); + if (contains) + return 0xff; + + contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); + if (contains) + return RAM_load8(inter->ram, offset); + + contains = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr, &offset); + if (contains) + { + log_debug("IRQ CONTROL read %08X", offset); + return 0; + } + + contains = UTIL_contains(CDROM_START, CDROM_SIZE, abs_addr, &offset); + if (contains) + { + return cdrom_load(inter->cdrom, offset); + } + + log_fatal("Unhandled Load8 At Address %08X", addr); + exit(EXIT_FAILURE); } u16 INTER_load16(Interconnect* inter, u32 addr) { - u32 offset; - u32 abs_addr; - u32 contains; + u32 offset; + u32 abs_addr; + u32 contains; + + offset = 0; + contains = 0; + abs_addr = mask_region(addr); + + if (addr % 2 != 0) + { + log_fatal("Unaligned_load16_abs_address: %08X", abs_addr); + exit(EXIT_FAILURE); + } + + /* Assert abs_address Mappings */ + contains = UTIL_contains(SPU_START, SPU_SIZE, abs_addr, &offset); + if (contains) + { + log_warn("Unhandled read from SPU register: %08X", offset); + return 0; + } - offset = 0; - contains = 0; - abs_addr = mask_region(addr); + contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); + if (contains) + return RAM_load16(inter->ram, offset); - if (addr % 2 != 0) - { - fprintf(stderr, "Unaligned_load16_abs_address: %08X\n", abs_addr); + contains = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr, &offset); + if (contains) + { + log_debug("IRQ CONTROL read %08X", offset); + return 0; + } + + log_fatal("Unhandled Load16 At Address %08X", abs_addr); exit(EXIT_FAILURE); - } - - /* Assert abs_address Mappings */ - contains = UTIL_contains(SPU_START, SPU_SIZE, abs_addr, &offset); - if (contains) - { -#ifndef DEBUG - fprintf(stderr, "Unhandled read from SPU register: %08X\n", offset); -#endif - return 0; - } - - contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); - if (contains) - return RAM_load16(inter->ram, offset); - - contains = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr, &offset); - if (contains) - { -#ifndef DEBUG - printf("IRQ CONTROL read %08X\n", offset); -#endif - return 0; - } - - fprintf(stderr, "Unhandled Load16 At Address %08X\n", abs_addr); - exit(EXIT_FAILURE); } - u32 +u32 INTER_load32(Interconnect* inter, u32 addr) { - u32 offset; - u32 abs_addr; - u32 contains; + u32 offset; + u32 abs_addr; + u32 contains; - offset = 0; - contains = 0; - abs_addr = mask_region(addr); + offset = 0; + contains = 0; + abs_addr = mask_region(addr); - if (addr % 4 != 0) - { - fprintf(stderr, "Unaligned_load32_abs_address: %08X\n", abs_addr); - exit(EXIT_FAILURE); - } - - /* Assert abs_address Mappings */ - contains = UTIL_contains(BIOS_START, BIOS_SIZE, abs_addr, &offset); - if (contains) - return BIOS_load32(inter->bios, offset); - - contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); - if (contains) - return RAM_load32(inter->ram, offset); - - contains = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr, &offset); - if (contains) - { -#ifndef DEBUG - printf("IRQ CONTROL read %08X\n", offset); -#endif - return 0; - } - - contains = UTIL_contains(TIMERS_START, TIMERS_SIZE, abs_addr, &offset); - if (contains) - { -#ifndef DEBUG - printf("TIMERS read %08X\n", offset); -#endif - return 0; - } - - contains = UTIL_contains(DMA_START, DMA_SIZE, abs_addr, &offset); - if (contains) - { - return INTER_dma_reg(inter, offset); - } - - contains = UTIL_contains(GPU_START, GPU_SIZE, abs_addr, &offset); - if (contains) - { - - LOG(LOG_DEBUG, "GPU read %08X\n", abs_addr); - - switch(offset) + if (addr % 4 != 0) + { + log_fatal("Unaligned_load32_abs_address: %08X", abs_addr); + exit(EXIT_FAILURE); + } + + /* Assert abs_address Mappings */ + contains = UTIL_contains(BIOS_START, BIOS_SIZE, abs_addr, &offset); + if (contains) + return BIOS_load32(inter->bios, offset); + + contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); + if (contains) + return RAM_load32(inter->ram, offset); + + contains = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr, &offset); + if (contains) + { + log_debug("IRQ CONTROL read %08X", offset); + return 0; + } + + contains = UTIL_contains(TIMERS_START, TIMERS_SIZE, abs_addr, &offset); + if (contains) + { + log_debug("TIMERS read %08X", offset); + return 0; + } + + contains = UTIL_contains(DMA_START, DMA_SIZE, abs_addr, &offset); + if (contains) + { + return INTER_dma_reg(inter, offset); + } + + contains = UTIL_contains(GPU_START, GPU_SIZE, abs_addr, &offset); + if (contains) { - case 0: return GPU_read(inter->gpu); /* NOT COMPLETE */ - case 4: return GPU_status(inter->gpu); - default: return 0; + + log_debug("GPU read %08X", abs_addr); + switch(offset) + { + case 0: return GPU_read(inter->gpu); /* NOT COMPLETE */ + case 4: return GPU_status(inter->gpu); + default: return 0; + } } - } - fprintf(stderr, "Unhandled Load32 At Address %08X\n", addr); - exit(EXIT_FAILURE); + log_fatal("Unhandled Load32 At Address %08X", addr); + exit(EXIT_FAILURE); } void INTER_store8(Interconnect* inter, u32 addr, u8 val) { - u32 offset; - u32 contains; - u32 abs_addr; - - offset = 0; - contains = 0; - abs_addr = mask_region(addr); - - contains = UTIL_contains(EXPANSION2_START, EXPANSION2_SIZE, abs_addr, &offset); - if (contains) - { -#ifndef DEBUG - fprintf(stdout, "Ignoring write to EXPANSION2 register at: %08X\n", abs_addr); -#endif - return; - } - - contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); - if (contains) - { - RAM_store8(inter->ram, offset, val); - return; - } - - contains = UTIL_contains(CDROM_START, CDROM_SIZE, abs_addr, &offset); - if (contains) - { - cdrom_write(inter->cdrom, offset, val); - return; - } - - fprintf(stderr, "Unhandled Store8 At Address %08X\n", abs_addr); - exit(EXIT_FAILURE); + u32 offset; + u32 contains; + u32 abs_addr; + + offset = 0; + contains = 0; + abs_addr = mask_region(addr); + + contains = UTIL_contains(EXPANSION2_START, EXPANSION2_SIZE, abs_addr, &offset); + if (contains) + { + log_debug("Ignoring write to EXPANSION2 register at: %08X", abs_addr); + return; + } + + contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); + if (contains) + { + RAM_store8(inter->ram, offset, val); + return; + } + + contains = UTIL_contains(CDROM_START, CDROM_SIZE, abs_addr, &offset); + if (contains) + { + cdrom_write(inter->cdrom, offset, val); + return; + } + + log_fatal("Unhandled Store8 At Address %08X", abs_addr); + exit(EXIT_FAILURE); } - void +void INTER_store16(Interconnect* inter, u32 addr, u16 val) { - u32 offset; - u32 contains; - u32 abs_addr; + u32 offset; + u32 contains; + u32 abs_addr; + + offset = 0; + contains = 0; + abs_addr = mask_region(addr); + + if (addr % 2 != 0) + { + log_fatal("Unaligned_store16_address: %08X", addr); + exit(EXIT_FAILURE); + } + + contains = UTIL_contains(SPU_START, SPU_SIZE, abs_addr, &offset); + if (contains) + { + log_debug("Ignoring SPU register write: %X", abs_addr); + return; + } - offset = 0; - contains = 0; - abs_addr = mask_region(addr); + contains = UTIL_contains(TIMERS_START, TIMERS_SIZE, abs_addr, &offset); + if (contains) + { + log_debug("Ignoring TIMER register write to offset: %X", offset); + return; + } + + contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); + if (contains) + { + RAM_store16(inter->ram, offset, val); + return; + } - if (addr % 2 != 0) - { - fprintf(stderr, "Unaligned_store16_address: %08X", addr); + contains = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr, &offset); + if (contains) + { + log_debug("IRQ control write %08X at address %08X", val, offset); + return; + } + + log_fatal("Unhandled Store16 At Address %08X", abs_addr); exit(EXIT_FAILURE); - } - - contains = UTIL_contains(SPU_START, SPU_SIZE, abs_addr, &offset); - if (contains) - { -#ifndef DEBUG - fprintf(stdout, "Ignoring SPU register write: %X\n", abs_addr); -#endif - return; - } - - contains = UTIL_contains(TIMERS_START, TIMERS_SIZE, abs_addr, &offset); - if (contains) - { -#ifndef DEBUG - fprintf(stdout, "Ignoring TIMER register write to offset: %X\n", offset); -#endif - return; - } - - contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); - if (contains) - { - RAM_store16(inter->ram, offset, val); - return; - } - - contains = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr, &offset); - if (contains) - { -#ifndef DEBUG - printf("IRQ control write %08X at address %08X\n", val, offset); -#endif - return; - } - - fprintf(stderr, "Unhandled Store16 At Address %08X\n", abs_addr); - exit(EXIT_FAILURE); } void INTER_store32(Interconnect* inter, u32 addr, u32 val) { - u32 offset; - u32 contains; - u32 abs_addr; - - offset = 0; - contains = 0; - abs_addr = mask_region(addr); - - if (addr % 4 != 0) { -#ifndef DEBUG - fprintf(stderr, "Unaligned_store32_address: %08X", addr); -#endif - } - - contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); - if (contains) - { - RAM_store32(inter->ram, offset, val); - return; - } - - contains = UTIL_contains(RAM_SIZE_START, RAM_SIZE_SIZE, abs_addr, &offset); - if (contains) - { -#ifndef DEBUG - fprintf(stdout, "Ignoring RAM_SIZE register write %X\n", abs_addr); -#endif - return; - } - - contains = UTIL_contains(CACHECONTROL_START, CACHECONTROL_SIZE, abs_addr, &offset); - if (contains) - { -#ifndef DEBUG - fprintf(stdout, "Ignoring CACHECONTROL abs_address write: %X\n", abs_addr); -#endif - return; - } - - contains = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr, &offset); - if (contains) - { -#ifndef DEBUG - fprintf(stdout, "Ignoring IRQ CONTROL write %08X to address %08X\n", val, offset); -#endif - return; - } - - contains = UTIL_contains(DMA_START, DMA_SIZE, abs_addr, &offset); - if (contains) - { - INTER_set_dma_reg(inter, offset, val); - return; - } - - contains = UTIL_contains(TIMERS_START, TIMERS_SIZE, abs_addr, &offset); - if (contains) - { -#ifndef DEBUG - fprintf(stdout, "TIMER register write %08X to offset: %08X\n", val, offset); -#endif - return; - } - - contains = UTIL_contains(GPU_START, GPU_SIZE, abs_addr, &offset); - if (contains) - { - LOG(LOG_DEBUG, "GPU write %08X to address %08X\n", val, offset); - switch (offset) { - case 0: GPU_gp0(inter->gpu, val); break; - case 4: GPU_gp1(inter->gpu, val); break; - default: fprintf(stderr, "GPU write %08X: %08X", offset, val); exit(EXIT_FAILURE); - } - - return; - } - - contains = UTIL_contains(SYSCONTROL_START, SYSCONTROL_SIZE, abs_addr, &offset); - if (contains) - { - switch(offset) { - case 0: - if (val != 0x1F000000) { - fprintf(stderr, "Bad Expansion 1 base abs_address: %08X", val); - exit(EXIT_FAILURE); + u32 offset; + u32 contains; + u32 abs_addr; + + offset = 0; + contains = 0; + abs_addr = mask_region(addr); + + if (addr % 4 != 0) + log_warn("Unaligned_store32_address: %08X", addr); + + contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); + if (contains) { + RAM_store32(inter->ram, offset, val); + return; + } + + contains = UTIL_contains(RAM_SIZE_START, RAM_SIZE_SIZE, abs_addr, &offset); + if (contains) + { + log_debug("Ignoring RAM_SIZE register write %X", abs_addr); + return; + } + + contains = UTIL_contains(CACHECONTROL_START, CACHECONTROL_SIZE, abs_addr, &offset); + if (contains) + { + log_debug("Ignoring CACHECONTROL abs_address write: %X", abs_addr); + return; + } + + contains = UTIL_contains(IRQ_CONTROL_START, IRQ_CONTROL_SIZE, abs_addr, &offset); + if (contains) + { + log_debug("Ignoring IRQ CONTROL write %08X to address %08X", val, offset); + return; + } + + contains = UTIL_contains(DMA_START, DMA_SIZE, abs_addr, &offset); + if (contains) + { + INTER_set_dma_reg(inter, offset, val); + return; + } + + contains = UTIL_contains(TIMERS_START, TIMERS_SIZE, abs_addr, &offset); + if (contains) + { + log_debug("TIMER register write %08X to offset: %08X", val, offset); + return; + } + + contains = UTIL_contains(GPU_START, GPU_SIZE, abs_addr, &offset); + if (contains) + { + log_debug("GPU write %08X to address %08X", val, offset); + switch (offset) { + case 0: GPU_gp0(inter->gpu, val); break; + case 4: GPU_gp1(inter->gpu, val); break; + default: log_fatal("GPU write %08X: %08X", offset, val); exit(EXIT_FAILURE); } - break; - case 4: - if (val != 0x1F802000) { - fprintf(stderr, "Bad expansion 2 base abs_address: %08X", val); - exit(EXIT_FAILURE); + + return; + } + + contains = UTIL_contains(SYSCONTROL_START, SYSCONTROL_SIZE, abs_addr, &offset); + if (contains) + { + switch(offset) { + case 0: + if (val != 0x1F000000) { + log_fatal("Bad Expansion 1 base abs_address: %08X", val); + exit(EXIT_FAILURE); + } + break; + case 4: + if (val != 0x1F802000) { + log_fatal("Bad expansion 2 base abs_address: %08X", val); + exit(EXIT_FAILURE); + } + break; + default: + log_warn("Unhandled write to SYSCONTROL register"); + return; } - break; - default: -#ifndef DEBUG - fprintf(stderr, "Unhandled write to SYSCONTROL register\n"); -#endif return; } - return; - } - fprintf(stderr, "Unhandled Store32 At Address %08X\n", addr); - exit(EXIT_FAILURE); + log_fatal("Unhandled Store32 At Address %08X", addr); + exit(EXIT_FAILURE); } u32 INTER_dma_reg(Interconnect* inter, u32 offset) { - u32 major, minor, val; - Channel* channel; - major = (offset & 0x70) >> 4; - minor = offset & 0xf; - - switch (major) { - case 0: case 1: case 2: case 3: case 4: case 5: case 6: - - channel = &inter->dma->channels[(Port)major]; - switch (minor) { - case 0: val = CHANNEL_base(channel); break; - case 4: val = CHANNEL_block_control(channel); break; - case 8: val = CHANNEL_control(channel); break; - default: fprintf(stderr, "Unhandled DMA read at %08X\n", offset); exit(EXIT_FAILURE); - } - break; - case 7: - switch (minor) { - case 0: val = DMA_control(inter->dma); break; - case 4: val = DMA_interrupt(inter->dma); break; - default: fprintf(stderr, "unhandled DMA access %08X\n", offset); exit(EXIT_FAILURE); - } - break; - default: fprintf(stderr, "unhandled DMA access %08X\n", offset); exit(EXIT_FAILURE); - } - - return val; + u32 major, minor, val; + Channel* channel; + major = (offset & 0x70) >> 4; + minor = offset & 0xf; + + switch (major) { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: + + channel = &inter->dma->channels[(Port)major]; + switch (minor) { + case 0: val = CHANNEL_base(channel); break; + case 4: val = CHANNEL_block_control(channel); break; + case 8: val = CHANNEL_control(channel); break; + default: log_fatal("Unhandled DMA read at %08X", offset); exit(EXIT_FAILURE); + } + break; + case 7: + switch (minor) { + case 0: val = DMA_control(inter->dma); break; + case 4: val = DMA_interrupt(inter->dma); break; + default: log_fatal("Unhandled DMA access %08X", offset); exit(EXIT_FAILURE); + } + break; + default: log_fatal("Unhandled DMA access %08X", offset); exit(EXIT_FAILURE); + } + + return val; } - void +void INTER_set_dma_reg(Interconnect* inter, u32 offset, u32 val) { - u32 major, minor; - Channel* channel; - Port port, active_port; - major = (offset & 0x70) >> 4; - minor = offset & 0xf; - active_port = PORT_INVALID; - - switch (major) { - case 0: case 1: case 2: case 3: case 4: case 5: case 6: - - port = (Port)major; - channel = &inter->dma->channels[port]; - - switch (minor) { - case 0: CHANNEL_set_base(channel, val); break; - case 4: CHANNEL_set_block_control(channel, val); break; - case 8: CHANNEL_set_control(channel, val); break; - default: fprintf(stderr, "Unhandled DMA write at %08X\n", offset); exit(EXIT_FAILURE); - } - if (CHANNEL_active(channel)) { - active_port = port; - } else { - active_port = PORT_INVALID; - } - break; - case 7: - switch (minor) { - case 0: DMA_set_control(inter->dma, val); break; - case 4: DMA_set_interrupt(inter->dma, val); break; - default: active_port = PORT_INVALID; break;/* fprintf(stderr, "unhandled DMA write %08X\n", offset); exit(EXIT_FAILURE); */ - } - break; - default: fprintf(stderr, "unhandled DMA write %08X\n", offset); exit(EXIT_FAILURE); - } - - if (active_port != PORT_INVALID) - INTER_do_dma(inter, (Port)active_port); + u32 major, minor; + Channel* channel; + Port port, active_port; + major = (offset & 0x70) >> 4; + minor = offset & 0xf; + active_port = PORT_INVALID; + + switch (major) { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: + + port = (Port)major; + channel = &inter->dma->channels[port]; + + switch (minor) { + case 0: CHANNEL_set_base(channel, val); break; + case 4: CHANNEL_set_block_control(channel, val); break; + case 8: CHANNEL_set_control(channel, val); break; + default: log_fatal("Unhandled DMA write at %08X", offset); exit(EXIT_FAILURE); + } + if (CHANNEL_active(channel)) { + active_port = port; + } else { + active_port = PORT_INVALID; + } + break; + case 7: + switch (minor) { + case 0: DMA_set_control(inter->dma, val); break; + case 4: DMA_set_interrupt(inter->dma, val); break; + default: active_port = PORT_INVALID; break;/* fprintf(stderr, "unhandled DMA write %08X\n", offset); exit(EXIT_FAILURE); */ + } + break; + default: log_fatal("unhandled DMA write %08X", offset); exit(EXIT_FAILURE); + } + + if (active_port != PORT_INVALID) + INTER_do_dma(inter, (Port)active_port); } - void +void INTER_do_dma(Interconnect* inter, Port port) { - Channel* ch; - if (port == PORT_INVALID) { - printf("%d\n", port); - fprintf(stderr, "Invalid port doing dma\n"); - exit(EXIT_FAILURE); - } + Channel* ch; + if (port == PORT_INVALID) { + log_fatal("Invalid port doing dma"); + exit(EXIT_FAILURE); + } - ch = &inter->dma->channels[(Port)port]; + ch = &inter->dma->channels[(Port)port]; - switch (ch->sync) { - case SYNC_LINKED_LIST: INTER_do_dma_linked_list(inter, port); break; - default: INTER_do_dma_block(inter, port); break; - } + switch (ch->sync) { + case SYNC_LINKED_LIST: INTER_do_dma_linked_list(inter, port); break; + default: INTER_do_dma_block(inter, port); break; + } } -void + void INTER_do_dma_block(Interconnect* inter, Port port) { - Channel *ch; - u32 addr; - u32 increment; - u32 src_word; - u32 remsz; - - ch = &inter->dma->channels[port]; - remsz = 0; + Channel *ch; + u32 addr; + u32 increment; + u32 src_word; + u32 remsz; + + ch = &inter->dma->channels[port]; + remsz = 0; + + switch (ch->step) { + case STEP_INCREMENT: increment = 4; break; + case STEP_DECREMENT: increment = -4; break; + default: log_fatal("Unreachable!"); exit(EXIT_FAILURE); + } - switch (ch->step) { - case STEP_INCREMENT: increment = 4; break; - case STEP_DECREMENT: increment = -4; break; - default: fprintf(stderr, "Unreachable!\n"); exit(EXIT_FAILURE); - } + addr = ch->base; - addr = ch->base; + /* printf("%d\n", port); + / printf("%08X %08X %d\n", ch->block_size, ch->block_count, (Port)ch->step); */ - /* printf("%d\n", port); - / printf("%08X %08X %d\n", ch->block_size, ch->block_count, (Port)ch->step); */ + if (!CHANNEL_transfer_size(ch, &remsz)) { + log_fatal("Couldn't figure out DMA block transfer size"); + exit(EXIT_FAILURE); + } - if (!CHANNEL_transfer_size(ch, &remsz)) { - fprintf(stderr, "Couldn't figure out DMA block transfer size\n"); - exit(EXIT_FAILURE); - } - - while (remsz > 0) { - u32 cur_addr; - cur_addr = addr & 0x1ffffc; - - switch (ch->direction) { - case DIR_FROM_RAM: - src_word = RAM_load32(inter->ram, cur_addr); - switch(port) { - case PORT_GPU: - GPU_gp0(inter->gpu, src_word); -#ifndef DEBUG - printf("GPU data %08X\n", src_word); -#endif - break; - default: - fprintf(stderr, "Unhandled DMA destination port: %d", (u8)port); - exit(EXIT_FAILURE); - } - break; - case DIR_TO_RAM: - switch(port) { - case PORT_OTC: - if (remsz == 1) { - src_word = 0xffffff; - } else { - src_word = (addr - 4) & 0x1fffff; - } - break; - default: - fprintf(stderr, "Unhandled DMA source port: %d", (u8)port); - exit(EXIT_FAILURE); + while (remsz > 0) { + u32 cur_addr; + cur_addr = addr & 0x1ffffc; + + switch (ch->direction) { + case DIR_FROM_RAM: + src_word = RAM_load32(inter->ram, cur_addr); + switch(port) { + case PORT_GPU: + GPU_gp0(inter->gpu, src_word); + log_debug("GPU data %08X", src_word); + break; + default: + log_fatal("Unhandled DMA destination port: %d", (u8)port); + exit(EXIT_FAILURE); + } + break; + case DIR_TO_RAM: + switch(port) { + case PORT_OTC: + if (remsz == 1) { + src_word = 0xffffff; + } else { + src_word = (addr - 4) & 0x1fffff; + } + break; + default: + log_fatal("Unhandled DMA source port: %d", (u8)port); + exit(EXIT_FAILURE); + } + RAM_store32(inter->ram, cur_addr, src_word); + break; + default: break; } - RAM_store32(inter->ram, cur_addr, src_word); - break; - default: break; - } - addr += increment; - remsz--; - } - CHANNEL_done(ch); + addr += increment; + remsz--; + } + CHANNEL_done(ch); } -void + void INTER_do_dma_linked_list(Interconnect* inter, Port port) { - Channel *ch; - u32 addr, header, remsz, command; + Channel *ch; + u32 addr, header, remsz, command; - ch = &inter->dma->channels[port]; - addr = ch->base & 0x1ffffc; + ch = &inter->dma->channels[port]; + addr = ch->base & 0x1ffffc; - if (ch->direction == DIR_TO_RAM) { - fprintf(stderr, "Invalid DMA direction for linked list mode\n"); - exit(EXIT_FAILURE); - } + if (ch->direction == DIR_TO_RAM) { + log_fatal("Invalid DMA direction for linked list mode"); + exit(EXIT_FAILURE); + } - if (port != PORT_GPU) { - fprintf(stderr, "Attempted linked list DMA on port %d\n", (u8)port); - exit(EXIT_FAILURE); - } + if (port != PORT_GPU) { + log_fatal("Attempted linked list DMA on port %d", (u8)port); + exit(EXIT_FAILURE); + } - while (1) { - header = RAM_load32(inter->ram, addr); - remsz = header >> 24; + while (1) { + header = RAM_load32(inter->ram, addr); + remsz = header >> 24; - while (remsz > 0) { - addr = (addr + 4) & 0x1ffffc; - command = RAM_load32(inter->ram, addr); - GPU_gp0(inter->gpu, command); -#ifndef DEBUG - printf("GPU command %08X\n", command); -#endif - remsz--; - } + while (remsz > 0) { + addr = (addr + 4) & 0x1ffffc; + command = RAM_load32(inter->ram, addr); + GPU_gp0(inter->gpu, command); + log_debug("GPU command %08X", command); + remsz--; + } - if ((header & 0x800000) != 0) - break; + if ((header & 0x800000) != 0) + break; - addr = header & 0x1ffffc; + addr = header & 0x1ffffc; - } - CHANNEL_done(ch); + } + CHANNEL_done(ch); } diff --git a/src/irq.h b/src/irq.h @@ -18,7 +18,7 @@ enum { IRQ_TIMER_2 = 6, IRQ_SIO = 7, IRQ_SPU = 9, - IRQ_PIO = 10, + IRQ_PIO = 10 }; enum diff --git a/src/log.c b/src/log.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2020 rxi + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "log.h" + +#define MAX_CALLBACKS 32 + +typedef struct { + log_LogFn fn; + void *udata; + int level; +} Callback; + +static struct { + void *udata; + log_LockFn lock; + int level; + bool quiet; + Callback callbacks[MAX_CALLBACKS]; +} L; + + +static const char *level_strings[] = { + "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" +}; + +#ifdef LOG_USE_COLOR +static const char *level_colors[] = { + "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m" +}; +#endif + + +static void stdout_callback(log_Event *ev) { + char buf[16]; + buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0'; +#ifdef LOG_USE_COLOR + fprintf( + ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", + buf, level_colors[ev->level], level_strings[ev->level], + ev->file, ev->line); +#else + fprintf( + ev->udata, "%s %-5s %s:%d: ", + buf, level_strings[ev->level], ev->file, ev->line); +#endif + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + + +static void file_callback(log_Event *ev) { + char buf[64]; + buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0'; + fprintf( + ev->udata, "%s %-5s %s:%d: ", + buf, level_strings[ev->level], ev->file, ev->line); + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + + +static void lock(void) { + if (L.lock) { L.lock(true, L.udata); } +} + + +static void unlock(void) { + if (L.lock) { L.lock(false, L.udata); } +} + + +const char* log_level_string(int level) { + return level_strings[level]; +} + + +void log_set_lock(log_LockFn fn, void *udata) { + L.lock = fn; + L.udata = udata; +} + + +void log_set_level(int level) { + L.level = level; +} + + +void log_set_quiet(bool enable) { + L.quiet = enable; +} + + +int log_add_callback(log_LogFn fn, void *udata, int level) { + for (int i = 0; i < MAX_CALLBACKS; i++) { + if (!L.callbacks[i].fn) { + L.callbacks[i] = (Callback) { fn, udata, level }; + return 0; + } + } + return -1; +} + + +int log_add_fp(FILE *fp, int level) { + return log_add_callback(file_callback, fp, level); +} + + +static void init_event(log_Event *ev, void *udata) { + if (!ev->time) { + time_t t = time(NULL); + ev->time = localtime(&t); + } + ev->udata = udata; +} + + +void log_log(int level, const char *file, int line, const char *fmt, ...) { + log_Event ev = { + .fmt = fmt, + .file = file, + .line = line, + .level = level, + }; + + lock(); + + if (!L.quiet && level >= L.level) { + init_event(&ev, stderr); + va_start(ev.ap, fmt); + stdout_callback(&ev); + va_end(ev.ap); + } + + for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) { + Callback *cb = &L.callbacks[i]; + if (level >= cb->level) { + init_event(&ev, cb->udata); + va_start(ev.ap, fmt); + cb->fn(&ev); + va_end(ev.ap); + } + } + + unlock(); +} diff --git a/src/log.h b/src/log.h @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2020 rxi + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See `log.c` for details. + */ + +#ifndef LOG_H +#define LOG_H + +#include <stdio.h> +#include <stdarg.h> +#include <stdbool.h> +#include <time.h> + +#define LOG_VERSION "0.1.0" + +typedef struct { + va_list ap; + const char *fmt; + const char *file; + struct tm *time; + void *udata; + int line; + int level; +} log_Event; + +typedef void (*log_LogFn)(log_Event *ev); +typedef void (*log_LockFn)(bool lock, void *udata); + +enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL }; + +#define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) +#define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) +#define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) +#define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) +#define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) +#define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) + +const char* log_level_string(int level); +void log_set_lock(log_LockFn fn, void *udata); +void log_set_level(int level); +void log_set_quiet(bool enable); +int log_add_callback(log_LogFn fn, void *udata, int level); +int log_add_fp(FILE *fp, int level); + +void log_log(int level, const char *file, int line, const char *fmt, ...); + +#endif diff --git a/src/main.c b/src/main.c @@ -1,5 +1,6 @@ #include <stdlib.h> -#include <SDL2/SDL.h> +#include <unistd.h> +#include <ncurses.h> #include "cpu.h" #include "interconnect.h" @@ -7,65 +8,61 @@ #include "mem.h" #include "gpu.h" #include "sr.h" -#include "MiniFB.h" +#include "log.h" + +#include <SDL2/SDL.h> SDL_Event ev; Interconnect *inter; +CPU *cpu; +FILE *fp_debug; -int WINDOW_STATE; - -void -keyboard(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed) +static void +frame(void) { - if (key == KB_KEY_ESCAPE) - exit(EXIT_FAILURE); - if (key == KB_KEY_A) - fprintf(stderr, "The value of OFFSET is: %08X", inter->cdrom->status & 3); + int c; + + for (c = 0; c < 1e5; c++) CPU_run_next_instruction(cpu); + + while(SDL_PollEvent(&ev) != 0) { + switch(ev.type) { + case SDL_QUIT: + SDL_Quit(); + exit(1); + case SDL_KEYDOWN: + if (ev.key.keysym.sym == SDLK_q) { + SDL_Quit(); + exit(1); + } + } + } } -int -main(int argc, char **argv) +void +init(void) { - int c; REN *ren; - CPU *cpu; - //lua_State *L = luaL_newstate(); - //luaL_openlibs(L); + SDL_Init(SDL_INIT_VIDEO); - //SDL_Init(SDL_INIT_VIDEO); - //SDL_SetRenderDrawColor(ren->renderer, 0xff, 0xff, 0xff, 0xff); - //SDL_RenderClear(ren->renderer); - //SDL_RenderPresent(ren->renderer); + /* Logging */ + log_set_quiet(1); + fp_debug = fopen("log_debug.txt", "w+"); + log_add_fp(fp_debug, LOG_DEBUG); inter = new_interconnect(); cpu = new_cpu(inter); ren = inter->gpu->ren; - mfb_set_keyboard_callback(inter->gpu->ren->window, keyboard); + SDL_SetRenderDrawColor(ren->renderer, 0xff, 0xff, 0xff, 0xff); + SDL_RenderClear(ren->renderer); + SDL_RenderPresent(ren->renderer); - while(1) { - //while(mfb_wait_sync(inter->gpu->ren->window)) { - /* Because it's too slow to run events every instr */ - for (c = 0; c < 1e5; c++) CPU_run_next_instruction(cpu); - - if (WINDOW_STATE < 0) - break; - - - //while(SDL_PollEvent(&ev) != 0) { - // switch(ev.type) { - // case SDL_QUIT: - // SDL_Quit(); - // exit(1); - // case SDL_KEYDOWN: - // if (ev.key.keysym.sym == SDLK_q) { - // SDL_Quit(); - // exit(1); - // } - // } - //} - } +} + +void +kill(void) +{ free(inter->bios->data); free(inter->bios); @@ -76,10 +73,22 @@ main(int argc, char **argv) free(inter->cdrom); free(inter); free(cpu); + fclose(fp_debug); + + SDL_Quit(); +} + +int +main(void) +{ + + init(); - //lua_close(L); + while(1) { + frame(); + } - //SDL_Quit(); + kill(); return 0; } diff --git a/src/mem.c b/src/mem.c @@ -4,6 +4,7 @@ #include "mem.h" #include "types.h" #include "util.h" +#include "log.h" Channel* CHANNEL_new(void) @@ -111,7 +112,7 @@ CHANNEL_transfer_size(Channel* ch, u32 *res) *res = (u32)((u32)ch->block_size * (u32)(ch->block_count)); return 1; case SYNC_LINKED_LIST: return 0; - default: fprintf(stderr, "UNREACHABLE"); exit(EXIT_FAILURE); + default: log_fatal("UNREACHABLE"); exit(EXIT_FAILURE); } } diff --git a/src/sr.c b/src/sr.c @@ -7,9 +7,7 @@ #include "types.h" #include "sr.h" -#include "defs.h" #include "util.h" -#include "MiniFB.h" ivec2 POSITION_from_gp0(u32 val) @@ -67,68 +65,64 @@ REN_FB_set(REN* ren, i32 x, i32 y, u8 r, u8 g, u8 b) { if (!ren->fb || x < 0 || y < 0 || x >= W || y >= H) return; - // Clamp color values r = r > 255 ? 255 : r; g = g > 255 ? 255 : g; b = b > 255 ? 255 : b; - // Direct write instead of memcpy fb = ren->fb + (x + y * W); *fb = r | (g << 8) | (b << 16); } -//C* -//FB_get(i32 x, i32 y) -//{ -// void* c = (!fb.data || x<0 || y<0 || x>=W || y>=H) ? (void*)0 : (void*)(C_new(fb.data[(x+y*W)])); -// return (C*)c; -//} - REN* REN_new(void) { REN* ren; ren = (REN*)malloc(sizeof(REN)); - ren->window = mfb_open_ex("my display", 800, 600, WF_RESIZABLE | WF_ALWAYS_ON_TOP); - //ren->window = SDL_CreateWindow("Ultimecia", 400 , 300, WIN_W, WIN_H, SDL_WINDOW_HIDDEN); - //ren->renderer = SDL_CreateRenderer(ren->window, -1, 0); - //ren->tex = SDL_CreateTexture(ren->renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STREAMING, W, H); - ren->verts = (ivec2*)malloc(sizeof(ivec2) * 10000); // Single allocation with larger size - ren->colors = (C*)malloc(sizeof(C) * 10000); // Single allocation with larger size + ren->window = SDL_CreateWindow("Ultimecia", 400 , 300, WIN_W, WIN_H, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); + ren->renderer = SDL_CreateRenderer(ren->window, -1, 0); + ren->tex = SDL_CreateTexture(ren->renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STREAMING, W, H); + ren->verts = (ivec2*)malloc(sizeof(ivec2) * 10000); + ren->colors = (C*)malloc(sizeof(C) * 10000); ren->fb = (u32*)malloc(W*H*sizeof(u32)); memset(ren->fb, 0, (u32)(W*H)*sizeof(u32)); ren->nvertices = 0; + return ren; } -// Draw a scanline with color interpolation void draw_scanline(REN* ren, int y, int x1, C c1, int x2, C c2) { + int dx, x; + float r, g, b, dr, dg, db; if (x1 > x2) { swap_int(&x1, &x2); swap_color(&c1, &c2); } - int dx = x2 - x1; + dx = x2 - x1; if (dx == 0) return; - float dr = (c2.r - c1.r) / (float)dx; - float dg = (c2.g - c1.g) / (float)dx; - float db = (c2.b - c1.b) / (float)dx; + dr = (c2.r - c1.r) / (float)dx; + dg = (c2.g - c1.g) / (float)dx; + db = (c2.b - c1.b) / (float)dx; - float r = c1.r, g = c1.g, b = c1.b; - for (int x = x1; x <= x2; x++) { + r = c1.r, g = c1.g, b = c1.b; + for (x = x1; x <= x2; x++) { REN_FB_set(ren, x, y, (u8)r,(u8)g,(u8)b); r += dr; g += dg; b += db; } } -// Rasterize triangle with color interpolation void REN_triangle(REN* ren, ivec2 verts[3], C colors[3]) { - // Check for degenerate triangles + + i32 y, dx01, dx02, dx12, dr01, dr02, dg02, db02, dg01, db01, dr12, dg12, db12, xL, xR; + u32 rL, rR, gL, bL, gR, bR; + + + /* Check for degenerate triangles */ if (verts[0].x == verts[1].x && verts[0].y == verts[1].y) return; if (verts[1].x == verts[2].x && verts[1].y == verts[2].y) return; if (verts[2].x == verts[0].x && verts[2].y == verts[0].y) return; @@ -138,40 +132,40 @@ REN_triangle(REN* ren, ivec2 verts[3], C colors[3]) if (verts[0].y > verts[2].y) { swap_vec2(&verts[0], &verts[2]); swap_color(&colors[0], &colors[2]); } if (verts[1].y > verts[2].y) { swap_vec2(&verts[1], &verts[2]); swap_color(&colors[1], &colors[2]); } - // Calculate edge slopes using fixed-point arithmetic - i32 dx01 = ((verts[1].x - verts[0].x) << 16) / (verts[1].y - verts[0].y + 1); - i32 dx02 = ((verts[2].x - verts[0].x) << 16) / (verts[2].y - verts[0].y + 1); - i32 dx12 = ((verts[2].x - verts[1].x) << 16) / (verts[2].y - verts[1].y + 1); - - // Calculate color slopes using fixed-point arithmetic - i32 dr01 = ((colors[1].r - colors[0].r) << 16) / (verts[1].y - verts[0].y + 1); - i32 dg01 = ((colors[1].g - colors[0].g) << 16) / (verts[1].y - verts[0].y + 1); - i32 db01 = ((colors[1].b - colors[0].b) << 16) / (verts[1].y - verts[0].y + 1); - - i32 dr02 = ((colors[2].r - colors[0].r) << 16) / (verts[2].y - verts[0].y + 1); - i32 dg02 = ((colors[2].g - colors[0].g) << 16) / (verts[2].y - verts[0].y + 1); - i32 db02 = ((colors[2].b - colors[0].b) << 16) / (verts[2].y - verts[0].y + 1); - - i32 dr12 = ((colors[2].r - colors[1].r) << 16) / (verts[2].y - verts[1].y + 1); - i32 dg12 = ((colors[2].g - colors[1].g) << 16) / (verts[2].y - verts[1].y + 1); - i32 db12 = ((colors[2].b - colors[1].b) << 16) / (verts[2].y - verts[1].y + 1); - - // Rasterize top part - i32 xL = verts[0].x << 16; - u32 rL = colors[0].r << 16, gL = colors[0].g << 16, bL = colors[0].b << 16; - i32 xR = verts[0].x << 16; - u32 rR = colors[0].r << 16, gR = colors[0].g << 16, bR = colors[0].b << 16; - - for (i32 y = verts[0].y; y < verts[1].y; y++) { - draw_scanline(ren, y, xL >> 16, (C){(u8)(rL >> 16), (u8)(gL >> 16), (u8)(bL >> 16)}, - xR >> 16, (C){(u8)(rR >> 16), (u8)(gR >> 16), (u8)(bR >> 16)}); + /* Calculate edge slopes using fixed-point arithmetic */ + dx01 = ((verts[1].x - verts[0].x) << 16) / (verts[1].y - verts[0].y + 1); + dx02 = ((verts[2].x - verts[0].x) << 16) / (verts[2].y - verts[0].y + 1); + dx12 = ((verts[2].x - verts[1].x) << 16) / (verts[2].y - verts[1].y + 1); + + /* Calculate color slopes using fixed-point arithmetic */ + dr01 = ((colors[1].r - colors[0].r) << 16) / (verts[1].y - verts[0].y + 1); + dg01 = ((colors[1].g - colors[0].g) << 16) / (verts[1].y - verts[0].y + 1); + db01 = ((colors[1].b - colors[0].b) << 16) / (verts[1].y - verts[0].y + 1); + + dr02 = ((colors[2].r - colors[0].r) << 16) / (verts[2].y - verts[0].y + 1); + dg02 = ((colors[2].g - colors[0].g) << 16) / (verts[2].y - verts[0].y + 1); + db02 = ((colors[2].b - colors[0].b) << 16) / (verts[2].y - verts[0].y + 1); + + dr12 = ((colors[2].r - colors[1].r) << 16) / (verts[2].y - verts[1].y + 1); + dg12 = ((colors[2].g - colors[1].g) << 16) / (verts[2].y - verts[1].y + 1); + db12 = ((colors[2].b - colors[1].b) << 16) / (verts[2].y - verts[1].y + 1); + + /* Rasterize top part */ + xL = verts[0].x << 16; + rL = colors[0].r << 16, gL = colors[0].g << 16, bL = colors[0].b << 16; + xR = verts[0].x << 16; + rR = colors[0].r << 16, gR = colors[0].g << 16, bR = colors[0].b << 16; + + for (y = verts[0].y; y < verts[1].y; y++) { + draw_scanline(ren, y, xL >> 16, (C){(rL >> 16), (gL >> 16), (bL >> 16)}, + xR >> 16, (C){(rR >> 16), (gR >> 16), (bR >> 16)}); xL += dx01; rL += dr01; gL += dg01; bL += db01; xR += dx02; rR += dr02; gR += dg02; bR += db02; } - // Rasterize bottom part + /* Rasterize bottom part */ xL = verts[1].x << 16, rL = colors[1].r << 16, gL = colors[1].g << 16, bL = colors[1].b << 16; - for (i32 y = verts[1].y; y < verts[2].y; y++) { + for (y = verts[1].y; y < verts[2].y; y++) { draw_scanline(ren, y, xL >> 16, (C){(u8)(rL >> 16), (u8)(gL >> 16), (u8)(bL >> 16)}, xR >> 16, (C){(u8)(rR >> 16), (u8)(gR >> 16), (u8)(bR >> 16)}); xL += dx12; rL += dr12; gL += dg12; bL += db12; @@ -200,7 +194,7 @@ REN_push_quad(REN* ren, ivec2 verts[4], C colors[4]) REN_flush(ren); - // First triangle: vertices 0,1,2 + /* First triangle: vertices 0,1,2 */ for (i = 0; i < 3; i++) { ren->verts[ren->nvertices] = verts[i]; ren->colors[ren->nvertices] = colors[i]; @@ -218,25 +212,22 @@ REN_flush(REN* ren) { u32 i; for (i = 0; i < ren->nvertices; i += 3) REN_triangle(ren, ren->verts + i, ren->colors + i); - ren->nvertices = 0; // Reset buffer for next frame + ren->nvertices = 0; } void REN_draw(REN* ren) { - //SDL_UpdateTexture(ren->tex, NULL, ren->fb, W * sizeof(u32)); - //SDL_RenderCopy(ren->renderer, ren->tex, NULL, NULL); - mfb_update_ex(ren->window, ren->fb, W , H); + SDL_UpdateTexture(ren->tex, NULL, ren->fb, W * sizeof(u32)); + SDL_RenderCopy(ren->renderer, ren->tex, NULL, NULL); } void REN_display(REN* ren) { - // Flush any remaining vertices before displaying - if (ren->nvertices > 0) { + if (ren->nvertices > 0) REN_flush(ren); - } REN_draw(ren); - //SDL_RenderPresent(ren->renderer); + SDL_RenderPresent(ren->renderer); } diff --git a/src/sr.h b/src/sr.h @@ -21,8 +21,7 @@ typedef struct { double x, y, z; } vec3f; enum mop {ADD, SUB, MUL, DIV}; typedef struct _RENDERER { - struct mfb_window* window; - //SDL_Window* window; + SDL_Window* window; SDL_Texture* tex; SDL_Renderer* renderer; ivec2* verts; diff --git a/src/time.c b/src/time.c @@ -0,0 +1,6 @@ +/* Time is endless */ + +#include "types.h" +typedef struct { + u32 time; +} time_t;