mirror of https://github.com/bsnes-emu/bsnes.git
Update to v082r06 release.
byuu says: Emulated MMC1, currently defaults to B2 configuration. Fixed a whole bunch of timing things, render things, nametable mirroring things, etc. Zelda and Mega Man II are fully playable, but they have odd vertical scrolling issues that make it a not so fun experience. Not sure what the problem is there, yet. The Y scroll register writes seem to be wonky ... I don't know. Keeping the Cartridge menu always visible now, so it's faster to load carts, but I am still hiding the non-loaded system menus.
This commit is contained in:
parent
8618334356
commit
4ca051a22f
|
@ -2,9 +2,36 @@
|
|||
|
||||
namespace NES {
|
||||
|
||||
namespace Mapper {
|
||||
unsigned Mapper::mirror(unsigned addr, unsigned size) const {
|
||||
unsigned base = 0;
|
||||
if(size) {
|
||||
unsigned mask = 1 << 23;
|
||||
while(addr >= size) {
|
||||
while(!(addr & mask)) mask >>= 1;
|
||||
addr -= mask;
|
||||
if(size > mask) {
|
||||
size -= mask;
|
||||
base += mask;
|
||||
}
|
||||
mask >>= 1;
|
||||
}
|
||||
base += addr;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
#include "none/none.cpp"
|
||||
#include "mmc1/mmc1.cpp"
|
||||
}
|
||||
|
||||
Cartridge cartridge;
|
||||
|
||||
void Cartridge::load(const string &xml, const uint8_t *data, unsigned size) {
|
||||
rom_size = size - 16;
|
||||
rom_data = new uint8[rom_size];
|
||||
memcpy(rom_data, data + 16, size - 16);
|
||||
|
||||
prg_size = data[4] * 0x4000;
|
||||
chr_size = data[5] * 0x2000;
|
||||
|
||||
|
@ -21,40 +48,53 @@ void Cartridge::load(const string &xml, const uint8_t *data, unsigned size) {
|
|||
chr_data = new uint8[chr_size]();
|
||||
}
|
||||
|
||||
mirroring = ((data[6] & 0x08) >> 2) | (data[6] & 0x01);
|
||||
|
||||
uint8 mapperNumber = ((data[7] >> 4) << 4) | (data[6] >> 4);
|
||||
switch(mapperNumber) {
|
||||
default: mapper = &mapperNone; break;
|
||||
case 0x01: mapper = &mapperMMC1; break;
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
void Cartridge::unload() {
|
||||
if(loaded == false) return;
|
||||
|
||||
delete[] rom_data;
|
||||
delete[] prg_data;
|
||||
delete[] chr_data;
|
||||
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
void Cartridge::power() {
|
||||
mapper->power();
|
||||
}
|
||||
|
||||
void Cartridge::reset() {
|
||||
mapper->reset();
|
||||
}
|
||||
|
||||
Cartridge::Cartridge() {
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
uint8 Cartridge::prg_read(uint16 addr) {
|
||||
if(addr >= 0x8000 && addr <= 0xffff) {
|
||||
addr &= 0x7fff;
|
||||
if(addr >= prg_size) addr &= prg_size - 1;
|
||||
return prg_data[addr];
|
||||
}
|
||||
return mapper->prg_read(addr);
|
||||
}
|
||||
|
||||
void Cartridge::prg_write(uint16 addr, uint8 data) {
|
||||
return mapper->prg_write(addr, data);
|
||||
}
|
||||
|
||||
uint8 Cartridge::chr_read(uint16 addr) {
|
||||
return chr_data[addr & 0x1fff];
|
||||
return mapper->chr_read(addr);
|
||||
}
|
||||
|
||||
void Cartridge::chr_write(uint16 addr, uint8 data) {
|
||||
if(chr_ram == false) return;
|
||||
chr_data[addr & 0x1fff] = data;
|
||||
return mapper->chr_write(addr, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,17 +1,46 @@
|
|||
namespace Mapper {
|
||||
struct Mapper {
|
||||
unsigned mirror(unsigned addr, unsigned size) const;
|
||||
|
||||
virtual uint8 prg_read(uint16 addr) = 0;
|
||||
virtual void prg_write(uint16 addr, uint8 data) = 0;
|
||||
|
||||
virtual uint8 chr_read(uint16 addr) = 0;
|
||||
virtual void chr_write(uint16 addr, uint8 data) = 0;
|
||||
|
||||
virtual void power() = 0;
|
||||
virtual void reset() = 0;
|
||||
};
|
||||
|
||||
#include "none/none.hpp"
|
||||
#include "mmc1/mmc1.hpp"
|
||||
}
|
||||
|
||||
struct Cartridge : property<Cartridge> {
|
||||
void load(const string &xml, const uint8_t *data, unsigned size);
|
||||
void unload();
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
readonly<bool> loaded;
|
||||
|
||||
Cartridge();
|
||||
|
||||
//privileged:
|
||||
Mapper::Mapper *mapper;
|
||||
Mapper::None mapperNone;
|
||||
Mapper::MMC1 mapperMMC1;
|
||||
|
||||
uint8 prg_read(uint16 addr);
|
||||
void prg_write(uint16 addr, uint8 data);
|
||||
|
||||
uint8 chr_read(uint16 addr);
|
||||
void chr_write(uint16 addr, uint8 data);
|
||||
|
||||
uint8 *rom_data;
|
||||
unsigned rom_size;
|
||||
|
||||
uint8 *prg_data;
|
||||
unsigned prg_size;
|
||||
|
||||
|
@ -19,6 +48,7 @@ struct Cartridge : property<Cartridge> {
|
|||
unsigned chr_size;
|
||||
|
||||
bool chr_ram;
|
||||
unsigned mirroring;
|
||||
};
|
||||
|
||||
extern Cartridge cartridge;
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
unsigned MMC1::ciram_addr(unsigned addr) const {
|
||||
switch(r[0] & 0x03) {
|
||||
case 0: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first)
|
||||
case 1: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second)
|
||||
case 2: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
|
||||
case 3: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
|
||||
}
|
||||
}
|
||||
|
||||
bool MMC1::prg_mode() const {
|
||||
return r[0] & 0x04;
|
||||
}
|
||||
|
||||
unsigned MMC1::prg_addr() const {
|
||||
if(r[0] & 0x08) return prg_bank() * 0x4000;
|
||||
return (prg_bank() & ~1) * 0x8000;
|
||||
}
|
||||
|
||||
bool MMC1::chr_mode() const {
|
||||
return r[0] & 0x10;
|
||||
}
|
||||
|
||||
unsigned MMC1::chr_banklo() const {
|
||||
return r[1];
|
||||
}
|
||||
|
||||
unsigned MMC1::chr_bankhi() const {
|
||||
return r[2];
|
||||
}
|
||||
|
||||
unsigned MMC1::prg_bank() const {
|
||||
return r[3] & 0x0f;
|
||||
}
|
||||
|
||||
bool MMC1::prg_ram_disable() const {
|
||||
return r[3] & 0x10;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
uint8& MMC1::prg_data(unsigned addr) {
|
||||
return cartridge.prg_data[mirror(addr, cartridge.prg_size)];
|
||||
}
|
||||
|
||||
uint8& MMC1::chr_data(unsigned addr) {
|
||||
return cartridge.chr_data[mirror(addr, cartridge.chr_size)];
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
uint8 MMC1::prg_read(uint16 readaddr) {
|
||||
unsigned addr = readaddr;
|
||||
|
||||
if(addr >= 0x6000 && addr <= 0x7fff) {
|
||||
if(prg_ram_disable() == false) return prg_ram[addr & 0x1fff];
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
if(addr >= 0x8000 && addr <= 0xffff) {
|
||||
if(prg_mode() == 0) {
|
||||
if(addr >= 0x8000 && addr <= 0xbfff) {
|
||||
addr = (addr & 0x3fff);
|
||||
return prg_data(addr);
|
||||
}
|
||||
if(addr >= 0xc000 && addr <= 0xffff) {
|
||||
addr = prg_addr() | (addr & 0x3fff);
|
||||
return prg_data(addr);
|
||||
}
|
||||
}
|
||||
|
||||
if(prg_mode() == 1) {
|
||||
if(addr >= 0x8000 && addr <= 0xbfff) {
|
||||
addr = prg_addr() | (addr & 0x3fff);
|
||||
return prg_data(addr);
|
||||
}
|
||||
if(addr >= 0xc000 && addr <= 0xffff) {
|
||||
addr = 15 * 0x4000 | (addr & 0x3fff);
|
||||
return prg_data(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MMC1::prg_write(uint16 addr, uint8 data) {
|
||||
if(addr >= 0x6000 && addr <= 0x7fff) {
|
||||
if(prg_ram_disable() == false) prg_ram[addr & 0x1fff] = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr >= 0x8000 && addr <= 0xffff) {
|
||||
if(data & 0x80) {
|
||||
shiftaddr = 0;
|
||||
r[0] |= 0x0c;
|
||||
} else {
|
||||
shiftdata >>= 1;
|
||||
shiftdata |= (data & 1) << 4;
|
||||
if(++shiftaddr == 5) {
|
||||
shiftaddr = 0;
|
||||
r[(addr >> 13) & 3] = shiftdata;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
uint8 MMC1::chr_read(uint16 readaddr) {
|
||||
unsigned addr = readaddr;
|
||||
|
||||
if(addr <= 0x0fff) {
|
||||
if(chr_mode() == 0) addr = chr_banklo() * 0x2000 + (addr & 0x1fff);
|
||||
if(chr_mode() == 1) addr = chr_banklo() * 0x1000 + (addr & 0x0fff);
|
||||
return chr_data(addr);
|
||||
}
|
||||
|
||||
if(addr <= 0x1fff) {
|
||||
if(chr_mode() == 0) addr = chr_banklo() * 0x2000 + (addr & 0x1fff);
|
||||
if(chr_mode() == 1) addr = chr_bankhi() * 0x1000 + (addr & 0x0fff);
|
||||
return chr_data(addr);
|
||||
}
|
||||
|
||||
if(addr <= 0x3eff) {
|
||||
addr = ciram_addr(addr);
|
||||
return ppu.ciram_read(addr);
|
||||
}
|
||||
|
||||
return ppu.cgram_read(addr);
|
||||
}
|
||||
|
||||
void MMC1::chr_write(uint16 readaddr, uint8 data) {
|
||||
unsigned addr = readaddr;
|
||||
|
||||
if(addr <= 0x0fff) {
|
||||
if(cartridge.chr_ram == false) return;
|
||||
if(chr_mode() == 0) addr = chr_banklo() * 0x2000 + (addr & 0x1fff);
|
||||
if(chr_mode() == 1) addr = chr_banklo() * 0x1000 + (addr & 0x0fff);
|
||||
chr_data(addr) = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr <= 0x1fff) {
|
||||
if(cartridge.chr_ram == false) return;
|
||||
if(chr_mode() == 0) addr = chr_banklo() * 0x2000 + (addr & 0x1fff);
|
||||
if(chr_mode() == 1) addr = chr_bankhi() * 0x1000 + (addr & 0x0fff);
|
||||
chr_data(addr) = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr <= 0x3eff) {
|
||||
addr = ciram_addr(addr);
|
||||
return ppu.ciram_write(addr, data);
|
||||
}
|
||||
|
||||
return ppu.cgram_write(addr, data);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void MMC1::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void MMC1::reset() {
|
||||
shiftaddr = 0;
|
||||
shiftdata = 0;
|
||||
|
||||
r[0] = 0x0c;
|
||||
r[1] = 0x00;
|
||||
r[2] = 0x01;
|
||||
r[3] = 0x0f;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
struct MMC1 : Mapper {
|
||||
uint8 prg_read(uint16 addr);
|
||||
void prg_write(uint16 addr, uint8 data);
|
||||
|
||||
uint8 chr_read(uint16 addr);
|
||||
void chr_write(uint16 addr, uint8 data);
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
private:
|
||||
uint8 prg_ram[8192];
|
||||
uint8 r[4];
|
||||
unsigned shiftaddr;
|
||||
unsigned shiftdata;
|
||||
|
||||
unsigned ciram_addr(unsigned addr) const;
|
||||
bool prg_mode() const;
|
||||
unsigned prg_addr() const;
|
||||
bool chr_mode() const;
|
||||
unsigned chr_banklo() const;
|
||||
unsigned chr_bankhi() const;
|
||||
unsigned prg_bank() const;
|
||||
bool prg_ram_disable() const;
|
||||
|
||||
uint8& prg_data(unsigned addr);
|
||||
uint8& chr_data(unsigned addr);
|
||||
};
|
|
@ -0,0 +1,43 @@
|
|||
uint8 None::prg_read(uint16 addr) {
|
||||
if(addr >= 0x8000 && addr <= 0xffff) {
|
||||
addr &= 0x7fff;
|
||||
if(addr >= cartridge.prg_size) addr &= cartridge.prg_size - 1;
|
||||
return cartridge.prg_data[addr];
|
||||
}
|
||||
}
|
||||
|
||||
void None::prg_write(uint16 addr, uint8 data) {
|
||||
}
|
||||
|
||||
uint8 None::chr_read(uint16 addr) {
|
||||
if(addr <= 0x1fff) {
|
||||
return cartridge.chr_data[addr & 0x1fff];
|
||||
}
|
||||
|
||||
if(addr <= 0x3eff) {
|
||||
if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
return ppu.ciram_read(addr & 0x07ff);
|
||||
}
|
||||
|
||||
return ppu.cgram_read(addr & 0x001f);
|
||||
}
|
||||
|
||||
void None::chr_write(uint16 addr, uint8 data) {
|
||||
if(addr <= 0x1fff) {
|
||||
if(cartridge.chr_ram == false) return;
|
||||
cartridge.chr_data[addr & 0x1fff] = data;
|
||||
}
|
||||
|
||||
if(addr <= 0x3eff) {
|
||||
if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
return ppu.ciram_write(addr & 0x07ff, data);
|
||||
}
|
||||
|
||||
return ppu.cgram_write(addr & 0x001f, data);
|
||||
}
|
||||
|
||||
void None::power() {
|
||||
}
|
||||
|
||||
void None::reset() {
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
struct None : Mapper {
|
||||
uint8 prg_read(uint16 addr);
|
||||
void prg_write(uint16 addr, uint8 data);
|
||||
|
||||
uint8 chr_read(uint16 addr);
|
||||
void chr_write(uint16 addr, uint8 data);
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
};
|
|
@ -1,13 +1,12 @@
|
|||
struct Flags {
|
||||
bool n, v, p, b, d, i, z, c;
|
||||
bool n, v, d, i, z, c;
|
||||
|
||||
inline operator unsigned() {
|
||||
return (n << 7) | (v << 6) | (p << 5) | (b << 4)
|
||||
| (d << 3) | (i << 2) | (z << 1) | (c << 0);
|
||||
return (n << 7) | (v << 6) | (d << 3) | (i << 2) | (z << 1) | (c << 0);
|
||||
}
|
||||
|
||||
inline Flags& operator=(uint8 data) {
|
||||
n = data & 0x80; v = data & 0x40; p = data & 0x20; b = data & 0x10;
|
||||
n = data & 0x80; v = data & 0x40;
|
||||
d = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01;
|
||||
return *this;
|
||||
}
|
||||
|
@ -95,6 +94,13 @@ void op_plp();
|
|||
void op_rti();
|
||||
void op_rts();
|
||||
|
||||
void opill_nop_absolute();
|
||||
void opill_nop_absolute_x();
|
||||
void opill_nop_immediate();
|
||||
void opill_nop_implied();
|
||||
void opill_nop_zero_page();
|
||||
void opill_nop_zero_page_x();
|
||||
|
||||
//exec.cpp
|
||||
void op_exec();
|
||||
|
||||
|
|
|
@ -185,8 +185,8 @@ string CPU::disassemble() {
|
|||
|
||||
output.append(
|
||||
"A:", hex<2>(regs.a), " X:", hex<2>(regs.x), " Y:", hex<2>(regs.y), " S:", hex<2>(regs.s), " ",
|
||||
regs.p.n ? "N" : "n", regs.p.v ? "V" : "v", regs.p.p ? "P" : "p", regs.p.b ? "B" : "b",
|
||||
regs.p.d ? "D" : "d", regs.p.i ? "I" : "i", regs.p.z ? "Z" : "z", regs.p.c ? "C" : "c"
|
||||
regs.p.n ? "N" : "n", regs.p.v ? "V" : "v", regs.p.d ? "D" : "d",
|
||||
regs.p.i ? "I" : "i", regs.p.z ? "Z" : "z", regs.p.c ? "C" : "c"
|
||||
);
|
||||
|
||||
return output;
|
||||
|
|
|
@ -1,21 +1,29 @@
|
|||
//I = illegal instruction (only used as a visual indicator)
|
||||
#define I
|
||||
|
||||
void CPU::op_exec() {
|
||||
uint8 opcode = op_readpci();
|
||||
switch(opcode) {
|
||||
case 0x00: return op_brk();
|
||||
case 0x01: return opi_read_indirect_zero_page_x<&CPU::opf_ora>();
|
||||
I case 0x04: return opill_nop_zero_page();
|
||||
case 0x05: return opi_read_zero_page<&CPU::opf_ora>();
|
||||
case 0x06: return opi_rmw_zero_page<&CPU::opf_asl>();
|
||||
case 0x08: return op_php();
|
||||
case 0x09: return opi_read_immediate<&CPU::opf_ora>();
|
||||
case 0x0a: return opi_shift<&CPU::opf_sla>();
|
||||
I case 0x0c: return opill_nop_absolute();
|
||||
case 0x0d: return opi_read_absolute<&CPU::opf_ora>();
|
||||
case 0x0e: return opi_rmw_absolute<&CPU::opf_asl>();
|
||||
case 0x10: return opi_branch(regs.p.n == 0);
|
||||
case 0x11: return opi_read_indirect_zero_page_y<&CPU::opf_ora>();
|
||||
I case 0x14: return opill_nop_zero_page_x();
|
||||
case 0x15: return opi_read_zero_page_x<&CPU::opf_ora>();
|
||||
case 0x16: return opi_rmw_zero_page_x<&CPU::opf_asl>();
|
||||
case 0x18: return opi_clear_flag(regs.p.c);
|
||||
case 0x19: return opi_read_absolute_y<&CPU::opf_ora>();
|
||||
I case 0x1a: return opill_nop_implied();
|
||||
I case 0x1c: return opill_nop_absolute_x();
|
||||
case 0x1d: return opi_read_absolute_x<&CPU::opf_ora>();
|
||||
case 0x1e: return opi_rmw_absolute_x<&CPU::opf_asl>();
|
||||
case 0x20: return op_jsr_absolute();
|
||||
|
@ -31,14 +39,18 @@ void CPU::op_exec() {
|
|||
case 0x2e: return opi_rmw_absolute<&CPU::opf_rol>();
|
||||
case 0x30: return opi_branch(regs.p.n == 1);
|
||||
case 0x31: return opi_read_indirect_zero_page_y<&CPU::opf_and>();
|
||||
I case 0x34: return opill_nop_zero_page_x();
|
||||
case 0x35: return opi_read_zero_page_x<&CPU::opf_and>();
|
||||
case 0x36: return opi_rmw_zero_page_x<&CPU::opf_rol>();
|
||||
case 0x38: return opi_set_flag(regs.p.c);
|
||||
case 0x39: return opi_read_absolute_y<&CPU::opf_and>();
|
||||
I case 0x3a: return opill_nop_implied();
|
||||
I case 0x3c: return opill_nop_absolute_x();
|
||||
case 0x3d: return opi_read_absolute_x<&CPU::opf_and>();
|
||||
case 0x3e: return opi_rmw_absolute_x<&CPU::opf_rol>();
|
||||
case 0x40: return op_rti();
|
||||
case 0x41: return opi_read_indirect_zero_page_x<&CPU::opf_eor>();
|
||||
I case 0x44: return opill_nop_zero_page();
|
||||
case 0x45: return opi_read_zero_page<&CPU::opf_eor>();
|
||||
case 0x46: return opi_rmw_zero_page<&CPU::opf_lsr>();
|
||||
case 0x48: return opi_push(regs.a);
|
||||
|
@ -49,15 +61,18 @@ void CPU::op_exec() {
|
|||
case 0x4e: return opi_rmw_absolute<&CPU::opf_lsr>();
|
||||
case 0x50: return opi_branch(regs.p.v == 0);
|
||||
case 0x51: return opi_read_indirect_zero_page_y<&CPU::opf_eor>();
|
||||
I case 0x54: return opill_nop_zero_page_x();
|
||||
case 0x55: return opi_read_zero_page_x<&CPU::opf_eor>();
|
||||
case 0x56: return opi_rmw_zero_page_x<&CPU::opf_lsr>();
|
||||
case 0x58: return opi_clear_flag(regs.p.i);
|
||||
case 0x59: return opi_read_absolute_y<&CPU::opf_eor>();
|
||||
case 0x5a: return opi_push(regs.y);
|
||||
I case 0x5a: return opill_nop_implied();
|
||||
I case 0x5c: return opill_nop_absolute_x();
|
||||
case 0x5d: return opi_read_absolute_x<&CPU::opf_eor>();
|
||||
case 0x5e: return opi_rmw_absolute_x<&CPU::opf_lsr>();
|
||||
case 0x60: return op_rts();
|
||||
case 0x61: return opi_read_indirect_zero_page_x<&CPU::opf_adc>();
|
||||
I case 0x64: return opill_nop_zero_page();
|
||||
case 0x65: return opi_read_zero_page<&CPU::opf_adc>();
|
||||
case 0x66: return opi_rmw_zero_page<&CPU::opf_ror>();
|
||||
case 0x68: return opi_pull(regs.a);
|
||||
|
@ -67,19 +82,24 @@ void CPU::op_exec() {
|
|||
case 0x6d: return opi_read_absolute<&CPU::opf_adc>();
|
||||
case 0x6e: return opi_rmw_absolute<&CPU::opf_ror>();
|
||||
case 0x70: return opi_branch(regs.p.v == 1);
|
||||
I case 0x74: return opill_nop_zero_page_x();
|
||||
case 0x71: return opi_read_indirect_zero_page_y<&CPU::opf_adc>();
|
||||
case 0x75: return opi_read_zero_page_x<&CPU::opf_adc>();
|
||||
case 0x76: return opi_rmw_zero_page_x<&CPU::opf_ror>();
|
||||
case 0x78: return opi_set_flag(regs.p.i);
|
||||
case 0x79: return opi_read_absolute_y<&CPU::opf_adc>();
|
||||
case 0x7a: return opi_pull(regs.y);
|
||||
I case 0x7a: return opill_nop_implied();
|
||||
I case 0x7c: return opill_nop_absolute_x();
|
||||
case 0x7d: return opi_read_absolute_x<&CPU::opf_adc>();
|
||||
case 0x7e: return opi_rmw_absolute_x<&CPU::opf_ror>();
|
||||
I case 0x80: return opill_nop_absolute();
|
||||
case 0x81: return opi_store_indirect_zero_page_x(regs.a);
|
||||
I case 0x82: return opill_nop_immediate();
|
||||
case 0x84: return opi_store_zero_page(regs.y);
|
||||
case 0x85: return opi_store_zero_page(regs.a);
|
||||
case 0x86: return opi_store_zero_page(regs.x);
|
||||
case 0x88: return opi_decrement(regs.y);
|
||||
I case 0x89: return opill_nop_immediate();
|
||||
case 0x8a: return opi_transfer(regs.x, regs.a, 1);
|
||||
case 0x8c: return opi_store_absolute(regs.y);
|
||||
case 0x8d: return opi_store_absolute(regs.a);
|
||||
|
@ -118,6 +138,7 @@ void CPU::op_exec() {
|
|||
case 0xbe: return opi_read_absolute_y<&CPU::opf_ldx>();
|
||||
case 0xc0: return opi_read_immediate<&CPU::opf_cpy>();
|
||||
case 0xc1: return opi_read_indirect_zero_page_x<&CPU::opf_cmp>();
|
||||
I case 0xc2: return opill_nop_immediate();
|
||||
case 0xc4: return opi_read_zero_page<&CPU::opf_cpy>();
|
||||
case 0xc5: return opi_read_zero_page<&CPU::opf_cmp>();
|
||||
case 0xc6: return opi_rmw_zero_page<&CPU::opf_dec>();
|
||||
|
@ -129,15 +150,18 @@ void CPU::op_exec() {
|
|||
case 0xce: return opi_rmw_absolute<&CPU::opf_dec>();
|
||||
case 0xd0: return opi_branch(regs.p.z == 0);
|
||||
case 0xd1: return opi_read_indirect_zero_page_y<&CPU::opf_cmp>();
|
||||
I case 0xd4: return opill_nop_zero_page_x();
|
||||
case 0xd5: return opi_read_zero_page_x<&CPU::opf_cmp>();
|
||||
case 0xd6: return opi_rmw_zero_page_x<&CPU::opf_dec>();
|
||||
case 0xd8: return opi_clear_flag(regs.p.d);
|
||||
case 0xd9: return opi_read_absolute_y<&CPU::opf_cmp>();
|
||||
case 0xda: return opi_push(regs.x);
|
||||
I case 0xda: return opill_nop_implied();
|
||||
I case 0xdc: return opill_nop_absolute_x();
|
||||
case 0xdd: return opi_read_absolute_x<&CPU::opf_cmp>();
|
||||
case 0xde: return opi_rmw_absolute_x<&CPU::opf_dec>();
|
||||
case 0xe0: return opi_read_immediate<&CPU::opf_cpx>();
|
||||
case 0xe1: return opi_read_indirect_zero_page_x<&CPU::opf_sbc>();
|
||||
I case 0xe2: return opill_nop_immediate();
|
||||
case 0xe4: return opi_read_zero_page<&CPU::opf_cpx>();
|
||||
case 0xe5: return opi_read_zero_page<&CPU::opf_sbc>();
|
||||
case 0xe6: return opi_rmw_zero_page<&CPU::opf_inc>();
|
||||
|
@ -149,19 +173,23 @@ void CPU::op_exec() {
|
|||
case 0xee: return opi_rmw_absolute<&CPU::opf_inc>();
|
||||
case 0xf0: return opi_branch(regs.p.z == 1);
|
||||
case 0xf1: return opi_read_indirect_zero_page_y<&CPU::opf_sbc>();
|
||||
I case 0xf4: return opill_nop_zero_page_x();
|
||||
case 0xf5: return opi_read_zero_page_x<&CPU::opf_sbc>();
|
||||
case 0xf6: return opi_rmw_zero_page_x<&CPU::opf_inc>();
|
||||
case 0xf8: return opi_set_flag(regs.p.d);
|
||||
case 0xf9: return opi_read_absolute_y<&CPU::opf_sbc>();
|
||||
case 0xfa: return opi_pull(regs.x);
|
||||
I case 0xfa: return opill_nop_implied();
|
||||
I case 0xfc: return opill_nop_absolute_x();
|
||||
case 0xfd: return opi_read_absolute_x<&CPU::opf_sbc>();
|
||||
case 0xfe: return opi_rmw_absolute_x<&CPU::opf_inc>();
|
||||
}
|
||||
|
||||
return op_nop();
|
||||
//return op_nop();
|
||||
|
||||
regs.pc--;
|
||||
print("Unimplemented opcode: ", hex<4>(regs.pc), " = ", hex<2>(bus.read(regs.pc)), "\n");
|
||||
print("Counter = ", opcodeCounter, "\n");
|
||||
while(true) scheduler.exit();
|
||||
}
|
||||
|
||||
#undef I
|
||||
|
|
|
@ -188,12 +188,15 @@ L op_readpc();
|
|||
}
|
||||
|
||||
void CPU::opi_pull(uint8 &r) {
|
||||
op_readpc();
|
||||
op_readpc();
|
||||
L r = op_readsp();
|
||||
regs.p.n = (r & 0x80);
|
||||
regs.p.z = (r == 0);
|
||||
}
|
||||
|
||||
void CPU::opi_push(uint8 &r) {
|
||||
op_readpc();
|
||||
L op_writesp(r);
|
||||
}
|
||||
|
||||
|
@ -277,6 +280,7 @@ void CPU::opi_rmw_absolute() {
|
|||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
rd = op_read(abs.w);
|
||||
op_readpc();
|
||||
call(op);
|
||||
L op_write(abs.w, rd);
|
||||
}
|
||||
|
@ -285,8 +289,9 @@ template<void (CPU::*op)()>
|
|||
void CPU::opi_rmw_absolute_x() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
op_page(abs.w, abs.w + regs.x);
|
||||
op_readpc();
|
||||
rd = op_read(abs.w + regs.x);
|
||||
op_readpc();
|
||||
call(op);
|
||||
L op_write(abs.w + regs.x, rd);
|
||||
}
|
||||
|
@ -387,7 +392,14 @@ L op_readpc();
|
|||
|
||||
void CPU::op_brk() {
|
||||
op_readpci();
|
||||
interrupt(0xfffe);
|
||||
op_writesp(regs.pc >> 8);
|
||||
op_writesp(regs.pc >> 0);
|
||||
op_writesp(regs.p | 0x30);
|
||||
abs.l = op_read(0xfffe);
|
||||
regs.p.i = 1;
|
||||
regs.p.d = 0;
|
||||
abs.h = op_read(0xffff);
|
||||
regs.pc = abs.w;
|
||||
}
|
||||
|
||||
void CPU::op_jmp_absolute() {
|
||||
|
@ -407,6 +419,7 @@ L iabs.h = op_read(abs.w); abs.l++;
|
|||
void CPU::op_jsr_absolute() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
op_readpc();
|
||||
regs.pc--;
|
||||
op_writesp(regs.pc >> 8);
|
||||
L op_writesp(regs.pc >> 0);
|
||||
|
@ -418,17 +431,20 @@ L op_readpc();
|
|||
}
|
||||
|
||||
void CPU::op_php() {
|
||||
L op_writesp(regs.p);
|
||||
op_readpc();
|
||||
L op_writesp(regs.p | 0x30);
|
||||
}
|
||||
|
||||
void CPU::op_plp() {
|
||||
L regs.p = op_readsp() | 0x30;
|
||||
op_readpc();
|
||||
op_readpc();
|
||||
L regs.p = op_readsp();
|
||||
}
|
||||
|
||||
void CPU::op_rti() {
|
||||
op_readpc();
|
||||
op_readpc();
|
||||
regs.p = op_readsp() | 0x30;
|
||||
regs.p = op_readsp();
|
||||
abs.l = op_readsp();
|
||||
L abs.h = op_readsp();
|
||||
regs.pc = abs.w;
|
||||
|
@ -443,5 +459,40 @@ L op_readpc();
|
|||
regs.pc = ++abs.w;
|
||||
}
|
||||
|
||||
//illegal opcodes
|
||||
//===============
|
||||
|
||||
void CPU::opill_nop_absolute() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
L op_readpc();
|
||||
}
|
||||
|
||||
void CPU::opill_nop_absolute_x() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
op_page(abs.w, abs.w + regs.x);
|
||||
L op_readpc();
|
||||
}
|
||||
|
||||
void CPU::opill_nop_immediate() {
|
||||
L rd = op_readpc();
|
||||
}
|
||||
|
||||
void CPU::opill_nop_implied() {
|
||||
L op_readpc();
|
||||
}
|
||||
|
||||
void CPU::opill_nop_zero_page() {
|
||||
zp = op_readpci();
|
||||
L op_readpc();
|
||||
}
|
||||
|
||||
void CPU::opill_nop_zero_page_x() {
|
||||
zp = op_readpci();
|
||||
op_readpc();
|
||||
L op_readpc();
|
||||
}
|
||||
|
||||
#undef call
|
||||
#undef L
|
||||
|
|
|
@ -29,8 +29,10 @@ void CPU::main() {
|
|||
continue;
|
||||
}
|
||||
|
||||
// if(lpc != regs.pc) { print(disassemble(), "\n"); } lpc = regs.pc;
|
||||
// if(lpc != regs.pc) { fprintf(fp, "%s\n", (const char*)disassemble()); fflush(fp); } lpc = regs.pc;
|
||||
if(trace) {
|
||||
if(lpc != regs.pc) { print(disassemble(), "\n"); } lpc = regs.pc;
|
||||
//if(lpc != regs.pc) { fprintf(fp, "%s\n", (const char*)disassemble()); fflush(fp); } lpc = regs.pc;
|
||||
}
|
||||
|
||||
op_exec();
|
||||
opcodeCounter++;
|
||||
|
@ -45,7 +47,7 @@ void CPU::add_clocks(unsigned clocks) {
|
|||
void CPU::interrupt(uint16 vector) {
|
||||
op_writesp(regs.pc >> 8);
|
||||
op_writesp(regs.pc >> 0);
|
||||
op_writesp(regs.p);
|
||||
op_writesp(regs.p | 0x20);
|
||||
abs.l = op_read(vector + 0);
|
||||
regs.p.i = 1;
|
||||
regs.p.d = 0;
|
||||
|
@ -58,7 +60,7 @@ void CPU::power() {
|
|||
regs.x = 0x00;
|
||||
regs.y = 0x00;
|
||||
regs.s = 0x00;
|
||||
regs.p = 0x34;
|
||||
regs.p = 0x04;
|
||||
|
||||
for(unsigned addr = 0; addr < 0x0800; addr++) ram[addr] = 0xff;
|
||||
ram[0x0008] = 0xf7;
|
||||
|
@ -120,7 +122,7 @@ void CPU::write(uint16 addr, uint8 data) {
|
|||
}
|
||||
|
||||
void CPU::oam_dma(uint16 addr) {
|
||||
// op_readpc();
|
||||
op_readpc();
|
||||
for(unsigned n = 0; n < 256; n++) {
|
||||
uint8 data = bus.read(addr + n);
|
||||
op_write(0x2004, data);
|
||||
|
|
|
@ -27,6 +27,8 @@ struct CPU : Processor {
|
|||
void write(uint16 addr, uint8 data);
|
||||
|
||||
void oam_dma(uint16 addr);
|
||||
|
||||
bool trace;
|
||||
};
|
||||
|
||||
extern CPU cpu;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
namespace NES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bnes";
|
||||
static const char Version[] = "000.01";
|
||||
static const char Version[] = "000.02";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -122,9 +122,9 @@ void PPU::reset() {
|
|||
|
||||
memset(buffer, 0, sizeof buffer);
|
||||
|
||||
memset(nram, 0, sizeof nram);
|
||||
memset(pram, 0, sizeof pram);
|
||||
memset(sram, 0, sizeof sram);
|
||||
memset(ciram, 0, sizeof ciram);
|
||||
memset(cgram, 0, sizeof cgram);
|
||||
memset(oam, 0, sizeof oam);
|
||||
}
|
||||
|
||||
uint8 PPU::read(uint16 addr) {
|
||||
|
@ -140,14 +140,14 @@ uint8 PPU::read(uint16 addr) {
|
|||
status.address_latch = 0;
|
||||
break;
|
||||
case 4: //OAMDATA
|
||||
result = sram[status.oam_addr++];
|
||||
result = oam[status.oam_addr++];
|
||||
break;
|
||||
case 7: //PPUDATA
|
||||
if(addr >= 0x3f00) {
|
||||
result = bus_read(status.vaddr);
|
||||
result = cartridge.chr_read(status.vaddr);
|
||||
} else {
|
||||
result = status.bus_data;
|
||||
status.bus_data = bus_read(status.vaddr);
|
||||
status.bus_data = cartridge.chr_read(status.vaddr);
|
||||
}
|
||||
status.vaddr += status.vram_increment;
|
||||
break;
|
||||
|
@ -185,7 +185,7 @@ void PPU::write(uint16 addr, uint8 data) {
|
|||
status.oam_addr = data;
|
||||
return;
|
||||
case 4: //OAMDATA
|
||||
sram[status.oam_addr++] = data;
|
||||
oam[status.oam_addr++] = data;
|
||||
return;
|
||||
case 5: //PPUSCROLL
|
||||
if(status.address_latch == 0) {
|
||||
|
@ -206,37 +206,28 @@ void PPU::write(uint16 addr, uint8 data) {
|
|||
status.address_latch ^= 1;
|
||||
return;
|
||||
case 7: //PPUDATA
|
||||
bus_write(status.vaddr, data);
|
||||
cartridge.chr_write(status.vaddr, data);
|
||||
status.vaddr += status.vram_increment;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 PPU::bus_read(uint16 addr) {
|
||||
if(addr <= 0x1fff) return cartridge.chr_read(addr);
|
||||
if(addr <= 0x3eff) return nram[addr & 0x07ff];
|
||||
if(addr <= 0x3fff) return pram[addr & 0x001f];
|
||||
uint8 PPU::ciram_read(uint16 addr) {
|
||||
return ciram[addr & 0x07ff];
|
||||
}
|
||||
|
||||
void PPU::bus_write(uint16 addr, uint8 data) {
|
||||
if(addr <= 0x1fff) {
|
||||
return cartridge.chr_write(addr, data);
|
||||
}
|
||||
void PPU::ciram_write(uint16 addr, uint8 data) {
|
||||
ciram[addr & 0x07ff] = data;
|
||||
}
|
||||
|
||||
if(addr <= 0x3eff) {
|
||||
nram[addr & 0x07ff] = data;
|
||||
return;
|
||||
}
|
||||
uint8 PPU::cgram_read(uint16 addr) {
|
||||
if((addr & 0x13) == 0x10) addr &= ~0x10;
|
||||
return cgram[addr & 0x1f];
|
||||
}
|
||||
|
||||
if(addr <= 0x3fff) {
|
||||
addr &= 0x1f;
|
||||
if(addr == 0x10) addr = 0x00;
|
||||
if(addr == 0x14) addr = 0x04;
|
||||
if(addr == 0x18) addr = 0x08;
|
||||
if(addr == 0x1c) addr = 0x0c;
|
||||
pram[addr] = data;
|
||||
return;
|
||||
}
|
||||
void PPU::cgram_write(uint16 addr, uint8 data) {
|
||||
if((addr & 0x13) == 0x10) addr &= ~0x10;
|
||||
cgram[addr & 0x1f] = data;
|
||||
}
|
||||
|
||||
bool PPU::raster_enable() const {
|
||||
|
@ -258,24 +249,26 @@ unsigned PPU::scrolly() const {
|
|||
void PPU::render_scanline() {
|
||||
uint32 *line = buffer + status.ly * 256;
|
||||
|
||||
uint8 oam[8][5];
|
||||
uint8 ioam[8][5];
|
||||
unsigned oamc = 0;
|
||||
|
||||
unsigned sprite_height = status.sprite_size ? 16 : 8;
|
||||
for(unsigned n = 0; n < 64; n++) {
|
||||
unsigned y = sram[(n * 4) + 0] + 1;
|
||||
unsigned y = oam[(n * 4) + 0] + 1;
|
||||
if(status.ly < y || status.ly >= y + sprite_height) continue;
|
||||
oam[oamc][0] = y;
|
||||
oam[oamc][1] = sram[(n * 4) + 1];
|
||||
oam[oamc][2] = sram[(n * 4) + 2];
|
||||
oam[oamc][3] = sram[(n * 4) + 3];
|
||||
oam[oamc][4] = n;
|
||||
ioam[oamc][0] = y;
|
||||
ioam[oamc][1] = oam[(n * 4) + 1];
|
||||
ioam[oamc][2] = oam[(n * 4) + 2];
|
||||
ioam[oamc][3] = oam[(n * 4) + 3];
|
||||
ioam[oamc][4] = n;
|
||||
if(++oamc >= 8) break;
|
||||
}
|
||||
|
||||
for(unsigned x = 0; x < 256; x++) {
|
||||
unsigned offsetx = x + scrollx();
|
||||
unsigned offsety = status.ly + scrolly();
|
||||
unsigned offsety = status.ly + (scrolly() < 240 ? scrolly() : 240 - scrolly());
|
||||
|
||||
//if(x==0&&status.ly==64) print("Y=", offsety, "\n");
|
||||
|
||||
bool screenx = offsetx & 256;
|
||||
bool screeny = offsety & 256;
|
||||
|
@ -285,8 +278,8 @@ void PPU::render_scanline() {
|
|||
|
||||
unsigned base = nametable_addr() + (screenx * 0x0400) + (screeny * 0x0800);
|
||||
|
||||
uint8 tile = bus_read(base + (offsety / 8) * 32 + (offsetx / 8));
|
||||
uint8 attr = bus_read(base + 0x03c0 + (offsety / 32) * 8 + (offsetx / 32));
|
||||
uint8 tile = cartridge.chr_read(base + (offsety / 8) * 32 + (offsetx / 8));
|
||||
uint8 attr = cartridge.chr_read(base + 0x03c0 + (offsety / 32) * 8 + (offsetx / 32));
|
||||
|
||||
if((offsety / 16) & 1) attr >>= 4;
|
||||
if((offsetx / 16) & 1) attr >>= 2;
|
||||
|
@ -294,8 +287,8 @@ void PPU::render_scanline() {
|
|||
unsigned tilex = offsetx & 7;
|
||||
unsigned tiley = offsety & 7;
|
||||
|
||||
uint8 tdlo = bus_read(status.bg_addr + tile * 16 + 0 + tiley);
|
||||
uint8 tdhi = bus_read(status.bg_addr + tile * 16 + 8 + tiley);
|
||||
uint8 tdlo = cartridge.chr_read(status.bg_addr + tile * 16 + 0 + tiley);
|
||||
uint8 tdhi = cartridge.chr_read(status.bg_addr + tile * 16 + 8 + tiley);
|
||||
|
||||
unsigned mask = 0x80 >> tilex;
|
||||
unsigned palette = 0;
|
||||
|
@ -308,40 +301,39 @@ void PPU::render_scanline() {
|
|||
}
|
||||
|
||||
for(unsigned n = 0; n < oamc; n++) {
|
||||
if(x < oam[n][3] || x >= oam[n][3] + 8) continue;
|
||||
if(x < ioam[n][3] || x >= ioam[n][3] + 8) continue;
|
||||
if(status.sprite_enable == false) continue;
|
||||
if(status.sprite_edge_enable == false && x < 8) continue;
|
||||
|
||||
unsigned spritex = x - oam[n][3];
|
||||
unsigned spritey = status.ly - oam[n][0];
|
||||
unsigned spritex = x - ioam[n][3];
|
||||
unsigned spritey = status.ly - ioam[n][0];
|
||||
|
||||
unsigned addr = (sprite_height == 8)
|
||||
? status.sprite_addr + oam[n][1] * 16
|
||||
: ((oam[n][1] & ~1) * 16) + ((oam[n][1] & 1) * 0x1000);
|
||||
? status.sprite_addr + ioam[n][1] * 16
|
||||
: ((ioam[n][1] & ~1) * 16) + ((ioam[n][1] & 1) * 0x1000);
|
||||
|
||||
if(oam[n][2] & 0x80) spritey ^= (sprite_height - 1);
|
||||
if(oam[n][2] & 0x40) spritex ^= 7;
|
||||
if(ioam[n][2] & 0x80) spritey ^= (sprite_height - 1);
|
||||
if(ioam[n][2] & 0x40) spritex ^= 7;
|
||||
if(spritey & 8) spritey += 8;
|
||||
|
||||
tdlo = bus_read(addr + 0 + spritey);
|
||||
tdhi = bus_read(addr + 8 + spritey);
|
||||
tdlo = cartridge.chr_read(addr + 0 + spritey);
|
||||
tdhi = cartridge.chr_read(addr + 8 + spritey);
|
||||
|
||||
mask = 0x80 >> spritex;
|
||||
unsigned sprite_palette = 0;
|
||||
sprite_palette |= (tdlo & mask) ? 1 : 0;
|
||||
sprite_palette |= (tdhi & mask) ? 2 : 0;
|
||||
if(sprite_palette == 0) continue;
|
||||
sprite_palette |= (oam[n][2] & 3) << 2;
|
||||
|
||||
bool priority = oam[n][2] & 0x20;
|
||||
if(priority == 0 || palette == 0) {
|
||||
if(oam[n][4] == 0) status.sprite_zero_hit = 1;
|
||||
palette = 16 + sprite_palette;
|
||||
}
|
||||
if(ioam[n][4] == 0) status.sprite_zero_hit = 1;
|
||||
sprite_palette |= (ioam[n][2] & 3) << 2;
|
||||
|
||||
bool priority = ioam[n][2] & 0x20;
|
||||
if(priority == 0 || palette == 0) palette = 16 + sprite_palette;
|
||||
break;
|
||||
}
|
||||
|
||||
*line++ = paletteRGB[pram[palette]];
|
||||
*line++ = paletteRGB[cgram[palette]];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,11 @@ struct PPU : Processor {
|
|||
uint8 read(uint16 addr);
|
||||
void write(uint16 addr, uint8 data);
|
||||
|
||||
uint8 bus_read(uint16 addr);
|
||||
void bus_write(uint16 addr, uint8 data);
|
||||
uint8 ciram_read(uint16 addr);
|
||||
void ciram_write(uint16 addr, uint8 data);
|
||||
|
||||
uint8 cgram_read(uint16 addr);
|
||||
void cgram_write(uint16 addr, uint8 data);
|
||||
|
||||
void render_scanline();
|
||||
|
||||
|
@ -62,9 +65,9 @@ struct PPU : Processor {
|
|||
|
||||
uint32 buffer[256 * 240];
|
||||
uint32 paletteRGB[64];
|
||||
uint8 nram[2048];
|
||||
uint8 pram[32];
|
||||
uint8 sram[256];
|
||||
uint8 ciram[2048];
|
||||
uint8 cgram[32];
|
||||
uint8 oam[256];
|
||||
};
|
||||
|
||||
extern PPU ppu;
|
||||
|
|
|
@ -9,12 +9,14 @@ void System::run() {
|
|||
}
|
||||
|
||||
void System::power() {
|
||||
cartridge.power();
|
||||
cpu.power();
|
||||
ppu.power();
|
||||
scheduler.power();
|
||||
}
|
||||
|
||||
void System::reset() {
|
||||
cartridge.reset();
|
||||
cpu.reset();
|
||||
ppu.reset();
|
||||
scheduler.reset();
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "082.05";
|
||||
static const char Version[] = "082.06";
|
||||
static const unsigned SerializerVersion = 21;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ FileBrowser::FileBrowser() {
|
|||
|
||||
char path[PATH_MAX];
|
||||
auto unused = getcwd(path);
|
||||
strcpy(path, "/media/sdb1/root/nes_images/");
|
||||
setPath(path);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ MainWindow::MainWindow() {
|
|||
|
||||
toolsMenu.setText("Tools");
|
||||
toolsShrinkWindow.setText("Shrink Window");
|
||||
toolsTest.setText("Test");
|
||||
|
||||
helpMenu.setText("Help");
|
||||
helpAbout.setText("About ...");
|
||||
|
@ -66,6 +67,7 @@ MainWindow::MainWindow() {
|
|||
|
||||
append(toolsMenu);
|
||||
toolsMenu.append(toolsShrinkWindow);
|
||||
toolsMenu.append(toolsTest);
|
||||
|
||||
append(helpMenu);
|
||||
helpMenu.append(helpAbout);
|
||||
|
@ -126,6 +128,10 @@ MainWindow::MainWindow() {
|
|||
|
||||
toolsShrinkWindow.onTick = [&] { utility->resizeMainWindow(true); };
|
||||
|
||||
toolsTest.onTick = [&] {
|
||||
NES::cpu.trace = toolsTest.checked();
|
||||
};
|
||||
|
||||
helpAbout.onTick = [&] {
|
||||
MessageWindow::information(*this, {
|
||||
application->title, "\n\n",
|
||||
|
|
|
@ -31,6 +31,7 @@ struct MainWindow : Window {
|
|||
|
||||
Menu toolsMenu;
|
||||
Item toolsShrinkWindow;
|
||||
CheckItem toolsTest;
|
||||
|
||||
Menu helpMenu;
|
||||
Item helpAbout;
|
||||
|
|
|
@ -5,14 +5,12 @@ void Utility::setMode(Interface::Mode mode) {
|
|||
video.clear();
|
||||
audio.clear();
|
||||
|
||||
mainWindow->cartridgeMenu.setVisible(false);
|
||||
mainWindow->nesMenu.setVisible(false);
|
||||
mainWindow->snesMenu.setVisible(false);
|
||||
mainWindow->gameBoyMenu.setVisible(false);
|
||||
|
||||
if(mode == Interface::Mode::None) {
|
||||
mainWindow->setTitle(application->title);
|
||||
mainWindow->cartridgeMenu.setVisible(true);
|
||||
mainWindow->setStatusText("No cartridge loaded");
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue