mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-08-11 09:24:10 +02:00
Update to v096r04 release.
byuu says: Changelog: - fixed S-DD1 RAM writes (Star Ocean audio fixed) - applied all of the DMG test ROM fixes discussed earlier; passes many more test ROMs now - at least until the GBVideoPlayer is working: for debugging purposes, CPU/PPU single-step now instead of sync just-in-time (~30% slower) - fixed OS X crash on NSTextView (hopefully, would be very odd if not) Unfortunately passing these test ROMs caused my favorite GB/GBC game to break all of its graphics =( Shin Megami Tensei - Devichil - Kuro no Sho (Japan) is all garbled now. I'm really quite bummed by this ... but I guess I'll go through and revert r04's fixes one at a time until I find what's causing it. On the plus side, Astro Rabby is playable now. Still acts weird when pressing B/A on the first screen, but the start button will start the game. EDIT: got it. Shin Megami Tensei - Devichil requires FF4F (VBK) to be readable. Before, it was always returning 0x00. With my return 0xFF patch, that broke. But it should be returning the VBK value, which also fixes it. Also need to handle FF68/FF6A reads. Was really hoping that'd help GBVideoPlayer too, but nope. It doesn't read any of those three registers.
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
#ifndef EMULATOR_HPP
|
#pragma once
|
||||||
#define EMULATOR_HPP
|
|
||||||
|
|
||||||
#include <nall/nall.hpp>
|
#include <nall/nall.hpp>
|
||||||
#include <nall/dsp.hpp>
|
#include <nall/dsp.hpp>
|
||||||
@@ -7,7 +6,7 @@ using namespace nall;
|
|||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "096.03";
|
static const string Version = "096.04";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
static const string Website = "http://byuu.org/";
|
||||||
@@ -55,5 +54,3 @@ template<typename R, typename... P> struct hook<auto (P...) -> R> {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
using varuint = varuint_t<uint>;
|
using varuint = varuint_t<uint>;
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
#ifndef EMULATOR_INTERFACE_HPP
|
#pragma once
|
||||||
#define EMULATOR_INTERFACE_HPP
|
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
|
|
||||||
@@ -113,5 +112,3 @@ struct Interface {
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
#ifndef FC_HPP
|
#pragma once
|
||||||
#define FC_HPP
|
|
||||||
|
|
||||||
#include <emulator/emulator.hpp>
|
#include <emulator/emulator.hpp>
|
||||||
#include <processor/r6502/r6502.hpp>
|
#include <processor/r6502/r6502.hpp>
|
||||||
@@ -53,7 +52,6 @@ namespace Famicom {
|
|||||||
#include <fc/ppu/ppu.hpp>
|
#include <fc/ppu/ppu.hpp>
|
||||||
#include <fc/cheat/cheat.hpp>
|
#include <fc/cheat/cheat.hpp>
|
||||||
#include <fc/video/video.hpp>
|
#include <fc/video/video.hpp>
|
||||||
#include <fc/interface/interface.hpp>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#include <fc/interface/interface.hpp>
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
#ifndef FC_HPP
|
|
||||||
namespace Famicom {
|
namespace Famicom {
|
||||||
#endif
|
|
||||||
|
|
||||||
struct ID {
|
struct ID {
|
||||||
enum : uint {
|
enum : uint {
|
||||||
@@ -58,6 +56,4 @@ private:
|
|||||||
|
|
||||||
extern Interface* interface;
|
extern Interface* interface;
|
||||||
|
|
||||||
#ifndef FC_HPP
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
@@ -65,7 +65,6 @@ auto APU::power() -> void {
|
|||||||
create(Main, 2 * 1024 * 1024);
|
create(Main, 2 * 1024 * 1024);
|
||||||
for(uint n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this;
|
for(uint n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this;
|
||||||
|
|
||||||
for(auto& n : mmio_data) n = 0x00;
|
|
||||||
sequencer_base = 0;
|
sequencer_base = 0;
|
||||||
sequencer_step = 0;
|
sequencer_step = 0;
|
||||||
|
|
||||||
@@ -74,42 +73,30 @@ auto APU::power() -> void {
|
|||||||
wave.power();
|
wave.power();
|
||||||
noise.power();
|
noise.power();
|
||||||
master.power();
|
master.power();
|
||||||
|
|
||||||
|
LinearFeedbackShiftRegisterGenerator r;
|
||||||
|
for(auto& n : wave.pattern) n = r();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto APU::mmio_read(uint16 addr) -> uint8 {
|
auto APU::mmio_read(uint16 addr) -> uint8 {
|
||||||
static const uint8 table[48] = {
|
//if(!master.enable && addr != 0xff26) return 0xff;
|
||||||
0x80, 0x3f, 0x00, 0xff, 0xbf, //square1
|
if(addr >= 0xff10 && addr <= 0xff14) return square1.read(addr);
|
||||||
0xff, 0x3f, 0x00, 0xff, 0xbf, //square2
|
if(addr >= 0xff15 && addr <= 0xff19) return square2.read(addr);
|
||||||
0x7f, 0xff, 0x9f, 0xff, 0xbf, //wave
|
if(addr >= 0xff1a && addr <= 0xff1e) return wave.read(addr);
|
||||||
0xff, 0xff, 0x00, 0x00, 0xbf, //noise
|
if(addr >= 0xff1f && addr <= 0xff23) return noise.read(addr);
|
||||||
0x00, 0x00, 0x70, //master
|
if(addr >= 0xff24 && addr <= 0xff26) return master.read(addr);
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //unmapped
|
if(addr >= 0xff30 && addr <= 0xff3f) return wave.read(addr);
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //wave pattern
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //wave pattern
|
|
||||||
};
|
|
||||||
|
|
||||||
if(addr == 0xff26) {
|
|
||||||
uint8 data = master.enable << 7;
|
|
||||||
if(square1.enable) data |= 0x01;
|
|
||||||
if(square2.enable) data |= 0x02;
|
|
||||||
if( wave.enable) data |= 0x04;
|
|
||||||
if( noise.enable) data |= 0x08;
|
|
||||||
return data | table[addr - 0xff10];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(addr >= 0xff10 && addr <= 0xff3f) return mmio_data[addr - 0xff10] | table[addr - 0xff10];
|
|
||||||
return 0xff;
|
return 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto APU::mmio_write(uint16 addr, uint8 data) -> void {
|
auto APU::mmio_write(uint16 addr, uint8 data) -> void {
|
||||||
if(addr >= 0xff10 && addr <= 0xff3f) mmio_data[addr - 0xff10] = data;
|
if(!master.enable && addr != 0xff26) return;
|
||||||
|
if(addr >= 0xff10 && addr <= 0xff14) return square1.write(addr, data);
|
||||||
if(addr >= 0xff10 && addr <= 0xff14) return square1.write (addr - 0xff10, data);
|
if(addr >= 0xff15 && addr <= 0xff19) return square2.write(addr, data);
|
||||||
if(addr >= 0xff15 && addr <= 0xff19) return square2.write (addr - 0xff15, data);
|
if(addr >= 0xff1a && addr <= 0xff1e) return wave.write(addr, data);
|
||||||
if(addr >= 0xff1a && addr <= 0xff1e) return wave.write (addr - 0xff1a, data);
|
if(addr >= 0xff1f && addr <= 0xff23) return noise.write(addr, data);
|
||||||
if(addr >= 0xff1f && addr <= 0xff23) return noise.write (addr - 0xff1f, data);
|
if(addr >= 0xff24 && addr <= 0xff26) return master.write(addr, data);
|
||||||
if(addr >= 0xff24 && addr <= 0xff26) return master.write (addr - 0xff24, data);
|
if(addr >= 0xff30 && addr <= 0xff3f) return wave.write(addr, data);
|
||||||
if(addr >= 0xff30 && addr <= 0xff3f) return wave.write_pattern(addr - 0xff30, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -15,7 +15,6 @@ struct APU : Thread, MMIO {
|
|||||||
#include "noise/noise.hpp"
|
#include "noise/noise.hpp"
|
||||||
#include "master/master.hpp"
|
#include "master/master.hpp"
|
||||||
|
|
||||||
uint8 mmio_data[48];
|
|
||||||
uint12 sequencer_base;
|
uint12 sequencer_base;
|
||||||
uint3 sequencer_step;
|
uint3 sequencer_step;
|
||||||
|
|
||||||
|
@@ -39,15 +39,42 @@ auto APU::Master::run() -> void {
|
|||||||
right >>= 1;
|
right >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto APU::Master::write(uint r, uint8 data) -> void {
|
auto APU::Master::read(uint16 addr) -> uint8 {
|
||||||
if(r == 0) { //$ff24 NR50
|
if(addr == 0xff24) { //NR50
|
||||||
|
return left_in_enable << 7 | left_volume << 4 | right_in_enable << 3 | right_volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff25) { //NR51
|
||||||
|
return channel4_left_enable << 7
|
||||||
|
| channel3_left_enable << 6
|
||||||
|
| channel2_left_enable << 5
|
||||||
|
| channel1_left_enable << 4
|
||||||
|
| channel4_right_enable << 3
|
||||||
|
| channel3_right_enable << 2
|
||||||
|
| channel2_right_enable << 1
|
||||||
|
| channel1_right_enable << 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff26) { //NR52
|
||||||
|
return enable << 7 | 0x70
|
||||||
|
| apu.noise.enable << 3
|
||||||
|
| apu.wave.enable << 2
|
||||||
|
| apu.square2.enable << 1
|
||||||
|
| apu.square1.enable << 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto APU::Master::write(uint16 addr, uint8 data) -> void {
|
||||||
|
if(addr == 0xff24) { //NR50
|
||||||
left_in_enable = data & 0x80;
|
left_in_enable = data & 0x80;
|
||||||
left_volume = (data >> 4) & 7;
|
left_volume = (data >> 4) & 7;
|
||||||
right_in_enable = data & 0x08;
|
right_in_enable = data & 0x08;
|
||||||
right_volume = (data >> 0) & 7;
|
right_volume = (data >> 0) & 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 1) { //$ff25 NR51
|
if(addr == 0xff25) { //NR51
|
||||||
channel4_left_enable = data & 0x80;
|
channel4_left_enable = data & 0x80;
|
||||||
channel3_left_enable = data & 0x40;
|
channel3_left_enable = data & 0x40;
|
||||||
channel2_left_enable = data & 0x20;
|
channel2_left_enable = data & 0x20;
|
||||||
@@ -58,8 +85,15 @@ auto APU::Master::write(uint r, uint8 data) -> void {
|
|||||||
channel1_right_enable = data & 0x01;
|
channel1_right_enable = data & 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 2) { //$ff26 NR52
|
if(addr == 0xff26) { //NR52
|
||||||
enable = data & 0x80;
|
enable = data & 0x80;
|
||||||
|
if(!enable) {
|
||||||
|
apu.square1.power();
|
||||||
|
apu.square2.power();
|
||||||
|
apu.wave.power();
|
||||||
|
apu.noise.power();
|
||||||
|
power();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
struct Master {
|
struct Master {
|
||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
auto write(uint r, uint8 data) -> void;
|
auto read(uint16 addr) -> uint8;
|
||||||
|
auto write(uint16 addr, uint8 data) -> void;
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
@@ -2,9 +2,14 @@ auto APU::Noise::dac_enable() const -> bool {
|
|||||||
return (envelope_volume || envelope_direction);
|
return (envelope_volume || envelope_direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto APU::Noise::get_period() const -> uint {
|
||||||
|
static const uint table[] = {4, 8, 16, 24, 32, 40, 48, 56};
|
||||||
|
return table[divisor] << frequency;
|
||||||
|
}
|
||||||
|
|
||||||
auto APU::Noise::run() -> void {
|
auto APU::Noise::run() -> void {
|
||||||
if(period && --period == 0) {
|
if(period && --period == 0) {
|
||||||
period = divisor << frequency;
|
period = get_period();
|
||||||
if(frequency < 14) {
|
if(frequency < 14) {
|
||||||
bool bit = (lfsr ^ (lfsr >> 1)) & 1;
|
bool bit = (lfsr ^ (lfsr >> 1)) & 1;
|
||||||
lfsr = (lfsr >> 1) ^ (bit << (narrow_lfsr ? 6 : 14));
|
lfsr = (lfsr >> 1) ^ (bit << (narrow_lfsr ? 6 : 14));
|
||||||
@@ -18,7 +23,7 @@ auto APU::Noise::run() -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto APU::Noise::clock_length() -> void {
|
auto APU::Noise::clock_length() -> void {
|
||||||
if(enable && counter) {
|
if(counter) {
|
||||||
if(++length == 0) enable = false;
|
if(++length == 0) enable = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,27 +36,50 @@ auto APU::Noise::clock_envelope() -> void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto APU::Noise::write(uint r, uint8 data) -> void {
|
auto APU::Noise::read(uint16 addr) -> uint8 {
|
||||||
if(r == 1) { //$ff20 NR41
|
if(addr == 0xff1f) { //NR40
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff20) { //NR41
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff21) { //NR42
|
||||||
|
return envelope_volume << 4 | envelope_direction << 3 | envelope_frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff22) { //NR43
|
||||||
|
return frequency << 4 | narrow_lfsr << 3 | divisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff23) { //NR44
|
||||||
|
return 0x80 | counter << 6 | 0x3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto APU::Noise::write(uint16 addr, uint8 data) -> void {
|
||||||
|
if(addr == 0xff20) { //NR41
|
||||||
length = data & 0x3f;
|
length = data & 0x3f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 2) { //$ff21 NR42
|
if(addr == 0xff21) { //NR42
|
||||||
envelope_volume = data >> 4;
|
envelope_volume = data >> 4;
|
||||||
envelope_direction = data & 0x08;
|
envelope_direction = data & 0x08;
|
||||||
envelope_frequency = data & 0x07;
|
envelope_frequency = data & 0x07;
|
||||||
if(dac_enable() == false) enable = false;
|
if(dac_enable() == false) enable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 3) { //$ff22 NR43
|
if(addr == 0xff22) { //NR43
|
||||||
frequency = data >> 4;
|
frequency = data >> 4;
|
||||||
narrow_lfsr = data & 0x08;
|
narrow_lfsr = data & 0x08;
|
||||||
divisor = (data & 0x07) << 3;
|
divisor = data & 0x07;
|
||||||
if(divisor == 0) divisor = 4;
|
period = get_period();
|
||||||
period = divisor << frequency;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 4) { //$ff34 NR44
|
if(addr == 0xff23) { //NR44
|
||||||
bool initialize = data & 0x80;
|
bool initialize = data & 0x80;
|
||||||
counter = data & 0x40;
|
counter = data & 0x40;
|
||||||
|
|
||||||
|
@@ -1,10 +1,12 @@
|
|||||||
struct Noise {
|
struct Noise {
|
||||||
auto dac_enable() const -> bool;
|
auto dac_enable() const -> bool;
|
||||||
|
auto get_period() const -> uint;
|
||||||
|
|
||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
auto clock_length() -> void;
|
auto clock_length() -> void;
|
||||||
auto clock_envelope() -> void;
|
auto clock_envelope() -> void;
|
||||||
auto write(uint r, uint8 data) -> void;
|
auto read(uint16 addr) -> uint8;
|
||||||
|
auto write(uint16 addr, uint8 data) -> void;
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
@@ -16,7 +18,7 @@ struct Noise {
|
|||||||
uint3 envelope_frequency;
|
uint3 envelope_frequency;
|
||||||
uint4 frequency;
|
uint4 frequency;
|
||||||
bool narrow_lfsr;
|
bool narrow_lfsr;
|
||||||
uint divisor;
|
uint3 divisor;
|
||||||
bool counter;
|
bool counter;
|
||||||
|
|
||||||
int16 output;
|
int16 output;
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
auto APU::serialize(serializer& s) -> void {
|
auto APU::serialize(serializer& s) -> void {
|
||||||
Thread::serialize(s);
|
Thread::serialize(s);
|
||||||
|
|
||||||
s.array(mmio_data);
|
|
||||||
s.integer(sequencer_base);
|
s.integer(sequencer_base);
|
||||||
s.integer(sequencer_step);
|
s.integer(sequencer_step);
|
||||||
|
|
||||||
|
@@ -37,7 +37,7 @@ auto APU::Square1::sweep(bool update) -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto APU::Square1::clock_length() -> void {
|
auto APU::Square1::clock_length() -> void {
|
||||||
if(counter && enable) {
|
if(counter) {
|
||||||
if(++length == 0) enable = false;
|
if(++length == 0) enable = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,31 +58,55 @@ auto APU::Square1::clock_envelope() -> void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto APU::Square1::write(uint r, uint8 data) -> void {
|
auto APU::Square1::read(uint16 addr) -> uint8 {
|
||||||
if(r == 0) { //$ff10 NR10
|
if(addr == 0xff10) { //NR10
|
||||||
|
return 0x80 | sweep_frequency << 4 | sweep_direction << 3 | sweep_shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff11) { //NR11
|
||||||
|
return duty << 6 | 0x3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff12) { //NR12
|
||||||
|
return envelope_volume << 4 | envelope_direction << 3 | envelope_frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff13) { //NR13
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff14) { //NR14
|
||||||
|
return 0x80 | counter << 6 | 0x3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto APU::Square1::write(uint16 addr, uint8 data) -> void {
|
||||||
|
if(addr == 0xff10) { //NR10
|
||||||
if(sweep_negate && sweep_direction && !(data & 0x08)) enable = false;
|
if(sweep_negate && sweep_direction && !(data & 0x08)) enable = false;
|
||||||
sweep_frequency = (data >> 4) & 7;
|
sweep_frequency = (data >> 4) & 7;
|
||||||
sweep_direction = data & 0x08;
|
sweep_direction = data & 0x08;
|
||||||
sweep_shift = data & 0x07;
|
sweep_shift = data & 0x07;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 1) { //$ff11 NR11
|
if(addr == 0xff11) { //NR11
|
||||||
duty = data >> 6;
|
duty = data >> 6;
|
||||||
length = data & 0x3f;
|
length = data & 0x3f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 2) { //$ff12 NR12
|
if(addr == 0xff12) { //NR12
|
||||||
envelope_volume = data >> 4;
|
envelope_volume = data >> 4;
|
||||||
envelope_direction = data & 0x08;
|
envelope_direction = data & 0x08;
|
||||||
envelope_frequency = data & 0x07;
|
envelope_frequency = data & 0x07;
|
||||||
if(dac_enable() == false) enable = false;
|
if(dac_enable() == false) enable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 3) { //$ff13 NR13
|
if(addr == 0xff13) { //NR13
|
||||||
frequency = (frequency & 0x0700) | data;
|
frequency = (frequency & 0x0700) | data;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 4) { //$ff14 NR14
|
if(addr == 0xff14) { //NR14
|
||||||
bool initialize = data & 0x80;
|
bool initialize = data & 0x80;
|
||||||
counter = data & 0x40;
|
counter = data & 0x40;
|
||||||
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
|
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
|
||||||
|
@@ -6,7 +6,8 @@ struct Square1 {
|
|||||||
auto clock_length() -> void;
|
auto clock_length() -> void;
|
||||||
auto clock_sweep() -> void;
|
auto clock_sweep() -> void;
|
||||||
auto clock_envelope() -> void;
|
auto clock_envelope() -> void;
|
||||||
auto write(uint r, uint8 data) -> void;
|
auto read(uint16 addr) -> uint8;
|
||||||
|
auto write(uint16 addr, uint8 data) -> void;
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
@@ -21,7 +21,7 @@ auto APU::Square2::run() -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto APU::Square2::clock_length() -> void {
|
auto APU::Square2::clock_length() -> void {
|
||||||
if(counter && enable) {
|
if(counter) {
|
||||||
if(++length == 0) enable = false;
|
if(++length == 0) enable = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,24 +34,48 @@ auto APU::Square2::clock_envelope() -> void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto APU::Square2::write(uint r, uint8 data) -> void {
|
auto APU::Square2::read(uint16 addr) -> uint8 {
|
||||||
if(r == 1) { //$ff16 NR21
|
if(addr == 0xff15) { //NR20
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff16) { //NR21
|
||||||
|
return duty << 6 | 0x3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff17) { //NR22
|
||||||
|
return envelope_volume << 4 | envelope_direction << 3 | envelope_frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff18) { //NR23
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff19) { //NR24
|
||||||
|
return 0x80 | counter << 6 | 0x3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto APU::Square2::write(uint16 addr, uint8 data) -> void {
|
||||||
|
if(addr == 0xff16) { //NR21
|
||||||
duty = data >> 6;
|
duty = data >> 6;
|
||||||
length = (data & 0x3f);
|
length = (data & 0x3f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 2) { //$ff17 NR22
|
if(addr == 0xff17) { //NR22
|
||||||
envelope_volume = data >> 4;
|
envelope_volume = data >> 4;
|
||||||
envelope_direction = data & 0x08;
|
envelope_direction = data & 0x08;
|
||||||
envelope_frequency = data & 0x07;
|
envelope_frequency = data & 0x07;
|
||||||
if(dac_enable() == false) enable = false;
|
if(dac_enable() == false) enable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 3) { //$ff18 NR23
|
if(addr == 0xff18) { //NR23
|
||||||
frequency = (frequency & 0x0700) | data;
|
frequency = (frequency & 0x0700) | data;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 4) { //$ff19 NR24
|
if(addr == 0xff19) { //NR24
|
||||||
bool initialize = data & 0x80;
|
bool initialize = data & 0x80;
|
||||||
counter = data & 0x40;
|
counter = data & 0x40;
|
||||||
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
|
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
|
||||||
|
@@ -4,7 +4,8 @@ struct Square2 {
|
|||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
auto clock_length() -> void;
|
auto clock_length() -> void;
|
||||||
auto clock_envelope() -> void;
|
auto clock_envelope() -> void;
|
||||||
auto write(uint r, uint8 data) -> void;
|
auto read(uint16 addr) -> uint8;
|
||||||
|
auto write(uint16 addr, uint8 data) -> void;
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
@@ -1,45 +1,73 @@
|
|||||||
|
auto APU::Wave::get_pattern(uint5 offset) const -> uint4 {
|
||||||
|
return pattern[offset >> 1] >> (offset & 1 ? 0 : 4);
|
||||||
|
}
|
||||||
|
|
||||||
auto APU::Wave::run() -> void {
|
auto APU::Wave::run() -> void {
|
||||||
if(period && --period == 0) {
|
if(period && --period == 0) {
|
||||||
period = 1 * (2048 - frequency);
|
period = 1 * (2048 - frequency);
|
||||||
pattern_sample = pattern[++pattern_offset];
|
pattern_sample = get_pattern(++pattern_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint4 sample = pattern_sample >> volume_shift;
|
static const uint shift[] = {4, 0, 1, 2}; //0%, 100%, 50%, 25%
|
||||||
|
uint4 sample = pattern_sample >> shift[volume];
|
||||||
if(enable == false) sample = 0;
|
if(enable == false) sample = 0;
|
||||||
|
|
||||||
output = sample;
|
output = sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto APU::Wave::clock_length() -> void {
|
auto APU::Wave::clock_length() -> void {
|
||||||
if(enable && counter) {
|
if(counter) {
|
||||||
if(++length == 0) enable = false;
|
if(++length == 0) enable = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto APU::Wave::write(uint r, uint8 data) -> void {
|
auto APU::Wave::read(uint16 addr) -> uint8 {
|
||||||
if(r == 0) { //$ff1a NR30
|
if(addr == 0xff1a) { //NR30
|
||||||
|
return dac_enable << 7 | 0x7f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff1b) { //NR31
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff1c) { //NR32
|
||||||
|
return 0x80 | volume << 5 | 0x1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff1d) { //NR33
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff1e) { //NR34
|
||||||
|
return 0x80 | counter << 6 | 0x3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr >= 0xff30 && addr <= 0xff3f) {
|
||||||
|
return pattern[addr & 15];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto APU::Wave::write(uint16 addr, uint8 data) -> void {
|
||||||
|
if(addr == 0xff1a) { //NR30
|
||||||
dac_enable = data & 0x80;
|
dac_enable = data & 0x80;
|
||||||
if(dac_enable == false) enable = false;
|
if(dac_enable == false) enable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 1) { //$ff1b NR31
|
if(addr == 0xff1b) { //NR31
|
||||||
length = data;
|
length = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 2) { //$ff1c NR32
|
if(addr == 0xff1c) { //NR32
|
||||||
switch((data >> 5) & 3) {
|
volume = data >> 5;
|
||||||
case 0: volume_shift = 4; break; // 0%
|
|
||||||
case 1: volume_shift = 0; break; //100%
|
|
||||||
case 2: volume_shift = 1; break; // 50%
|
|
||||||
case 3: volume_shift = 2; break; // 25%
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 3) { //$ff1d NR33
|
if(addr == 0xff1d) { //NR33
|
||||||
frequency = (frequency & 0x0700) | data;
|
frequency = (frequency & 0x0700) | data;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 4) { //$ff1e NR34
|
if(addr == 0xff1e) { //NR34
|
||||||
bool initialize = data & 0x80;
|
bool initialize = data & 0x80;
|
||||||
counter = data & 0x40;
|
counter = data & 0x40;
|
||||||
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
|
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
|
||||||
@@ -50,25 +78,20 @@ auto APU::Wave::write(uint r, uint8 data) -> void {
|
|||||||
pattern_offset = 0;
|
pattern_offset = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
auto APU::Wave::write_pattern(uint p, uint8 data) -> void {
|
if(addr >= 0xff30 && addr <= 0xff3f) {
|
||||||
p <<= 1;
|
pattern[addr & 15] = data;
|
||||||
pattern[p + 0] = (data >> 4) & 15;
|
}
|
||||||
pattern[p + 1] = (data >> 0) & 15;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto APU::Wave::power() -> void {
|
auto APU::Wave::power() -> void {
|
||||||
enable = 0;
|
enable = 0;
|
||||||
|
|
||||||
dac_enable = 0;
|
dac_enable = 0;
|
||||||
volume_shift = 0;
|
volume = 0;
|
||||||
frequency = 0;
|
frequency = 0;
|
||||||
counter = 0;
|
counter = 0;
|
||||||
|
|
||||||
LinearFeedbackShiftRegisterGenerator r;
|
|
||||||
for(auto& n : pattern) n = r() & 15;
|
|
||||||
|
|
||||||
output = 0;
|
output = 0;
|
||||||
length = 0;
|
length = 0;
|
||||||
period = 0;
|
period = 0;
|
||||||
@@ -80,7 +103,7 @@ auto APU::Wave::serialize(serializer& s) -> void {
|
|||||||
s.integer(enable);
|
s.integer(enable);
|
||||||
|
|
||||||
s.integer(dac_enable);
|
s.integer(dac_enable);
|
||||||
s.integer(volume_shift);
|
s.integer(volume);
|
||||||
s.integer(frequency);
|
s.integer(frequency);
|
||||||
s.integer(counter);
|
s.integer(counter);
|
||||||
s.array(pattern);
|
s.array(pattern);
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
struct Wave {
|
struct Wave {
|
||||||
|
auto get_pattern(uint5 offset) const -> uint4;
|
||||||
|
|
||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
auto clock_length() -> void;
|
auto clock_length() -> void;
|
||||||
auto write(uint r, uint8 data) -> void;
|
auto read(uint16 addr) -> uint8;
|
||||||
auto write_pattern(uint p, uint8 data) -> void;
|
auto write(uint16 addr, uint8 data) -> void;
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
@@ -10,10 +12,10 @@ struct Wave {
|
|||||||
bool enable;
|
bool enable;
|
||||||
|
|
||||||
bool dac_enable;
|
bool dac_enable;
|
||||||
uint volume_shift;
|
uint2 volume;
|
||||||
uint11 frequency;
|
uint11 frequency;
|
||||||
bool counter;
|
bool counter;
|
||||||
uint8 pattern[32];
|
uint8 pattern[16];
|
||||||
|
|
||||||
int16 output;
|
int16 output;
|
||||||
uint8 length;
|
uint8 length;
|
||||||
|
@@ -81,13 +81,13 @@ auto CPU::interrupt_test() -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::interrupt_exec(uint16 pc) -> void {
|
auto CPU::interrupt_exec(uint16 pc) -> void {
|
||||||
|
op_io();
|
||||||
|
op_io();
|
||||||
|
op_io();
|
||||||
r.ime = 0;
|
r.ime = 0;
|
||||||
op_write(--r[SP], r[PC] >> 8);
|
op_write(--r[SP], r[PC] >> 8);
|
||||||
op_write(--r[SP], r[PC] >> 0);
|
op_write(--r[SP], r[PC] >> 0);
|
||||||
r[PC] = pc;
|
r[PC] = pc;
|
||||||
op_io();
|
|
||||||
op_io();
|
|
||||||
op_io();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::stop() -> bool {
|
auto CPU::stop() -> bool {
|
||||||
@@ -201,8 +201,8 @@ auto CPU::power() -> void {
|
|||||||
status.interrupt_enable_vblank = 0;
|
status.interrupt_enable_vblank = 0;
|
||||||
|
|
||||||
oamdma.active = false;
|
oamdma.active = false;
|
||||||
|
oamdma.clock = 0;
|
||||||
oamdma.bank = 0;
|
oamdma.bank = 0;
|
||||||
oamdma.offset = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -36,7 +36,7 @@ struct CPU : Processor::LR35902, Thread, MMIO {
|
|||||||
auto hblank() -> void;
|
auto hblank() -> void;
|
||||||
|
|
||||||
struct Status {
|
struct Status {
|
||||||
uint clock;
|
uint22 clock;
|
||||||
|
|
||||||
//$ff00 JOYP
|
//$ff00 JOYP
|
||||||
bool p15;
|
bool p15;
|
||||||
@@ -53,7 +53,7 @@ struct CPU : Processor::LR35902, Thread, MMIO {
|
|||||||
bool serial_clock;
|
bool serial_clock;
|
||||||
|
|
||||||
//$ff04 DIV
|
//$ff04 DIV
|
||||||
uint8 div;
|
uint16 div;
|
||||||
|
|
||||||
//$ff05 TIMA
|
//$ff05 TIMA
|
||||||
uint8 tima;
|
uint8 tima;
|
||||||
@@ -109,8 +109,8 @@ struct CPU : Processor::LR35902, Thread, MMIO {
|
|||||||
|
|
||||||
struct OAMDMA {
|
struct OAMDMA {
|
||||||
bool active;
|
bool active;
|
||||||
|
uint clock;
|
||||||
uint8 bank;
|
uint8 bank;
|
||||||
uint8 offset;
|
|
||||||
} oamdma;
|
} oamdma;
|
||||||
|
|
||||||
uint8 wram[32768]; //GB=8192, GBC=32768
|
uint8 wram[32768]; //GB=8192, GBC=32768
|
||||||
|
@@ -6,14 +6,16 @@ auto CPU::op_io() -> void {
|
|||||||
auto CPU::op_read(uint16 addr) -> uint8 {
|
auto CPU::op_read(uint16 addr) -> uint8 {
|
||||||
cycle_edge();
|
cycle_edge();
|
||||||
add_clocks(4);
|
add_clocks(4);
|
||||||
if(oamdma.active && (addr < 0xff80 || addr == 0xffff)) return 0xff;
|
//OAM is inaccessible during OAMDMA transfer
|
||||||
|
if(oamdma.active && oamdma.clock >= 8 && addr >= 0xfe00 && addr <= 0xfe9f) return 0xff;
|
||||||
return bus.read(addr);
|
return bus.read(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::op_write(uint16 addr, uint8 data) -> void {
|
auto CPU::op_write(uint16 addr, uint8 data) -> void {
|
||||||
cycle_edge();
|
cycle_edge();
|
||||||
add_clocks(4);
|
add_clocks(4);
|
||||||
if(oamdma.active && (addr < 0xff80 || addr == 0xffff)) return;
|
//OAM is inaccessible during OAMDMA transfer
|
||||||
|
if(oamdma.active && oamdma.clock >= 8 && addr >= 0xfe00 && addr <= 0xfe9f) return;
|
||||||
bus.write(addr, data);
|
bus.write(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -53,7 +53,7 @@ auto CPU::mmio_read(uint16 addr) -> uint8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(addr == 0xff04) { //DIV
|
if(addr == 0xff04) { //DIV
|
||||||
return status.div;
|
return status.div >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(addr == 0xff05) { //TIMA
|
if(addr == 0xff05) { //TIMA
|
||||||
@@ -188,8 +188,8 @@ auto CPU::mmio_write(uint16 addr, uint8 data) -> void {
|
|||||||
|
|
||||||
if(addr == 0xff46) { //DMA
|
if(addr == 0xff46) { //DMA
|
||||||
oamdma.active = true;
|
oamdma.active = true;
|
||||||
|
oamdma.clock = 0;
|
||||||
oamdma.bank = data;
|
oamdma.bank = data;
|
||||||
oamdma.offset = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +225,7 @@ auto CPU::mmio_write(uint16 addr, uint8 data) -> void {
|
|||||||
|
|
||||||
if(status.dma_mode == 0) {
|
if(status.dma_mode == 0) {
|
||||||
do {
|
do {
|
||||||
for(unsigned n = 0; n < 16; n++) {
|
for(auto n : range(16)) {
|
||||||
dma_write(status.dma_target++, dma_read(status.dma_source++));
|
dma_write(status.dma_target++, dma_read(status.dma_source++));
|
||||||
}
|
}
|
||||||
add_clocks(8 << status.speed_double);
|
add_clocks(8 << status.speed_double);
|
||||||
|
@@ -55,6 +55,6 @@ auto CPU::serialize(serializer& s) -> void {
|
|||||||
s.integer(status.interrupt_enable_vblank);
|
s.integer(status.interrupt_enable_vblank);
|
||||||
|
|
||||||
s.integer(oamdma.active);
|
s.integer(oamdma.active);
|
||||||
|
s.integer(oamdma.clock);
|
||||||
s.integer(oamdma.bank);
|
s.integer(oamdma.bank);
|
||||||
s.integer(oamdma.offset);
|
|
||||||
}
|
}
|
||||||
|
@@ -3,39 +3,46 @@
|
|||||||
// 154 scanlines/frame
|
// 154 scanlines/frame
|
||||||
|
|
||||||
auto CPU::add_clocks(uint clocks) -> void {
|
auto CPU::add_clocks(uint clocks) -> void {
|
||||||
|
if(system.sgb()) system.clocks_executed += clocks;
|
||||||
|
|
||||||
|
while(clocks--) {
|
||||||
if(oamdma.active) {
|
if(oamdma.active) {
|
||||||
for(uint n = 0; n < 4 * clocks; n++) {
|
uint offset = oamdma.clock++;
|
||||||
bus.write(0xfe00 + oamdma.offset, bus.read((oamdma.bank << 8) + oamdma.offset));
|
if((offset & 3) == 0) {
|
||||||
if(++oamdma.offset == 160) {
|
offset >>= 2;
|
||||||
|
if(offset == 0) {
|
||||||
|
//warm-up
|
||||||
|
} else if(offset == 161) {
|
||||||
|
//cool-down; disable
|
||||||
oamdma.active = false;
|
oamdma.active = false;
|
||||||
break;
|
} else {
|
||||||
|
bus.write(0xfe00 + offset - 1, bus.read((oamdma.bank << 8) + offset - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
system.clocks_executed += clocks;
|
if(++status.clock == 0) {
|
||||||
if(system.sgb()) scheduler.exit(Scheduler::ExitReason::StepEvent);
|
|
||||||
|
|
||||||
status.clock += clocks;
|
|
||||||
if(status.clock >= 4 * 1024 * 1024) {
|
|
||||||
status.clock -= 4 * 1024 * 1024;
|
|
||||||
cartridge.mbc3.second();
|
cartridge.mbc3.second();
|
||||||
}
|
}
|
||||||
|
|
||||||
//4MHz / N(hz) - 1 = mask
|
//4MHz / N(hz) - 1 = mask
|
||||||
if((status.clock & 15) == 0) timer_262144hz();
|
status.div++;
|
||||||
if((status.clock & 63) == 0) timer_65536hz();
|
if((status.div & 15) == 0) timer_262144hz();
|
||||||
if((status.clock & 255) == 0) timer_16384hz();
|
if((status.div & 63) == 0) timer_65536hz();
|
||||||
if((status.clock & 511) == 0) timer_8192hz();
|
if((status.div & 255) == 0) timer_16384hz();
|
||||||
if((status.clock & 1023) == 0) timer_4096hz();
|
if((status.div & 511) == 0) timer_8192hz();
|
||||||
|
if((status.div & 1023) == 0) timer_4096hz();
|
||||||
|
|
||||||
ppu.clock -= clocks * ppu.frequency;
|
ppu.clock -= ppu.frequency;
|
||||||
if(ppu.clock < 0) co_switch(scheduler.active_thread = ppu.thread);
|
if(ppu.clock < 0) co_switch(scheduler.active_thread = ppu.thread);
|
||||||
|
|
||||||
apu.clock -= clocks * apu.frequency;
|
apu.clock -= apu.frequency;
|
||||||
if(apu.clock < 0) co_switch(scheduler.active_thread = apu.thread);
|
if(apu.clock < 0) co_switch(scheduler.active_thread = apu.thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(system.sgb()) scheduler.exit(Scheduler::ExitReason::StepEvent);
|
||||||
|
}
|
||||||
|
|
||||||
auto CPU::timer_262144hz() -> void {
|
auto CPU::timer_262144hz() -> void {
|
||||||
if(status.timer_enable && status.timer_clock == 1) {
|
if(status.timer_enable && status.timer_clock == 1) {
|
||||||
if(++status.tima == 0) {
|
if(++status.tima == 0) {
|
||||||
@@ -61,8 +68,6 @@ auto CPU::timer_16384hz() -> void {
|
|||||||
interrupt_raise(Interrupt::Timer);
|
interrupt_raise(Interrupt::Timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status.div++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::timer_8192hz() -> void {
|
auto CPU::timer_8192hz() -> void {
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
#ifndef GB_HPP
|
#pragma once
|
||||||
#define GB_HPP
|
|
||||||
|
|
||||||
#include <emulator/emulator.hpp>
|
#include <emulator/emulator.hpp>
|
||||||
#include <processor/lr35902/lr35902.hpp>
|
#include <processor/lr35902/lr35902.hpp>
|
||||||
@@ -52,6 +51,6 @@ namespace GameBoy {
|
|||||||
#include <gb/apu/apu.hpp>
|
#include <gb/apu/apu.hpp>
|
||||||
#include <gb/cheat/cheat.hpp>
|
#include <gb/cheat/cheat.hpp>
|
||||||
#include <gb/video/video.hpp>
|
#include <gb/video/video.hpp>
|
||||||
};
|
}
|
||||||
|
|
||||||
#endif
|
#include <gb/interface/interface.hpp>
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
#ifndef GB_HPP
|
|
||||||
namespace GameBoy {
|
namespace GameBoy {
|
||||||
#endif
|
|
||||||
|
|
||||||
struct ID {
|
struct ID {
|
||||||
enum : uint {
|
enum : uint {
|
||||||
@@ -72,6 +70,4 @@ private:
|
|||||||
|
|
||||||
extern Interface* interface;
|
extern Interface* interface;
|
||||||
|
|
||||||
#ifndef GB_HPP
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
@@ -45,12 +45,14 @@ auto PPU::main() -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::add_clocks(uint clocks) -> void {
|
auto PPU::add_clocks(uint clocks) -> void {
|
||||||
status.lx += clocks;
|
while(clocks--) {
|
||||||
clock += clocks * cpu.frequency;
|
status.lx++;
|
||||||
|
clock += cpu.frequency;
|
||||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||||
co_switch(scheduler.active_thread = cpu.thread);
|
co_switch(scheduler.active_thread = cpu.thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto PPU::scanline() -> void {
|
auto PPU::scanline() -> void {
|
||||||
status.lx = 0;
|
status.lx = 0;
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
#ifndef GBA_HPP
|
#pragma once
|
||||||
#define GBA_HPP
|
|
||||||
|
|
||||||
#include <emulator/emulator.hpp>
|
#include <emulator/emulator.hpp>
|
||||||
#include <processor/arm/arm.hpp>
|
#include <processor/arm/arm.hpp>
|
||||||
@@ -56,7 +55,6 @@ namespace GameBoyAdvance {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#include <gba/memory/memory.hpp>
|
#include <gba/memory/memory.hpp>
|
||||||
#include <gba/interface/interface.hpp>
|
|
||||||
#include <gba/scheduler/scheduler.hpp>
|
#include <gba/scheduler/scheduler.hpp>
|
||||||
#include <gba/system/system.hpp>
|
#include <gba/system/system.hpp>
|
||||||
#include <gba/cartridge/cartridge.hpp>
|
#include <gba/cartridge/cartridge.hpp>
|
||||||
@@ -67,4 +65,4 @@ namespace GameBoyAdvance {
|
|||||||
#include <gba/video/video.hpp>
|
#include <gba/video/video.hpp>
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#include <gba/interface/interface.hpp>
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
#ifndef GBA_HPP
|
|
||||||
namespace GameBoyAdvance {
|
namespace GameBoyAdvance {
|
||||||
#endif
|
|
||||||
|
|
||||||
struct ID {
|
struct ID {
|
||||||
enum : uint {
|
enum : uint {
|
||||||
@@ -55,6 +53,4 @@ private:
|
|||||||
|
|
||||||
extern Interface* interface;
|
extern Interface* interface;
|
||||||
|
|
||||||
#ifndef GBA_HPP
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
@@ -103,9 +103,9 @@ auto LR35902::op_ld_sp_hl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<uint x> auto LR35902::op_push_rr() {
|
template<uint x> auto LR35902::op_push_rr() {
|
||||||
|
op_io();
|
||||||
op_write(--r[SP], r[x] >> 8);
|
op_write(--r[SP], r[x] >> 8);
|
||||||
op_write(--r[SP], r[x] >> 0);
|
op_write(--r[SP], r[x] >> 0);
|
||||||
op_io();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<uint x> auto LR35902::op_pop_rr() {
|
template<uint x> auto LR35902::op_pop_rr() {
|
||||||
@@ -297,24 +297,24 @@ template<uint x> auto LR35902::op_dec_rr() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto LR35902::op_add_sp_n() {
|
auto LR35902::op_add_sp_n() {
|
||||||
op_io();
|
|
||||||
op_io();
|
|
||||||
int n = (int8)op_read(r[PC]++);
|
int n = (int8)op_read(r[PC]++);
|
||||||
r.f.z = 0;
|
r.f.z = 0;
|
||||||
r.f.n = 0;
|
r.f.n = 0;
|
||||||
r.f.h = ((r[SP] & 0x0f) + (n & 0x0f)) > 0x0f;
|
r.f.h = ((r[SP] & 0x0f) + (n & 0x0f)) > 0x0f;
|
||||||
r.f.c = ((r[SP] & 0xff) + (n & 0xff)) > 0xff;
|
r.f.c = ((r[SP] & 0xff) + (n & 0xff)) > 0xff;
|
||||||
r[SP] += n;
|
r[SP] += n;
|
||||||
|
op_io();
|
||||||
|
op_io();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto LR35902::op_ld_hl_sp_n() {
|
auto LR35902::op_ld_hl_sp_n() {
|
||||||
op_io();
|
|
||||||
int n = (int8)op_read(r[PC]++);
|
int n = (int8)op_read(r[PC]++);
|
||||||
r.f.z = 0;
|
r.f.z = 0;
|
||||||
r.f.n = 0;
|
r.f.n = 0;
|
||||||
r.f.h = ((r[SP] & 0x0f) + (n & 0x0f)) > 0x0f;
|
r.f.h = ((r[SP] & 0x0f) + (n & 0x0f)) > 0x0f;
|
||||||
r.f.c = ((r[SP] & 0xff) + (n & 0xff)) > 0xff;
|
r.f.c = ((r[SP] & 0xff) + (n & 0xff)) > 0xff;
|
||||||
r[HL] = r[SP] + n;
|
r[HL] = r[SP] + n;
|
||||||
|
op_io();
|
||||||
}
|
}
|
||||||
|
|
||||||
//rotate/shift commands
|
//rotate/shift commands
|
||||||
@@ -618,20 +618,20 @@ template<uint x, bool y> auto LR35902::op_jr_f_n() {
|
|||||||
auto LR35902::op_call_nn() {
|
auto LR35902::op_call_nn() {
|
||||||
uint8 lo = op_read(r[PC]++);
|
uint8 lo = op_read(r[PC]++);
|
||||||
uint8 hi = op_read(r[PC]++);
|
uint8 hi = op_read(r[PC]++);
|
||||||
|
op_io();
|
||||||
op_write(--r[SP], r[PC] >> 8);
|
op_write(--r[SP], r[PC] >> 8);
|
||||||
op_write(--r[SP], r[PC] >> 0);
|
op_write(--r[SP], r[PC] >> 0);
|
||||||
r[PC] = (hi << 8) | (lo << 0);
|
r[PC] = (hi << 8) | (lo << 0);
|
||||||
op_io();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<uint x, bool y> auto LR35902::op_call_f_nn() {
|
template<uint x, bool y> auto LR35902::op_call_f_nn() {
|
||||||
uint8 lo = op_read(r[PC]++);
|
uint8 lo = op_read(r[PC]++);
|
||||||
uint8 hi = op_read(r[PC]++);
|
uint8 hi = op_read(r[PC]++);
|
||||||
if(r.f[x] == y) {
|
if(r.f[x] == y) {
|
||||||
|
op_io();
|
||||||
op_write(--r[SP], r[PC] >> 8);
|
op_write(--r[SP], r[PC] >> 8);
|
||||||
op_write(--r[SP], r[PC] >> 0);
|
op_write(--r[SP], r[PC] >> 0);
|
||||||
r[PC] = (hi << 8) | (lo << 0);
|
r[PC] = (hi << 8) | (lo << 0);
|
||||||
op_io();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -661,8 +661,8 @@ auto LR35902::op_reti() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<uint n> auto LR35902::op_rst_n() {
|
template<uint n> auto LR35902::op_rst_n() {
|
||||||
|
op_io();
|
||||||
op_write(--r[SP], r[PC] >> 8);
|
op_write(--r[SP], r[PC] >> 8);
|
||||||
op_write(--r[SP], r[PC] >> 0);
|
op_write(--r[SP], r[PC] >> 0);
|
||||||
r[PC] = n;
|
r[PC] = n;
|
||||||
op_io();
|
|
||||||
}
|
}
|
||||||
|
@@ -146,26 +146,14 @@ auto SDD1::mcurom_read(uint addr, uint8) -> uint8 {
|
|||||||
auto SDD1::mcurom_write(uint addr, uint8 data) -> void {
|
auto SDD1::mcurom_write(uint addr, uint8 data) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//map address=00-3f,80-bf:6000-7fff mask=0xe000
|
||||||
|
//map address=70-7d:0000-7fff mask=0x8000
|
||||||
auto SDD1::mcuram_read(uint addr, uint8 data) -> uint8 {
|
auto SDD1::mcuram_read(uint addr, uint8 data) -> uint8 {
|
||||||
if((addr & 0x60e000) == 0x006000) { //$00-3f,80-bf:6000-7fff
|
|
||||||
return ram.read(addr & 0x1fff, data);
|
return ram.read(addr & 0x1fff, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0xf08000) == 0x700000) { //$70-7f:0000-7fff
|
|
||||||
return ram.read(addr & 0x1fff, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto SDD1::mcuram_write(uint addr, uint8 data) -> void {
|
auto SDD1::mcuram_write(uint addr, uint8 data) -> void {
|
||||||
if((addr & 0x60e000) == 0x006000) { //$00-3f,80-bf:6000-7fff
|
|
||||||
return ram.write(addr & 0x1fff, data);
|
return ram.write(addr & 0x1fff, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0xf08000) == 0x700000) { //$70-7f:0000-7fff
|
|
||||||
return ram.write(addr & 0x1fff, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
#ifndef SFC_HPP
|
|
||||||
namespace SuperFamicom {
|
namespace SuperFamicom {
|
||||||
#endif
|
|
||||||
|
|
||||||
struct ID {
|
struct ID {
|
||||||
enum : uint {
|
enum : uint {
|
||||||
@@ -126,6 +124,4 @@ struct Interface : Emulator::Interface {
|
|||||||
|
|
||||||
extern Interface* interface;
|
extern Interface* interface;
|
||||||
|
|
||||||
#ifndef SFC_HPP
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
#ifndef SFC_HPP
|
#pragma once
|
||||||
#define SFC_HPP
|
|
||||||
|
|
||||||
#include <emulator/emulator.hpp>
|
#include <emulator/emulator.hpp>
|
||||||
#include <processor/arm/arm.hpp>
|
#include <processor/arm/arm.hpp>
|
||||||
@@ -71,10 +70,9 @@ namespace SuperFamicom {
|
|||||||
#include <sfc/slot/slot.hpp>
|
#include <sfc/slot/slot.hpp>
|
||||||
#include <sfc/cartridge/cartridge.hpp>
|
#include <sfc/cartridge/cartridge.hpp>
|
||||||
#include <sfc/cheat/cheat.hpp>
|
#include <sfc/cheat/cheat.hpp>
|
||||||
#include <sfc/interface/interface.hpp>
|
|
||||||
|
|
||||||
#include <sfc/memory/memory-inline.hpp>
|
#include <sfc/memory/memory-inline.hpp>
|
||||||
#include <sfc/ppu/counter/counter-inline.hpp>
|
#include <sfc/ppu/counter/counter-inline.hpp>
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#include <sfc/interface/interface.hpp>
|
||||||
|
@@ -78,15 +78,13 @@ auto pTextEdit::setCursor(Cursor cursor) -> void {
|
|||||||
|
|
||||||
auto pTextEdit::setEditable(bool editable) -> void {
|
auto pTextEdit::setEditable(bool editable) -> void {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
[[cocoaView content] setEditable:editable];
|
[[cocoaView content] setEditable:(editable && self().enabled(true))];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pTextEdit::setEnabled(bool enabled) -> void {
|
auto pTextEdit::setEnabled(bool enabled) -> void {
|
||||||
pWidget::setEnabled(enabled);
|
pWidget::setEnabled(enabled);
|
||||||
@autoreleasepool {
|
setEditable(self().editable); //Cocoa lacks NSTextView::setEnabled; simulate via setEnabled()
|
||||||
[[cocoaView content] setEnabled:enabled];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pTextEdit::setFont(const Font& font) -> void {
|
auto pTextEdit::setFont(const Font& font) -> void {
|
||||||
|
Reference in New Issue
Block a user