Compare commits
20 Commits
f5d89e0b9b
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b330059cb | |||
| f8ce706839 | |||
| 454cce304f | |||
| dffbb9c741 | |||
| dc6b3b6a78 | |||
| 1b343e4dcc | |||
| 9d3204daba | |||
| 144c588012 | |||
| b9de64d113 | |||
| 03631bf235 | |||
| 8fc576cda2 | |||
| 1c0f243d04 | |||
| 91a230ee44 | |||
| ab7b26c5e6 | |||
| a617fec42a | |||
| a64a18d1be | |||
| 974251540d | |||
| 44f4f1a85b | |||
| 7f5760d826 | |||
| 59feaf274f |
439
APU.cpp
Normal file
439
APU.cpp
Normal file
@@ -0,0 +1,439 @@
|
||||
#include "APU.h"
|
||||
#include <SDL2/SDL.h>
|
||||
//#include "audio_viewer.h"
|
||||
namespace APU
|
||||
{
|
||||
#define SAMPLING_FREQ 44100
|
||||
#define AUDIO_BUFFER_SIZE 2048
|
||||
const float cycles_per_sample = 4194304.0f / SAMPLING_FREQ;
|
||||
|
||||
SDL_AudioDeviceID sdlAudioDevice;
|
||||
uint8_t sound_buffer[AUDIO_BUFFER_SIZE];
|
||||
uint16_t sound_pos=0;
|
||||
uint16_t sound_start=0;
|
||||
float t_sound = 0.0f;
|
||||
uint32_t samples_generated=0;
|
||||
uint32_t samples_time =0;
|
||||
uint32_t samples_t=0;
|
||||
|
||||
#define CH1 channels[0]
|
||||
#define CH2 channels[1]
|
||||
#define CH3 channels[2]
|
||||
#define CH4 channels[3]
|
||||
|
||||
#define apu_enabled (NR52&0x80)
|
||||
#define DAC1_enabled ((NR12&0xf8)!=0)
|
||||
#define DAC2_enabled ((NR22&0xf8)!=0)
|
||||
#define DAC3_enabled ((NR30&0x80)!=0)
|
||||
#define DAC4_enabled ((NR42&0xf8)!=0)
|
||||
|
||||
uint8_t duty_cycles[4][8] = {
|
||||
{1, 1, 1, 1, 1, 1, 1, 0},
|
||||
{1, 1, 1, 1, 1, 1, 0, 0},
|
||||
{1, 1, 1, 1, 0, 0, 0, 0},
|
||||
{1, 1, 0, 0, 0, 0, 0, 0},
|
||||
};
|
||||
struct channel_t
|
||||
{
|
||||
bool enabled = false;
|
||||
uint8_t length_timer = 0;
|
||||
bool length_enable = false;
|
||||
uint16_t period_divider = 0;
|
||||
uint8_t duty_cycle=0;
|
||||
uint8_t duty_step = 0;
|
||||
uint8_t volume = 0;
|
||||
uint8_t envelope_sweep_timer=0;
|
||||
};
|
||||
|
||||
channel_t channels[4];
|
||||
uint8_t DIVAPU = 0;
|
||||
|
||||
uint8_t NR10 = 0; // 0xff10 - Sound channel 1 sweep
|
||||
uint8_t NR11 = 0; // 0xff11 - Sound channel 1 length timer & duty cycle
|
||||
uint8_t NR12 = 0; // 0xff12 - Sound channel 1 volume & envelope
|
||||
uint8_t NR13 = 0; // 0xff13 - Sound channel 1 period low
|
||||
uint8_t NR14 = 0; // 0xff14 - Sound channel 1 period high & control
|
||||
// 0xff15 - Not used?
|
||||
uint8_t NR21 = 0; // 0xff16 - Sound channel 2 length timer & duty cycle
|
||||
uint8_t NR22 = 0; // 0xff17 - Sound channel 2 volume & envelope
|
||||
uint8_t NR23 = 0; // 0xff18 - Sound channel 2 period low
|
||||
uint8_t NR24 = 0; // 0xff19 - Sound channel 2 period high & control
|
||||
|
||||
uint8_t NR30 = 0; // 0xff1a - Sound channel 3 DAC enable
|
||||
uint8_t NR31 = 0; // 0xff1b - Sound channel 3 length timer
|
||||
uint8_t NR32 = 0; // 0xff1c - Sound channel 3 output level
|
||||
uint8_t NR33 = 0; // 0xff1d - Sound channel 3 period low
|
||||
uint8_t NR34 = 0; // 0xff1e - Sound channel 3 period high & control
|
||||
// 0xff1f - Not used?
|
||||
uint8_t NR41 = 0; // 0xff20 - Sound channel 4 length timer
|
||||
uint8_t NR42 = 0; // 0xff21 - Sound channel 4 volume & envelope
|
||||
uint8_t NR43 = 0; // 0xff22 - Sound channel 4 frequency & randomness
|
||||
uint8_t NR44 = 0; // 0xff23 - Sound channel 4 control
|
||||
uint8_t NR50 = 0; // 0xff24 - Master volume & VIN panning
|
||||
uint8_t NR51 = 0; // 0xff25 - Sound panning
|
||||
uint8_t NR52 = 0; // 0xff26 - Sound on/off
|
||||
// 0xff27-0xff2f - Not used?
|
||||
uint8_t WaveRAM[16]; // 0xff30-0xff3f
|
||||
uint16_t LFSR = 0;
|
||||
|
||||
|
||||
void silence()
|
||||
{
|
||||
SDL_PauseAudioDevice(sdlAudioDevice, 1);
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
SDL_PauseAudioDevice(sdlAudioDevice, 0);
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
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();
|
||||
//audio_viewer::init();
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
NR10 = 0;
|
||||
NR11 = 0;
|
||||
NR12 = 0;
|
||||
NR13 = 0;
|
||||
NR14 = 0;
|
||||
NR21 = 0;
|
||||
NR22 = 0;
|
||||
NR23 = 0;
|
||||
NR24 = 0;
|
||||
NR30 = 0;
|
||||
NR31 = 0;
|
||||
NR32 = 0;
|
||||
NR33 = 0;
|
||||
NR34 = 0;
|
||||
NR41 = 0;
|
||||
NR42 = 0;
|
||||
NR43 = 0;
|
||||
NR44 = 0;
|
||||
NR50 = 0;
|
||||
NR51 = 0;
|
||||
NR52 = 0;
|
||||
CH1.duty_cycle = 0;
|
||||
LFSR = 0;
|
||||
for (int i=0; i<16; ++i) WaveRAM[i]=0;
|
||||
}
|
||||
|
||||
uint8_t getLFSR()
|
||||
{
|
||||
LFSR = (LFSR&0x7fff) | ( (LFSR&1)==((LFSR>>1)&1) ? 0x8000 : 0x0000 );
|
||||
if (NR43&0x08) LFSR = (LFSR&0xff7f) | ((LFSR>>8)&0x0080);
|
||||
LFSR=LFSR>>1;
|
||||
|
||||
return LFSR&1;
|
||||
}
|
||||
|
||||
void triggerCH1()
|
||||
{
|
||||
CH1.enabled = true;
|
||||
CH1.length_timer=NR11&0x3f;
|
||||
CH1.period_divider = NR13 | ((NR14 &0x7)<<8);
|
||||
CH1.envelope_sweep_timer = 0;
|
||||
CH1.volume = NR12>>4;
|
||||
// sweep does several things (check documentation)
|
||||
}
|
||||
|
||||
void triggerCH2()
|
||||
{
|
||||
CH2.enabled = true;
|
||||
CH2.length_timer=NR21&0x3f;
|
||||
CH2.period_divider = NR23 | ((NR24 &0x7)<<8);
|
||||
CH2.envelope_sweep_timer = 0;
|
||||
CH2.volume = NR22>>4;
|
||||
// sweep does several things (check documentation)
|
||||
}
|
||||
|
||||
void triggerCH3()
|
||||
{
|
||||
CH3.enabled = true;
|
||||
CH3.length_timer=NR31;
|
||||
CH3.period_divider = NR33 | ((NR34 &0x7)<<8);
|
||||
CH3.envelope_sweep_timer = 0;
|
||||
CH3.volume = (NR32>>5)&0x3;
|
||||
// sweep does several things (check documentation)
|
||||
}
|
||||
|
||||
void triggerCH4()
|
||||
{
|
||||
CH4.enabled = true;
|
||||
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);
|
||||
CH4.envelope_sweep_timer = 0;
|
||||
CH4.volume = NR42>>4;
|
||||
// sweep does several things (check documentation)
|
||||
}
|
||||
|
||||
uint8_t readRegister(uint16_t address)
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
case 0xff10: return NR10; break;
|
||||
case 0xff11: return NR11 & 0xc0; break;
|
||||
case 0xff12: return NR12; break;
|
||||
case 0xff13: return 0x00; break;
|
||||
case 0xff14: return NR14 & 0x40; break;
|
||||
|
||||
case 0xff16: return NR21 & 0xc0; break;
|
||||
case 0xff17: return NR22; break;
|
||||
case 0xff18: return 0x00; break;
|
||||
case 0xff19: return NR24 & 0x40; break;
|
||||
|
||||
case 0xff1a: return NR30; break;
|
||||
case 0xff1b: return 0x00; break;
|
||||
case 0xff1c: return NR32; break;
|
||||
case 0xff1d: return 0x00; break;
|
||||
case 0xff1e: return NR34 & 0x40; break;
|
||||
|
||||
case 0xff20: return 0x00; break;
|
||||
case 0xff21: return NR42; break;
|
||||
case 0xff22: return NR43; break;
|
||||
case 0xff23: return NR44 & 0x40; break;
|
||||
|
||||
case 0xff24: return NR50; break;
|
||||
case 0xff25: return NR51; break;
|
||||
case 0xff26: return NR52; break;
|
||||
|
||||
case 0xff30: return WaveRAM[0]; break;
|
||||
case 0xff31: return WaveRAM[1]; break;
|
||||
case 0xff32: return WaveRAM[2]; break;
|
||||
case 0xff33: return WaveRAM[3]; break;
|
||||
case 0xff34: return WaveRAM[4]; break;
|
||||
case 0xff35: return WaveRAM[5]; break;
|
||||
case 0xff36: return WaveRAM[6]; break;
|
||||
case 0xff37: return WaveRAM[7]; break;
|
||||
case 0xff38: return WaveRAM[8]; break;
|
||||
case 0xff39: return WaveRAM[9]; break;
|
||||
case 0xff3a: return WaveRAM[10]; break;
|
||||
case 0xff3b: return WaveRAM[11]; break;
|
||||
case 0xff3c: return WaveRAM[12]; break;
|
||||
case 0xff3d: return WaveRAM[13]; break;
|
||||
case 0xff3e: return WaveRAM[14]; break;
|
||||
case 0xff3f: return WaveRAM[15]; break;
|
||||
}
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void writeRegister(uint16_t address, uint8_t value)
|
||||
{
|
||||
if (!apu_enabled && (address!=0xff26)) return;
|
||||
|
||||
switch(address)
|
||||
{
|
||||
case 0xff10: NR10 = value; break;
|
||||
case 0xff11: NR11 = value; CH1.length_timer=NR11&0x3f; CH1.duty_cycle = NR11>>6; break;
|
||||
case 0xff12: NR12 = value; break;
|
||||
case 0xff13: NR13 = value; break;
|
||||
case 0xff14: NR14 = value; CH1.length_enable=(value&0x40); if (value&0x80) triggerCH1(); break;
|
||||
|
||||
case 0xff16: NR21 = value; CH2.length_timer=NR21&0x3f; CH2.duty_cycle = NR21>>6; break;
|
||||
case 0xff17: NR22 = value; break;
|
||||
case 0xff18: NR23 = value; break;
|
||||
case 0xff19: NR24 = value; CH2.length_enable=(value&0x40); if (value&0x80) triggerCH2(); break;
|
||||
|
||||
case 0xff1a: NR30 = value; break;
|
||||
case 0xff1b: NR31 = value; CH3.length_timer=NR31; break;
|
||||
case 0xff1c: NR32 = value; break;
|
||||
case 0xff1d: NR33 = value; break;
|
||||
case 0xff1e: NR34 = value; CH3.length_enable=(value&0x40); if (value&0x80) triggerCH3(); break;
|
||||
|
||||
case 0xff20: NR41 = value; CH1.length_timer=NR11&0x3f; CH1.duty_cycle = NR11>>6; break;
|
||||
case 0xff21: NR42 = value; break;
|
||||
case 0xff22: NR43 = value; break;
|
||||
case 0xff23: NR44 = value; CH4.length_enable=(value&0x40); if (value&0x80) triggerCH4(); break;
|
||||
|
||||
case 0xff24: NR50 = value; break;
|
||||
case 0xff25: NR51 = value; break;
|
||||
case 0xff26: if (value&0x80) reset(); NR52 = (value&0x80) | (NR52 & 0x0f); break;
|
||||
|
||||
case 0xff30: WaveRAM[0] = value; break;
|
||||
case 0xff31: WaveRAM[1] = value; break;
|
||||
case 0xff32: WaveRAM[2] = value; break;
|
||||
case 0xff33: WaveRAM[3] = value; break;
|
||||
case 0xff34: WaveRAM[4] = value; break;
|
||||
case 0xff35: WaveRAM[5] = value; break;
|
||||
case 0xff36: WaveRAM[6] = value; break;
|
||||
case 0xff37: WaveRAM[7] = value; break;
|
||||
case 0xff38: WaveRAM[8] = value; break;
|
||||
case 0xff39: WaveRAM[9] = value; break;
|
||||
case 0xff3a: WaveRAM[10] = value; break;
|
||||
case 0xff3b: WaveRAM[11] = value; break;
|
||||
case 0xff3c: WaveRAM[12] = value; break;
|
||||
case 0xff3d: WaveRAM[13] = value; break;
|
||||
case 0xff3e: WaveRAM[14] = value; break;
|
||||
case 0xff3f: WaveRAM[15] = value; break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t DIVAPU_envelope_sweep = 0;
|
||||
uint8_t DIVAPU_length = 0;
|
||||
uint8_t DIVAPU_CH1_freq_sweep = 0;
|
||||
|
||||
void incDIVAPU()
|
||||
{
|
||||
DIVAPU++;
|
||||
DIVAPU_length++;
|
||||
if (DIVAPU_length==2) {
|
||||
DIVAPU_length=0;
|
||||
if (CH1.enabled && CH1.length_enable) {
|
||||
if (CH1.length_timer==63) {
|
||||
CH1.enabled = false;
|
||||
CH1.length_timer=0;
|
||||
} else {
|
||||
CH1.length_timer++;
|
||||
}
|
||||
}
|
||||
if (CH2.enabled && CH2.length_enable) {
|
||||
if (CH2.length_timer==63) {
|
||||
CH2.enabled = false;
|
||||
CH2.length_timer=0;
|
||||
} else {
|
||||
CH2.length_timer++;
|
||||
}
|
||||
}
|
||||
if (CH3.enabled && CH3.length_enable) {
|
||||
if (CH3.length_timer==255) {
|
||||
CH3.enabled = false;
|
||||
CH3.length_timer = 0;
|
||||
} else {
|
||||
CH3.length_timer++;
|
||||
}
|
||||
}
|
||||
if (CH4.enabled && CH4.length_enable) {
|
||||
if (CH4.length_timer==63) {
|
||||
CH4.enabled = false;
|
||||
CH4.length_timer=0;
|
||||
} else {
|
||||
CH4.length_timer++;
|
||||
}
|
||||
}
|
||||
}
|
||||
DIVAPU_CH1_freq_sweep++;
|
||||
if (DIVAPU_CH1_freq_sweep==4) {
|
||||
DIVAPU_CH1_freq_sweep=0;
|
||||
// Do the freq sweep thing
|
||||
}
|
||||
DIVAPU_envelope_sweep++;
|
||||
if (DIVAPU_envelope_sweep==8) {
|
||||
DIVAPU_envelope_sweep=0;
|
||||
if ( CH1.enabled && (NR12&0x7) ) { // If sweep pace != 0, envelope sweep is enabled
|
||||
CH1.envelope_sweep_timer++;
|
||||
if ( CH1.envelope_sweep_timer == (NR12&0x07) ) { // if timer == envelope sweep, increase or decrease volume
|
||||
CH1.envelope_sweep_timer=0;
|
||||
if (NR12&0x8) { // bit set increases, reset decreases
|
||||
if (CH1.volume<0x0f) CH1.volume++;
|
||||
} else {
|
||||
if (CH1.volume>0) CH1.volume--;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( CH2.enabled && (NR22&0x7) ) { // If sweep pace != 0, envelope sweep is enabled
|
||||
CH2.envelope_sweep_timer++;
|
||||
if ( CH2.envelope_sweep_timer == (NR22&0x07) ) { // if timer == envelope sweep, increase or decrease volume
|
||||
CH2.envelope_sweep_timer=0;
|
||||
if (NR22&0x8) { // bit set increases, reset decreases
|
||||
if (CH2.volume<0x0f) CH2.volume++;
|
||||
} else {
|
||||
if (CH2.volume>0) CH2.volume--;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( CH4.enabled && (NR42&0x7) ) { // If sweep pace != 0, envelope sweep is enabled
|
||||
CH4.envelope_sweep_timer++;
|
||||
if ( CH4.envelope_sweep_timer == (NR42&0x07) ) { // if timer == envelope sweep, increase or decrease volume
|
||||
CH4.envelope_sweep_timer=0;
|
||||
if (NR42&0x8) { // bit set increases, reset decreases
|
||||
if (CH4.volume<0x0f) CH4.volume++;
|
||||
} else {
|
||||
if (CH4.volume>0) CH4.volume--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t dots = 0;
|
||||
uint32_t dotsCH3 = 0;
|
||||
uint32_t dotsCH4 = 0;
|
||||
void update(uint32_t dt)
|
||||
{
|
||||
dots += dt;
|
||||
while (dots>=4) {
|
||||
dots -= 4;
|
||||
CH1.period_divider++;
|
||||
if (CH1.period_divider==2048) {
|
||||
CH1.period_divider = NR13 | ((NR14 &0x7)<<8);
|
||||
CH1.duty_step++;
|
||||
if (CH1.duty_step==8) CH1.duty_step=0;
|
||||
}
|
||||
CH2.period_divider++;
|
||||
if (CH2.period_divider==2048) {
|
||||
CH2.period_divider = NR23 | ((NR24 &0x7)<<8);
|
||||
CH2.duty_step++;
|
||||
if (CH2.duty_step==8) CH2.duty_step=0;
|
||||
}
|
||||
}
|
||||
dotsCH3 += dt;
|
||||
while (dotsCH3>=2) {
|
||||
dotsCH3 -= 2;
|
||||
CH3.period_divider++;
|
||||
if (CH3.period_divider==2048) {
|
||||
CH3.period_divider = NR33 | ((NR34 &0x7)<<8);
|
||||
CH3.duty_step++;
|
||||
if (CH3.duty_step==32) CH3.duty_step=0;
|
||||
}
|
||||
}
|
||||
dotsCH4 += dt;
|
||||
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;
|
||||
CH4.period_divider = clock_shift << (NR43&0x07);
|
||||
CH4.duty_step=getLFSR();
|
||||
}
|
||||
}
|
||||
|
||||
t_sound += dt;
|
||||
samples_t += dt;
|
||||
if (t_sound>=cycles_per_sample) {
|
||||
t_sound-=cycles_per_sample;
|
||||
|
||||
uint16_t sampleCH1 = 0;
|
||||
if (apu_enabled && DAC1_enabled) sampleCH1 = (duty_cycles[CH1.duty_cycle][CH1.duty_step]*CH1.volume)<<2;
|
||||
|
||||
uint16_t sampleCH2 = 0;
|
||||
if (apu_enabled && DAC2_enabled) sampleCH2 = (duty_cycles[CH2.duty_cycle][CH2.duty_step]*CH2.volume)<<2;
|
||||
|
||||
uint16_t sampleCH3 = 0;
|
||||
if (apu_enabled && DAC3_enabled) {
|
||||
uint8_t step = CH3.duty_step>>1;
|
||||
uint8_t actual_sample = (CH3.duty_step&1 ? WaveRAM[step]&0x0f : WaveRAM[step]>>4)<<2;
|
||||
sampleCH3 = CH3.volume==0 ? 0 : CH3.volume==1 ? actual_sample : CH3.volume==2 ? actual_sample>>1 : actual_sample>>2;
|
||||
}
|
||||
|
||||
uint16_t sampleCH4 = 0;
|
||||
if (apu_enabled && DAC4_enabled) sampleCH4 = (CH4.duty_step*CH4.volume)<<2;
|
||||
|
||||
uint8_t sample = (sampleCH1+sampleCH2+sampleCH3+sampleCH4)&0xff;
|
||||
|
||||
sound_buffer[(sound_pos++)&(AUDIO_BUFFER_SIZE-1)] = sample;
|
||||
//audio_viewer::addsample(sample);
|
||||
}
|
||||
if (sound_pos>=1000) {
|
||||
SDL_QueueAudio(sdlAudioDevice, sound_buffer, sound_pos);
|
||||
sound_pos = 0;
|
||||
while (SDL_GetQueuedAudioSize(sdlAudioDevice) > 4096 ) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
APU.h
Normal file
15
APU.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
namespace APU
|
||||
{
|
||||
uint8_t readRegister(uint16_t address);
|
||||
void writeRegister(uint16_t address, uint8_t value);
|
||||
|
||||
void init();
|
||||
void reset();
|
||||
void silence();
|
||||
void resume();
|
||||
void incDIVAPU();
|
||||
void update(uint32_t dt);
|
||||
}
|
||||
8
Makefile
8
Makefile
@@ -2,10 +2,16 @@ compile:
|
||||
g++ -g *.cpp -lSDL2 -o gb
|
||||
|
||||
run: compile
|
||||
./gb
|
||||
./gb tetris.gb
|
||||
|
||||
debug: compile
|
||||
gdb --args gb tetris.gb
|
||||
|
||||
debug1: compile
|
||||
gdb -ex run gb
|
||||
|
||||
release:
|
||||
g++ -O3 *.cpp -lSDL2 -o gb
|
||||
|
||||
profile:
|
||||
g++ -g *.cpp -lSDL2 -o gb -pg
|
||||
|
||||
39
audio_viewer.cpp
Normal file
39
audio_viewer.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "audio_viewer.h"
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#define NUM_SAMPLES 256
|
||||
#define MAX_VOLUME 256
|
||||
namespace audio_viewer
|
||||
{
|
||||
SDL_Window *win = nullptr;
|
||||
SDL_Renderer *ren = nullptr;
|
||||
//SDL_Texture *tex = nullptr;
|
||||
uint8_t buffer[NUM_SAMPLES];
|
||||
uint8_t pos = 0;
|
||||
uint8_t screen[NUM_SAMPLES*MAX_VOLUME];
|
||||
|
||||
void init()
|
||||
{
|
||||
win = SDL_CreateWindow("Audio viewer", 1, 1, 256, 256, SDL_WINDOW_SHOWN);
|
||||
ren = SDL_CreateRenderer(win, -1, 0);
|
||||
//tex = SDL_CreateTexture(ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 256, 256);
|
||||
for (int i=0; i<NUM_SAMPLES; ++i) buffer[i] = 0;
|
||||
}
|
||||
|
||||
void addsample(uint8_t sample)
|
||||
{
|
||||
buffer[pos] = sample;
|
||||
pos = (pos+1)%NUM_SAMPLES;
|
||||
}
|
||||
|
||||
void refresh()
|
||||
{
|
||||
SDL_SetRenderDrawColor(ren, 0, 0, 0, 0);
|
||||
SDL_RenderClear(ren);
|
||||
SDL_SetRenderDrawColor(ren, 255, 255, 255, 255);
|
||||
for (int i=0; i<NUM_SAMPLES;++i) {
|
||||
SDL_RenderDrawLine(ren, i, buffer[(pos+i)%NUM_SAMPLES], i+1, buffer[(pos+i+1)%NUM_SAMPLES]);
|
||||
}
|
||||
SDL_RenderPresent(ren);
|
||||
}
|
||||
}
|
||||
9
audio_viewer.h
Normal file
9
audio_viewer.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
namespace audio_viewer
|
||||
{
|
||||
void init();
|
||||
void addsample(uint8_t sample);
|
||||
void refresh();
|
||||
}
|
||||
12
debug.cpp
12
debug.cpp
@@ -1,8 +1,10 @@
|
||||
#include "debug.h"
|
||||
#include <SDL2/SDL.h>
|
||||
#include <cstring>
|
||||
#include "sm83.h"
|
||||
#include "sm83dis.h"
|
||||
#include "mem.h"
|
||||
#include "APU.h"
|
||||
//#include "z80analyze.h"
|
||||
#include "ui.h"
|
||||
#include "ui_window.h"
|
||||
@@ -348,7 +350,7 @@ namespace debug
|
||||
|
||||
void pause()
|
||||
{
|
||||
//zx_ula::sound_disable();
|
||||
APU::silence();
|
||||
is_paused = true;
|
||||
breakpoints[sm83::getPC()] &= ~8;
|
||||
}
|
||||
@@ -360,7 +362,8 @@ namespace debug
|
||||
pause();
|
||||
is_debugging = true;
|
||||
show();
|
||||
if ( gbscreen::getFullRefresh()) gbscreen::fullrefresh();
|
||||
gbscreen::redraw(true);
|
||||
//if ( gbscreen::getFullRefresh()) gbscreen::fullrefresh();
|
||||
}
|
||||
|
||||
void cont() {
|
||||
@@ -368,7 +371,7 @@ namespace debug
|
||||
is_debugging = is_paused = false;
|
||||
refresh();
|
||||
gbscreen::focus();
|
||||
//zx_ula::sound_enable();
|
||||
APU::resume();
|
||||
}
|
||||
|
||||
const bool debugging() { return is_debugging; }
|
||||
@@ -777,7 +780,8 @@ namespace debug
|
||||
uint8_t dt = sm83::step();
|
||||
//zx_tape::update(dt);
|
||||
//zx_ula::sound_update(dt);
|
||||
gbscreen::fullrefresh();
|
||||
gbscreen::refresh(dt);
|
||||
gbscreen::redraw();
|
||||
//z80analyze::refresh();
|
||||
} else if (strcmp(cmd, "c")==0 || strcmp(cmd, "cont")==0) {
|
||||
sm83::step();
|
||||
|
||||
202
gbscreen.cpp
202
gbscreen.cpp
@@ -1,6 +1,8 @@
|
||||
#include "gbscreen.h"
|
||||
#include <cstring>
|
||||
#include "sm83.h"
|
||||
#include "mem.h"
|
||||
#include "audio_viewer.h"
|
||||
//#include "zx_ula.h"
|
||||
#include <SDL2/SDL.h>
|
||||
#include "ui_window.h"
|
||||
@@ -9,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;
|
||||
@@ -22,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;
|
||||
@@ -33,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) {
|
||||
@@ -71,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,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();
|
||||
}
|
||||
|
||||
@@ -131,30 +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);
|
||||
const uint8_t SCY = mem::readMem(0xff42);
|
||||
const uint8_t SCX = mem::readMem(0xff43);
|
||||
const uint8_t BGP = mem::readMem(0xff47);
|
||||
if ((LCDC & 0x1) == 0) {
|
||||
for (int i=0; i<160; ++i) line_buffer[i]=0;
|
||||
return;
|
||||
}
|
||||
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 );
|
||||
@@ -169,19 +217,45 @@ namespace gbscreen
|
||||
}
|
||||
}
|
||||
|
||||
struct oam_entry_t
|
||||
void fill_line_buffer_win()
|
||||
{
|
||||
uint8_t y, x, tile, attr;
|
||||
};
|
||||
oam_entry_t *oam = nullptr;
|
||||
if ((LCDC & 0x21) != 0x21) return;
|
||||
if (LY<WY) return;
|
||||
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;
|
||||
|
||||
void fill_line_buffer_obj(uint8_t LY)
|
||||
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 = 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 = 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 );
|
||||
line_buffer[pi++] = (BGP >> (index*2)) & 0x3;
|
||||
} else {
|
||||
ox--;
|
||||
}
|
||||
a=a<<1; b=b<<1;
|
||||
if (pi==160) return;
|
||||
}
|
||||
tx = (tx+1)&0x1f;
|
||||
}
|
||||
}
|
||||
|
||||
void fill_line_buffer_obj()
|
||||
{
|
||||
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;
|
||||
@@ -202,14 +276,14 @@ namespace gbscreen
|
||||
obj=0;
|
||||
while (obj_list[obj] != 255) {
|
||||
oam_entry_t *o = &oam[obj_list[obj]];
|
||||
const uint8_t ly = uint8_t(LY-o->y) & 0x7;
|
||||
const uint8_t ly = uint8_t(LY-o->y) & 0xf;
|
||||
|
||||
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 ? 8-ly : ly; // està invertit verticalment?
|
||||
uint16_t tile_address = 0x8000 + (tile<<4) + (yflip*2);
|
||||
uint8_t yflip = o->attr&0x40 ? (height-1)-ly : ly; // està invertit verticalment?
|
||||
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
|
||||
@@ -219,7 +293,7 @@ namespace gbscreen
|
||||
const uint8_t ppos = 1 << ( o->attr&0x20 ? i : 7-i);
|
||||
const uint8_t val = (a&ppos ? 1 : 0) + (b&ppos ? 2 : 0 ); // agafem el pixel que toca
|
||||
if (val) { // Si el pixel no es transparent...
|
||||
const uint8_t color = (OBP[(LCDC>>4)&1] >> (val*2)) & 0x3;
|
||||
const uint8_t color = (OBP[(o->attr>>4)&1] >> (val*2)) & 0x3;
|
||||
pixels[o->x+i-8] = color | o->attr&0x80;; // el pintem al buffer, amb el flag de prioritat respecte al BKG
|
||||
x_pos[o->x+i-8] = o->x; // I apuntem la seua x per a comparar després
|
||||
}
|
||||
@@ -240,25 +314,21 @@ 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];
|
||||
}
|
||||
}
|
||||
|
||||
// gestió de en quin dot i linea estem, i tot el que ha de passar
|
||||
bool stat_interrupt = false;
|
||||
uint8_t interrupts = 0x00;
|
||||
dots_in_scanline++;
|
||||
if ( (dots_in_scanline==80) && (LY<144) )
|
||||
{
|
||||
@@ -267,38 +337,34 @@ namespace gbscreen
|
||||
else if ( (dots_in_scanline==252) && (LY<144) )
|
||||
{
|
||||
STAT = (STAT & 0xFC); // Set mode 0
|
||||
if (STAT&0x08) stat_interrupt = true;
|
||||
if (STAT&0x08) interrupts |= INTERRUPT_LCD;
|
||||
}
|
||||
else if (dots_in_scanline==456)
|
||||
{
|
||||
dots_in_scanline = 0;
|
||||
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);
|
||||
sm83::interrupt(INTERRUPT_VBLANK);
|
||||
if (STAT&0x10) stat_interrupt = true;
|
||||
interrupts |= INTERRUPT_VBLANK;
|
||||
if (STAT&0x10) interrupts |= INTERRUPT_LCD;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LY<144)
|
||||
{
|
||||
STAT = (STAT & 0xFC) | 0x02; // Set mode 2
|
||||
if (STAT&0x20) stat_interrupt = true;
|
||||
fill_line_buffer_bkg(LY);
|
||||
fill_line_buffer_obj(LY);
|
||||
}
|
||||
else if (LY==154)
|
||||
{
|
||||
LY=0;
|
||||
if (STAT&0x20) interrupts |= INTERRUPT_LCD;
|
||||
fill_line_buffer_bkg();
|
||||
fill_line_buffer_win();
|
||||
fill_line_buffer_obj();
|
||||
}
|
||||
}
|
||||
if (LY==LYC)
|
||||
{
|
||||
STAT = (STAT & 0xFB) | 0x40;
|
||||
if (STAT&0x04) stat_interrupt = true;
|
||||
STAT = (STAT & 0xFB) | 0x04;
|
||||
if (STAT&0x40) interrupts |= INTERRUPT_LCD;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -306,40 +372,32 @@ namespace gbscreen
|
||||
}
|
||||
}
|
||||
|
||||
if (stat_interrupt)
|
||||
if (interrupts)
|
||||
{
|
||||
mem::writeMem(0xff41, STAT);
|
||||
mem::writeMem(0xff44, LY);
|
||||
sm83::interrupt(INTERRUPT_LCD);
|
||||
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;
|
||||
}
|
||||
|
||||
void debugrefresh(const uint32_t dt)
|
||||
{
|
||||
if (full_refresh) fullrefresh(); else refresh(dt);
|
||||
/*if (full_refresh) fullrefresh(); else*/ refresh(dt);
|
||||
redraw();
|
||||
}
|
||||
|
||||
void redraw(const bool present)
|
||||
@@ -351,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)
|
||||
@@ -363,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
|
||||
@@ -373,7 +439,7 @@ namespace gbscreen
|
||||
if (fullscreen) SDL_GetWindowSize(win, &rect.w, &rect.h);
|
||||
SDL_RenderFillRect(ren, &rect);
|
||||
}
|
||||
|
||||
//audio_viewer::refresh();
|
||||
}
|
||||
|
||||
void present()
|
||||
|
||||
29
main.cpp
29
main.cpp
@@ -63,7 +63,9 @@ int main(int argc, char *argv[])
|
||||
if (argc < 2) { printf("ABORTING: No rom specified.\n"); exit(1); }
|
||||
|
||||
const uint32_t clock = 4194304;
|
||||
const uint32_t update_freq = clock / 10;
|
||||
const uint32_t update_freq = clock >> 3;
|
||||
|
||||
SDL_Init(SDL_INIT_EVERYTHING);
|
||||
|
||||
FILE *f = fopen(argv[1], "rb");
|
||||
if (!f) { printf("ABORTING: Rom not found.\n"); exit(1); }
|
||||
@@ -73,12 +75,12 @@ int main(int argc, char *argv[])
|
||||
uint8_t *buffer = (uint8_t*)malloc(filesize);
|
||||
fread(buffer, filesize, 1, f);
|
||||
fclose(f);
|
||||
|
||||
mem::init(buffer, filesize);
|
||||
|
||||
sm83dis::loadSymbols();
|
||||
sm83::reset();
|
||||
|
||||
SDL_Init(SDL_INIT_EVERYTHING);
|
||||
gbscreen::init(0);
|
||||
debug::init();
|
||||
|
||||
@@ -105,7 +107,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
//zx_ula::sound_init();
|
||||
|
||||
debug::stop();
|
||||
//debug::stop();
|
||||
|
||||
bool should_exit = false;
|
||||
SDL_Event e;
|
||||
@@ -120,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();
|
||||
@@ -175,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;
|
||||
@@ -186,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();
|
||||
@@ -202,7 +203,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (t_states>=update_freq)
|
||||
{
|
||||
while (SDL_GetTicks()<time+100) {}
|
||||
while (SDL_GetTicks()<(time+125)) {}
|
||||
t_states -= update_freq;
|
||||
time = SDL_GetTicks();
|
||||
//z80analyze::refresh();
|
||||
|
||||
224
mbc1.cpp
224
mbc1.cpp
@@ -1,5 +1,6 @@
|
||||
#include "mbc1.h"
|
||||
#include "mem.h"
|
||||
#include "sm83.h"
|
||||
#include <stdlib.h>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
@@ -8,193 +9,74 @@ namespace mbc1
|
||||
#define ROM_BANK_SIZE 0x4000
|
||||
#define RAM_BANK_SIZE 0x2000
|
||||
|
||||
uint8_t bootrom[256];
|
||||
uint8_t *rom;
|
||||
uint8_t vram[8192];
|
||||
uint8_t exram[4 * RAM_BANK_SIZE];
|
||||
uint8_t wram[8192];
|
||||
uint8_t hram[512];
|
||||
|
||||
uint8_t tags[65536];
|
||||
|
||||
uint8_t current_rom_bank = 1;
|
||||
uint8_t current_ram_bank = 0;
|
||||
bool ram_enabled = false;
|
||||
bool banking_mode = false; // false = ROM banking mode, true = RAM banking mode
|
||||
|
||||
uint8_t getKeypad(uint8_t value)
|
||||
{
|
||||
const uint8_t *keys = SDL_GetKeyboardState(NULL);
|
||||
value = value & 0xf0;
|
||||
if (value & 0x10) {
|
||||
if (!keys[SDL_SCANCODE_RETURN]) value = value | 0x8;
|
||||
if (!keys[SDL_SCANCODE_SPACE]) value = value | 0x4;
|
||||
if (!keys[SDL_SCANCODE_Z]) value = value | 0x2;
|
||||
if (!keys[SDL_SCANCODE_X]) value = value | 0x1;
|
||||
} else if (value & 0x20) {
|
||||
if (!keys[SDL_SCANCODE_DOWN]) value = value | 0x8;
|
||||
if (!keys[SDL_SCANCODE_UP]) value = value | 0x4;
|
||||
if (!keys[SDL_SCANCODE_LEFT]) value = value | 0x2;
|
||||
if (!keys[SDL_SCANCODE_RIGHT]) value = value | 0x1;
|
||||
} else {
|
||||
value = value | 0x0f;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
uint8_t readMem(uint16_t address)
|
||||
{
|
||||
if (address < 0x8000) {
|
||||
if ( (address < 0x0100) && ((hram[0x150]&0x01)==0) ) return bootrom[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];
|
||||
}
|
||||
} else if (address < 0xA000) {
|
||||
return vram[address - 0x8000];
|
||||
} else if (address < 0xC000) {
|
||||
if (ram_enabled) {
|
||||
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
|
||||
} else if (address < 0xE000) {
|
||||
return wram[address - 0xC000];
|
||||
} else if (address < 0xFE00) {
|
||||
return wram[address - 0xE000];
|
||||
} else {
|
||||
if (address==0xFF00) {
|
||||
hram[address - 0XFE00] = getKeypad(hram[address - 0XFE00]);
|
||||
}
|
||||
return hram[address - 0XFE00];
|
||||
}
|
||||
}
|
||||
|
||||
void writeMem(uint16_t address, uint8_t value)
|
||||
{
|
||||
if (address < 0x8000) {
|
||||
if (address < 0x2000) {
|
||||
// Enable/disable RAM
|
||||
ram_enabled = (value & 0x0F) == 0x0A;
|
||||
} else if (address < 0x4000) {
|
||||
// Select ROM bank
|
||||
value &= 0x1F; // Lower 5 bits are used
|
||||
if (value == 0) value = 1; // Bank 0 is not allowed
|
||||
current_rom_bank = (current_rom_bank & 0x60) | value;
|
||||
} else if (address < 0x6000) {
|
||||
// Select RAM bank or upper bits of ROM bank
|
||||
if (banking_mode) {
|
||||
current_ram_bank = value & 0x03; // 2 bits for RAM bank
|
||||
} else {
|
||||
current_rom_bank = (current_rom_bank & 0x1F) | ((value & 0x03) << 5);
|
||||
}
|
||||
} else {
|
||||
// Select banking mode
|
||||
banking_mode = value & 0x01;
|
||||
}
|
||||
} else if (address < 0xA000) {
|
||||
vram[address - 0x8000] = value;
|
||||
} else if (address < 0xC000) {
|
||||
if (ram_enabled) {
|
||||
uint32_t banked_address = (current_ram_bank * RAM_BANK_SIZE) + (address - 0xA000);
|
||||
exram[banked_address] = value;
|
||||
}
|
||||
} else if (address < 0xE000) {
|
||||
wram[address - 0xC000] = value;
|
||||
} else if (address < 0xFE00) {
|
||||
wram[address - 0xE000] = value;
|
||||
} else {
|
||||
if ( (address==0xFF50) && ((value&0x01) != 1) ) return; //Only allow disabling boot room
|
||||
if ( (address==0xFF00) ) { value = value & 0x30; }
|
||||
if ( (address==0xFF04) ) { hram[address-0xFE00] = 0; return; }
|
||||
if ( (address==0xFF46) ) mem::init_dma_transfer(value);
|
||||
hram[address - 0xFE00] = value;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t getTag(uint16_t address)
|
||||
{
|
||||
return tags[address];
|
||||
}
|
||||
|
||||
void setTag(uint16_t address, uint8_t value)
|
||||
{
|
||||
tags[address] = value;
|
||||
}
|
||||
|
||||
void saveState(FILE* f)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void loadState(FILE *f)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint8_t* rawPtr(uint16_t address)
|
||||
{
|
||||
if (address < 0x8000) {
|
||||
if ( (address < 0x0100) && ((hram[0x150]&0x01)==0) ) return &bootrom[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];
|
||||
}
|
||||
} else if (address < 0xA000) {
|
||||
return &vram[address - 0x8000];
|
||||
} else if (address < 0xC000) {
|
||||
if (ram_enabled) {
|
||||
uint32_t banked_address = (current_ram_bank * RAM_BANK_SIZE) + (address - 0xA000);
|
||||
return &exram[banked_address];
|
||||
}
|
||||
return nullptr; // Return open bus value when RAM is disabled
|
||||
} else if (address < 0xE000) {
|
||||
return &wram[address - 0xC000];
|
||||
} else if (address < 0xFE00) {
|
||||
return &wram[address - 0xE000];
|
||||
} else {
|
||||
return &hram[address - 0XFE00];
|
||||
}
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
FILE *f = fopen("dmg_boot.bin", "rb");
|
||||
if (!f) { printf("ABORTING: 'dmg_boot.bin' not found!\n"); exit(1); }
|
||||
fseek(f, 0, SEEK_END);
|
||||
const int size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
fread(bootrom, size, 1, f);
|
||||
fclose(f);
|
||||
|
||||
for (int i=0; i<8192; ++i) { vram[i] = 0; }
|
||||
for (int i=0; i<4*RAM_BANK_SIZE; ++i) { exram[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<65536; ++i) { tags[i] = MEMTAG_NONE; }
|
||||
}
|
||||
|
||||
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
|
||||
value &= 0x1F; // Lower 5 bits are used
|
||||
if (value == 0) value = 1; // Bank 0 is not allowed
|
||||
current_rom_bank = (current_rom_bank & 0x60) | value;
|
||||
} else if (address < 0x6000) {
|
||||
// Select RAM bank or upper bits of ROM bank
|
||||
if (banking_mode) {
|
||||
current_ram_bank = value & 0x03; // 2 bits for RAM bank
|
||||
} else {
|
||||
current_rom_bank = (current_rom_bank & 0x1F) | ((value & 0x03) << 5);
|
||||
}
|
||||
} else {
|
||||
// Select banking mode
|
||||
banking_mode = value & 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t readRam(uint16_t address)
|
||||
{
|
||||
if (ram_enabled) {
|
||||
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) {
|
||||
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)
|
||||
{
|
||||
mem::readMem = mbc1::readMem;
|
||||
mem::writeMem = mbc1::writeMem;
|
||||
mem::getTag = mbc1::getTag;
|
||||
mem::setTag = mbc1::setTag;
|
||||
mem::saveState = mbc1::saveState;
|
||||
mem::loadState = mbc1::loadState;
|
||||
mem::reset = mbc1::reset;
|
||||
mem::rawPtr = mbc1::rawPtr;
|
||||
|
||||
mbc1::rom = rom;
|
||||
|
||||
reset();
|
||||
}
|
||||
}
|
||||
6
mbc1.h
6
mbc1.h
@@ -4,4 +4,10 @@
|
||||
namespace mbc1
|
||||
{
|
||||
void init(uint8_t *rom, uint32_t rom_size, uint32_t ram_size);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
138
mbc_none.cpp
138
mbc_none.cpp
@@ -1,150 +1,22 @@
|
||||
#include "mbc_none.h"
|
||||
#include "mem.h"
|
||||
#include <stdlib.h>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
namespace mbc_none
|
||||
{
|
||||
uint8_t bootrom[256];
|
||||
uint8_t *rom;
|
||||
uint8_t vram[8192];
|
||||
uint8_t exram[8192];
|
||||
uint8_t wram[8192];
|
||||
uint8_t hram[512];
|
||||
|
||||
uint8_t tags[65536];
|
||||
void reset() { } // nothing to do
|
||||
|
||||
uint8_t getKeypad(uint8_t value)
|
||||
{
|
||||
const uint8_t *keys = SDL_GetKeyboardState(NULL);
|
||||
value = value & 0xf0;
|
||||
if (value & 0x10) {
|
||||
if (!keys[SDL_SCANCODE_RETURN]) value = value | 0x8;
|
||||
if (!keys[SDL_SCANCODE_SPACE]) value = value | 0x4;
|
||||
if (!keys[SDL_SCANCODE_Z]) value = value | 0x2;
|
||||
if (!keys[SDL_SCANCODE_X]) value = value | 0x1;
|
||||
} else if (value & 0x20) {
|
||||
if (!keys[SDL_SCANCODE_DOWN]) value = value | 0x8;
|
||||
if (!keys[SDL_SCANCODE_UP]) value = value | 0x4;
|
||||
if (!keys[SDL_SCANCODE_LEFT]) value = value | 0x2;
|
||||
if (!keys[SDL_SCANCODE_RIGHT]) value = value | 0x1;
|
||||
} else {
|
||||
value = value | 0x0f;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
uint8_t readRom(uint16_t address) { return rom[address]; }
|
||||
|
||||
uint8_t readMem(uint16_t address)
|
||||
{
|
||||
if (address < 0x8000) {
|
||||
if ( (address < 0x0100) && ((hram[0x150]&0x01)==0) ) return bootrom[address];
|
||||
return rom[address];
|
||||
} else if (address < 0xA000) {
|
||||
return vram[address - 0x8000];
|
||||
} else if (address < 0xC000) {
|
||||
return exram[address - 0xA000];
|
||||
} else if (address < 0xE000) {
|
||||
return wram[address - 0xC000];
|
||||
} else if (address < 0xFE00) {
|
||||
return wram[address - 0xE000];
|
||||
} else {
|
||||
if (address==0xFF00) {
|
||||
hram[address - 0XFE00] = getKeypad(hram[address - 0XFE00]);
|
||||
}
|
||||
return hram[address - 0XFE00];
|
||||
}
|
||||
}
|
||||
void writeRom(uint16_t address, uint8_t value) { } // do nothing
|
||||
|
||||
void writeMem(uint16_t address, uint8_t value)
|
||||
{
|
||||
if (address < 0x8000) {
|
||||
// Read Only Memory, you know...
|
||||
//rom[address] = value;
|
||||
} else if (address < 0xA000) {
|
||||
vram[address - 0x8000] = value;
|
||||
} else if (address < 0xC000) {
|
||||
exram[address - 0xA000] = value;
|
||||
} else if (address < 0xE000) {
|
||||
wram[address - 0xC000] = value;
|
||||
} else if (address < 0xFE00) {
|
||||
wram[address - 0xE000] = value;
|
||||
} else {
|
||||
if ( (address==0xFF50) && ((value&0x01) != 1) ) return; //Only allow disabling boot room
|
||||
if ( (address==0xFF00) ) { value = value & 0x30; }
|
||||
if ( (address==0xFF04) ) { hram[address-0xFE00] = 0; return; }
|
||||
if ( (address==0xFF46) ) mem::init_dma_transfer(value);
|
||||
hram[address - 0xFE00] = value;
|
||||
}
|
||||
}
|
||||
uint8_t readRam(uint16_t address) { return 0xff; }
|
||||
|
||||
uint8_t getTag(uint16_t address)
|
||||
{
|
||||
return tags[address];
|
||||
}
|
||||
|
||||
void setTag(uint16_t address, uint8_t value)
|
||||
{
|
||||
tags[address] = value;
|
||||
}
|
||||
|
||||
void saveState(FILE* f)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void loadState(FILE *f)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint8_t* rawPtr(uint16_t address)
|
||||
{
|
||||
if (address < 0x8000) {
|
||||
if ( (address < 0x0100) && ((hram[0x150]&0x01)==0) ) return &bootrom[address];
|
||||
return &rom[address];
|
||||
} else if (address < 0xA000) {
|
||||
return &vram[address - 0x8000];
|
||||
} else if (address < 0xC000) {
|
||||
return &exram[address - 0xA000];
|
||||
} else if (address < 0xE000) {
|
||||
return &wram[address - 0xC000];
|
||||
} else if (address < 0xFE00) {
|
||||
return &wram[address - 0xE000];
|
||||
} else {
|
||||
return &hram[address - 0XFE00];
|
||||
}
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
FILE *f = fopen("dmg_boot.bin", "rb");
|
||||
if (!f) { printf("ABORTING: 'dmg_boot.bin' not found!\n"); exit(1); }
|
||||
fseek(f, 0, SEEK_END);
|
||||
const int size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
fread(bootrom, size, 1, f);
|
||||
fclose(f);
|
||||
|
||||
for (int i=0; i<8192; ++i) { vram[i] = 0; }
|
||||
for (int i=0; i<8192; ++i) { exram[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<65536; ++i) { tags[i] = MEMTAG_NONE; }
|
||||
}
|
||||
void writeRam(uint16_t address, uint8_t value) { } // do nothing
|
||||
|
||||
void init(uint8_t *rom, uint32_t rom_size, uint32_t ram_size)
|
||||
{
|
||||
mem::readMem = mbc_none::readMem;
|
||||
mem::writeMem = mbc_none::writeMem;
|
||||
mem::getTag = mbc_none::getTag;
|
||||
mem::setTag = mbc_none::setTag;
|
||||
mem::saveState = mbc_none::saveState;
|
||||
mem::loadState = mbc_none::loadState;
|
||||
mem::reset = mbc_none::reset;
|
||||
mem::rawPtr = mbc_none::rawPtr;
|
||||
|
||||
mbc_none::rom = rom;
|
||||
|
||||
reset();
|
||||
}
|
||||
}
|
||||
@@ -4,4 +4,10 @@
|
||||
namespace mbc_none
|
||||
{
|
||||
void init(uint8_t *rom, uint32_t rom_size, uint32_t ram_size);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
220
mem.cpp
220
mem.cpp
@@ -2,21 +2,39 @@
|
||||
#include "sm83.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include "APU.h"
|
||||
|
||||
#include "mbc_none.h"
|
||||
#include "mbc1.h"
|
||||
#include "mbc3.h"
|
||||
|
||||
#define DIV hram[0x104] // 0xff04 - 0xfe00
|
||||
#define TIMA hram[0x105] // 0xff05 - 0xfe00
|
||||
#define TMA hram[0x106] // 0xff06 - 0xfe00
|
||||
#define TAC hram[0x107] // 0xff07 - 0xfe00
|
||||
namespace mem
|
||||
{
|
||||
void (*reset)(void);
|
||||
uint8_t(*readMem)(uint16_t);
|
||||
void (*writeMem)(uint16_t, uint8_t);
|
||||
uint8_t(*getTag)(uint16_t);
|
||||
void (*setTag)(uint16_t, uint8_t);
|
||||
void (*saveState)(FILE*);
|
||||
void (*loadState)(FILE*);
|
||||
uint8_t*(*rawPtr)(uint16_t);
|
||||
|
||||
void (*resetMbc)(void);
|
||||
uint8_t (*readRom)(uint16_t);
|
||||
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;
|
||||
uint8_t vram[8192];
|
||||
uint8_t wram[8192];
|
||||
uint8_t hram[512];
|
||||
|
||||
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;
|
||||
@@ -27,27 +45,175 @@ namespace mem
|
||||
|
||||
void init(uint8_t* rom, const int size)
|
||||
{
|
||||
//if (memory) free(memory);
|
||||
//memory = (uint8_t*)malloc(size);
|
||||
title = (char*)&rom[0x134];
|
||||
uint8_t mapper_type = rom[0x147];
|
||||
uint32_t rom_size = 32768 * (1 << rom[0x148]);
|
||||
mapper_type = rom[0x147];
|
||||
rom_size = 32768 * (1 << rom[0x148]);
|
||||
int sizes[] = { 0, 0, 8, 32, 128, 64};
|
||||
uint32_t ram_size = sizes[rom[0x149]] * 1024;
|
||||
ram_size = sizes[rom[0x149]] * 1024;
|
||||
|
||||
switch (mapper_type)
|
||||
{
|
||||
case 0x00:
|
||||
mbc_none::init(rom, rom_size, ram_size);
|
||||
mem::resetMbc = mbc_none::reset;
|
||||
mem::readRom = mbc_none::readRom;
|
||||
mem::writeRom = mbc_none::writeRom;
|
||||
mem::readRam = mbc_none::readRam;
|
||||
mem::writeRam = mbc_none::writeRam;
|
||||
break;
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
mbc1::init(rom, rom_size, ram_size);
|
||||
mem::resetMbc = mbc1::reset;
|
||||
mem::readRom = mbc1::readRom;
|
||||
mem::writeRom = mbc1::writeRom;
|
||||
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();
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
FILE *f = fopen("dmg_boot.bin", "rb");
|
||||
if (!f) { printf("ABORTING: 'dmg_boot.bin' not found!\n"); exit(1); }
|
||||
fseek(f, 0, SEEK_END);
|
||||
const int size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
fread(bootrom, size, 1, f);
|
||||
fclose(f);
|
||||
|
||||
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<512; ++i) { hram[i] = 0; }
|
||||
for (int i=0; i<65536; ++i) { tags[i] = MEMTAG_NONE; }
|
||||
|
||||
resetMbc();
|
||||
APU::reset();
|
||||
}
|
||||
|
||||
uint8_t getKeypad(uint8_t value)
|
||||
{
|
||||
const uint8_t *keys = SDL_GetKeyboardState(NULL);
|
||||
value = value & 0xf0;
|
||||
if (value & 0x10) {
|
||||
if (!keys[SDL_SCANCODE_RETURN]) value = value | 0x8;
|
||||
if (!keys[SDL_SCANCODE_SPACE]) value = value | 0x4;
|
||||
if (!keys[SDL_SCANCODE_Z]) value = value | 0x2;
|
||||
if (!keys[SDL_SCANCODE_X]) value = value | 0x1;
|
||||
} else if (value & 0x20) {
|
||||
if (!keys[SDL_SCANCODE_DOWN]) value = value | 0x8;
|
||||
if (!keys[SDL_SCANCODE_UP]) value = value | 0x4;
|
||||
if (!keys[SDL_SCANCODE_LEFT]) value = value | 0x2;
|
||||
if (!keys[SDL_SCANCODE_RIGHT]) value = value | 0x1;
|
||||
} else {
|
||||
value = value | 0x0f;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
uint8_t readMem(uint16_t address)
|
||||
{
|
||||
if (address < 0x8000) {
|
||||
if ( (address < 0x0100) && ((hram[0x150]&0x01)==0) ) return bootrom[address];
|
||||
return readRom(address);
|
||||
} else if (address < 0xA000) {
|
||||
return vram[address - 0x8000];
|
||||
} else if (address < 0xC000) {
|
||||
return readRam(address);
|
||||
} else if (address < 0xE000) {
|
||||
return wram[address - 0xC000];
|
||||
} else if (address < 0xFE00) {
|
||||
return wram[address - 0xE000];
|
||||
} else {
|
||||
if (address==0xFF00) {
|
||||
hram[address - 0XFE00] = getKeypad(hram[address - 0XFE00]);
|
||||
} else if (address>=0xFF10 && address<=0xFF3F) { return APU::readRegister(address); }
|
||||
return hram[address - 0XFE00];
|
||||
}
|
||||
}
|
||||
|
||||
void writeMem(uint16_t address, uint8_t value)
|
||||
{
|
||||
if (address < 0x8000) {
|
||||
writeRom(address, value);
|
||||
} else if (address < 0xA000) {
|
||||
vram[address - 0x8000] = value;
|
||||
} else if (address < 0xC000) {
|
||||
writeRam(address, value);
|
||||
} else if (address < 0xE000) {
|
||||
wram[address - 0xC000] = value;
|
||||
} else if (address < 0xFE00) {
|
||||
wram[address - 0xE000] = value;
|
||||
} else {
|
||||
if ( (address==0xFF50) && ((value&0x01) != 1) ) {
|
||||
return; //Only allow disabling boot room
|
||||
} else if ( (address==0xFF00) ) {
|
||||
value = value & 0x30;
|
||||
} else if ( (address==0xFF04) ) {
|
||||
hram[address-0xFE00] = 0;
|
||||
return;
|
||||
} else if ( (address==0xFF0F) ) { // IF
|
||||
hram[address-0xFE00] = value;
|
||||
sm83::processInterrupts();
|
||||
return;
|
||||
} else if (address>=0xFF10 && address<=0xFF3F) { // APU
|
||||
APU::writeRegister(address, value);
|
||||
return;
|
||||
} else if ( (address==0xFF46) ) { // OAM DMA
|
||||
mem::init_dma_transfer(value);
|
||||
}
|
||||
hram[address - 0xFE00] = value;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t getTag(uint16_t address)
|
||||
{
|
||||
return tags[address];
|
||||
}
|
||||
|
||||
void setTag(uint16_t address, uint8_t value)
|
||||
{
|
||||
tags[address] = value;
|
||||
}
|
||||
|
||||
void saveState(FILE* f)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void loadState(FILE* f)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint8_t *rawVram()
|
||||
{
|
||||
return vram;
|
||||
}
|
||||
|
||||
uint8_t *rawHram(uint16_t address)
|
||||
{
|
||||
return &hram[address-0xfe00];
|
||||
}
|
||||
|
||||
|
||||
void init_dma_transfer(uint8_t source)
|
||||
{
|
||||
dma_address = source << 8;
|
||||
@@ -58,37 +224,45 @@ 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) {
|
||||
div_counter -= 256;
|
||||
uint8_t *div = mem::rawPtr(0xff04);
|
||||
*div = *div + 1;
|
||||
bool bitset = DIV&0x10;
|
||||
DIV++;
|
||||
if (bitset && !(DIV&0x10)) APU::incDIVAPU();
|
||||
}
|
||||
|
||||
// Timer
|
||||
uint8_t *t_regs = mem::rawPtr(0xff05);
|
||||
if (*(t_regs+2)&0x4) { // if bit 3 of mem(0xff07) is 1, timer enabled
|
||||
uint16_t freq = timer_frequencies[*(t_regs+2)&0x03];
|
||||
if (TAC&0x4) { // if bit 3 of mem(0xff07) is 1, timer enabled
|
||||
uint16_t freq = timer_frequencies[TAC&0x03];
|
||||
timer_counter += dt;
|
||||
if (timer_counter>=freq) {
|
||||
timer_counter -= freq;
|
||||
if ((*t_regs)<255)
|
||||
(*t_regs)++;
|
||||
if (TIMA<255)
|
||||
TIMA++;
|
||||
else {
|
||||
*t_regs = *(t_regs+1);
|
||||
TIMA = TMA;
|
||||
sm83::interrupt(INTERRUPT_TIMER);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// APU
|
||||
APU::update(dt);
|
||||
|
||||
// OAM DMA
|
||||
if (dma_pos<160) {
|
||||
dma_dots += dt;
|
||||
while (dma_dots >= 4 && dma_pos<160) {
|
||||
dma_dots -= 4;
|
||||
mem::writeMem(0xfe00|dma_pos, mem::readMem(dma_address|dma_pos));
|
||||
hram[dma_pos] = mem::readMem(dma_address|dma_pos);
|
||||
dma_pos++;
|
||||
}
|
||||
}
|
||||
|
||||
17
mem.h
17
mem.h
@@ -25,18 +25,19 @@ namespace mem
|
||||
#define MBC7 7
|
||||
|
||||
void init(uint8_t* rom, const int size);
|
||||
extern void (*reset)(void);
|
||||
void reset();
|
||||
|
||||
extern uint8_t(*readMem)(uint16_t);
|
||||
extern void (*writeMem)(uint16_t, uint8_t);
|
||||
uint8_t readMem(uint16_t address);
|
||||
void writeMem(uint16_t address, uint8_t value);
|
||||
|
||||
extern uint8_t(*getTag)(uint16_t);
|
||||
extern void (*setTag)(uint16_t, uint8_t);
|
||||
uint8_t getTag(uint16_t address);
|
||||
void setTag(uint16_t address, uint8_t value);
|
||||
|
||||
extern void (*saveState)(FILE*);
|
||||
extern void (*loadState)(FILE*);
|
||||
void saveState(FILE* f);
|
||||
void loadState(FILE* f);
|
||||
|
||||
extern uint8_t*(*rawPtr)(uint16_t);
|
||||
uint8_t *rawVram();
|
||||
uint8_t *rawHram(uint16_t address);
|
||||
|
||||
void init_dma_transfer(uint8_t source);
|
||||
void update_mapped(const uint32_t dt);
|
||||
|
||||
123
sm83.cpp
123
sm83.cpp
@@ -46,6 +46,7 @@ namespace sm83
|
||||
|
||||
uint8_t *_rIME = ®s[12];
|
||||
|
||||
bool halted = false;
|
||||
bool exit_from_halt = false;
|
||||
int pending_ei = 0;
|
||||
|
||||
@@ -156,6 +157,7 @@ namespace sm83
|
||||
void POP(uint16_t *a)
|
||||
{
|
||||
*a = READ_MEM_16(rSP);
|
||||
if (a == _rAF) *a = *a & 0xfff0;
|
||||
rSP+=2;
|
||||
}
|
||||
|
||||
@@ -244,7 +246,8 @@ namespace sm83
|
||||
const uint8_t res = rA + b;
|
||||
rF=0;
|
||||
if (res==0) SET_FLAGS(fZ);
|
||||
if ( (res & 0x0f) < (rA & 0x0f) ) SET_FLAGS(fH);
|
||||
//if ( (res & 0x0f) < (rA & 0x0f) ) SET_FLAGS(fH);
|
||||
if ( (rA&0x0f) + (b&0x0f) > 0x0f ) SET_FLAGS(fH);
|
||||
if ( res < rA ) SET_FLAGS(fC);
|
||||
rA = (uint8_t)res;
|
||||
}
|
||||
@@ -257,7 +260,8 @@ namespace sm83
|
||||
uint16_t res = rA + b + 1;
|
||||
rF=0;
|
||||
if (res==0) SET_FLAGS(fZ);
|
||||
if ( (res & 0x0f) <= (rA & 0x0f) ) SET_FLAGS(fH);
|
||||
//if ( (res & 0x0f) <= (rA & 0x0f) ) SET_FLAGS(fH);
|
||||
if ( (rA&0x0f) + (b&0x0f) + 1 > 0x0f ) SET_FLAGS(fH);
|
||||
if ( res > 255 ) SET_FLAGS(fC);
|
||||
rA = (uint8_t)res;
|
||||
}
|
||||
@@ -269,7 +273,8 @@ namespace sm83
|
||||
rF=0;
|
||||
if (res==0) SET_FLAGS(fZ);
|
||||
SET_FLAGS(fN);
|
||||
if ( (res & 0x0f) > (rA & 0x0f) ) SET_FLAGS(fH);
|
||||
//if ( (res & 0x0f) > (rA & 0x0f) ) SET_FLAGS(fH);
|
||||
if ( int(rA&0x0f) - int(b&0x0f) < 0 ) SET_FLAGS(fH);
|
||||
if ( res > rA ) SET_FLAGS(fC);
|
||||
if (update) rA = (uint8_t)res;
|
||||
}
|
||||
@@ -283,7 +288,8 @@ namespace sm83
|
||||
rF=0;
|
||||
if (res==0) SET_FLAGS(fZ);
|
||||
SET_FLAGS(fN);
|
||||
if ( (res & 0x0f) >= (rA & 0x0f) ) SET_FLAGS(fH);
|
||||
//if ( (res & 0x0f) >= (rA & 0x0f) ) SET_FLAGS(fH);
|
||||
if ( int(rA&0x0f) - int(b&0x0f) - 1 < 0 ) SET_FLAGS(fH);
|
||||
if ( res >= rA ) SET_FLAGS(fC);
|
||||
rA = (uint8_t)res;
|
||||
}
|
||||
@@ -366,7 +372,7 @@ namespace sm83
|
||||
t+=4;
|
||||
}
|
||||
*/
|
||||
void DAA()
|
||||
void oldDAA()
|
||||
{
|
||||
bool carry_set = false;
|
||||
uint8_t old = rA;
|
||||
@@ -379,6 +385,49 @@ namespace sm83
|
||||
if (carry_set) SET_FLAGS(fC);
|
||||
}
|
||||
|
||||
void notsooldDAA()
|
||||
{
|
||||
bool carry_set = false;
|
||||
bool halfcarry_set = true;
|
||||
if (!(rF & fN)) {
|
||||
if ((rF & fC) || rA > 0x99) { rA += 0x60; carry_set = true; }
|
||||
if ((rF & fH) || ((rA & 0x0f) > 0x09)) { halfcarry_set = false; rA += 0x6; }
|
||||
} else if ( (rF & fC) && (rF & fH) ) {
|
||||
rA += 0x9A;
|
||||
halfcarry_set = false;
|
||||
} else if (rF & fC) {
|
||||
rA += 0xA0;
|
||||
} else if (rF & fH) {
|
||||
rA += 0xFA;
|
||||
halfcarry_set = false;
|
||||
}
|
||||
KEEP_FLAGS(fN);
|
||||
if (rA==0) SET_FLAGS(fZ);
|
||||
if (carry_set) SET_FLAGS(fC);
|
||||
//if (halfcarry_set) SET_FLAGS(fH);
|
||||
//rF = rF & ~fH;
|
||||
}
|
||||
|
||||
void DAA()
|
||||
{
|
||||
int t = rA;
|
||||
int corr = 0;
|
||||
corr |= (rF & fH) ? 0x06 : 0x00;
|
||||
corr |= (rF & fC) ? 0x60 : 0x00;
|
||||
if (rF & fN)
|
||||
t -= corr;
|
||||
else {
|
||||
corr |= (t & 0x0F) > 0x09 ? 0x06 : 0x00;
|
||||
corr |= (t > 0x99) ? 0x60 : 0x00;
|
||||
t += corr;
|
||||
}
|
||||
KEEP_FLAGS(fN);
|
||||
if (t==0) SET_FLAGS(fZ);
|
||||
if (corr & 0x60 != 0) SET_FLAGS(fC);
|
||||
t &= 0xFF;
|
||||
rA = t;
|
||||
}
|
||||
|
||||
void CPL()
|
||||
{
|
||||
rA = ~rA;
|
||||
@@ -473,27 +522,33 @@ namespace sm83
|
||||
|
||||
void processInterrupts()
|
||||
{
|
||||
const uint8_t IF = mem::readMem(0xff0f);
|
||||
uint8_t *IE = mem::rawHram(0xffff);
|
||||
uint8_t *IF = mem::rawHram(0xff0f);
|
||||
if ( (*IF & *IE) == 0 ) return;
|
||||
if (halted) {
|
||||
//exit_from_halt = true;
|
||||
halted = false;
|
||||
rPC++;
|
||||
}
|
||||
if (ime==0) return;
|
||||
if ( (IF & 0x1f) == 0) return;
|
||||
DI();
|
||||
PUSH(rPC);
|
||||
t+=20;
|
||||
if (IF & INTERRUPT_VBLANK) {
|
||||
//t+=20;
|
||||
if (*IF & INTERRUPT_VBLANK) {
|
||||
rPC = 0x40;
|
||||
mem::writeMem(0xff0f, IF & ~INTERRUPT_VBLANK);
|
||||
} else if (IF & INTERRUPT_LCD) {
|
||||
rPC = 0x40;
|
||||
mem::writeMem(0xff0f, IF & ~INTERRUPT_LCD);
|
||||
} else if (IF & INTERRUPT_TIMER) {
|
||||
rPC = 0x40;
|
||||
mem::writeMem(0xff0f, IF & ~INTERRUPT_TIMER);
|
||||
} else if (IF & INTERRUPT_SERIAL) {
|
||||
rPC = 0x40;
|
||||
mem::writeMem(0xff0f, IF & ~INTERRUPT_SERIAL);
|
||||
} else if (IF & INTERRUPT_JOYPAD) {
|
||||
rPC = 0x40;
|
||||
mem::writeMem(0xff0f, IF & ~INTERRUPT_JOYPAD);
|
||||
*IF = *IF & ~INTERRUPT_VBLANK;
|
||||
} else if (*IF & INTERRUPT_LCD) {
|
||||
rPC = 0x48;
|
||||
*IF = *IF & ~INTERRUPT_LCD;
|
||||
} else if (*IF & INTERRUPT_TIMER) {
|
||||
rPC = 0x50;
|
||||
*IF = *IF & ~INTERRUPT_TIMER;
|
||||
} else if (*IF & INTERRUPT_SERIAL) {
|
||||
rPC = 0x58;
|
||||
*IF = *IF & ~INTERRUPT_SERIAL;
|
||||
} else if (*IF & INTERRUPT_JOYPAD) {
|
||||
rPC = 0x60;
|
||||
*IF = *IF & ~INTERRUPT_JOYPAD;
|
||||
}
|
||||
/*if (options[Z80_OPTION_BREAK_ON_INTERRUPT]) {
|
||||
printf("Break on interrupt! 0x%2x, PC: 0x%2x\n", address, rPC);
|
||||
@@ -536,12 +591,24 @@ namespace sm83
|
||||
|
||||
void HALT()
|
||||
{
|
||||
if (exit_from_halt) {
|
||||
if (!halted) {
|
||||
const uint8_t IE = mem::readMem(0xffff);
|
||||
const uint8_t IF = mem::readMem(0xff0f);
|
||||
if ( (ime==0) && ((IF & IE) != 0) ) {
|
||||
// [TODO] HALT BUG
|
||||
if (pending_ei==2) rPC--;
|
||||
return;
|
||||
} else {
|
||||
halted = true;
|
||||
}
|
||||
}
|
||||
/*if (exit_from_halt) {
|
||||
exit_from_halt = false;
|
||||
} else {
|
||||
halted = false;
|
||||
} else {*/
|
||||
//printf("HALT\n");
|
||||
rPC--;
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
void STOP()
|
||||
@@ -552,10 +619,10 @@ namespace sm83
|
||||
void interrupt(uint8_t type)
|
||||
{
|
||||
const uint8_t IE = mem::readMem(0xffff);
|
||||
if (IE & type) exit_from_halt = true;
|
||||
//if (IE & type) exit_from_halt = true;
|
||||
const uint8_t IF = mem::readMem(0xff0f);
|
||||
mem::writeMem(0xff0f, IF | (IE & type));
|
||||
processInterrupts();
|
||||
mem::writeMem(0xff0f, IF | type);
|
||||
//processInterrupts();
|
||||
}
|
||||
|
||||
static inline const uint8_t RLC(const uint8_t v)
|
||||
|
||||
1
sm83.h
1
sm83.h
@@ -20,6 +20,7 @@ namespace sm83
|
||||
void setClock(uint32_t freq);
|
||||
uint32_t getClock();
|
||||
|
||||
void processInterrupts();
|
||||
void interrupt(uint8_t type);
|
||||
|
||||
uint32_t step();
|
||||
|
||||
BIN
supermarioland2.gb
Normal file
BIN
supermarioland2.gb
Normal file
Binary file not shown.
1
ui.cpp
1
ui.cpp
@@ -1,5 +1,6 @@
|
||||
#include "ui.h"
|
||||
#include <SDL2/SDL.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace ui
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user