Compare commits
6 Commits
9d3204daba
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b330059cb | |||
| f8ce706839 | |||
| 454cce304f | |||
| dffbb9c741 | |||
| dc6b3b6a78 | |||
| 1b343e4dcc |
31
APU.cpp
31
APU.cpp
@@ -1,11 +1,10 @@
|
||||
#include "APU.h"
|
||||
#include <SDL2/SDL.h>
|
||||
//#include "audio_viewer.h"
|
||||
|
||||
namespace APU
|
||||
{
|
||||
#define SAMPLING_FREQ 44100
|
||||
#define AUDIO_BUFFER_SIZE 8192
|
||||
#define AUDIO_BUFFER_SIZE 2048
|
||||
const float cycles_per_sample = 4194304.0f / SAMPLING_FREQ;
|
||||
|
||||
SDL_AudioDeviceID sdlAudioDevice;
|
||||
@@ -78,14 +77,6 @@ namespace APU
|
||||
uint16_t LFSR = 0;
|
||||
|
||||
|
||||
void audioCallback(void * userdata, uint8_t * stream, int len)
|
||||
{
|
||||
for (int i=0;i<len;++i)
|
||||
{
|
||||
stream[i] = sound_buffer[(sound_start++)&(AUDIO_BUFFER_SIZE-1)];
|
||||
}
|
||||
}
|
||||
|
||||
void silence()
|
||||
{
|
||||
SDL_PauseAudioDevice(sdlAudioDevice, 1);
|
||||
@@ -98,7 +89,7 @@ namespace APU
|
||||
|
||||
void init()
|
||||
{
|
||||
SDL_AudioSpec audioSpec{SAMPLING_FREQ, AUDIO_U8, 1, 0, AUDIO_BUFFER_SIZE>>1, 0, 0, &audioCallback, 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);
|
||||
resume();
|
||||
//samples_time=SDL_GetTicks();
|
||||
@@ -147,7 +138,7 @@ namespace APU
|
||||
CH1.enabled = true;
|
||||
CH1.length_timer=NR11&0x3f;
|
||||
CH1.period_divider = NR13 | ((NR14 &0x7)<<8);
|
||||
// envelope timer is reset
|
||||
CH1.envelope_sweep_timer = 0;
|
||||
CH1.volume = NR12>>4;
|
||||
// sweep does several things (check documentation)
|
||||
}
|
||||
@@ -157,7 +148,7 @@ namespace APU
|
||||
CH2.enabled = true;
|
||||
CH2.length_timer=NR21&0x3f;
|
||||
CH2.period_divider = NR23 | ((NR24 &0x7)<<8);
|
||||
// envelope timer is reset
|
||||
CH2.envelope_sweep_timer = 0;
|
||||
CH2.volume = NR22>>4;
|
||||
// sweep does several things (check documentation)
|
||||
}
|
||||
@@ -167,7 +158,7 @@ namespace APU
|
||||
CH3.enabled = true;
|
||||
CH3.length_timer=NR31;
|
||||
CH3.period_divider = NR33 | ((NR34 &0x7)<<8);
|
||||
// envelope timer is reset
|
||||
CH3.envelope_sweep_timer = 0;
|
||||
CH3.volume = (NR32>>5)&0x3;
|
||||
// sweep does several things (check documentation)
|
||||
}
|
||||
@@ -178,7 +169,7 @@ namespace APU
|
||||
CH4.length_timer=NR41&0x3f;
|
||||
uint8_t clock_shift = ((NR43&0xf0)>>4);// if (clock_shift==0) clock_shift = 1;
|
||||
CH4.period_divider = clock_shift << (NR43&0x07);
|
||||
// envelope timer is reset
|
||||
CH4.envelope_sweep_timer = 0;
|
||||
CH4.volume = NR42>>4;
|
||||
// sweep does several things (check documentation)
|
||||
}
|
||||
@@ -403,8 +394,8 @@ namespace APU
|
||||
}
|
||||
}
|
||||
dotsCH4 += dt;
|
||||
while (dotsCH4>=16) {
|
||||
dotsCH4 -= 16;
|
||||
while (dotsCH4>=64) {
|
||||
dotsCH4 -= 64;
|
||||
CH4.period_divider--;
|
||||
if (CH4.period_divider==0) {
|
||||
uint8_t clock_shift = ((NR43&0xf0)>>3); if (clock_shift==0) clock_shift = 1;
|
||||
@@ -438,7 +429,11 @@ namespace APU
|
||||
|
||||
sound_buffer[(sound_pos++)&(AUDIO_BUFFER_SIZE-1)] = sample;
|
||||
//audio_viewer::addsample(sample);
|
||||
//if (ear) last_1 = sound_pos;
|
||||
}
|
||||
if (sound_pos>=1000) {
|
||||
SDL_QueueAudio(sdlAudioDevice, sound_buffer, sound_pos);
|
||||
sound_pos = 0;
|
||||
while (SDL_GetQueuedAudioSize(sdlAudioDevice) > 4096 ) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Makefile
3
Makefile
@@ -12,3 +12,6 @@ debug1: compile
|
||||
|
||||
release:
|
||||
g++ -O3 *.cpp -lSDL2 -o gb
|
||||
|
||||
profile:
|
||||
g++ -g *.cpp -lSDL2 -o gb -pg
|
||||
|
||||
155
gbscreen.cpp
155
gbscreen.cpp
@@ -11,9 +11,14 @@
|
||||
|
||||
namespace gbscreen
|
||||
{
|
||||
uint32_t palette[4] = {
|
||||
//0xFFFFFF, 0xFF0000, 0x00FF00, 0x0000FF
|
||||
0xFFFFFF, 0xAAAAAA, 0x555555, 0x000000
|
||||
struct oam_entry_t
|
||||
{
|
||||
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;
|
||||
@@ -24,7 +29,8 @@ namespace gbscreen
|
||||
uint32_t t_states_per_scanline = 456;
|
||||
uint32_t vsync_lines = 10;
|
||||
|
||||
uint8_t zoom = 2;
|
||||
uint8_t zoom = 3;
|
||||
uint8_t use_palette=1;
|
||||
bool fullscreen = false;
|
||||
bool full_refresh = true;
|
||||
int fullscreen_scale = 1;
|
||||
@@ -35,11 +41,35 @@ namespace gbscreen
|
||||
uint32_t t_screen = 0;
|
||||
|
||||
uint8_t gb_pixels[160*144];
|
||||
uint8_t *ptr_pixel = gb_pixels;
|
||||
|
||||
uint16_t dots_in_scanline = 0;
|
||||
uint8_t line_buffer[160];
|
||||
|
||||
uint8_t *_LCDC = nullptr;
|
||||
uint8_t *_STAT = nullptr;
|
||||
uint8_t *_SCY = nullptr;
|
||||
uint8_t *_SCX = nullptr;
|
||||
uint8_t *_LY = nullptr;
|
||||
uint8_t *_LYC = nullptr;
|
||||
uint8_t *_BGP = nullptr;
|
||||
uint8_t *_WY = nullptr;
|
||||
uint8_t *_WX = nullptr;
|
||||
uint8_t *OBP = nullptr;
|
||||
|
||||
oam_entry_t *oam = nullptr;
|
||||
uint8_t *vram = nullptr;
|
||||
|
||||
#define LCDC (*_LCDC)
|
||||
#define STAT (*_STAT)
|
||||
#define SCY (*_SCY)
|
||||
#define SCX (*_SCX)
|
||||
#define LY (*_LY)
|
||||
#define LYC (*_LYC)
|
||||
#define BGP (*_BGP)
|
||||
#define WY (*_WY)
|
||||
#define WX (*_WX)
|
||||
|
||||
|
||||
bool eventHandler(SDL_Event *e)
|
||||
{
|
||||
if (e->type==SDL_WINDOWEVENT) {
|
||||
@@ -73,6 +103,8 @@ namespace gbscreen
|
||||
//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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,6 +149,20 @@ namespace gbscreen
|
||||
dest_rect.h = 144 * zoom;
|
||||
}
|
||||
|
||||
_LCDC = mem::rawHram(0xff40);
|
||||
_STAT = mem::rawHram(0xff41);
|
||||
_SCY = mem::rawHram(0xff42);
|
||||
_SCX = mem::rawHram(0xff43);
|
||||
_LY = mem::rawHram(0xff44);
|
||||
_LYC = mem::rawHram(0xff45);
|
||||
_BGP = mem::rawHram(0xff47);
|
||||
_WY = mem::rawHram(0xff4a);
|
||||
_WX = mem::rawHram(0xff4b);
|
||||
OBP = mem::rawHram(0xff48);
|
||||
|
||||
oam = (oam_entry_t*)mem::rawHram(0xfe00);
|
||||
vram = mem::rawVram();
|
||||
|
||||
focus();
|
||||
}
|
||||
|
||||
@@ -133,34 +179,30 @@ namespace gbscreen
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
|
||||
void fill_line_buffer_bkg(uint8_t LY)
|
||||
|
||||
void fill_line_buffer_bkg()
|
||||
{
|
||||
const uint8_t LCDC = mem::readMem(0xff40);
|
||||
if ((LCDC & 0x1) == 0) {
|
||||
for (int i=0; i<160; ++i) line_buffer[i]=0;
|
||||
return;
|
||||
}
|
||||
const uint8_t SCY = mem::readMem(0xff42);
|
||||
const uint8_t SCX = mem::readMem(0xff43);
|
||||
const uint8_t BGP = mem::readMem(0xff47);
|
||||
const uint16_t ty = uint8_t(SCY+LY) >> 3;
|
||||
const uint8_t ly = uint8_t(SCY+LY) & 0x7;
|
||||
uint16_t tx = SCX >> 3;
|
||||
uint8_t ox = SCX & 0x7;
|
||||
|
||||
uint16_t base_tilemap_address = LCDC&0x8 ? 0x9c00 : 0x9800;
|
||||
uint16_t base_tilemap_address = LCDC&0x8 ? 0x1c00 : 0x1800;
|
||||
|
||||
int pi = 0;
|
||||
while(true) {
|
||||
uint16_t tilemap_address = base_tilemap_address + tx + (ty<<5);
|
||||
uint16_t tile = mem::readMem(tilemap_address);
|
||||
uint16_t base_tile_address = 0x8000;
|
||||
if ( ((LCDC&0x10)==0) && (tile<128) ) base_tile_address = 0x9000;
|
||||
uint16_t tile = vram[tilemap_address];
|
||||
uint16_t base_tile_address = 0x0000;
|
||||
if ( ((LCDC&0x10)==0) && (tile<128) ) base_tile_address = 0x1000;
|
||||
uint16_t tile_address = base_tile_address + (tile<<4) + (ly*2);
|
||||
|
||||
uint8_t a = mem::readMem(tile_address);
|
||||
uint8_t b = mem::readMem(tile_address+1);
|
||||
uint8_t a = vram[tile_address];
|
||||
uint8_t b = vram[tile_address+1];
|
||||
for (int i=0; i<8; ++i) {
|
||||
if (ox==0) {
|
||||
uint8_t index = (a&0x80 ? 1 : 0) + (b&0x80 ? 2 : 0 );
|
||||
@@ -175,31 +217,27 @@ namespace gbscreen
|
||||
}
|
||||
}
|
||||
|
||||
void fill_line_buffer_win(uint8_t LY)
|
||||
void fill_line_buffer_win()
|
||||
{
|
||||
const uint8_t LCDC = mem::readMem(0xff40);
|
||||
if ((LCDC & 0x21) != 0x21) return;
|
||||
const uint8_t WY = mem::readMem(0xff4a);
|
||||
if (LY<WY) return;
|
||||
const uint8_t WX = mem::readMem(0xff4b);
|
||||
const uint8_t BGP = mem::readMem(0xff47);
|
||||
const uint16_t ty = uint8_t(LY-WY) >> 3;
|
||||
const uint8_t ly = uint8_t(LY-WY) & 0x7;
|
||||
uint8_t ox = WX<7 ? 7-WX : 0;
|
||||
uint16_t tx = 0;
|
||||
|
||||
uint16_t base_tilemap_address = LCDC&0x40 ? 0x9c00 : 0x9800;
|
||||
uint16_t base_tilemap_address = LCDC&0x40 ? 0x1c00 : 0x1800;
|
||||
|
||||
int pi = WX<7 ? 0 : WX-7;
|
||||
while(true) {
|
||||
uint16_t tilemap_address = base_tilemap_address + tx + (ty<<5);
|
||||
uint16_t tile = mem::readMem(tilemap_address);
|
||||
uint16_t base_tile_address = 0x8000;
|
||||
if ( ((LCDC&0x10)==0) && (tile<128) ) base_tile_address = 0x9000;
|
||||
uint16_t tile = vram[tilemap_address];
|
||||
uint16_t base_tile_address = 0x0000;
|
||||
if ( ((LCDC&0x10)==0) && (tile<128) ) base_tile_address = 0x1000;
|
||||
uint16_t tile_address = base_tile_address + (tile<<4) + (ly*2);
|
||||
|
||||
uint8_t a = mem::readMem(tile_address);
|
||||
uint8_t b = mem::readMem(tile_address+1);
|
||||
uint8_t a = vram[tile_address];
|
||||
uint8_t b = vram[tile_address+1];
|
||||
for (int i=0; i<8; ++i) {
|
||||
if (ox==0) {
|
||||
uint8_t index = (a&0x80 ? 1 : 0) + (b&0x80 ? 2 : 0 );
|
||||
@@ -214,19 +252,10 @@ namespace gbscreen
|
||||
}
|
||||
}
|
||||
|
||||
struct oam_entry_t
|
||||
void fill_line_buffer_obj()
|
||||
{
|
||||
uint8_t y, x, tile, attr;
|
||||
};
|
||||
oam_entry_t *oam = nullptr;
|
||||
|
||||
void fill_line_buffer_obj(uint8_t LY)
|
||||
{
|
||||
const uint8_t LCDC = mem::readMem(0xff40);
|
||||
const uint8_t OBP[2] = { mem::readMem(0xff48), mem::readMem(0xff49) };
|
||||
if ((LCDC & 0x2) == 0) return;
|
||||
|
||||
oam = (oam_entry_t*)mem::rawPtr(0xfe00);
|
||||
const uint8_t height = (LCDC & 0x4) ? 16 : 8;
|
||||
uint8_t obj_list[10] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
|
||||
int num_obj_found=0;
|
||||
@@ -251,10 +280,10 @@ namespace gbscreen
|
||||
|
||||
uint16_t tile = height==8 ? o->tile : o->tile & 0xFE; // si es dos tiles de alt, el primer sempre comença en numero parell
|
||||
uint8_t yflip = o->attr&0x40 ? (height-1)-ly : ly; // està invertit verticalment?
|
||||
uint16_t tile_address = 0x8000 + (tile<<4) + (yflip*2);
|
||||
uint16_t tile_address = 0x0000 + (tile<<4) + (yflip*2);
|
||||
|
||||
uint8_t a = mem::readMem(tile_address);
|
||||
uint8_t b = mem::readMem(tile_address+1);
|
||||
uint8_t a = vram[tile_address];
|
||||
uint8_t b = vram[tile_address+1];
|
||||
|
||||
for (int i=0; i<8; ++i) { // Per a cada pixel de la linea del tile...
|
||||
if (o->x+i>=168) break; // Si ja estem fora de la pantalla per la dreta, eixim del bucle
|
||||
@@ -285,20 +314,16 @@ namespace gbscreen
|
||||
|
||||
void refresh(const uint32_t dt, const bool full)
|
||||
{
|
||||
const uint8_t LCDC = mem::readMem(0xff40);
|
||||
if ((LCDC&0x80)==0) return;
|
||||
|
||||
uint8_t STAT = mem::readMem(0xff41);
|
||||
uint8_t LY = mem::readMem(0xff44);
|
||||
const uint8_t LYC = mem::readMem(0xff45);
|
||||
for (int i=0;i<dt;++i)
|
||||
{
|
||||
// Açò va volcant els pixels del line_buffer en pantalla
|
||||
if ( (STAT&0x3)==3) {
|
||||
uint16_t current_pixel = dots_in_scanline-80;
|
||||
if (current_pixel<160) {
|
||||
//*(ptr_pixel++) = line_buffer[current_pixel];
|
||||
gb_pixels[current_pixel+LY*160] = line_buffer[current_pixel];
|
||||
//uint8_t pixel = gb_pixels[current_pixel+LY*160];
|
||||
gb_pixels[current_pixel+LY*160] = line_buffer[current_pixel];// > line_buffer[current_pixel] ? pixel-1 : line_buffer[current_pixel];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,11 +343,10 @@ namespace gbscreen
|
||||
{
|
||||
dots_in_scanline = 0;
|
||||
LY++;
|
||||
if (LY==154) LY=0;
|
||||
if (LY==144)
|
||||
{
|
||||
STAT = (STAT & 0xFC) | 0x01; // Set mode 1
|
||||
//mem::writeMem(0xff41, STAT);
|
||||
//mem::writeMem(0xff44, LY);
|
||||
interrupts |= INTERRUPT_VBLANK;
|
||||
if (STAT&0x10) interrupts |= INTERRUPT_LCD;
|
||||
}
|
||||
@@ -332,13 +356,9 @@ namespace gbscreen
|
||||
{
|
||||
STAT = (STAT & 0xFC) | 0x02; // Set mode 2
|
||||
if (STAT&0x20) interrupts |= INTERRUPT_LCD;
|
||||
fill_line_buffer_bkg(LY);
|
||||
fill_line_buffer_win(LY);
|
||||
fill_line_buffer_obj(LY);
|
||||
}
|
||||
else if (LY==154)
|
||||
{
|
||||
LY=0;
|
||||
fill_line_buffer_bkg();
|
||||
fill_line_buffer_win();
|
||||
fill_line_buffer_obj();
|
||||
}
|
||||
}
|
||||
if (LY==LYC)
|
||||
@@ -354,32 +374,23 @@ namespace gbscreen
|
||||
|
||||
if (interrupts)
|
||||
{
|
||||
mem::writeMem(0xff41, STAT);
|
||||
mem::writeMem(0xff44, LY);
|
||||
sm83::interrupt(interrupts);
|
||||
}
|
||||
|
||||
t_screen++;
|
||||
if (t_screen>=t_states_total)
|
||||
{
|
||||
t_screen=0;
|
||||
ptr_pixel = gb_pixels;
|
||||
t_screen-=t_states_total;
|
||||
redraw();
|
||||
//if (!full) sm83::interrupt(INTERRUPT_VBLANK);
|
||||
}
|
||||
}
|
||||
mem::writeMem(0xff41, STAT);
|
||||
mem::writeMem(0xff44, LY);
|
||||
}
|
||||
|
||||
void fullrefresh()
|
||||
{
|
||||
uint32_t tmp = t_screen;
|
||||
t_screen = 0;
|
||||
//uint8_t * tmp_ptr = ptr_pixel;
|
||||
//ptr_pixel = gb_pixels;
|
||||
refresh(t_states_total, true);
|
||||
//ptr_pixel = tmp_ptr;
|
||||
t_screen = tmp;
|
||||
}
|
||||
|
||||
@@ -398,7 +409,7 @@ namespace gbscreen
|
||||
Uint32* pixels;
|
||||
int pitch;
|
||||
SDL_LockTexture(tex, NULL, (void**)&pixels, &pitch);
|
||||
for (int i=0; i<160*144;++i) *(pixels++) = palette[gb_pixels[i]];
|
||||
for (int i=0; i<160*144;++i) *(pixels++) = palette[use_palette][gb_pixels[i]];
|
||||
SDL_UnlockTexture(tex);
|
||||
|
||||
if (fullscreen)
|
||||
@@ -410,6 +421,14 @@ namespace gbscreen
|
||||
// Pintem la textura a pantalla
|
||||
SDL_RenderCopy(ren, tex, NULL, &dest_rect);
|
||||
|
||||
// Pintem les ralles dels pixels
|
||||
if (zoom>2) {
|
||||
SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetRenderDrawColor(ren, 160, 170, 5, 96);
|
||||
for (int i=0;i<144;++i) SDL_RenderDrawLine(ren, 0, i*zoom, 159*zoom, i*zoom);
|
||||
for (int i=0;i<160;++i) SDL_RenderDrawLine(ren, i*zoom, 0, i*zoom, 143*zoom);
|
||||
}
|
||||
|
||||
if (present)
|
||||
SDL_RenderPresent(ren);
|
||||
else
|
||||
@@ -420,7 +439,7 @@ namespace gbscreen
|
||||
if (fullscreen) SDL_GetWindowSize(win, &rect.w, &rect.h);
|
||||
SDL_RenderFillRect(ren, &rect);
|
||||
}
|
||||
audio_viewer::refresh();
|
||||
//audio_viewer::refresh();
|
||||
}
|
||||
|
||||
void present()
|
||||
|
||||
19
main.cpp
19
main.cpp
@@ -122,13 +122,13 @@ int main(int argc, char *argv[])
|
||||
bool result = true;
|
||||
|
||||
if (e.type == SDL_QUIT) { should_exit=true; break; }
|
||||
if (e.type == SDL_MOUSEBUTTONDOWN) result = ui::window::sendEvent(e.button.windowID, &e);
|
||||
if (e.type == SDL_MOUSEBUTTONUP) result = ui::window::sendEvent(e.button.windowID, &e);
|
||||
if (e.type == SDL_MOUSEMOTION) result = ui::window::sendEvent(e.motion.windowID, &e);
|
||||
if (e.type == SDL_WINDOWEVENT) result = ui::window::sendEvent(e.window.windowID, &e);
|
||||
if (e.type == SDL_MOUSEWHEEL) result = ui::window::sendEvent(e.wheel.windowID, &e);
|
||||
if (e.type == SDL_TEXTINPUT) result = ui::window::sendEvent(e.text.windowID, &e);
|
||||
if (e.type == SDL_KEYDOWN) {
|
||||
else if (e.type == SDL_MOUSEBUTTONDOWN) result = ui::window::sendEvent(e.button.windowID, &e);
|
||||
else if (e.type == SDL_MOUSEBUTTONUP) result = ui::window::sendEvent(e.button.windowID, &e);
|
||||
else if (e.type == SDL_MOUSEMOTION) result = ui::window::sendEvent(e.motion.windowID, &e);
|
||||
else if (e.type == SDL_WINDOWEVENT) result = ui::window::sendEvent(e.window.windowID, &e);
|
||||
else if (e.type == SDL_MOUSEWHEEL) result = ui::window::sendEvent(e.wheel.windowID, &e);
|
||||
else if (e.type == SDL_TEXTINPUT) result = ui::window::sendEvent(e.text.windowID, &e);
|
||||
else if (e.type == SDL_KEYDOWN) {
|
||||
if (e.key.keysym.scancode==SDL_SCANCODE_F5) {
|
||||
if (debug::debugging()) {
|
||||
debug::history::gototop();
|
||||
@@ -177,8 +177,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
result = ui::window::sendEvent(e.key.windowID, &e);
|
||||
}
|
||||
|
||||
if (e.type == SDL_MOUSEBUTTONUP && e.button.button==1) ui::setClicked(true);
|
||||
else if (e.type == SDL_MOUSEBUTTONUP && e.button.button==1) ui::setClicked(true);
|
||||
|
||||
if (!result)
|
||||
should_exit = true; break;
|
||||
@@ -188,7 +187,7 @@ int main(int argc, char *argv[])
|
||||
bool fastload=false;
|
||||
|
||||
// En cada bucle fem 10 pasos de la CPU, sino s'ofega
|
||||
for (int i=0;i<5;++i) {
|
||||
for (int i=0;i<20;++i) {
|
||||
if (debug::isbreak(sm83::getPC(), 9)) {
|
||||
debug::stop();
|
||||
gbscreen::redraw();
|
||||
|
||||
128
mbc3.cpp
Normal file
128
mbc3.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
#include "mbc3.h"
|
||||
#include "mem.h"
|
||||
#include "sm83.h"
|
||||
#include <stdlib.h>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
namespace mbc3
|
||||
{
|
||||
#define ROM_BANK_SIZE 0x4000
|
||||
#define RAM_BANK_SIZE 0x2000
|
||||
|
||||
uint8_t *rom;
|
||||
uint8_t exram[4 * RAM_BANK_SIZE];
|
||||
|
||||
uint8_t current_rom_bank = 1;
|
||||
uint8_t current_ram_bank = 0;
|
||||
bool ram_enabled = false;
|
||||
bool rtc_mode = false; // false = ROM banking mode, true = RAM banking mode
|
||||
uint8_t rtc_reg = 0;
|
||||
uint8_t rtc_latch = 1;
|
||||
|
||||
uint8_t RTC[5] {0,0,0,0,0};
|
||||
uint8_t RTC_latched[5] {0,0,0,0,0};
|
||||
|
||||
void reset()
|
||||
{
|
||||
for (int i=0; i<4*RAM_BANK_SIZE; ++i) { exram[i] = 0; }
|
||||
}
|
||||
|
||||
void tick()
|
||||
{
|
||||
RTC[0]++;
|
||||
if (RTC[0]==60) {
|
||||
RTC[0] = 0;
|
||||
RTC[1]++;
|
||||
if (RTC[1]==60) {
|
||||
RTC[1] = 0;
|
||||
RTC[2]++;
|
||||
if (RTC[2]==24) {
|
||||
if (RTC[3]==0xff) {
|
||||
RTC[3]=0;
|
||||
if (RTC[4]&0x01) {
|
||||
RTC[4] = RTC[4] & 0xfe;
|
||||
RTC[4] = (RTC[4] & 0x80) ? RTC[4] & 0x7f : RTC[4] | 0x80;
|
||||
} else {
|
||||
RTC[4] = RTC[4] | 0x01;
|
||||
}
|
||||
} else RTC[3]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void latchClock()
|
||||
{
|
||||
for (int i=0; i<5; ++i) RTC_latched[i] = RTC[i];
|
||||
}
|
||||
|
||||
uint8_t readRom(uint16_t address)
|
||||
{
|
||||
if (address < 0x4000) {
|
||||
// ROM Bank 0
|
||||
return rom[address];
|
||||
} else {
|
||||
// Switchable ROM bank
|
||||
uint32_t banked_address = (current_rom_bank * ROM_BANK_SIZE) + (address - 0x4000);
|
||||
return rom[banked_address];
|
||||
}
|
||||
}
|
||||
|
||||
void writeRom(uint16_t address, uint8_t value)
|
||||
{
|
||||
if (address < 0x2000) {
|
||||
// Enable/disable RAM
|
||||
ram_enabled = (value & 0x0F) == 0x0A;
|
||||
} else if (address < 0x4000) {
|
||||
// Select ROM bank
|
||||
if (value == 0) value = 1; // Bank 0 is not allowed
|
||||
current_rom_bank = current_rom_bank = (value & 0x7F);
|
||||
} else if (address < 0x6000) {
|
||||
// Select RAM bank or upper bits of ROM bank
|
||||
if (value<=0x03) {
|
||||
rtc_mode = false;
|
||||
current_ram_bank = value & 0x03; // 2 bits for RAM bank
|
||||
} else if ( (value >= 0x8) && (value <= 0x0c) ) {
|
||||
rtc_mode = true;
|
||||
rtc_reg = value-8;
|
||||
}
|
||||
} else {
|
||||
// Select banking mode
|
||||
if ( (rtc_latch == 0) && (value == 1) ) {
|
||||
latchClock();
|
||||
}
|
||||
rtc_latch = value;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t readRam(uint16_t address)
|
||||
{
|
||||
if (ram_enabled) {
|
||||
if (rtc_mode) {
|
||||
return RTC_latched[rtc_reg];
|
||||
} else {
|
||||
uint32_t banked_address = (current_ram_bank * RAM_BANK_SIZE) + (address - 0xa000);
|
||||
return exram[banked_address];
|
||||
}
|
||||
}
|
||||
return 0xff; // Return open bus value when RAM is disabled
|
||||
}
|
||||
|
||||
void writeRam(uint16_t address, uint8_t value)
|
||||
{
|
||||
if (ram_enabled) {
|
||||
if (rtc_mode) {
|
||||
RTC[rtc_reg] = RTC_latched[rtc_reg] = value;
|
||||
} else {
|
||||
uint32_t banked_address = (current_ram_bank * RAM_BANK_SIZE) + (address - 0xa000);
|
||||
exram[banked_address] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void init(uint8_t *rom, uint32_t rom_size, uint32_t ram_size)
|
||||
{
|
||||
mbc3::rom = rom;
|
||||
reset();
|
||||
}
|
||||
}
|
||||
15
mbc3.h
Normal file
15
mbc3.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mbc3
|
||||
{
|
||||
void init(uint8_t *rom, uint32_t rom_size, uint32_t ram_size);
|
||||
|
||||
void tick();
|
||||
|
||||
void reset();
|
||||
uint8_t readRom(uint16_t address);
|
||||
void writeRom(uint16_t address, uint8_t value);
|
||||
uint8_t readRam(uint16_t address);
|
||||
void writeRam(uint16_t address, uint8_t value);
|
||||
}
|
||||
31
mem.cpp
31
mem.cpp
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "mbc_none.h"
|
||||
#include "mbc1.h"
|
||||
#include "mbc3.h"
|
||||
|
||||
#define DIV hram[0x104] // 0xff04 - 0xfe00
|
||||
#define TIMA hram[0x105] // 0xff05 - 0xfe00
|
||||
@@ -19,6 +20,7 @@ namespace mem
|
||||
void (*writeRom)(uint16_t, uint8_t);
|
||||
uint8_t (*readRam)(uint16_t);
|
||||
void (*writeRam)(uint16_t, uint8_t);
|
||||
void (*tick)(void) = nullptr;;
|
||||
|
||||
uint8_t bootrom[256];
|
||||
uint8_t *rom;
|
||||
@@ -29,8 +31,10 @@ namespace mem
|
||||
uint8_t tags[65536];
|
||||
|
||||
char *title = nullptr;
|
||||
uint8_t mapper_type = 0;
|
||||
uint32_t rom_size = 0;
|
||||
uint32_t ram_size = 0;
|
||||
uint16_t timer = 0;
|
||||
|
||||
uint16_t dma_address = 0;
|
||||
uint8_t dma_pos = 160;
|
||||
@@ -42,7 +46,7 @@ namespace mem
|
||||
void init(uint8_t* rom, const int size)
|
||||
{
|
||||
title = (char*)&rom[0x134];
|
||||
uint8_t mapper_type = rom[0x147];
|
||||
mapper_type = rom[0x147];
|
||||
rom_size = 32768 * (1 << rom[0x148]);
|
||||
int sizes[] = { 0, 0, 8, 32, 128, 64};
|
||||
ram_size = sizes[rom[0x149]] * 1024;
|
||||
@@ -67,6 +71,19 @@ namespace mem
|
||||
mem::readRam = mbc1::readRam;
|
||||
mem::writeRam = mbc1::writeRam;
|
||||
break;
|
||||
case 0x0f:
|
||||
case 0x10:
|
||||
case 0x11:
|
||||
case 0x12:
|
||||
case 0x13:
|
||||
mbc3::init(rom, rom_size, ram_size);
|
||||
mem::resetMbc = mbc3::reset;
|
||||
mem::readRom = mbc3::readRom;
|
||||
mem::writeRom = mbc3::writeRom;
|
||||
mem::readRam = mbc3::readRam;
|
||||
mem::writeRam = mbc3::writeRam;
|
||||
mem::tick = mbc3::tick;
|
||||
break;
|
||||
};
|
||||
|
||||
APU::init();
|
||||
@@ -186,7 +203,12 @@ namespace mem
|
||||
|
||||
}
|
||||
|
||||
uint8_t *rawPtr(uint16_t address)
|
||||
uint8_t *rawVram()
|
||||
{
|
||||
return vram;
|
||||
}
|
||||
|
||||
uint8_t *rawHram(uint16_t address)
|
||||
{
|
||||
return &hram[address-0xfe00];
|
||||
}
|
||||
@@ -202,6 +224,11 @@ namespace mem
|
||||
uint16_t timer_frequencies[4] { 256*4, 4*4, 16*4, 64*4 };
|
||||
void update_mapped(const uint32_t dt)
|
||||
{
|
||||
timer+=dt;
|
||||
if (timer >= 4194304 ) {
|
||||
timer -= 4194304;
|
||||
if (mem::tick) mem::tick();
|
||||
}
|
||||
// DIV Divider register (0xFF04) (val com a timer bàsic)
|
||||
div_counter += dt;
|
||||
if (div_counter>=256) {
|
||||
|
||||
3
mem.h
3
mem.h
@@ -36,7 +36,8 @@ namespace mem
|
||||
void saveState(FILE* f);
|
||||
void loadState(FILE* f);
|
||||
|
||||
uint8_t *rawPtr(uint16_t address);
|
||||
uint8_t *rawVram();
|
||||
uint8_t *rawHram(uint16_t address);
|
||||
|
||||
void init_dma_transfer(uint8_t source);
|
||||
void update_mapped(const uint32_t dt);
|
||||
|
||||
4
sm83.cpp
4
sm83.cpp
@@ -522,8 +522,8 @@ namespace sm83
|
||||
|
||||
void processInterrupts()
|
||||
{
|
||||
uint8_t *IE = mem::rawPtr(0xffff);
|
||||
uint8_t *IF = mem::rawPtr(0xff0f);
|
||||
uint8_t *IE = mem::rawHram(0xffff);
|
||||
uint8_t *IF = mem::rawHram(0xff0f);
|
||||
if ( (*IF & *IE) == 0 ) return;
|
||||
if (halted) {
|
||||
//exit_from_halt = true;
|
||||
|
||||
BIN
supermarioland2.gb
Normal file
BIN
supermarioland2.gb
Normal file
Binary file not shown.
Reference in New Issue
Block a user