Compare commits

..

6 Commits

Author SHA1 Message Date
JailDoctor 35afea447b - [CHG] Més neteja de basura
- [FIX] Intentant arreglar un "pop" que fa el só al inici, he descobert que no fa falta més sincronització que la del àudio!
- [CHG] De fet, ara en compte de fer 20 cicles de cpu cada iteració, faig un cicle per iteració i nomes refresque events cada 125ms. No detecte canvis, pero seria molt més net. A vore que tal.
- [NEW] Comence la classe directora "gameboy"
2026-06-04 23:00:14 +02:00
JailDoctor 8ba37d215a - [CHG] Pasada la gestió de tags de memòria de sm83 a debug
- [CHG] Netejada l'interficie debug->sm83
- [CHG] Un poc més de neteja de codi en general
2026-06-04 19:07:30 +02:00
JailDoctor ed2c014c7e - [CHG] Gestió de interrupcions pasada a "mem" (futur "bus")
- [CHG] Reorganitzacions i neteja de codi
- [NEW] Constants del espai io en la seua pròpia capçalera
- [NEW] Comentaris en algunes parts menys obvies del codi
- [CHG] Alguns defines passats a constexpr
- [CHG] display::init() no feia més que cridar a display::reinit(). Concretats els dos en display::init()
- [ONGOING] Passant la responsabilitat de tornar el foco a la finestra principal (que estaba en el mòdul debug) al gestor de finestres.
2026-06-04 13:44:50 +02:00
JailDoctor 2fe0ce6152 - [CHG] Tot el codi mogut a la carpeta "source" 2026-06-03 18:07:16 +02:00
JailDoctor 88a02d49f7 - [CHG] Separat mòdul "gbscreen" en mòduls "ppu" i "display"
- [CHG] Constants de interrupcions tretes a la seua propia capçalera
- [CHG] Renombrat mòdul APU a apu
2026-06-03 12:10:42 +02:00
JailDoctor 816b12e3b8 - [FIX] Més neteja: llevats els refresh de gbscreen que no s'usaven 2026-06-03 11:37:46 +02:00
36 changed files with 757 additions and 813 deletions
+3 -3
View File
@@ -1,5 +1,5 @@
compile: compile:
g++ -g *.cpp -lSDL2 -o gb g++ -g source/*.cpp -lSDL2 -o gb
run: compile run: compile
./gb tetris.gb ./gb tetris.gb
@@ -11,7 +11,7 @@ debug1: compile
gdb -ex run gb gdb -ex run gb
release: release:
g++ -O3 *.cpp -lSDL2 -o gb g++ -O3 source/*.cpp -lSDL2 -o gb
profile: profile:
g++ -g *.cpp -lSDL2 -o gb -pg g++ -g source/*.cpp -lSDL2 -o gb -pg
-25
View File
@@ -1,25 +0,0 @@
#pragma once
#include <SDL2/SDL.h>
namespace gbscreen
{
void init(int mode);
void reinit();
void focus();
void refresh(const uint32_t dt, const bool full=false);
void fullrefresh();
void debugrefresh();
void redraw(const bool present=true);
void present();
void setTitle(const char* title);
void incZoom();
void decZoom();
void toggleFullscreen();
const bool getFullscreen();
void toggleFullRefresh();
const bool getFullRefresh();
//SDL_Renderer *getrenderer();
}
+1 -1
View File
@@ -2,5 +2,5 @@
cppflags = -g cppflags = -g
libs = -lSDL2 libs = -lSDL2
executable = gb executable = gb
sourcepath = . sourcepath = source
buildpath = build buildpath = build
+7 -6
View File
@@ -1,7 +1,7 @@
#include "APU.h" #include "apu.h"
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
//#include "audio_viewer.h"
namespace APU namespace apu
{ {
#define SAMPLING_FREQ 44100 #define SAMPLING_FREQ 44100
#define AUDIO_BUFFER_SIZE 2048 #define AUDIO_BUFFER_SIZE 2048
@@ -10,9 +10,7 @@ namespace APU
SDL_AudioDeviceID sdlAudioDevice; SDL_AudioDeviceID sdlAudioDevice;
uint8_t sound_buffer[AUDIO_BUFFER_SIZE]; uint8_t sound_buffer[AUDIO_BUFFER_SIZE];
uint16_t sound_pos=0; uint16_t sound_pos=0;
uint16_t sound_start=0;
float t_sound = 0.0f; float t_sound = 0.0f;
uint32_t samples_generated=0;
#define CH1 channels[0] #define CH1 channels[0]
#define CH2 channels[1] #define CH2 channels[1]
@@ -87,9 +85,11 @@ namespace APU
void init() void init()
{ {
for (int i=0; i<AUDIO_BUFFER_SIZE; ++i) sound_buffer[i] = 128;
SDL_AudioSpec audioSpec{SAMPLING_FREQ, AUDIO_U8, 1, 0, AUDIO_BUFFER_SIZE, 0, 0, NULL, NULL}; SDL_AudioSpec audioSpec{SAMPLING_FREQ, AUDIO_U8, 1, 0, AUDIO_BUFFER_SIZE, 0, 0, NULL, NULL};
sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0); sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0);
resume(); resume();
SDL_QueueAudio(sdlAudioDevice, sound_buffer, 2000);
} }
void reset() void reset()
@@ -428,7 +428,8 @@ namespace APU
if (sound_pos>=1000) { if (sound_pos>=1000) {
SDL_QueueAudio(sdlAudioDevice, sound_buffer, sound_pos); SDL_QueueAudio(sdlAudioDevice, sound_buffer, sound_pos);
sound_pos = 0; sound_pos = 0;
while (SDL_GetQueuedAudioSize(sdlAudioDevice) > 4096 ) {} while (SDL_GetQueuedAudioSize(sdlAudioDevice) > 4096 ) { SDL_Delay(1); }
} }
} }
} }
+1 -1
View File
@@ -1,7 +1,7 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
namespace APU namespace apu
{ {
uint8_t readRegister(uint16_t address); uint8_t readRegister(uint16_t address);
void writeRegister(uint16_t address, uint8_t value); void writeRegister(uint16_t address, uint8_t value);
+76 -47
View File
@@ -4,11 +4,12 @@
#include "sm83.h" #include "sm83.h"
#include "sm83dis.h" #include "sm83dis.h"
#include "mem.h" #include "mem.h"
#include "APU.h" #include "ppu.h"
#include "apu.h"
//#include "z80analyze.h" //#include "z80analyze.h"
#include "ui.h" #include "ui.h"
#include "ui_window.h" #include "ui_window.h"
#include "gbscreen.h" #include "display.h"
#define RESIZING_NONE 0 #define RESIZING_NONE 0
#define RESIZING_MEMORY 1 #define RESIZING_MEMORY 1
@@ -27,6 +28,8 @@ namespace debug
int con_h = 6; int con_h = 6;
int sym_h = 14; int sym_h = 14;
uint8_t tags[65536];
int resizing_type = RESIZING_MEMORY; int resizing_type = RESIZING_MEMORY;
bool resizing = false; bool resizing = false;
@@ -107,10 +110,9 @@ namespace debug
con_y = win_h - con_h; con_y = win_h - con_h;
sym_h = win_h - sym_y; sym_h = win_h - sym_y;
debug::refresh(); debug::refresh();
gbscreen::redraw();
} else if (e->window.event == SDL_WINDOWEVENT_CLOSE) { } else if (e->window.event == SDL_WINDOWEVENT_CLOSE) {
hide(); hide();
gbscreen::focus(); //display::focus();
} }
} }
if (e->type == SDL_MOUSEWHEEL) { if (e->type == SDL_MOUSEWHEEL) {
@@ -304,10 +306,63 @@ namespace debug
void processCommand(); void processCommand();
uint8_t getTag(uint16_t address)
{
return tags[address];
}
void setTag(uint16_t address, uint8_t value)
{
tags[address] = value;
}
void onInstructionExecute(uint16_t address)
{
uint8_t &tag = tags[address];
if ( !(tag & MEMTAG_IGNORE) ) tag |= MEMTAG_INST;
tag |= (!(tag&MEMTAG_TOUCHED) ? MEMTAG_TREPEAT : MEMTAG_TINST);
setcursor(sm83::getPC());
history::store();
}
void onMemRead(uint16_t address, bool code)
{
if (isbreak(address, 2)) stop();
uint8_t &tag = tags[address];
if ( tag & MEMTAG_IGNORE) return;
if ( code ) {
tag |= MEMTAG_CODE;
} else if ( !(tag & MEMTAG_INST) ) {
tag |= MEMTAG_DATA;
}
}
void onMemWrite(uint16_t address)
{
if (isbreak(address, 4)) stop();
mem_modified[address] = true;
uint8_t &tag = tags[address];
if ( tag & MEMTAG_IGNORE ) return;
if ( !(tag & MEMTAG_INST) ) {
tag |= ( MEMTAG_DATA | MEMTAG_TDATA );
}
}
void init() void init()
{ {
is_debugging = is_paused = false; is_debugging = is_paused = false;
for (int i=0; i<65536; ++i) breakpoints[i]=0; for (int i=0; i<65536; ++i) {
breakpoints[i]=0;
tags[i] = MEMTAG_NONE;
}
if (!cur_df) cur_df = SDL_GetCursor(); if (!cur_df) cur_df = SDL_GetCursor();
if (!cur_ns) cur_ns = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS); if (!cur_ns) cur_ns = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
if (!cur_we) cur_we = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); if (!cur_we) cur_we = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
@@ -350,7 +405,7 @@ namespace debug
void pause() void pause()
{ {
APU::silence(); apu::silence();
is_paused = true; is_paused = true;
breakpoints[sm83::getPC()] &= ~8; breakpoints[sm83::getPC()] &= ~8;
} }
@@ -358,20 +413,19 @@ namespace debug
void stop() void stop()
{ {
//history::gototop(); //history::gototop();
gbscreen::setTitle(" (stopped)"); display::setTitle(" (stopped)");
pause(); pause();
is_debugging = true; is_debugging = true;
show(); show();
gbscreen::redraw(true); display::redraw(true);
//if ( gbscreen::getFullRefresh()) gbscreen::fullrefresh();
} }
void cont() { void cont() {
gbscreen::setTitle(""); display::setTitle("");
is_debugging = is_paused = false; is_debugging = is_paused = false;
refresh(); refresh();
gbscreen::focus(); display::focus();
APU::resume(); apu::resume();
} }
const bool debugging() { return is_debugging; } const bool debugging() { return is_debugging; }
@@ -381,10 +435,9 @@ namespace debug
uint16_t find_previous_opcode(uint16_t pc) uint16_t find_previous_opcode(uint16_t pc)
{ {
pc--; pc--;
uint8_t tag = mem::getTag(pc); if ( !(tags[pc] & (MEMTAG_CODE | MEMTAG_INST) ) ) return pc;
if ( !(tag & (MEMTAG_CODE | MEMTAG_INST) ) ) return pc;
while ( !(mem::getTag(pc) & MEMTAG_INST) ) pc--; while ( !(tags[pc] & MEMTAG_INST) ) pc--;
return pc; return pc;
@@ -410,7 +463,7 @@ namespace debug
void printDissasemblerLine(const uint16_t address, const int line, const bool heuristics=false) void printDissasemblerLine(const uint16_t address, const int line, const bool heuristics=false)
{ {
uint8_t colors[4] = { COLOR_RED, COLOR_CYAN, COLOR_WHITE, COLOR_WHITE}; uint8_t colors[4] = { COLOR_RED, COLOR_CYAN, COLOR_WHITE, COLOR_WHITE};
const uint8_t tag = mem::getTag(address); const uint8_t &tag = tags[address];
if ( !(tag & (MEMTAG_TINST | MEMTAG_TREPEAT)) ) colors[3]=COLOR_GRAY; if ( !(tag & (MEMTAG_TINST | MEMTAG_TREPEAT)) ) colors[3]=COLOR_GRAY;
if ( !(tag & MEMTAG_TOUCHED) ) colors[1]=COLOR_GRAY; if ( !(tag & MEMTAG_TOUCHED) ) colors[1]=COLOR_GRAY;
@@ -428,7 +481,7 @@ namespace debug
const int opcodesize = sm83dis::getOpcodeSize(address); const int opcodesize = sm83dis::getOpcodeSize(address);
for (int i=0; i<opcodesize; ++i) { for (int i=0; i<opcodesize; ++i) {
const uint8_t tag = mem::getTag(address+i); const uint8_t &tag = tags[address+i];
const uint32_t color = !(tag & MEMTAG_KNOWN) ? COLOR_GRAY : (tag & MEMTAG_DATA) ? ( (tag & (MEMTAG_CODE|MEMTAG_INST)) ? COLOR_MAGENTA : COLOR_BLUE ) : COLOR_GREEN; const uint32_t color = !(tag & MEMTAG_KNOWN) ? COLOR_GRAY : (tag & MEMTAG_DATA) ? ( (tag & (MEMTAG_CODE|MEMTAG_INST)) ? COLOR_MAGENTA : COLOR_BLUE ) : COLOR_GREEN;
ui::printrect(19+i*3,line,2,1,color); ui::printrect(19+i*3,line,2,1,color);
} }
@@ -608,7 +661,7 @@ namespace debug
ui::printtxt(1,i, tohex(mem_viewer_cursor, 4), COLOR_CYAN); ui::printtxt(1,i, tohex(mem_viewer_cursor, 4), COLOR_CYAN);
for (int j=0; j<16; ++j) { for (int j=0; j<16; ++j) {
const uint8_t tag = mem::getTag(mem_viewer_cursor); const uint8_t &tag = tags[mem_viewer_cursor];
const uint32_t color = !(tag & MEMTAG_KNOWN) ? COLOR_GRAY : (tag & MEMTAG_DATA) ? ( (tag & (MEMTAG_CODE|MEMTAG_INST)) ? COLOR_MAGENTA : COLOR_BLUE ) : COLOR_GREEN; const uint32_t color = !(tag & MEMTAG_KNOWN) ? COLOR_GRAY : (tag & MEMTAG_DATA) ? ( (tag & (MEMTAG_CODE|MEMTAG_INST)) ? COLOR_MAGENTA : COLOR_BLUE ) : COLOR_GREEN;
ui::printrect(6+j*3,i,2,1,color); ui::printrect(6+j*3,i,2,1,color);
ui::printrect(54+j,i,1,1,color); ui::printrect(54+j,i,1,1,color);
@@ -780,8 +833,8 @@ namespace debug
uint8_t dt = sm83::step(); uint8_t dt = sm83::step();
//zx_tape::update(dt); //zx_tape::update(dt);
//zx_ula::sound_update(dt); //zx_ula::sound_update(dt);
gbscreen::refresh(dt); ppu::refresh(dt);
gbscreen::redraw(); display::redraw();
//z80analyze::refresh(); //z80analyze::refresh();
} else if (strcmp(cmd, "c")==0 || strcmp(cmd, "cont")==0) { } else if (strcmp(cmd, "c")==0 || strcmp(cmd, "cont")==0) {
sm83::step(); sm83::step();
@@ -886,7 +939,7 @@ namespace debug
getcmd(); getcmd();
int address = getnum(cmd); int address = getnum(cmd);
if (address<0 || address>=65536) { sendToConsoleLog("Illegal address"); return; } if (address<0 || address>=65536) { sendToConsoleLog("Illegal address"); return; }
if ( !(mem::getTag(address) & MEMTAG_INST) ) address = find_previous_opcode(address); if ( !(tags[address] & MEMTAG_INST) ) address = find_previous_opcode(address);
debug::setcursor(address); debug::setcursor(address);
} else if (strcmp(cmd, "sym")==0 || strcmp(cmd, "symbol")==0) { } else if (strcmp(cmd, "sym")==0 || strcmp(cmd, "symbol")==0) {
getcmd(); getcmd();
@@ -938,7 +991,7 @@ namespace debug
} else if (strcmp(cmd, "ignore")==0) { } else if (strcmp(cmd, "ignore")==0) {
getcmd(); getcmd();
const int address = getnum(cmd); const int address = getnum(cmd);
mem::setTag(address, mem::getTag(address) | MEMTAG_IGNORE); tags[address] |= MEMTAG_IGNORE;
} else if (strcmp(cmd, "search")==0) { } else if (strcmp(cmd, "search")==0) {
getcmd(); getcmd();
if (strcmp(cmd, "next")==0) { if (strcmp(cmd, "next")==0) {
@@ -979,30 +1032,6 @@ namespace debug
return t; return t;
} }
void setmemmodified(const uint16_t addr)
{
mem_modified[addr] = true;
}
void loadngo(const char* filename, const char* addr)
{
/*
int address = getnum(addr);
if (address<0 || address>65536) { sendToConsoleLog("Illegal offset"); return; }
FILE *f = fopen(filename, "rb");
fseek(f, 0, SEEK_END);
int size = ftell(f);
fseek(f, 0, SEEK_SET);
uint32_t memsize;
uint8_t *memory = mem::getRawPointer(&memsize);
fread(memory+address, size, 1, f);
fclose(f);
sm83::setPC(address);
is_debugging = is_paused = false;
*/
}
void savestate(const char *filename) void savestate(const char *filename)
{ {
uint8_t *regs = sm83::getRegs(); uint8_t *regs = sm83::getRegs();
@@ -1026,7 +1055,7 @@ namespace debug
void setcursor(const uint16_t address) void setcursor(const uint16_t address)
{ {
//if (!debugging()) return; //if (!debugging()) return;
if ( !(mem::getTag(address) & MEMTAG_INST) ) if ( !(tags[address] & MEMTAG_INST) )
cursor = find_previous_opcode(address); cursor = find_previous_opcode(address);
else else
cursor = address; cursor = address;
+20 -3
View File
@@ -3,6 +3,26 @@
namespace debug namespace debug
{ {
#define MEMTAG_NONE 0x00
#define MEMTAG_DATA 0x01
#define MEMTAG_INST 0x02
#define MEMTAG_CODE 0x04
#define MEMTAG_IGNORE 0x08
#define MEMTAG_TDATA 0x10
#define MEMTAG_TINST 0x20
#define MEMTAG_TREPEAT 0x40
#define MEMTAG_MODIFIED 0x80
#define MEMTAG_KNOWN 0x07
#define MEMTAG_TOUCHED 0x70
uint8_t getTag(uint16_t address);
void setTag(uint16_t address, uint8_t value);
void onInstructionExecute(uint16_t address);
void onMemRead(uint16_t address, bool code=false);
void onMemWrite(uint16_t address);
void init(); void init();
void show(); void show();
void focus(); void focus();
@@ -13,7 +33,6 @@ namespace debug
void cont(); void cont();
const bool debugging(); const bool debugging();
const bool paused(); const bool paused();
void setmemmodified(const uint16_t addr);
void refresh(); void refresh();
void sendToConsole(const char* text); void sendToConsole(const char* text);
@@ -29,8 +48,6 @@ namespace debug
void savestate(const char *filename); void savestate(const char *filename);
void loadstate(const char *filename); void loadstate(const char *filename);
void loadngo(const char* filename, const char* addr);
void setcursor(const uint16_t address); void setcursor(const uint16_t address);
void cursorfwd(); void cursorfwd();
void cursorback(); void cursorback();
+207
View File
@@ -0,0 +1,207 @@
#include "display.h"
#include <cstring>
#include "sm83.h"
#include "ppu.h"
#include <SDL2/SDL.h>
#include "ui_window.h"
#include "debug.h"
#include "ui.h"
namespace display
{
uint32_t palette[2][4] = {
{ 0xFFFFFF, 0xAAAAAA, 0x555555, 0x000000 },
{ 0xA0AA05, 0x749527, 0x487F49, 0x2E4326/*0x1D6A6B*/ }
};
SDL_Window *win = nullptr;
SDL_Renderer *ren = nullptr;
SDL_Texture *tex = nullptr;
SDL_Texture *uitex = nullptr;
uint8_t zoom = 3;
uint8_t use_palette=1;
bool fullscreen = false;
int fullscreen_scale = 1;
SDL_Rect dest_rect;
bool eventHandler(SDL_Event *e)
{
if (e->type==SDL_WINDOWEVENT) {
if (e->window.event==SDL_WINDOWEVENT_CLOSE) {
return false;
} else if ((e->window.event==SDL_WINDOWEVENT_SHOWN) || (e->window.event==SDL_WINDOWEVENT_EXPOSED)) {
redraw();
}
}
if (!debug::debugging()) {
if (debug::paused()) {
if (e->type == SDL_KEYDOWN) {
if (e->key.keysym.scancode==SDL_SCANCODE_ESCAPE) {
const uint8_t dt = sm83::step();
debug::cont();
ppu::refresh(dt);
}
}
} else {
if (e->type == SDL_KEYDOWN) {
if (e->key.keysym.scancode==SDL_SCANCODE_ESCAPE) {
debug::pause();
display::redraw();
} else if (e->key.keysym.scancode==SDL_SCANCODE_F1) {
display::decZoom();
} else if (e->key.keysym.scancode==SDL_SCANCODE_F2) {
display::incZoom();
} else if (e->key.keysym.scancode==SDL_SCANCODE_F3) {
display::toggleFullscreen();
} else if (e->key.keysym.scancode==SDL_SCANCODE_Q && e->key.keysym.mod & KMOD_CTRL) {
return false;
}
}
}
}
if (e->type == SDL_MOUSEMOTION) {
SDL_ShowCursor(true);
}
return true;
}
void init()
{
if (win) ui::window::unregisterWindow(SDL_GetWindowID(win));
if (tex) SDL_DestroyTexture(tex);
if (uitex) SDL_DestroyTexture(uitex);
if (ren) SDL_DestroyRenderer(ren);
if (win) SDL_DestroyWindow(win);
const int z = fullscreen ? 1 : zoom;
win = SDL_CreateWindow("Gameboy Screen", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 160*z, 144*z, fullscreen?SDL_WINDOW_FULLSCREEN_DESKTOP:SDL_WINDOW_SHOWN);
ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
tex = SDL_CreateTexture(ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 160, 144);
uitex = ui::createtexture(ren);
ui::window::registerWindow(SDL_GetWindowID(win), eventHandler);
if (fullscreen)
{
int w, h;
SDL_GetWindowSize(win, &w, &h);
fullscreen_scale = h/144;
dest_rect.w = 160 * fullscreen_scale;
dest_rect.h = 144 * fullscreen_scale;
dest_rect.x = (w - dest_rect.w)/2;
dest_rect.y = (h - dest_rect.h)/2;
}
else
{
dest_rect.x = dest_rect.y = 0;
dest_rect.w = 160 * zoom;
dest_rect.h = 144 * zoom;
}
focus();
}
void focus()
{
if (win)
{
SDL_RaiseWindow(win);
redraw();
}
}
void redraw(const bool present)
{
//if (zx_tape::getplaying() && zx_tape::getOption(ZXTAPE_OPTION_FAST_LOAD)) return;
ui::setrenderer(ren, uitex);
const uint8_t *ppu_pixels = ppu::getpixels();
Uint32* pixels;
int pitch;
SDL_LockTexture(tex, NULL, (void**)&pixels, &pitch);
for (int i=0; i<160*144;++i) *(pixels++) = palette[use_palette][ppu_pixels[i]];
SDL_UnlockTexture(tex);
if (fullscreen)
{
SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);
SDL_RenderClear(ren);
}
// Pintem la textura a pantalla
SDL_RenderCopy(ren, tex, NULL, &dest_rect);
// Pintem les ralles dels pixels
if (zoom>2 || fullscreen) {
SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(ren, 160, 170, 5, 96);
const float scale = fullscreen ? fullscreen_scale : zoom;
for (int i=0;i<144;++i) SDL_RenderDrawLine(ren, dest_rect.x, dest_rect.y+i*scale, dest_rect.x+159*scale, dest_rect.y+i*scale);
for (int i=0;i<160;++i) SDL_RenderDrawLine(ren, dest_rect.x+i*scale, dest_rect.y, dest_rect.x+i*scale, dest_rect.y+143*scale);
}
if (present)
SDL_RenderPresent(ren);
else
{
SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(ren, 0, 0, 0, 128);
SDL_Rect rect {0,0,160*zoom,144*zoom};
if (fullscreen) SDL_GetWindowSize(win, &rect.w, &rect.h);
SDL_RenderFillRect(ren, &rect);
}
}
void present()
{
SDL_RenderPresent(ren);
}
void setTitle(const char* title)
{
char tmp[256];
strcpy(tmp, "Gameboy Screen");
strcat(tmp, title);
SDL_SetWindowTitle(win, tmp);
}
void setZoom(const int value)
{
if (fullscreen) return;
if (value < 1) return;
SDL_DisplayMode dm;
SDL_GetCurrentDisplayMode(0, &dm);
if (160*value > dm.w) return;
if (144*value > dm.h) return;
zoom = value;
init();
}
void incZoom()
{
if (fullscreen) return;
setZoom(zoom+1);
}
void decZoom()
{
if (fullscreen) return;
setZoom(zoom-1);
}
void toggleFullscreen()
{
fullscreen = !fullscreen;
init();
}
const bool getFullscreen()
{
return fullscreen;
}
}
+15
View File
@@ -0,0 +1,15 @@
#pragma once
namespace display
{
void init();
void focus();
void redraw(const bool present=true);
void present();
void setTitle(const char* title);
void incZoom();
void decZoom();
void toggleFullscreen();
const bool getFullscreen();
}
+16
View File
@@ -0,0 +1,16 @@
#include "gameboy.h"
gameboy::gameboy(const std::string &rom_file)
{
}
gameboy::~gameboy()
{
}
void gameboy::step()
{
}
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <string>
class gameboy
{
public:
gameboy(const std::string &rom_file);
~gameboy();
void step();
private:
};
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include <stdint.h>
namespace gb
{
namespace interrupts
{
constexpr uint8_t VBLANK = 0x01;
constexpr uint8_t LCD = 0x02;
constexpr uint8_t TIMER = 0x04;
constexpr uint8_t SERIAL = 0x08;
constexpr uint8_t JOYPAD = 0x10;
}
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#define io_interrupts_address 0xff0f
+52 -48
View File
@@ -3,9 +3,10 @@
#include "sm83.h" #include "sm83.h"
#include "mem.h" #include "mem.h"
#include "ppu.h"
#include "sm83dis.h" #include "sm83dis.h"
#include "debug.h" #include "debug.h"
#include "gbscreen.h" #include "display.h"
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <string.h> #include <string.h>
#include "ui.h" #include "ui.h"
@@ -21,31 +22,25 @@ namespace actions
{ {
const uint8_t dt = sm83::step(); const uint8_t dt = sm83::step();
debug::cont(); debug::cont();
gbscreen::refresh(dt); ppu::refresh(dt);
} }
int decZoom(int value) int decZoom(int value)
{ {
gbscreen::decZoom(); display::decZoom();
return 0; return 0;
} }
int incZoom(int value) int incZoom(int value)
{ {
gbscreen::incZoom(); display::incZoom();
return 0; return 0;
} }
int fullscreen(int value) int fullscreen(int value)
{ {
gbscreen::toggleFullscreen(); display::toggleFullscreen();
return gbscreen::getFullscreen(); return display::getFullscreen();
}
int fullrefresh(int value)
{
gbscreen::toggleFullRefresh();
return gbscreen::getFullRefresh();
} }
int showAnalyzer(int value) int showAnalyzer(int value)
@@ -57,13 +52,17 @@ namespace actions
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
// Control de paràmetres
if (argc < 2) { printf("ABORTING: No rom specified.\n"); exit(1); } if (argc < 2) { printf("ABORTING: No rom specified.\n"); exit(1); }
// Velocitat de rellotge
const uint32_t clock = 4194304; const uint32_t clock = 4194304;
const uint32_t update_freq = clock >> 3; const uint32_t update_freq = clock >> 3;
// Inicia SDL
SDL_Init(SDL_INIT_EVERYTHING); SDL_Init(SDL_INIT_EVERYTHING);
// Carrega la rom
FILE *f = fopen(argv[1], "rb"); FILE *f = fopen(argv[1], "rb");
if (!f) { printf("ABORTING: Rom not found.\n"); exit(1); } if (!f) { printf("ABORTING: Rom not found.\n"); exit(1); }
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
@@ -73,14 +72,18 @@ int main(int argc, char *argv[])
fread(buffer, filesize, 1, f); fread(buffer, filesize, 1, f);
fclose(f); fclose(f);
// i mem inicialitza el mbc
mem::init(buffer, filesize); mem::init(buffer, filesize);
// Iniciem tots els sistemes
sm83dis::loadSymbols(); sm83dis::loadSymbols();
sm83::reset(); sm83::reset();
gbscreen::init(0); ppu::init();
display::init();
debug::init(); debug::init();
// Iniciem el menú princpal (ací? perqué? No es de display.h?)
ui::menu::init(); ui::menu::init();
ui::menu::setexitcallback(actions::exitMenu); ui::menu::setexitcallback(actions::exitMenu);
@@ -94,26 +97,21 @@ int main(int argc, char *argv[])
menu = ui::menu::addsubmenu("SCREEN"); menu = ui::menu::addsubmenu("SCREEN");
ui::menu::addoption(menu, "DEC ZOOM", actions::decZoom); ui::menu::addoption(menu, "DEC ZOOM", actions::decZoom);
ui::menu::addoption(menu, "INC ZOOM", actions::incZoom); ui::menu::addoption(menu, "INC ZOOM", actions::incZoom);
ui::menu::addbooloption(menu, "FULLSCREEN", gbscreen::getFullscreen(), actions::fullscreen); ui::menu::addbooloption(menu, "FULLSCREEN", display::getFullscreen(), actions::fullscreen);
ui::menu::addseparator(menu);
ui::menu::addbooloption(menu, "FULL REFRESH", gbscreen::getFullRefresh(), actions::fullrefresh);
menu = ui::menu::addsubmenu("EMULATION"); menu = ui::menu::addsubmenu("EMULATION");
ui::menu::addbooloption(menu, "STOP ON INVALID OP", sm83::getOption(SM83_OPTION_STOP_ON_INVALID), actions::decZoom); ui::menu::addbooloption(menu, "STOP ON INVALID OP", sm83::getOption(SM83_OPTION_STOP_ON_INVALID), actions::decZoom);
ui::menu::addoption(menu, "SHOW ANALYZER", actions::showAnalyzer); ui::menu::addoption(menu, "SHOW ANALYZER", actions::showAnalyzer);
//zx_ula::sound_init();
//debug::stop();
bool should_exit = false; bool should_exit = false;
SDL_Event e; SDL_Event e;
time = SDL_GetTicks(); time = SDL_GetTicks();
t_states = 0; t_states = 0;
uint8_t wait = 125;
while (!should_exit) while (!should_exit)
{ {
if (wait==0) {
while (SDL_PollEvent(&e)) while (SDL_PollEvent(&e))
{ {
bool result = true; bool result = true;
@@ -131,12 +129,12 @@ int main(int argc, char *argv[])
debug::history::gototop(); debug::history::gototop();
const uint8_t dt = sm83::step(); const uint8_t dt = sm83::step();
debug::cont(); debug::cont();
gbscreen::refresh(dt); ppu::refresh(dt);
} }
} else if (e.key.keysym.scancode==SDL_SCANCODE_F8) { } else if (e.key.keysym.scancode==SDL_SCANCODE_F8) {
if (!debug::debugging()) { if (!debug::debugging()) {
debug::stop(); debug::stop();
gbscreen::redraw(); display::redraw();
} else { } else {
debug::show(); debug::show();
} }
@@ -146,9 +144,8 @@ int main(int argc, char *argv[])
debug::history::gototop(); debug::history::gototop();
const uint8_t dt = sm83::step(); const uint8_t dt = sm83::step();
debug::refresh(); debug::refresh();
//gbscreen::fullrefresh(); ppu::refresh(dt);
gbscreen::refresh(dt); display::redraw();
gbscreen::redraw();
//z80analyze::refresh(); //z80analyze::refresh();
} }
} else if (e.key.keysym.scancode==SDL_SCANCODE_F11) { } else if (e.key.keysym.scancode==SDL_SCANCODE_F11) {
@@ -157,8 +154,8 @@ int main(int argc, char *argv[])
debug::history::gototop(); debug::history::gototop();
const uint8_t dt = debug::next(); const uint8_t dt = debug::next();
debug::refresh(); debug::refresh();
gbscreen::refresh(dt); ppu::refresh(dt);
gbscreen::redraw(); display::redraw();
//z80analyze::refresh(); //z80analyze::refresh();
} }
} else if (e.key.keysym.scancode==SDL_SCANCODE_F12) { } else if (e.key.keysym.scancode==SDL_SCANCODE_F12) {
@@ -167,8 +164,8 @@ int main(int argc, char *argv[])
debug::history::gototop(); debug::history::gototop();
const uint8_t dt = debug::stepout(); const uint8_t dt = debug::stepout();
debug::refresh(); debug::refresh();
gbscreen::refresh(dt); ppu::refresh(dt);
gbscreen::redraw(); display::redraw();
//z80analyze::refresh(); //z80analyze::refresh();
} }
} }
@@ -179,41 +176,48 @@ int main(int argc, char *argv[])
if (!result) if (!result)
should_exit = true; break; should_exit = true; break;
} }
}
if (!debug::debugging() && !debug::paused()) { if (!debug::debugging() && !debug::paused()) {
bool fastload=false; // En cada pas de bucle fem 10 pasos de la CPU, sino s'ofega
//for (int i=0;i<20;++i) {
// En cada bucle fem 10 pasos de la CPU, sino s'ofega
for (int i=0;i<20;++i) {
if (debug::isbreak(sm83::getPC(), 9)) { if (debug::isbreak(sm83::getPC(), 9)) {
debug::stop(); debug::stop();
gbscreen::redraw(); display::redraw();
break; break;
} else { } else {
uint8_t dt = sm83::step(); uint8_t dt = sm83::step();
t_states += dt; t_states += dt;
//zx_ula::sound_update(dt); ppu::refresh(dt);
gbscreen::refresh(dt);
if (debug::debugging()) break; if (debug::debugging()) break;
} }
} //}
if (t_states>=update_freq) // Sincronització:
{ // la frequència del rellotge diu quants t_states pot executar per segon.
while (SDL_GetTicks()<(time+125)) {} // update_freq es la freq del rellotge / 8. Per tant, el nombre de t_states que
t_states -= update_freq; // pot executar cada 125 ms. Ací comprobem si ja havem executat eixe nombre
time = SDL_GetTicks(); // de t_states i, si ho havem fet, esperem fins que passen 125ms des de l'ultima
//z80analyze::refresh(); // vegada que ho comprobarem.
} //if (t_states>=update_freq)
//z80analyze::refresh(true); //{
// while (SDL_GetTicks()<(time+125)) {}
// t_states -= update_freq;
// time = SDL_GetTicks();
//}
} else if (!debug::debugging() && debug::paused()) { } else if (!debug::debugging() && debug::paused()) {
gbscreen::redraw(false); display::redraw(false);
ui::menu::show(); ui::menu::show();
gbscreen::present(); display::present();
} }
if (wait == 0) {
ui::setClicked(false); ui::setClicked(false);
wait = 125;
} else {
wait--;
}
} }
return 0; return 0;
View File
View File
View File
View File
View File
+11 -19
View File
@@ -3,8 +3,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include "APU.h" #include "apu.h"
#include "io_constants.h"
#include "mbc_none.h" #include "mbc_none.h"
#include "mbc1.h" #include "mbc1.h"
#include "mbc3.h" #include "mbc3.h"
@@ -28,8 +28,6 @@ namespace mem
uint8_t wram[8192]; uint8_t wram[8192];
uint8_t hram[512]; uint8_t hram[512];
uint8_t tags[65536];
char *title = nullptr; char *title = nullptr;
uint8_t mapper_type = 0; uint8_t mapper_type = 0;
uint32_t rom_size = 0; uint32_t rom_size = 0;
@@ -86,7 +84,7 @@ namespace mem
break; break;
}; };
APU::init(); apu::init();
} }
void reset() void reset()
@@ -102,10 +100,9 @@ namespace mem
for (int i=0; i<8192; ++i) { vram[i] = 0; } for (int i=0; i<8192; ++i) { vram[i] = 0; }
for (int i=0; i<8192; ++i) { wram[i] = 0; } for (int i=0; i<8192; ++i) { wram[i] = 0; }
for (int i=0; i<512; ++i) { hram[i] = 0; } for (int i=0; i<512; ++i) { hram[i] = 0; }
for (int i=0; i<65536; ++i) { tags[i] = MEMTAG_NONE; }
resetMbc(); resetMbc();
APU::reset(); apu::reset();
} }
uint8_t getKeypad(uint8_t value) uint8_t getKeypad(uint8_t value)
@@ -144,7 +141,7 @@ namespace mem
} else { } else {
if (address==0xFF00) { if (address==0xFF00) {
hram[address - 0XFE00] = getKeypad(hram[address - 0XFE00]); hram[address - 0XFE00] = getKeypad(hram[address - 0XFE00]);
} else if (address>=0xFF10 && address<=0xFF3F) { return APU::readRegister(address); } } else if (address>=0xFF10 && address<=0xFF3F) { return apu::readRegister(address); }
return hram[address - 0XFE00]; return hram[address - 0XFE00];
} }
} }
@@ -174,7 +171,7 @@ namespace mem
sm83::processInterrupts(); sm83::processInterrupts();
return; return;
} else if (address>=0xFF10 && address<=0xFF3F) { // APU } else if (address>=0xFF10 && address<=0xFF3F) { // APU
APU::writeRegister(address, value); apu::writeRegister(address, value);
return; return;
} else if ( (address==0xFF46) ) { // OAM DMA } else if ( (address==0xFF46) ) { // OAM DMA
mem::init_dma_transfer(value); mem::init_dma_transfer(value);
@@ -183,14 +180,9 @@ namespace mem
} }
} }
uint8_t getTag(uint16_t address) void requestInterrupt(uint8_t type)
{ {
return tags[address]; mem::writeMem(io_interrupts_address, mem::readMem(io_interrupts_address) | type);
}
void setTag(uint16_t address, uint8_t value)
{
tags[address] = value;
} }
void saveState(FILE* f) void saveState(FILE* f)
@@ -235,7 +227,7 @@ namespace mem
div_counter -= 256; div_counter -= 256;
bool bitset = DIV&0x10; bool bitset = DIV&0x10;
DIV++; DIV++;
if (bitset && !(DIV&0x10)) APU::incDIVAPU(); if (bitset && !(DIV&0x10)) apu::incDIVAPU();
} }
// Timer // Timer
@@ -248,14 +240,14 @@ namespace mem
TIMA++; TIMA++;
else { else {
TIMA = TMA; TIMA = TMA;
sm83::interrupt(INTERRUPT_TIMER); mem::requestInterrupt(gb::interrupts::TIMER);
} }
} }
} }
// APU // APU
APU::update(dt); apu::update(dt);
// OAM DMA // OAM DMA
if (dma_pos<160) { if (dma_pos<160) {
+1 -16
View File
@@ -3,19 +3,6 @@
#include <stdio.h> #include <stdio.h>
namespace mem namespace mem
{ {
#define MEMTAG_NONE 0x00
#define MEMTAG_DATA 0x01
#define MEMTAG_INST 0x02
#define MEMTAG_CODE 0x04
#define MEMTAG_IGNORE 0x08
#define MEMTAG_TDATA 0x10
#define MEMTAG_TINST 0x20
#define MEMTAG_TREPEAT 0x40
#define MEMTAG_MODIFIED 0x80
#define MEMTAG_KNOWN 0x07
#define MEMTAG_TOUCHED 0x70
#define MBC_NONE 0 #define MBC_NONE 0
#define MBC1 1 #define MBC1 1
#define MBC2 2 #define MBC2 2
@@ -29,9 +16,7 @@ namespace mem
uint8_t readMem(uint16_t address); uint8_t readMem(uint16_t address);
void writeMem(uint16_t address, uint8_t value); void writeMem(uint16_t address, uint8_t value);
void requestInterrupt(uint8_t type);
uint8_t getTag(uint16_t address);
void setTag(uint16_t address, uint8_t value);
void saveState(FILE* f); void saveState(FILE* f);
void loadState(FILE* f); void loadState(FILE* f);
+16 -256
View File
@@ -1,46 +1,22 @@
#include "gbscreen.h" #include "ppu.h"
#include <cstring>
#include "sm83.h"
#include "mem.h" #include "mem.h"
#include "audio_viewer.h" #include "interrupts.h"
//#include "zx_ula.h" #include "display.h"
#include <SDL2/SDL.h>
#include "ui_window.h"
#include "debug.h"
#include "ui.h"
namespace gbscreen namespace ppu
{ {
struct oam_entry_t struct oam_entry_t
{ {
uint8_t y, x, tile, attr; uint8_t y, x, tile, attr;
}; };
uint32_t palette[2][4] = {
{ 0xFFFFFF, 0xAAAAAA, 0x555555, 0x000000 },
{ 0xA0AA05, 0x749527, 0x487F49, 0x2E4326/*0x1D6A6B*/ }
};
SDL_Window *win = nullptr;
SDL_Renderer *ren = nullptr;
SDL_Texture *tex = nullptr;
SDL_Texture *uitex = nullptr;
uint32_t t_states_total = 70224; uint32_t t_states_total = 70224;
uint32_t t_states_per_scanline = 456; uint32_t t_states_per_scanline = 456;
uint32_t vsync_lines = 10; uint32_t vsync_lines = 10;
uint8_t zoom = 3;
uint8_t use_palette=1;
bool fullscreen = false;
bool full_refresh = true;
int fullscreen_scale = 1;
SDL_Rect dest_rect;
//uint32_t time=0;
uint32_t t_screen = 0; uint32_t t_screen = 0;
uint8_t gb_pixels[160*144]; uint8_t pixels[160*144];
uint16_t dots_in_scanline = 0; uint16_t dots_in_scanline = 0;
uint8_t line_buffer[160]; uint8_t line_buffer[160];
@@ -69,88 +45,10 @@ namespace gbscreen
#define WY (*_WY) #define WY (*_WY)
#define WX (*_WX) #define WX (*_WX)
#define IF 0xff0f
bool last_interrupt_lcd_state = false; bool last_interrupt_lcd_state = false;
bool eventHandler(SDL_Event *e) void init()
{ {
if (e->type==SDL_WINDOWEVENT) {
if (e->window.event==SDL_WINDOWEVENT_CLOSE) {
return false;
} else if ((e->window.event==SDL_WINDOWEVENT_SHOWN) || (e->window.event==SDL_WINDOWEVENT_EXPOSED)) {
redraw();
}
}
if (!debug::debugging()) {
if (debug::paused()) {
if (e->type == SDL_KEYDOWN) {
if (e->key.keysym.scancode==SDL_SCANCODE_ESCAPE) {
const uint8_t dt = sm83::step();
debug::cont();
gbscreen::refresh(dt);
}
}
} else {
if (e->type == SDL_KEYDOWN) {
if (e->key.keysym.scancode==SDL_SCANCODE_ESCAPE) {
debug::pause();
gbscreen::redraw();
} else if (e->key.keysym.scancode==SDL_SCANCODE_F1) {
gbscreen::decZoom();
} else if (e->key.keysym.scancode==SDL_SCANCODE_F2) {
gbscreen::incZoom();
} else if (e->key.keysym.scancode==SDL_SCANCODE_F3) {
gbscreen::toggleFullscreen();
} else if (e->key.keysym.scancode==SDL_SCANCODE_F6) {
//zx_tape::play();
} else if (e->key.keysym.scancode==SDL_SCANCODE_F7) {
//zx_tape::rewind();
} else if (e->key.keysym.scancode==SDL_SCANCODE_Q && e->key.keysym.mod & KMOD_CTRL) {
return false;
}
}
}
}
if (e->type == SDL_MOUSEMOTION) {
SDL_ShowCursor(true);
}
return true;
}
void reinit()
{
if (win) ui::window::unregisterWindow(SDL_GetWindowID(win));
if (tex) SDL_DestroyTexture(tex);
if (uitex) SDL_DestroyTexture(uitex);
if (ren) SDL_DestroyRenderer(ren);
if (win) SDL_DestroyWindow(win);
const int z = fullscreen ? 1 : zoom;
win = SDL_CreateWindow("Gameboy Screen", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 160*z, 144*z, fullscreen?SDL_WINDOW_FULLSCREEN_DESKTOP:SDL_WINDOW_SHOWN);
ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
tex = SDL_CreateTexture(ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 160, 144);
uitex = ui::createtexture(ren);
ui::window::registerWindow(SDL_GetWindowID(win), eventHandler);
if (fullscreen)
{
int w, h;
SDL_GetWindowSize(win, &w, &h);
fullscreen_scale = h/144;
dest_rect.w = 160 * fullscreen_scale;
dest_rect.h = 144 * fullscreen_scale;
dest_rect.x = (w - dest_rect.w)/2;
dest_rect.y = (h - dest_rect.h)/2;
}
else
{
dest_rect.x = dest_rect.y = 0;
dest_rect.w = 160 * zoom;
dest_rect.h = 144 * zoom;
}
_LCDC = mem::rawHram(0xff40); _LCDC = mem::rawHram(0xff40);
_STAT = mem::rawHram(0xff41); _STAT = mem::rawHram(0xff41);
_SCY = mem::rawHram(0xff42); _SCY = mem::rawHram(0xff42);
@@ -164,22 +62,6 @@ namespace gbscreen
oam = (oam_entry_t*)mem::rawHram(0xfe00); oam = (oam_entry_t*)mem::rawHram(0xfe00);
vram = mem::rawVram(); vram = mem::rawVram();
focus();
}
void init(int mode)
{
reinit();
}
void focus()
{
if (win)
{
SDL_RaiseWindow(win);
redraw();
}
} }
void fill_line_buffer_bkg() void fill_line_buffer_bkg()
@@ -324,13 +206,11 @@ namespace gbscreen
if ( (STAT&0x3)==3) { if ( (STAT&0x3)==3) {
uint16_t current_pixel = dots_in_scanline-80; uint16_t current_pixel = dots_in_scanline-80;
if (current_pixel<160) { if (current_pixel<160) {
//uint8_t pixel = gb_pixels[current_pixel+LY*160]; pixels[current_pixel+LY*160] = line_buffer[current_pixel];
gb_pixels[current_pixel+LY*160] = line_buffer[current_pixel];// > line_buffer[current_pixel] ? pixel-1 : line_buffer[current_pixel];
} }
} }
// gestió de en quin dot i linea estem, i tot el que ha de passar // gestió de en quin dot i linea estem, i tot el que ha de passar
//uint8_t interrupts = 0x00;
bool current_interrupt_lcd_state = false; bool current_interrupt_lcd_state = false;
dots_in_scanline++; dots_in_scanline++;
if ( (dots_in_scanline==80) && (LY<144) ) if ( (dots_in_scanline==80) && (LY<144) )
@@ -340,7 +220,7 @@ namespace gbscreen
else if ( (dots_in_scanline==252) && (LY<144) ) else if ( (dots_in_scanline==252) && (LY<144) )
{ {
STAT = (STAT & 0xFC); // Set mode 0 STAT = (STAT & 0xFC); // Set mode 0
if (STAT&0x08) current_interrupt_lcd_state = true; // interrupts |= INTERRUPT_LCD; if (STAT&0x08) current_interrupt_lcd_state = true;
} }
else if (dots_in_scanline==456) else if (dots_in_scanline==456)
{ {
@@ -350,17 +230,16 @@ namespace gbscreen
if (LY==144) if (LY==144)
{ {
// Set vblank interrupt // Set vblank interrupt
mem::writeMem(IF, mem::readMem(IF) | INTERRUPT_VBLANK); mem::requestInterrupt(gb::interrupts::VBLANK);
STAT = (STAT & 0xFC) | 0x01; // Set mode 1 STAT = (STAT & 0xFC) | 0x01; // Set mode 1
//interrupts |= INTERRUPT_VBLANK; if (STAT&0x10) current_interrupt_lcd_state = true;
if (STAT&0x10) current_interrupt_lcd_state = true; //interrupts |= INTERRUPT_LCD;
} }
else else
{ {
if (LY<144) if (LY<144)
{ {
STAT = (STAT & 0xFC) | 0x02; // Set mode 2 STAT = (STAT & 0xFC) | 0x02; // Set mode 2
if (STAT&0x20) current_interrupt_lcd_state = true; // interrupts |= INTERRUPT_LCD; if (STAT&0x20) current_interrupt_lcd_state = true;
fill_line_buffer_bkg(); fill_line_buffer_bkg();
fill_line_buffer_win(); fill_line_buffer_win();
fill_line_buffer_obj(); fill_line_buffer_obj();
@@ -369,7 +248,7 @@ namespace gbscreen
if (LY==LYC) if (LY==LYC)
{ {
STAT = (STAT & 0xFB) | 0x04; STAT = (STAT & 0xFB) | 0x04;
if (STAT&0x40) current_interrupt_lcd_state = true; // interrupts |= INTERRUPT_LCD; if (STAT&0x40) current_interrupt_lcd_state = true;
} }
else else
{ {
@@ -379,8 +258,7 @@ namespace gbscreen
if (!last_interrupt_lcd_state && current_interrupt_lcd_state) if (!last_interrupt_lcd_state && current_interrupt_lcd_state)
{ {
mem::writeMem(IF, mem::readMem(IF) | INTERRUPT_LCD); mem::requestInterrupt(gb::interrupts::LCD);
//sm83::interrupt(interrupts);
} }
last_interrupt_lcd_state = current_interrupt_lcd_state; last_interrupt_lcd_state = current_interrupt_lcd_state;
@@ -388,131 +266,13 @@ namespace gbscreen
if (t_screen>=t_states_total) if (t_screen>=t_states_total)
{ {
t_screen-=t_states_total; t_screen-=t_states_total;
redraw(); display::redraw();
} }
} }
} }
void fullrefresh() const uint8_t *getpixels()
{ {
uint32_t tmp = t_screen; return pixels;
t_screen = 0;
refresh(t_states_total, true);
t_screen = tmp;
} }
void debugrefresh(const uint32_t dt)
{
/*if (full_refresh) fullrefresh(); else*/ refresh(dt);
redraw();
}
void redraw(const bool present)
{
//if (zx_tape::getplaying() && zx_tape::getOption(ZXTAPE_OPTION_FAST_LOAD)) return;
ui::setrenderer(ren, uitex);
Uint32* pixels;
int pitch;
SDL_LockTexture(tex, NULL, (void**)&pixels, &pitch);
for (int i=0; i<160*144;++i) *(pixels++) = palette[use_palette][gb_pixels[i]];
SDL_UnlockTexture(tex);
if (fullscreen)
{
SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);
SDL_RenderClear(ren);
}
// Pintem la textura a pantalla
SDL_RenderCopy(ren, tex, NULL, &dest_rect);
// Pintem les ralles dels pixels
if (zoom>2 || fullscreen) {
SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(ren, 160, 170, 5, 96);
const float scale = fullscreen ? fullscreen_scale : zoom;
for (int i=0;i<144;++i) SDL_RenderDrawLine(ren, dest_rect.x, dest_rect.y+i*scale, dest_rect.x+159*scale, dest_rect.y+i*scale);
for (int i=0;i<160;++i) SDL_RenderDrawLine(ren, dest_rect.x+i*scale, dest_rect.y, dest_rect.x+i*scale, dest_rect.y+143*scale);
}
if (present)
SDL_RenderPresent(ren);
else
{
SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(ren, 0, 0, 0, 128);
SDL_Rect rect {0,0,160*zoom,144*zoom};
if (fullscreen) SDL_GetWindowSize(win, &rect.w, &rect.h);
SDL_RenderFillRect(ren, &rect);
}
//audio_viewer::refresh();
}
void present()
{
SDL_RenderPresent(ren);
}
void setTitle(const char* title)
{
char tmp[256];
strcpy(tmp, "Gameboy Screen");
strcat(tmp, title);
SDL_SetWindowTitle(win, tmp);
}
void setZoom(const int value)
{
if (fullscreen) return;
if (value < 1) return;
SDL_DisplayMode dm;
SDL_GetCurrentDisplayMode(0, &dm);
if (160*value > dm.w) return;
if (144*value > dm.h) return;
zoom = value;
reinit();
}
void incZoom()
{
if (fullscreen) return;
setZoom(zoom+1);
}
void decZoom()
{
if (fullscreen) return;
setZoom(zoom-1);
}
void toggleFullscreen()
{
fullscreen = !fullscreen;
reinit();
}
const bool getFullscreen()
{
return fullscreen;
}
void toggleFullRefresh()
{
full_refresh = !full_refresh;
}
const bool getFullRefresh()
{
return full_refresh;
}
//SDL_Renderer *getrenderer()
//{
// return ren;
//}
} }
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include <stdint.h>
namespace ppu
{
void init();
void refresh(const uint32_t dt, const bool full=false);
const uint8_t *getpixels();
}
+17 -108
View File
@@ -46,10 +46,6 @@ namespace sm83
uint8_t *_rIME = &regs[12]; uint8_t *_rIME = &regs[12];
bool halted = false;
bool exit_from_halt = false;
int pending_ei = 0;
#define rA (*_rA) #define rA (*_rA)
#define rF (*_rF) #define rF (*_rF)
#define rB (*_rB) #define rB (*_rB)
@@ -71,41 +67,26 @@ namespace sm83
#define EX(a,b) {auto temp=a;a=b;b=temp;} #define EX(a,b) {auto temp=a;a=b;b=temp;}
bool reading_m1 = false; bool halted = false;
bool exit_from_halt = false;
int pending_ei = 0;
uint8_t READ_MEM_8(const uint16_t addr, const bool code=false) uint8_t READ_MEM_8(const uint16_t addr, const bool code=false)
{ {
if (debug::isbreak(addr, 2)) debug::stop();
t+=4; t+=4;
debug::onMemRead(addr, code);
const uint8_t tag = mem::getTag(addr);
if ( !(tag&MEMTAG_IGNORE) ) {
if (!code) {
if ( tag & MEMTAG_INST ) {
} else {
mem::setTag(addr, tag | MEMTAG_DATA);
}
} else {
if ( (reading_m1) && ( tag & MEMTAG_DATA ) ) {
}
}
}
reading_m1 = false;
return mem::readMem(addr); return mem::readMem(addr);
} }
uint8_t READ_MEM_8() uint8_t READ_MEM_8()
{ {
const uint8_t data = READ_MEM_8(rPC, true); const uint8_t data = READ_MEM_8(rPC, true);
const uint8_t tag = mem::getTag(rPC);
if ( !(tag & MEMTAG_IGNORE) ) mem::setTag(rPC, tag | MEMTAG_CODE);
rPC++; rPC++;
return data; return data;
} }
uint8_t READ_M1() uint8_t READ_M1()
{ {
reading_m1 = true;
return READ_MEM_8(); return READ_MEM_8();
} }
@@ -125,19 +106,7 @@ namespace sm83
{ {
t+=4; t+=4;
mem::writeMem(addr, value); mem::writeMem(addr, value);
debug::onMemWrite(addr);
if (debug::isbreak(addr, 4)) debug::stop();
debug::setmemmodified(addr);
const uint8_t tag = mem::getTag(addr);
if ( !(tag & MEMTAG_IGNORE) ) {
if ( tag & MEMTAG_INST ) {
//printf("WARNING! WRITING DATA OVER CODE!!! $%4X\n", addr);
//z80debug::stop();
} else {
mem::setTag(addr, tag | MEMTAG_DATA | MEMTAG_TDATA);
}
}
return value; return value;
} }
@@ -502,19 +471,6 @@ namespace sm83
{ {
POP(_rPC); POP(_rPC);
if (cond != cUnconditional) t += 4; if (cond != cUnconditional) t += 4;
/*if (options[Z80_OPTION_BREAK_ON_RET]) {
if (calls_stacked>0) {
calls_stacked--;
printf("RET: calls still stacked: %i\n", calls_stacked);
} else {
printf("RET: BREAK\n");
options[Z80_OPTION_BREAK_ON_RET] = false;
z80debug::setcursor(rPC);
z80debug::history::store();
z80debug::stop();
}
}*/
} }
} }
@@ -534,28 +490,22 @@ namespace sm83
DI(); DI();
PUSH(rPC); PUSH(rPC);
//t+=20; //t+=20;
if (*IF & INTERRUPT_VBLANK) { if (*IF & gb::interrupts::VBLANK) {
rPC = 0x40; rPC = 0x40;
*IF = *IF & ~INTERRUPT_VBLANK; *IF = *IF & ~gb::interrupts::VBLANK;
} else if (*IF & INTERRUPT_LCD) { } else if (*IF & gb::interrupts::LCD) {
rPC = 0x48; rPC = 0x48;
*IF = *IF & ~INTERRUPT_LCD; *IF = *IF & ~gb::interrupts::LCD;
} else if (*IF & INTERRUPT_TIMER) { } else if (*IF & gb::interrupts::TIMER) {
rPC = 0x50; rPC = 0x50;
*IF = *IF & ~INTERRUPT_TIMER; *IF = *IF & ~gb::interrupts::TIMER;
} else if (*IF & INTERRUPT_SERIAL) { } else if (*IF & gb::interrupts::SERIAL) {
rPC = 0x58; rPC = 0x58;
*IF = *IF & ~INTERRUPT_SERIAL; *IF = *IF & ~gb::interrupts::SERIAL;
} else if (*IF & INTERRUPT_JOYPAD) { } else if (*IF & gb::interrupts::JOYPAD) {
rPC = 0x60; rPC = 0x60;
*IF = *IF & ~INTERRUPT_JOYPAD; *IF = *IF & ~gb::interrupts::JOYPAD;
} }
/*if (options[Z80_OPTION_BREAK_ON_INTERRUPT]) {
printf("Break on interrupt! 0x%2x, PC: 0x%2x\n", address, rPC);
z80debug::setcursor(rPC);
z80debug::history::store();
z80debug::stop();
}*/
} }
void RETI() void RETI()
@@ -602,13 +552,7 @@ namespace sm83
halted = true; halted = true;
} }
} }
/*if (exit_from_halt) {
exit_from_halt = false;
halted = false;
} else {*/
//printf("HALT\n");
rPC--; rPC--;
//}
} }
void STOP() void STOP()
@@ -616,15 +560,6 @@ namespace sm83
HALT(); HALT();
} }
void interrupt(uint8_t type)
{
const uint8_t IE = mem::readMem(0xffff);
//if (IE & type) exit_from_halt = true;
const uint8_t IF = mem::readMem(0xff0f);
mem::writeMem(0xff0f, IF | type);
//processInterrupts();
}
static inline const uint8_t RLC(const uint8_t v) static inline const uint8_t RLC(const uint8_t v)
{ {
const uint8_t res = (v>>7) | (v<<1); const uint8_t res = (v>>7) | (v<<1);
@@ -739,21 +674,9 @@ namespace sm83
rHL--; rHL--;
} }
void INVALID(uint8_t opcode)
{
printf("INVALID OPCODE AT: %04x\n", current_opcode_address);
//if (options[Z80_OPTION_STOP_ON_INVALID]) z80debug::stop();
}
bool opcode_ignored = false;
void IgnoreOpcode() void IgnoreOpcode()
{ {
debug::setcursor(rPC);
debug::history::store();
debug::stop(); debug::stop();
/*t-=3;
rPC--;
opcode_ignored=true;*/
} }
void reset() void reset()
@@ -779,21 +702,11 @@ namespace sm83
uint32_t step() uint32_t step()
{ {
do {
opcode_ignored = false;
current_opcode_address = rPC; current_opcode_address = rPC;
t = 0; t = 0;
const uint8_t opcode = READ_M1(); const uint8_t opcode = READ_M1();
uint8_t tag = mem::getTag(current_opcode_address);
if ( !(tag & MEMTAG_IGNORE) )
tag = tag | MEMTAG_INST;
mem::setTag(current_opcode_address, tag | (!(tag&MEMTAG_TOUCHED) ? MEMTAG_TREPEAT : MEMTAG_TINST) );
uint16_t tmp; uint16_t tmp;
//if (opcode!=0xED && opcode!=0xCB && opcode!=0xDD && opcode!=0xFD ) z80debug::useOpcode(opcode, 0);
switch (opcode) switch (opcode)
{ {
case 0x00: /* NOP */ break; case 0x00: /* NOP */ break;
@@ -1069,14 +982,12 @@ namespace sm83
case 0xFF: RST(0x38); break; case 0xFF: RST(0x38); break;
} }
} while (opcode_ignored);
if (pending_ei==2) { pending_ei=0; actualEI(); } if (pending_ei==2) { pending_ei=0; actualEI(); }
if (pending_ei==1) pending_ei=2; if (pending_ei==1) pending_ei=2;
debug::setcursor(rPC); debug::onInstructionExecute(current_opcode_address);
debug::history::store();
mem::update_mapped(t); mem::update_mapped(t);
return t; return t;
} }
@@ -1084,8 +995,6 @@ namespace sm83
{ {
const uint8_t opcode = READ_M1(); const uint8_t opcode = READ_M1();
//z80debug::useOpcode(opcode, 2);
switch (opcode) switch (opcode)
{ {
case 0x00: rB = RLC(rB); break; case 0x00: rB = RLC(rB); break;
+1 -7
View File
@@ -1,15 +1,10 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include "interrupts.h"
namespace sm83 namespace sm83
{ {
#define INTERRUPT_VBLANK 0x01
#define INTERRUPT_LCD 0x02
#define INTERRUPT_TIMER 0x04
#define INTERRUPT_SERIAL 0x08
#define INTERRUPT_JOYPAD 0x10
#define SM83_OPTION_STOP_ON_INVALID 0 #define SM83_OPTION_STOP_ON_INVALID 0
#define SM83_OPTION_BREAK_ON_INTERRUPT 1 #define SM83_OPTION_BREAK_ON_INTERRUPT 1
#define SM83_OPTION_BREAK_ON_RET 2 #define SM83_OPTION_BREAK_ON_RET 2
@@ -21,7 +16,6 @@ namespace sm83
uint32_t getClock(); uint32_t getClock();
void processInterrupts(); void processInterrupts();
void interrupt(uint8_t type);
uint32_t step(); uint32_t step();
-1
View File
@@ -1,5 +1,4 @@
#include "sm83dis.h" #include "sm83dis.h"
#include "sm83.h"
#include "mem.h" #include "mem.h"
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
View File
View File
View File
View File
View File
View File