Revert the following commits, from newest to oldest, which all hacked around cothread savestates:
a60be7d2c9
a7b6a9af4d
57b1df8487
9119e4f4ea
b2c0910376
587270cad2
74c26d9b11
5e3d6555b0
451f786660
This commit is contained in:
parent
767ae4d8b9
commit
9ecf86a80a
|
@ -60,24 +60,19 @@ void CPU::enter() {
|
|||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
if (regs.hang == HangType::Wait) this->op_wai();
|
||||
else if (regs.hang == HangType::Stop) this->op_stp();
|
||||
else
|
||||
{
|
||||
if(status.nmi_pending) {
|
||||
status.nmi_pending = false;
|
||||
regs.vector = (regs.e == false ? 0xffea : 0xfffa);
|
||||
op_irq();
|
||||
}
|
||||
if(status.nmi_pending) {
|
||||
status.nmi_pending = false;
|
||||
regs.vector = (regs.e == false ? 0xffea : 0xfffa);
|
||||
op_irq();
|
||||
}
|
||||
|
||||
if(status.irq_pending) {
|
||||
status.irq_pending = false;
|
||||
regs.vector = (regs.e == false ? 0xffee : 0xfffe);
|
||||
op_irq();
|
||||
}
|
||||
if(status.irq_pending) {
|
||||
status.irq_pending = false;
|
||||
regs.vector = (regs.e == false ? 0xffee : 0xfffe);
|
||||
op_irq();
|
||||
}
|
||||
|
||||
op_step();
|
||||
}
|
||||
op_step();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,10 +16,7 @@ void PPU::step(unsigned clocks) {
|
|||
|
||||
void PPU::synchronize_cpu() {
|
||||
if(CPU::Threaded == true) {
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All)
|
||||
co_switch(cpu.thread);
|
||||
else if(clock >= 0 && scheduler.sync == Scheduler::SynchronizeMode::All)
|
||||
interface()->message("PPU had to advance nondeterministically!");
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
||||
} else {
|
||||
while(clock >= 0) cpu.enter();
|
||||
}
|
||||
|
@ -28,33 +25,15 @@ void PPU::synchronize_cpu() {
|
|||
void PPU::Enter() { ppu.enter(); }
|
||||
|
||||
void PPU::enter() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::CPU) {
|
||||
synchronize_cpu(); // when in CPU sync mode, always switch back to CPU as soon as possible
|
||||
}
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
switch(uindex)
|
||||
{
|
||||
case 0: enter1(); break;
|
||||
case 1: enter2(); break;
|
||||
case 2: enter3(); break;
|
||||
case 3: enter4(); break;
|
||||
}
|
||||
uindex++;
|
||||
uindex &= 3;
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::enter1() {
|
||||
}
|
||||
|
||||
//H = 0 (initialize)
|
||||
scanline();
|
||||
add_clocks(10);
|
||||
}
|
||||
|
||||
void PPU::enter2() {
|
||||
|
||||
//H = 10 (cache mode7 registers + OAM address reset)
|
||||
cache.m7_hofs = regs.m7_hofs;
|
||||
cache.m7_vofs = regs.m7_vofs;
|
||||
|
@ -71,15 +50,11 @@ void PPU::enter2() {
|
|||
}
|
||||
}
|
||||
add_clocks(502);
|
||||
}
|
||||
|
||||
void PPU::enter3() {
|
||||
|
||||
//H = 512 (render)
|
||||
render_scanline();
|
||||
add_clocks(640);
|
||||
}
|
||||
|
||||
void PPU::enter4() {
|
||||
|
||||
//H = 1152 (cache OBSEL)
|
||||
if(cache.oam_basesize != regs.oam_basesize) {
|
||||
cache.oam_basesize = regs.oam_basesize;
|
||||
|
@ -88,6 +63,8 @@ void PPU::enter4() {
|
|||
cache.oam_nameselect = regs.oam_nameselect;
|
||||
cache.oam_tdaddr = regs.oam_tdaddr;
|
||||
add_clocks(lineclocks() - 1152); //seek to start of next scanline
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::add_clocks(unsigned clocks) {
|
||||
|
@ -372,8 +349,6 @@ void PPU::reset() {
|
|||
create(Enter, system.cpu_frequency());
|
||||
PPUcounter::reset();
|
||||
memset(surface, 0, 512 * 512 * sizeof(uint32));
|
||||
|
||||
uindex = 0;
|
||||
|
||||
//zero 01-dec-2012 - gotta reset these sometime, somewhere
|
||||
memset(oam_itemlist, 0, sizeof(oam_itemlist));
|
||||
|
|
|
@ -1,84 +1,78 @@
|
|||
class PPU : public Processor, public PPUcounter {
|
||||
public:
|
||||
uint8* vram; //[128 * 1024]
|
||||
uint8* oam; //[544]
|
||||
uint8* cgram; //[512]
|
||||
|
||||
enum : bool { Threaded = true };
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_cpu();
|
||||
|
||||
#include "memory/memory.hpp"
|
||||
#include "mmio/mmio.hpp"
|
||||
#include "render/render.hpp"
|
||||
class PPU : public Processor, public PPUcounter {
|
||||
public:
|
||||
uint8* vram; //[128 * 1024]
|
||||
uint8* oam; //[544]
|
||||
uint8* cgram; //[512]
|
||||
|
||||
int uindex;
|
||||
|
||||
uint32 *surface;
|
||||
uint32 *output;
|
||||
|
||||
uint8 ppu1_version;
|
||||
uint8 ppu2_version;
|
||||
|
||||
static void Enter();
|
||||
void add_clocks(unsigned clocks);
|
||||
|
||||
uint8 region;
|
||||
unsigned line;
|
||||
|
||||
enum { NTSC = 0, PAL = 1 };
|
||||
enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5, COL = 5 };
|
||||
enum { SC_32x32 = 0, SC_64x32 = 1, SC_32x64 = 2, SC_64x64 = 3 };
|
||||
|
||||
struct {
|
||||
bool interlace;
|
||||
bool overscan;
|
||||
} display;
|
||||
|
||||
struct {
|
||||
//$2101
|
||||
uint8 oam_basesize;
|
||||
uint8 oam_nameselect;
|
||||
uint16 oam_tdaddr;
|
||||
|
||||
//$210d-$210e
|
||||
uint16 m7_hofs, m7_vofs;
|
||||
|
||||
//$211b-$2120
|
||||
uint16 m7a, m7b, m7c, m7d, m7x, m7y;
|
||||
} cache;
|
||||
|
||||
alwaysinline bool interlace() const { return display.interlace; }
|
||||
alwaysinline bool overscan() const { return display.overscan; }
|
||||
alwaysinline bool hires() const { return (regs.pseudo_hires || regs.bg_mode == 5 || regs.bg_mode == 6); }
|
||||
|
||||
uint16 mosaic_table[16][4096];
|
||||
void render_line();
|
||||
|
||||
void update_oam_status();
|
||||
//required functions
|
||||
void scanline();
|
||||
void render_scanline();
|
||||
void frame();
|
||||
enum : bool { Threaded = true };
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_cpu();
|
||||
|
||||
#include "memory/memory.hpp"
|
||||
#include "mmio/mmio.hpp"
|
||||
#include "render/render.hpp"
|
||||
|
||||
uint32 *surface;
|
||||
uint32 *output;
|
||||
|
||||
uint8 ppu1_version;
|
||||
uint8 ppu2_version;
|
||||
|
||||
static void Enter();
|
||||
void add_clocks(unsigned clocks);
|
||||
|
||||
uint8 region;
|
||||
unsigned line;
|
||||
|
||||
enum { NTSC = 0, PAL = 1 };
|
||||
enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5, COL = 5 };
|
||||
enum { SC_32x32 = 0, SC_64x32 = 1, SC_32x64 = 2, SC_64x64 = 3 };
|
||||
|
||||
struct {
|
||||
bool interlace;
|
||||
bool overscan;
|
||||
} display;
|
||||
|
||||
struct {
|
||||
//$2101
|
||||
uint8 oam_basesize;
|
||||
uint8 oam_nameselect;
|
||||
uint16 oam_tdaddr;
|
||||
|
||||
//$210d-$210e
|
||||
uint16 m7_hofs, m7_vofs;
|
||||
|
||||
//$211b-$2120
|
||||
uint16 m7a, m7b, m7c, m7d, m7x, m7y;
|
||||
} cache;
|
||||
|
||||
alwaysinline bool interlace() const { return display.interlace; }
|
||||
alwaysinline bool overscan() const { return display.overscan; }
|
||||
alwaysinline bool hires() const { return (regs.pseudo_hires || regs.bg_mode == 5 || regs.bg_mode == 6); }
|
||||
|
||||
uint16 mosaic_table[16][4096];
|
||||
void render_line();
|
||||
|
||||
void update_oam_status();
|
||||
//required functions
|
||||
void scanline();
|
||||
void render_scanline();
|
||||
void frame();
|
||||
void enter();
|
||||
void enter1();
|
||||
void enter2();
|
||||
void enter3();
|
||||
void enter4();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
bool layer_enabled[5][4];
|
||||
void layer_enable(unsigned layer, unsigned priority, bool enable);
|
||||
unsigned frameskip;
|
||||
unsigned framecounter;
|
||||
void set_frameskip(unsigned frameskip);
|
||||
|
||||
void serialize(serializer&);
|
||||
void initialize();
|
||||
PPU();
|
||||
~PPU();
|
||||
};
|
||||
|
||||
extern PPU ppu;
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
bool layer_enabled[5][4];
|
||||
void layer_enable(unsigned layer, unsigned priority, bool enable);
|
||||
unsigned frameskip;
|
||||
unsigned framecounter;
|
||||
void set_frameskip(unsigned frameskip);
|
||||
|
||||
void serialize(serializer&);
|
||||
void initialize();
|
||||
PPU();
|
||||
~PPU();
|
||||
};
|
||||
|
||||
extern PPU ppu;
|
||||
|
|
|
@ -1,210 +1,208 @@
|
|||
#ifdef PPU_CPP
|
||||
|
||||
void PPUcounter::serialize(serializer &s) {
|
||||
s.integer(status.interlace);
|
||||
s.integer(status.field);
|
||||
s.integer(status.vcounter);
|
||||
s.integer(status.hcounter);
|
||||
|
||||
s.array(history.field);
|
||||
s.array(history.vcounter);
|
||||
s.array(history.hcounter);
|
||||
s.integer(history.index);
|
||||
}
|
||||
|
||||
void PPU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
s.array(vram,128 * 1024);
|
||||
s.array(oam,544);
|
||||
s.array(cgram,512);
|
||||
|
||||
s.integer(ppu1_version);
|
||||
s.integer(ppu2_version);
|
||||
|
||||
s.integer(region);
|
||||
s.integer(line);
|
||||
|
||||
s.integer(display.interlace);
|
||||
s.integer(display.overscan);
|
||||
|
||||
s.integer(cache.oam_basesize);
|
||||
s.integer(cache.oam_nameselect);
|
||||
s.integer(cache.oam_tdaddr);
|
||||
|
||||
s.integer(regs.ppu1_mdr);
|
||||
s.integer(regs.ppu2_mdr);
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_y[n]);
|
||||
|
||||
s.integer(regs.ioamaddr);
|
||||
s.integer(regs.icgramaddr);
|
||||
|
||||
s.integer(regs.display_disabled);
|
||||
s.integer(regs.display_brightness);
|
||||
|
||||
s.integer(regs.oam_basesize);
|
||||
s.integer(regs.oam_nameselect);
|
||||
s.integer(regs.oam_tdaddr);
|
||||
|
||||
s.integer(regs.oam_baseaddr);
|
||||
s.integer(regs.oam_addr);
|
||||
s.integer(regs.oam_priority);
|
||||
s.integer(regs.oam_firstsprite);
|
||||
|
||||
s.integer(regs.oam_latchdata);
|
||||
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_tilesize[n]);
|
||||
s.integer(regs.bg3_priority);
|
||||
s.integer(regs.bg_mode);
|
||||
|
||||
s.integer(regs.mosaic_size);
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.mosaic_enabled[n]);
|
||||
s.integer(regs.mosaic_countdown);
|
||||
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_scaddr[n]);
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_scsize[n]);
|
||||
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_tdaddr[n]);
|
||||
|
||||
s.integer(regs.bg_ofslatch);
|
||||
s.integer(regs.m7_hofs);
|
||||
s.integer(regs.m7_vofs);
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_hofs[n]);
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_vofs[n]);
|
||||
|
||||
s.integer(regs.vram_incmode);
|
||||
s.integer(regs.vram_mapping);
|
||||
s.integer(regs.vram_incsize);
|
||||
|
||||
s.integer(regs.vram_addr);
|
||||
|
||||
s.integer(regs.mode7_repeat);
|
||||
s.integer(regs.mode7_vflip);
|
||||
s.integer(regs.mode7_hflip);
|
||||
|
||||
s.integer(regs.m7_latch);
|
||||
s.integer(regs.m7a);
|
||||
s.integer(regs.m7b);
|
||||
s.integer(regs.m7c);
|
||||
s.integer(regs.m7d);
|
||||
s.integer(regs.m7x);
|
||||
s.integer(regs.m7y);
|
||||
|
||||
s.integer(regs.cgram_addr);
|
||||
|
||||
s.integer(regs.cgram_latchdata);
|
||||
|
||||
for(unsigned n = 0; n < 6; n++) s.integer(regs.window1_enabled[n]);
|
||||
for(unsigned n = 0; n < 6; n++) s.integer(regs.window1_invert [n]);
|
||||
for(unsigned n = 0; n < 6; n++) s.integer(regs.window2_enabled[n]);
|
||||
for(unsigned n = 0; n < 6; n++) s.integer(regs.window2_invert [n]);
|
||||
|
||||
s.integer(regs.window1_left);
|
||||
s.integer(regs.window1_right);
|
||||
s.integer(regs.window2_left);
|
||||
s.integer(regs.window2_right);
|
||||
|
||||
for(unsigned n = 0; n < 6; n++) s.integer(regs.window_mask[n]);
|
||||
for(unsigned n = 0; n < 5; n++) s.integer(regs.bg_enabled[n]);
|
||||
for(unsigned n = 0; n < 5; n++) s.integer(regs.bgsub_enabled[n]);
|
||||
for(unsigned n = 0; n < 5; n++) s.integer(regs.window_enabled[n]);
|
||||
for(unsigned n = 0; n < 5; n++) s.integer(regs.sub_window_enabled[n]);
|
||||
|
||||
s.integer(regs.color_mask);
|
||||
s.integer(regs.colorsub_mask);
|
||||
s.integer(regs.addsub_mode);
|
||||
s.integer(regs.direct_color);
|
||||
|
||||
s.integer(regs.color_mode);
|
||||
s.integer(regs.color_halve);
|
||||
for(unsigned n = 0; n < 6; n++) s.integer(regs.color_enabled[n]);
|
||||
|
||||
s.integer(regs.color_r);
|
||||
s.integer(regs.color_g);
|
||||
s.integer(regs.color_b);
|
||||
s.integer(regs.color_rgb);
|
||||
|
||||
s.integer(regs.mode7_extbg);
|
||||
s.integer(regs.pseudo_hires);
|
||||
s.integer(regs.overscan);
|
||||
s.integer(regs.scanlines);
|
||||
s.integer(regs.oam_interlace);
|
||||
s.integer(regs.interlace);
|
||||
|
||||
s.integer(regs.hcounter);
|
||||
s.integer(regs.vcounter);
|
||||
s.integer(regs.latch_hcounter);
|
||||
s.integer(regs.latch_vcounter);
|
||||
s.integer(regs.counters_latched);
|
||||
|
||||
s.integer(regs.vram_readbuffer);
|
||||
|
||||
s.integer(regs.time_over);
|
||||
s.integer(regs.range_over);
|
||||
s.integer(regs.oam_itemcount);
|
||||
s.integer(regs.oam_tilecount);
|
||||
|
||||
for(unsigned n = 0; n < 256; n++) {
|
||||
s.integer(pixel_cache[n].src_main);
|
||||
s.integer(pixel_cache[n].src_sub);
|
||||
s.integer(pixel_cache[n].bg_main);
|
||||
s.integer(pixel_cache[n].bg_sub);
|
||||
s.integer(pixel_cache[n].ce_main);
|
||||
s.integer(pixel_cache[n].ce_sub);
|
||||
s.integer(pixel_cache[n].pri_main);
|
||||
s.integer(pixel_cache[n].pri_sub);
|
||||
}
|
||||
|
||||
//zero TODO - only on load
|
||||
//better to just take a small speed hit than store all of bg_tiledata[3][] ...
|
||||
flush_tiledata_cache();
|
||||
|
||||
for(unsigned n = 0; n < 6; n++) {
|
||||
s.array(window[n].main, 256);
|
||||
s.array(window[n].sub, 256);
|
||||
}
|
||||
|
||||
for(unsigned n = 0; n < 4; n++) {
|
||||
s.integer(bg_info[n].tw);
|
||||
s.integer(bg_info[n].th);
|
||||
s.integer(bg_info[n].mx);
|
||||
s.integer(bg_info[n].my);
|
||||
s.integer(bg_info[n].scx);
|
||||
s.integer(bg_info[n].scy);
|
||||
}
|
||||
|
||||
for(unsigned n = 0; n < 128; n++) {
|
||||
s.integer(sprite_list[n].width);
|
||||
s.integer(sprite_list[n].height);
|
||||
s.integer(sprite_list[n].x);
|
||||
s.integer(sprite_list[n].y);
|
||||
s.integer(sprite_list[n].character);
|
||||
s.integer(sprite_list[n].use_nameselect);
|
||||
s.integer(sprite_list[n].vflip);
|
||||
s.integer(sprite_list[n].hflip);
|
||||
s.integer(sprite_list[n].palette);
|
||||
s.integer(sprite_list[n].priority);
|
||||
s.integer(sprite_list[n].size);
|
||||
}
|
||||
s.integer(sprite_list_valid);
|
||||
s.integer(active_sprite);
|
||||
|
||||
s.array(oam_itemlist, 32);
|
||||
|
||||
for(unsigned n = 0; n < 34; n++) {
|
||||
s.integer(oam_tilelist[n].x);
|
||||
s.integer(oam_tilelist[n].y);
|
||||
s.integer(oam_tilelist[n].pri);
|
||||
s.integer(oam_tilelist[n].pal);
|
||||
s.integer(oam_tilelist[n].tile);
|
||||
s.integer(oam_tilelist[n].hflip);
|
||||
}
|
||||
|
||||
s.array(oam_line_pal, 256);
|
||||
s.array(oam_line_pri, 256);
|
||||
#ifdef PPU_CPP
|
||||
|
||||
s.integer(uindex);
|
||||
}
|
||||
|
||||
#endif
|
||||
void PPUcounter::serialize(serializer &s) {
|
||||
s.integer(status.interlace);
|
||||
s.integer(status.field);
|
||||
s.integer(status.vcounter);
|
||||
s.integer(status.hcounter);
|
||||
|
||||
s.array(history.field);
|
||||
s.array(history.vcounter);
|
||||
s.array(history.hcounter);
|
||||
s.integer(history.index);
|
||||
}
|
||||
|
||||
void PPU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
s.array(vram,128 * 1024);
|
||||
s.array(oam,544);
|
||||
s.array(cgram,512);
|
||||
|
||||
s.integer(ppu1_version);
|
||||
s.integer(ppu2_version);
|
||||
|
||||
s.integer(region);
|
||||
s.integer(line);
|
||||
|
||||
s.integer(display.interlace);
|
||||
s.integer(display.overscan);
|
||||
|
||||
s.integer(cache.oam_basesize);
|
||||
s.integer(cache.oam_nameselect);
|
||||
s.integer(cache.oam_tdaddr);
|
||||
|
||||
s.integer(regs.ppu1_mdr);
|
||||
s.integer(regs.ppu2_mdr);
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_y[n]);
|
||||
|
||||
s.integer(regs.ioamaddr);
|
||||
s.integer(regs.icgramaddr);
|
||||
|
||||
s.integer(regs.display_disabled);
|
||||
s.integer(regs.display_brightness);
|
||||
|
||||
s.integer(regs.oam_basesize);
|
||||
s.integer(regs.oam_nameselect);
|
||||
s.integer(regs.oam_tdaddr);
|
||||
|
||||
s.integer(regs.oam_baseaddr);
|
||||
s.integer(regs.oam_addr);
|
||||
s.integer(regs.oam_priority);
|
||||
s.integer(regs.oam_firstsprite);
|
||||
|
||||
s.integer(regs.oam_latchdata);
|
||||
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_tilesize[n]);
|
||||
s.integer(regs.bg3_priority);
|
||||
s.integer(regs.bg_mode);
|
||||
|
||||
s.integer(regs.mosaic_size);
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.mosaic_enabled[n]);
|
||||
s.integer(regs.mosaic_countdown);
|
||||
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_scaddr[n]);
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_scsize[n]);
|
||||
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_tdaddr[n]);
|
||||
|
||||
s.integer(regs.bg_ofslatch);
|
||||
s.integer(regs.m7_hofs);
|
||||
s.integer(regs.m7_vofs);
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_hofs[n]);
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_vofs[n]);
|
||||
|
||||
s.integer(regs.vram_incmode);
|
||||
s.integer(regs.vram_mapping);
|
||||
s.integer(regs.vram_incsize);
|
||||
|
||||
s.integer(regs.vram_addr);
|
||||
|
||||
s.integer(regs.mode7_repeat);
|
||||
s.integer(regs.mode7_vflip);
|
||||
s.integer(regs.mode7_hflip);
|
||||
|
||||
s.integer(regs.m7_latch);
|
||||
s.integer(regs.m7a);
|
||||
s.integer(regs.m7b);
|
||||
s.integer(regs.m7c);
|
||||
s.integer(regs.m7d);
|
||||
s.integer(regs.m7x);
|
||||
s.integer(regs.m7y);
|
||||
|
||||
s.integer(regs.cgram_addr);
|
||||
|
||||
s.integer(regs.cgram_latchdata);
|
||||
|
||||
for(unsigned n = 0; n < 6; n++) s.integer(regs.window1_enabled[n]);
|
||||
for(unsigned n = 0; n < 6; n++) s.integer(regs.window1_invert [n]);
|
||||
for(unsigned n = 0; n < 6; n++) s.integer(regs.window2_enabled[n]);
|
||||
for(unsigned n = 0; n < 6; n++) s.integer(regs.window2_invert [n]);
|
||||
|
||||
s.integer(regs.window1_left);
|
||||
s.integer(regs.window1_right);
|
||||
s.integer(regs.window2_left);
|
||||
s.integer(regs.window2_right);
|
||||
|
||||
for(unsigned n = 0; n < 6; n++) s.integer(regs.window_mask[n]);
|
||||
for(unsigned n = 0; n < 5; n++) s.integer(regs.bg_enabled[n]);
|
||||
for(unsigned n = 0; n < 5; n++) s.integer(regs.bgsub_enabled[n]);
|
||||
for(unsigned n = 0; n < 5; n++) s.integer(regs.window_enabled[n]);
|
||||
for(unsigned n = 0; n < 5; n++) s.integer(regs.sub_window_enabled[n]);
|
||||
|
||||
s.integer(regs.color_mask);
|
||||
s.integer(regs.colorsub_mask);
|
||||
s.integer(regs.addsub_mode);
|
||||
s.integer(regs.direct_color);
|
||||
|
||||
s.integer(regs.color_mode);
|
||||
s.integer(regs.color_halve);
|
||||
for(unsigned n = 0; n < 6; n++) s.integer(regs.color_enabled[n]);
|
||||
|
||||
s.integer(regs.color_r);
|
||||
s.integer(regs.color_g);
|
||||
s.integer(regs.color_b);
|
||||
s.integer(regs.color_rgb);
|
||||
|
||||
s.integer(regs.mode7_extbg);
|
||||
s.integer(regs.pseudo_hires);
|
||||
s.integer(regs.overscan);
|
||||
s.integer(regs.scanlines);
|
||||
s.integer(regs.oam_interlace);
|
||||
s.integer(regs.interlace);
|
||||
|
||||
s.integer(regs.hcounter);
|
||||
s.integer(regs.vcounter);
|
||||
s.integer(regs.latch_hcounter);
|
||||
s.integer(regs.latch_vcounter);
|
||||
s.integer(regs.counters_latched);
|
||||
|
||||
s.integer(regs.vram_readbuffer);
|
||||
|
||||
s.integer(regs.time_over);
|
||||
s.integer(regs.range_over);
|
||||
s.integer(regs.oam_itemcount);
|
||||
s.integer(regs.oam_tilecount);
|
||||
|
||||
for(unsigned n = 0; n < 256; n++) {
|
||||
s.integer(pixel_cache[n].src_main);
|
||||
s.integer(pixel_cache[n].src_sub);
|
||||
s.integer(pixel_cache[n].bg_main);
|
||||
s.integer(pixel_cache[n].bg_sub);
|
||||
s.integer(pixel_cache[n].ce_main);
|
||||
s.integer(pixel_cache[n].ce_sub);
|
||||
s.integer(pixel_cache[n].pri_main);
|
||||
s.integer(pixel_cache[n].pri_sub);
|
||||
}
|
||||
|
||||
//zero TODO - only on load
|
||||
//better to just take a small speed hit than store all of bg_tiledata[3][] ...
|
||||
flush_tiledata_cache();
|
||||
|
||||
for(unsigned n = 0; n < 6; n++) {
|
||||
s.array(window[n].main, 256);
|
||||
s.array(window[n].sub, 256);
|
||||
}
|
||||
|
||||
for(unsigned n = 0; n < 4; n++) {
|
||||
s.integer(bg_info[n].tw);
|
||||
s.integer(bg_info[n].th);
|
||||
s.integer(bg_info[n].mx);
|
||||
s.integer(bg_info[n].my);
|
||||
s.integer(bg_info[n].scx);
|
||||
s.integer(bg_info[n].scy);
|
||||
}
|
||||
|
||||
for(unsigned n = 0; n < 128; n++) {
|
||||
s.integer(sprite_list[n].width);
|
||||
s.integer(sprite_list[n].height);
|
||||
s.integer(sprite_list[n].x);
|
||||
s.integer(sprite_list[n].y);
|
||||
s.integer(sprite_list[n].character);
|
||||
s.integer(sprite_list[n].use_nameselect);
|
||||
s.integer(sprite_list[n].vflip);
|
||||
s.integer(sprite_list[n].hflip);
|
||||
s.integer(sprite_list[n].palette);
|
||||
s.integer(sprite_list[n].priority);
|
||||
s.integer(sprite_list[n].size);
|
||||
}
|
||||
s.integer(sprite_list_valid);
|
||||
s.integer(active_sprite);
|
||||
|
||||
s.array(oam_itemlist, 32);
|
||||
|
||||
for(unsigned n = 0; n < 34; n++) {
|
||||
s.integer(oam_tilelist[n].x);
|
||||
s.integer(oam_tilelist[n].y);
|
||||
s.integer(oam_tilelist[n].pri);
|
||||
s.integer(oam_tilelist[n].pal);
|
||||
s.integer(oam_tilelist[n].tile);
|
||||
s.integer(oam_tilelist[n].hflip);
|
||||
}
|
||||
|
||||
s.array(oam_line_pal, 256);
|
||||
s.array(oam_line_pri, 256);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,87 +1,82 @@
|
|||
#include <snes/snes.hpp>
|
||||
|
||||
#define HITACHIDSP_CPP
|
||||
namespace SNES {
|
||||
|
||||
#include "memory.cpp"
|
||||
#include "opcodes.cpp"
|
||||
#include "registers.cpp"
|
||||
#include "serialization.cpp"
|
||||
HitachiDSP hitachidsp;
|
||||
|
||||
//zero 01-sep-2014 - dont clobber these when reconstructing!
|
||||
unsigned HitachiDSP::frequency;
|
||||
uint24 HitachiDSP::dataROM[1024];
|
||||
|
||||
void HitachiDSP::Enter() { hitachidsp.enter(); }
|
||||
|
||||
void HitachiDSP::enter() {
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define HITACHIDSP_CPP
|
||||
namespace SNES {
|
||||
|
||||
#include "memory.cpp"
|
||||
#include "opcodes.cpp"
|
||||
#include "registers.cpp"
|
||||
#include "serialization.cpp"
|
||||
HitachiDSP hitachidsp;
|
||||
|
||||
//zero 01-sep-2014 - dont clobber these when reconstructing!
|
||||
unsigned HitachiDSP::frequency;
|
||||
uint24 HitachiDSP::dataROM[1024];
|
||||
|
||||
void HitachiDSP::Enter() { hitachidsp.enter(); }
|
||||
|
||||
void HitachiDSP::enter() {
|
||||
while(true) {
|
||||
// exit requested due to savestate
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
// if we bail out due to savestating, the first thing we'll try afterwards is synchronize_cpu() again
|
||||
synchronize_cpu();
|
||||
|
||||
switch(state) {
|
||||
case State::Idle:
|
||||
step(1);
|
||||
break;
|
||||
case State::DMA:
|
||||
for(unsigned n = 0; n < regs.dma_length; n++) {
|
||||
bus.write(regs.dma_target + n, bus.read(regs.dma_source + n));
|
||||
step(2);
|
||||
}
|
||||
state = State::Idle;
|
||||
break;
|
||||
case State::Execute:
|
||||
unsigned offset = regs.program_offset + regs.pc * 2;
|
||||
opcode = bus_read(offset + 0) << 0;
|
||||
opcode |= bus_read(offset + 1) << 8;
|
||||
regs.pc = (regs.pc & 0xffff00) | ((regs.pc + 1) & 0x0000ff);
|
||||
exec();
|
||||
step(1);
|
||||
break;
|
||||
}
|
||||
switch(state) {
|
||||
case State::Idle:
|
||||
step(1);
|
||||
break;
|
||||
case State::DMA:
|
||||
for(unsigned n = 0; n < regs.dma_length; n++) {
|
||||
bus.write(regs.dma_target + n, bus.read(regs.dma_source + n));
|
||||
step(2);
|
||||
}
|
||||
state = State::Idle;
|
||||
break;
|
||||
case State::Execute:
|
||||
unsigned offset = regs.program_offset + regs.pc * 2;
|
||||
opcode = bus_read(offset + 0) << 0;
|
||||
opcode |= bus_read(offset + 1) << 8;
|
||||
regs.pc = (regs.pc & 0xffff00) | ((regs.pc + 1) & 0x0000ff);
|
||||
exec();
|
||||
step(1);
|
||||
break;
|
||||
}
|
||||
|
||||
// this call is gone, but it's the first thing we try at the top of the loop AFTER we bail out
|
||||
//synchronize_cpu();
|
||||
}
|
||||
}
|
||||
|
||||
void HitachiDSP::init() {
|
||||
}
|
||||
|
||||
void HitachiDSP::load() {
|
||||
}
|
||||
|
||||
void HitachiDSP::unload() {
|
||||
}
|
||||
|
||||
void HitachiDSP::power() {
|
||||
}
|
||||
|
||||
void HitachiDSP::reset() {
|
||||
create(HitachiDSP::Enter, frequency);
|
||||
state = State::Idle;
|
||||
|
||||
regs.n = 0;
|
||||
regs.z = 0;
|
||||
regs.c = 0;
|
||||
|
||||
regs.dma_source = 0x000000;
|
||||
regs.dma_length = 0x0000;
|
||||
regs.dma_target = 0x000000;
|
||||
regs.r1f48 = 0x00;
|
||||
regs.program_offset = 0x000000;
|
||||
regs.r1f4c = 0x00;
|
||||
regs.page_number = 0x0000;
|
||||
regs.program_counter = 0x00;
|
||||
regs.r1f50 = 0x33;
|
||||
regs.r1f51 = 0x00;
|
||||
regs.r1f52 = 0x01;
|
||||
}
|
||||
|
||||
}
|
||||
synchronize_cpu();
|
||||
}
|
||||
}
|
||||
|
||||
void HitachiDSP::init() {
|
||||
}
|
||||
|
||||
void HitachiDSP::load() {
|
||||
}
|
||||
|
||||
void HitachiDSP::unload() {
|
||||
}
|
||||
|
||||
void HitachiDSP::power() {
|
||||
}
|
||||
|
||||
void HitachiDSP::reset() {
|
||||
create(HitachiDSP::Enter, frequency);
|
||||
state = State::Idle;
|
||||
|
||||
regs.n = 0;
|
||||
regs.z = 0;
|
||||
regs.c = 0;
|
||||
|
||||
regs.dma_source = 0x000000;
|
||||
regs.dma_length = 0x0000;
|
||||
regs.dma_target = 0x000000;
|
||||
regs.r1f48 = 0x00;
|
||||
regs.program_offset = 0x000000;
|
||||
regs.r1f4c = 0x00;
|
||||
regs.page_number = 0x0000;
|
||||
regs.program_counter = 0x00;
|
||||
regs.r1f50 = 0x33;
|
||||
regs.r1f51 = 0x00;
|
||||
regs.r1f52 = 0x01;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,25 +19,20 @@ void SA1::enter() {
|
|||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
if (regs.hang == HangType::Wait) this->op_wai();
|
||||
else if (regs.hang == HangType::Stop) this->op_stp();
|
||||
else
|
||||
{
|
||||
if(mmio.sa1_rdyb || mmio.sa1_resb) {
|
||||
//SA-1 co-processor is asleep
|
||||
tick();
|
||||
synchronize_cpu();
|
||||
continue;
|
||||
}
|
||||
if(mmio.sa1_rdyb || mmio.sa1_resb) {
|
||||
//SA-1 co-processor is asleep
|
||||
tick();
|
||||
synchronize_cpu();
|
||||
continue;
|
||||
}
|
||||
|
||||
if(status.interrupt_pending) {
|
||||
status.interrupt_pending = false;
|
||||
op_irq();
|
||||
continue;
|
||||
}
|
||||
if(status.interrupt_pending) {
|
||||
status.interrupt_pending = false;
|
||||
op_irq();
|
||||
continue;
|
||||
}
|
||||
|
||||
(this->*opcode_table[op_readpc()])();
|
||||
}
|
||||
(this->*opcode_table[op_readpc()])();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -72,28 +72,16 @@ L rd.h = op_readlong(vectorN + 1);
|
|||
}
|
||||
|
||||
void CPUcore::op_stp() {
|
||||
if(regs.hang == HangType::Stop)
|
||||
goto SKIP;
|
||||
regs.hang = HangType::Stop;
|
||||
while(regs.wai = true) {
|
||||
L op_io();
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
SKIP: ;
|
||||
}
|
||||
regs.hang = HangType::None;
|
||||
}
|
||||
}
|
||||
|
||||
void CPUcore::op_wai() {
|
||||
if (regs.hang == HangType::Wait)
|
||||
goto SKIP;
|
||||
regs.wai = true;
|
||||
regs.hang = HangType::Wait;
|
||||
while(regs.wai) {
|
||||
L op_io();
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
SKIP: ;
|
||||
}
|
||||
regs.hang = HangType::None;
|
||||
}
|
||||
op_io();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
enum class HangType: unsigned { None, Wait, Stop };
|
||||
|
||||
struct flag_t {
|
||||
bool n, v, m, x, d, i, z, c;
|
||||
|
||||
|
@ -75,14 +73,11 @@ struct regs_t {
|
|||
|
||||
bool irq; //IRQ pin (0 = low, 1 = trigger)
|
||||
bool wai; //raised during wai, cleared after interrupt triggered
|
||||
|
||||
uint8 mdr; //memory data register
|
||||
uint16 vector; //interrupt vector address
|
||||
|
||||
HangType hang;
|
||||
|
||||
regs_t():
|
||||
a(r[0]), x(r[1]), y(r[2]), z(r[3]), s(r[4]), d(r[5]), db(0), e(false), irq(false), wai(false), mdr(0), vector(0), hang(HangType::None) {
|
||||
a(r[0]), x(r[1]), y(r[2]), z(r[3]), s(r[4]), d(r[5]), db(0), e(false), irq(false), wai(false), mdr(0), vector(0) {
|
||||
z = 0;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -26,10 +26,6 @@ void CPUcore::core_serialize(serializer &s) {
|
|||
s.integer(regs.mdr);
|
||||
s.integer(regs.vector);
|
||||
|
||||
unsigned junk = (unsigned)regs.hang;
|
||||
s.integer(junk);
|
||||
regs.hang = (HangType)junk;
|
||||
|
||||
s.integer(aa.d);
|
||||
s.integer(rd.d);
|
||||
s.integer(sp);
|
||||
|
|
|
@ -1,184 +1,180 @@
|
|||
#include <snes/snes.hpp>
|
||||
|
||||
#define CPU_CPP
|
||||
namespace SNES {
|
||||
|
||||
CPU cpu;
|
||||
|
||||
#include "serialization.cpp"
|
||||
#include "dma/dma.cpp"
|
||||
#include "memory/memory.cpp"
|
||||
#include "mmio/mmio.cpp"
|
||||
#include "timing/timing.cpp"
|
||||
|
||||
void CPU::step(unsigned clocks) {
|
||||
smp.clock -= clocks * (uint64)smp.frequency;
|
||||
ppu.clock -= clocks;
|
||||
for(unsigned i = 0; i < coprocessors.size(); i++) {
|
||||
Processor &chip = *coprocessors[i];
|
||||
chip.clock -= clocks * (uint64)chip.frequency;
|
||||
}
|
||||
input.port1->clock -= clocks * (uint64)input.port1->frequency;
|
||||
input.port2->clock -= clocks * (uint64)input.port2->frequency;
|
||||
synchronize_controllers();
|
||||
}
|
||||
|
||||
void CPU::synchronize_smp() {
|
||||
if(SMP::Threaded == true) {
|
||||
if(smp.clock < 0) co_switch(smp.thread);
|
||||
} else {
|
||||
while(smp.clock < 0) smp.enter();
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::synchronize_ppu() {
|
||||
if(PPU::Threaded == true) {
|
||||
if(ppu.clock < 0) co_switch(ppu.thread);
|
||||
} else {
|
||||
while(ppu.clock < 0) ppu.enter();
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::synchronize_coprocessors() {
|
||||
for(unsigned i = 0; i < coprocessors.size(); i++) {
|
||||
Processor &chip = *coprocessors[i];
|
||||
if(chip.clock < 0) co_switch(chip.thread);
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::synchronize_controllers() {
|
||||
if(input.port1->clock < 0) co_switch(input.port1->thread);
|
||||
if(input.port2->clock < 0) co_switch(input.port2->thread);
|
||||
}
|
||||
|
||||
void CPU::Enter() { cpu.enter(); }
|
||||
|
||||
void CPU::enter() {
|
||||
while(true) {
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define CPU_CPP
|
||||
namespace SNES {
|
||||
|
||||
CPU cpu;
|
||||
|
||||
#include "serialization.cpp"
|
||||
#include "dma/dma.cpp"
|
||||
#include "memory/memory.cpp"
|
||||
#include "mmio/mmio.cpp"
|
||||
#include "timing/timing.cpp"
|
||||
|
||||
void CPU::step(unsigned clocks) {
|
||||
smp.clock -= clocks * (uint64)smp.frequency;
|
||||
ppu.clock -= clocks;
|
||||
for(unsigned i = 0; i < coprocessors.size(); i++) {
|
||||
Processor &chip = *coprocessors[i];
|
||||
chip.clock -= clocks * (uint64)chip.frequency;
|
||||
}
|
||||
input.port1->clock -= clocks * (uint64)input.port1->frequency;
|
||||
input.port2->clock -= clocks * (uint64)input.port2->frequency;
|
||||
synchronize_controllers();
|
||||
}
|
||||
|
||||
void CPU::synchronize_smp() {
|
||||
if(SMP::Threaded == true) {
|
||||
if(smp.clock < 0) co_switch(smp.thread);
|
||||
} else {
|
||||
while(smp.clock < 0) smp.enter();
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::synchronize_ppu() {
|
||||
if(PPU::Threaded == true) {
|
||||
if(ppu.clock < 0) co_switch(ppu.thread);
|
||||
} else {
|
||||
while(ppu.clock < 0) ppu.enter();
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::synchronize_coprocessors() {
|
||||
for(unsigned i = 0; i < coprocessors.size(); i++) {
|
||||
Processor &chip = *coprocessors[i];
|
||||
if(chip.clock < 0) co_switch(chip.thread);
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::synchronize_controllers() {
|
||||
if(input.port1->clock < 0) co_switch(input.port1->thread);
|
||||
if(input.port2->clock < 0) co_switch(input.port2->thread);
|
||||
}
|
||||
|
||||
void CPU::Enter() { cpu.enter(); }
|
||||
|
||||
void CPU::enter() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::CPU) {
|
||||
// we can only stop if there's enough time for at least one more event
|
||||
// on both the PPU and the SMP
|
||||
if (smp.clock < 0 && ppu.clock < 0) {
|
||||
scheduler.sync = Scheduler::SynchronizeMode::All;
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
if(status.interrupt_pending) {
|
||||
status.interrupt_pending = false;
|
||||
if(status.nmi_pending) {
|
||||
status.nmi_pending = false;
|
||||
regs.vector = (regs.e == false ? 0xffea : 0xfffa);
|
||||
op_irq();
|
||||
debugger.op_nmi();
|
||||
} else if(status.irq_pending) {
|
||||
status.irq_pending = false;
|
||||
regs.vector = (regs.e == false ? 0xffee : 0xfffe);
|
||||
op_irq();
|
||||
debugger.op_irq();
|
||||
} else if(status.reset_pending) {
|
||||
status.reset_pending = false;
|
||||
add_clocks(186);
|
||||
regs.pc.l = bus.read(0xfffc);
|
||||
regs.pc.h = bus.read(0xfffd);
|
||||
}
|
||||
}
|
||||
|
||||
op_step();
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::op_step() {
|
||||
debugger.op_exec(regs.pc.d);
|
||||
|
||||
if (interface()->wanttrace & TRACE_CPU_MASK)
|
||||
{
|
||||
char tmp[512];
|
||||
disassemble_opcode(tmp, regs.pc.d);
|
||||
tmp[511] = 0;
|
||||
interface()->cpuTrace(TRACE_CPU, tmp);
|
||||
}
|
||||
|
||||
(this->*opcode_table[op_readpcfirst()])();
|
||||
}
|
||||
|
||||
void CPU::enable() {
|
||||
function<uint8 (unsigned)> read = { &CPU::mmio_read, (CPU*)&cpu };
|
||||
function<void (unsigned, uint8)> write = { &CPU::mmio_write, (CPU*)&cpu };
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, read, write);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, read, write);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4200, 0x421f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, read, write);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, read, write);
|
||||
|
||||
read = [](unsigned addr) { cdlInfo.set(eCDLog_AddrType_WRAM, addr); return cpu.wram[addr]; };
|
||||
write = [](unsigned addr, uint8 data) { cpu.wram[addr] = data; };
|
||||
|
||||
bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
|
||||
bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
|
||||
bus.map(Bus::MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff, read, write);
|
||||
}
|
||||
|
||||
void CPU::power() {
|
||||
cpu_version = config.cpu.version;
|
||||
for(int i=0;i<128*1024;i++) wram[i] = random(config.cpu.wram_init_value);
|
||||
|
||||
regs.a = regs.x = regs.y = 0x0000;
|
||||
regs.s = 0x01ff;
|
||||
|
||||
mmio_power();
|
||||
dma_power();
|
||||
timing_power();
|
||||
|
||||
//zero 01-dec-2012
|
||||
//gotta clear these to something, sometime
|
||||
aa.d = rd.d = sp = dp = 0;
|
||||
}
|
||||
|
||||
void CPU::reset() {
|
||||
create(Enter, system.cpu_frequency());
|
||||
coprocessors.reset();
|
||||
PPUcounter::reset();
|
||||
|
||||
//note: some registers are not fully reset by SNES
|
||||
regs.pc = 0x000000;
|
||||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
regs.s.h = 0x01;
|
||||
regs.d = 0x0000;
|
||||
regs.db = 0x00;
|
||||
regs.p = 0x34;
|
||||
regs.e = 1;
|
||||
regs.mdr = 0x00;
|
||||
regs.wai = false;
|
||||
regs.vector = 0xfffc; //reset vector address
|
||||
update_table();
|
||||
|
||||
mmio_reset();
|
||||
dma_reset();
|
||||
timing_reset();
|
||||
}
|
||||
|
||||
CPU::CPU()
|
||||
: wram(nullptr)
|
||||
{
|
||||
PPUcounter::scanline = { &CPU::scanline, this };
|
||||
}
|
||||
|
||||
CPU::~CPU() {
|
||||
interface()->freeSharedMemory(wram);
|
||||
}
|
||||
|
||||
void CPU::initialize()
|
||||
{
|
||||
wram = (uint8*)interface()->allocSharedMemory("WRAM",128 * 1024);
|
||||
}
|
||||
|
||||
}
|
||||
scheduler.sync = Scheduler::SynchronizeMode::All;
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
if(status.interrupt_pending) {
|
||||
status.interrupt_pending = false;
|
||||
if(status.nmi_pending) {
|
||||
status.nmi_pending = false;
|
||||
regs.vector = (regs.e == false ? 0xffea : 0xfffa);
|
||||
op_irq();
|
||||
debugger.op_nmi();
|
||||
} else if(status.irq_pending) {
|
||||
status.irq_pending = false;
|
||||
regs.vector = (regs.e == false ? 0xffee : 0xfffe);
|
||||
op_irq();
|
||||
debugger.op_irq();
|
||||
} else if(status.reset_pending) {
|
||||
status.reset_pending = false;
|
||||
add_clocks(186);
|
||||
regs.pc.l = bus.read(0xfffc);
|
||||
regs.pc.h = bus.read(0xfffd);
|
||||
}
|
||||
}
|
||||
|
||||
op_step();
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::op_step() {
|
||||
debugger.op_exec(regs.pc.d);
|
||||
|
||||
if (interface()->wanttrace & TRACE_CPU_MASK)
|
||||
{
|
||||
char tmp[512];
|
||||
disassemble_opcode(tmp, regs.pc.d);
|
||||
tmp[511] = 0;
|
||||
interface()->cpuTrace(TRACE_CPU, tmp);
|
||||
}
|
||||
|
||||
(this->*opcode_table[op_readpcfirst()])();
|
||||
}
|
||||
|
||||
void CPU::enable() {
|
||||
function<uint8 (unsigned)> read = { &CPU::mmio_read, (CPU*)&cpu };
|
||||
function<void (unsigned, uint8)> write = { &CPU::mmio_write, (CPU*)&cpu };
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, read, write);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, read, write);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4200, 0x421f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, read, write);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, read, write);
|
||||
|
||||
read = [](unsigned addr) { cdlInfo.set(eCDLog_AddrType_WRAM, addr); return cpu.wram[addr]; };
|
||||
write = [](unsigned addr, uint8 data) { cpu.wram[addr] = data; };
|
||||
|
||||
bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
|
||||
bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
|
||||
bus.map(Bus::MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff, read, write);
|
||||
}
|
||||
|
||||
void CPU::power() {
|
||||
cpu_version = config.cpu.version;
|
||||
for(int i=0;i<128*1024;i++) wram[i] = random(config.cpu.wram_init_value);
|
||||
|
||||
regs.a = regs.x = regs.y = 0x0000;
|
||||
regs.s = 0x01ff;
|
||||
|
||||
mmio_power();
|
||||
dma_power();
|
||||
timing_power();
|
||||
|
||||
//zero 01-dec-2012
|
||||
//gotta clear these to something, sometime
|
||||
aa.d = rd.d = sp = dp = 0;
|
||||
}
|
||||
|
||||
void CPU::reset() {
|
||||
create(Enter, system.cpu_frequency());
|
||||
coprocessors.reset();
|
||||
PPUcounter::reset();
|
||||
|
||||
//note: some registers are not fully reset by SNES
|
||||
regs.pc = 0x000000;
|
||||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
regs.s.h = 0x01;
|
||||
regs.d = 0x0000;
|
||||
regs.db = 0x00;
|
||||
regs.p = 0x34;
|
||||
regs.e = 1;
|
||||
regs.mdr = 0x00;
|
||||
regs.wai = false;
|
||||
regs.vector = 0xfffc; //reset vector address
|
||||
update_table();
|
||||
|
||||
mmio_reset();
|
||||
dma_reset();
|
||||
timing_reset();
|
||||
}
|
||||
|
||||
CPU::CPU()
|
||||
: wram(nullptr)
|
||||
{
|
||||
PPUcounter::scanline = { &CPU::scanline, this };
|
||||
}
|
||||
|
||||
CPU::~CPU() {
|
||||
interface()->freeSharedMemory(wram);
|
||||
}
|
||||
|
||||
void CPU::initialize()
|
||||
{
|
||||
wram = (uint8*)interface()->allocSharedMemory("WRAM",128 * 1024);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,275 +1,272 @@
|
|||
#include <snes/snes.hpp>
|
||||
|
||||
#define SMPCORE_CPP
|
||||
namespace SNES {
|
||||
|
||||
#include "algorithms.cpp"
|
||||
//#include "opcodes.cpp"
|
||||
#include "disassembler.cpp"
|
||||
#include "serialization.cpp"
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#include "uop.cpp"
|
||||
#define SMPCORE_CPP
|
||||
namespace SNES {
|
||||
|
||||
/*
|
||||
void SMPcore::op_step() {
|
||||
switch(opcode = op_readpc()) {
|
||||
case 0x00: return op_nop();
|
||||
case 0x01: return op_jst();
|
||||
case 0x02: return op_set_bit();
|
||||
case 0x03: return op_branch_bit();
|
||||
case 0x04: return op_read_dp<&SMPcore::op_or>(regs.a);
|
||||
case 0x05: return op_read_addr<&SMPcore::op_or>(regs.a);
|
||||
case 0x06: return op_read_ix<&SMPcore::op_or>();
|
||||
case 0x07: return op_read_idpx<&SMPcore::op_or>();
|
||||
case 0x08: return op_read_const<&SMPcore::op_or>(regs.a);
|
||||
case 0x09: return op_write_dp_dp<&SMPcore::op_or>();
|
||||
case 0x0a: return op_set_addr_bit();
|
||||
case 0x0b: return op_adjust_dp<&SMPcore::op_asl>();
|
||||
case 0x0c: return op_adjust_addr<&SMPcore::op_asl>();
|
||||
case 0x0d: return op_push(regs.p);
|
||||
case 0x0e: return op_test_addr(1);
|
||||
case 0x0f: return op_brk();
|
||||
case 0x10: return op_branch(regs.p.n == 0);
|
||||
case 0x11: return op_jst();
|
||||
case 0x12: return op_set_bit();
|
||||
case 0x13: return op_branch_bit();
|
||||
case 0x14: return op_read_dpi<&SMPcore::op_or>(regs.a, regs.x);
|
||||
case 0x15: return op_read_addri<&SMPcore::op_or>(regs.x);
|
||||
case 0x16: return op_read_addri<&SMPcore::op_or>(regs.y);
|
||||
case 0x17: return op_read_idpy<&SMPcore::op_or>();
|
||||
case 0x18: return op_write_dp_const<&SMPcore::op_or>();
|
||||
case 0x19: return op_write_ix_iy<&SMPcore::op_or>();
|
||||
case 0x1a: return op_adjust_dpw(-1);
|
||||
case 0x1b: return op_adjust_dpx<&SMPcore::op_asl>();
|
||||
case 0x1c: return op_adjust<&SMPcore::op_asl>(regs.a);
|
||||
case 0x1d: return op_adjust<&SMPcore::op_dec>(regs.x);
|
||||
case 0x1e: return op_read_addr<&SMPcore::op_cmp>(regs.x);
|
||||
case 0x1f: return op_jmp_iaddrx();
|
||||
case 0x20: return op_set_flag(regs.p.p, 0);
|
||||
case 0x21: return op_jst();
|
||||
case 0x22: return op_set_bit();
|
||||
case 0x23: return op_branch_bit();
|
||||
case 0x24: return op_read_dp<&SMPcore::op_and>(regs.a);
|
||||
case 0x25: return op_read_addr<&SMPcore::op_and>(regs.a);
|
||||
case 0x26: return op_read_ix<&SMPcore::op_and>();
|
||||
case 0x27: return op_read_idpx<&SMPcore::op_and>();
|
||||
case 0x28: return op_read_const<&SMPcore::op_and>(regs.a);
|
||||
case 0x29: return op_write_dp_dp<&SMPcore::op_and>();
|
||||
case 0x2a: return op_set_addr_bit();
|
||||
case 0x2b: return op_adjust_dp<&SMPcore::op_rol>();
|
||||
case 0x2c: return op_adjust_addr<&SMPcore::op_rol>();
|
||||
case 0x2d: return op_push(regs.a);
|
||||
case 0x2e: return op_bne_dp();
|
||||
case 0x2f: return op_branch(true);
|
||||
case 0x30: return op_branch(regs.p.n == 1);
|
||||
case 0x31: return op_jst();
|
||||
case 0x32: return op_set_bit();
|
||||
case 0x33: return op_branch_bit();
|
||||
case 0x34: return op_read_dpi<&SMPcore::op_and>(regs.a, regs.x);
|
||||
case 0x35: return op_read_addri<&SMPcore::op_and>(regs.x);
|
||||
case 0x36: return op_read_addri<&SMPcore::op_and>(regs.y);
|
||||
case 0x37: return op_read_idpy<&SMPcore::op_and>();
|
||||
case 0x38: return op_write_dp_const<&SMPcore::op_and>();
|
||||
case 0x39: return op_write_ix_iy<&SMPcore::op_and>();
|
||||
case 0x3a: return op_adjust_dpw(+1);
|
||||
case 0x3b: return op_adjust_dpx<&SMPcore::op_rol>();
|
||||
case 0x3c: return op_adjust<&SMPcore::op_rol>(regs.a);
|
||||
case 0x3d: return op_adjust<&SMPcore::op_inc>(regs.x);
|
||||
case 0x3e: return op_read_dp<&SMPcore::op_cmp>(regs.x);
|
||||
case 0x3f: return op_jsr_addr();
|
||||
case 0x40: return op_set_flag(regs.p.p, 1);
|
||||
case 0x41: return op_jst();
|
||||
case 0x42: return op_set_bit();
|
||||
case 0x43: return op_branch_bit();
|
||||
case 0x44: return op_read_dp<&SMPcore::op_eor>(regs.a);
|
||||
case 0x45: return op_read_addr<&SMPcore::op_eor>(regs.a);
|
||||
case 0x46: return op_read_ix<&SMPcore::op_eor>();
|
||||
case 0x47: return op_read_idpx<&SMPcore::op_eor>();
|
||||
case 0x48: return op_read_const<&SMPcore::op_eor>(regs.a);
|
||||
case 0x49: return op_write_dp_dp<&SMPcore::op_eor>();
|
||||
case 0x4a: return op_set_addr_bit();
|
||||
case 0x4b: return op_adjust_dp<&SMPcore::op_lsr>();
|
||||
case 0x4c: return op_adjust_addr<&SMPcore::op_lsr>();
|
||||
case 0x4d: return op_push(regs.x);
|
||||
case 0x4e: return op_test_addr(0);
|
||||
case 0x4f: return op_jsp_dp();
|
||||
case 0x50: return op_branch(regs.p.v == 0);
|
||||
case 0x51: return op_jst();
|
||||
case 0x52: return op_set_bit();
|
||||
case 0x53: return op_branch_bit();
|
||||
case 0x54: return op_read_dpi<&SMPcore::op_eor>(regs.a, regs.x);
|
||||
case 0x55: return op_read_addri<&SMPcore::op_eor>(regs.x);
|
||||
case 0x56: return op_read_addri<&SMPcore::op_eor>(regs.y);
|
||||
case 0x57: return op_read_idpy<&SMPcore::op_eor>();
|
||||
case 0x58: return op_write_dp_const<&SMPcore::op_eor>();
|
||||
case 0x59: return op_write_ix_iy<&SMPcore::op_eor>();
|
||||
case 0x5a: return op_read_dpw<&SMPcore::op_cpw>();
|
||||
case 0x5b: return op_adjust_dpx<&SMPcore::op_lsr>();
|
||||
case 0x5c: return op_adjust<&SMPcore::op_lsr>(regs.a);
|
||||
case 0x5d: return op_transfer(regs.a, regs.x);
|
||||
case 0x5e: return op_read_addr<&SMPcore::op_cmp>(regs.y);
|
||||
case 0x5f: return op_jmp_addr();
|
||||
case 0x60: return op_set_flag(regs.p.c, 0);
|
||||
case 0x61: return op_jst();
|
||||
case 0x62: return op_set_bit();
|
||||
case 0x63: return op_branch_bit();
|
||||
case 0x64: return op_read_dp<&SMPcore::op_cmp>(regs.a);
|
||||
case 0x65: return op_read_addr<&SMPcore::op_cmp>(regs.a);
|
||||
case 0x66: return op_read_ix<&SMPcore::op_cmp>();
|
||||
case 0x67: return op_read_idpx<&SMPcore::op_cmp>();
|
||||
case 0x68: return op_read_const<&SMPcore::op_cmp>(regs.a);
|
||||
case 0x69: return op_write_dp_dp<&SMPcore::op_cmp>();
|
||||
case 0x6a: return op_set_addr_bit();
|
||||
case 0x6b: return op_adjust_dp<&SMPcore::op_ror>();
|
||||
case 0x6c: return op_adjust_addr<&SMPcore::op_ror>();
|
||||
case 0x6d: return op_push(regs.y);
|
||||
case 0x6e: return op_bne_dpdec();
|
||||
case 0x6f: return op_rts();
|
||||
case 0x70: return op_branch(regs.p.v == 1);
|
||||
case 0x71: return op_jst();
|
||||
case 0x72: return op_set_bit();
|
||||
case 0x73: return op_branch_bit();
|
||||
case 0x74: return op_read_dpi<&SMPcore::op_cmp>(regs.a, regs.x);
|
||||
case 0x75: return op_read_addri<&SMPcore::op_cmp>(regs.x);
|
||||
case 0x76: return op_read_addri<&SMPcore::op_cmp>(regs.y);
|
||||
case 0x77: return op_read_idpy<&SMPcore::op_cmp>();
|
||||
case 0x78: return op_write_dp_const<&SMPcore::op_cmp>();
|
||||
case 0x79: return op_write_ix_iy<&SMPcore::op_cmp>();
|
||||
case 0x7a: return op_read_dpw<&SMPcore::op_adw>();
|
||||
case 0x7b: return op_adjust_dpx<&SMPcore::op_ror>();
|
||||
case 0x7c: return op_adjust<&SMPcore::op_ror>(regs.a);
|
||||
case 0x7d: return op_transfer(regs.x, regs.a);
|
||||
case 0x7e: return op_read_dp<&SMPcore::op_cmp>(regs.y);
|
||||
case 0x7f: return op_rti();
|
||||
case 0x80: return op_set_flag(regs.p.c, 1);
|
||||
case 0x81: return op_jst();
|
||||
case 0x82: return op_set_bit();
|
||||
case 0x83: return op_branch_bit();
|
||||
case 0x84: return op_read_dp<&SMPcore::op_adc>(regs.a);
|
||||
case 0x85: return op_read_addr<&SMPcore::op_adc>(regs.a);
|
||||
case 0x86: return op_read_ix<&SMPcore::op_adc>();
|
||||
case 0x87: return op_read_idpx<&SMPcore::op_adc>();
|
||||
case 0x88: return op_read_const<&SMPcore::op_adc>(regs.a);
|
||||
case 0x89: return op_write_dp_dp<&SMPcore::op_adc>();
|
||||
case 0x8a: return op_set_addr_bit();
|
||||
case 0x8b: return op_adjust_dp<&SMPcore::op_dec>();
|
||||
case 0x8c: return op_adjust_addr<&SMPcore::op_dec>();
|
||||
case 0x8d: return op_read_const<&SMPcore::op_ld>(regs.y);
|
||||
case 0x8e: return op_plp();
|
||||
case 0x8f: return op_write_dp_const<&SMPcore::op_st>();
|
||||
case 0x90: return op_branch(regs.p.c == 0);
|
||||
case 0x91: return op_jst();
|
||||
case 0x92: return op_set_bit();
|
||||
case 0x93: return op_branch_bit();
|
||||
case 0x94: return op_read_dpi<&SMPcore::op_adc>(regs.a, regs.x);
|
||||
case 0x95: return op_read_addri<&SMPcore::op_adc>(regs.x);
|
||||
case 0x96: return op_read_addri<&SMPcore::op_adc>(regs.y);
|
||||
case 0x97: return op_read_idpy<&SMPcore::op_adc>();
|
||||
case 0x98: return op_write_dp_const<&SMPcore::op_adc>();
|
||||
case 0x99: return op_write_ix_iy<&SMPcore::op_adc>();
|
||||
case 0x9a: return op_read_dpw<&SMPcore::op_sbw>();
|
||||
case 0x9b: return op_adjust_dpx<&SMPcore::op_dec>();
|
||||
case 0x9c: return op_adjust<&SMPcore::op_dec>(regs.a);
|
||||
case 0x9d: return op_transfer(regs.s, regs.x);
|
||||
case 0x9e: return op_div_ya_x();
|
||||
case 0x9f: return op_xcn();
|
||||
case 0xa0: return op_set_flag(regs.p.i, 1);
|
||||
case 0xa1: return op_jst();
|
||||
case 0xa2: return op_set_bit();
|
||||
case 0xa3: return op_branch_bit();
|
||||
case 0xa4: return op_read_dp<&SMPcore::op_sbc>(regs.a);
|
||||
case 0xa5: return op_read_addr<&SMPcore::op_sbc>(regs.a);
|
||||
case 0xa6: return op_read_ix<&SMPcore::op_sbc>();
|
||||
case 0xa7: return op_read_idpx<&SMPcore::op_sbc>();
|
||||
case 0xa8: return op_read_const<&SMPcore::op_sbc>(regs.a);
|
||||
case 0xa9: return op_write_dp_dp<&SMPcore::op_sbc>();
|
||||
case 0xaa: return op_set_addr_bit();
|
||||
case 0xab: return op_adjust_dp<&SMPcore::op_inc>();
|
||||
case 0xac: return op_adjust_addr<&SMPcore::op_inc>();
|
||||
case 0xad: return op_read_const<&SMPcore::op_cmp>(regs.y);
|
||||
case 0xae: return op_pull(regs.a);
|
||||
case 0xaf: return op_sta_ixinc();
|
||||
case 0xb0: return op_branch(regs.p.c == 1);
|
||||
case 0xb1: return op_jst();
|
||||
case 0xb2: return op_set_bit();
|
||||
case 0xb3: return op_branch_bit();
|
||||
case 0xb4: return op_read_dpi<&SMPcore::op_sbc>(regs.a, regs.x);
|
||||
case 0xb5: return op_read_addri<&SMPcore::op_sbc>(regs.x);
|
||||
case 0xb6: return op_read_addri<&SMPcore::op_sbc>(regs.y);
|
||||
case 0xb7: return op_read_idpy<&SMPcore::op_sbc>();
|
||||
case 0xb8: return op_write_dp_const<&SMPcore::op_sbc>();
|
||||
case 0xb9: return op_write_ix_iy<&SMPcore::op_sbc>();
|
||||
case 0xba: return op_read_dpw<&SMPcore::op_ldw>();
|
||||
case 0xbb: return op_adjust_dpx<&SMPcore::op_inc>();
|
||||
case 0xbc: return op_adjust<&SMPcore::op_inc>(regs.a);
|
||||
case 0xbd: return op_transfer(regs.x, regs.s);
|
||||
case 0xbe: return op_das();
|
||||
case 0xbf: return op_lda_ixinc();
|
||||
case 0xc0: return op_set_flag(regs.p.i, 0);
|
||||
case 0xc1: return op_jst();
|
||||
case 0xc2: return op_set_bit();
|
||||
case 0xc3: return op_branch_bit();
|
||||
case 0xc4: return op_write_dp(regs.a);
|
||||
case 0xc5: return op_write_addr(regs.a);
|
||||
case 0xc6: return op_sta_ix();
|
||||
case 0xc7: return op_sta_idpx();
|
||||
case 0xc8: return op_read_const<&SMPcore::op_cmp>(regs.x);
|
||||
case 0xc9: return op_write_addr(regs.x);
|
||||
case 0xca: return op_set_addr_bit();
|
||||
case 0xcb: return op_write_dp(regs.y);
|
||||
case 0xcc: return op_write_addr(regs.y);
|
||||
case 0xcd: return op_read_const<&SMPcore::op_ld>(regs.x);
|
||||
case 0xce: return op_pull(regs.x);
|
||||
case 0xcf: return op_mul_ya();
|
||||
case 0xd0: return op_branch(regs.p.z == 0);
|
||||
case 0xd1: return op_jst();
|
||||
case 0xd2: return op_set_bit();
|
||||
case 0xd3: return op_branch_bit();
|
||||
case 0xd4: return op_write_dpi(regs.a, regs.x);
|
||||
case 0xd5: return op_write_addri(regs.x);
|
||||
case 0xd6: return op_write_addri(regs.y);
|
||||
case 0xd7: return op_sta_idpy();
|
||||
case 0xd8: return op_write_dp(regs.x);
|
||||
case 0xd9: return op_write_dpi(regs.x, regs.y);
|
||||
case 0xda: return op_stw_dp();
|
||||
case 0xdb: return op_write_dpi(regs.y, regs.x);
|
||||
case 0xdc: return op_adjust<&SMPcore::op_dec>(regs.y);
|
||||
case 0xdd: return op_transfer(regs.y, regs.a);
|
||||
case 0xde: return op_bne_dpx();
|
||||
case 0xdf: return op_daa();
|
||||
case 0xe0: return op_clv();
|
||||
case 0xe1: return op_jst();
|
||||
case 0xe2: return op_set_bit();
|
||||
case 0xe3: return op_branch_bit();
|
||||
case 0xe4: return op_read_dp<&SMPcore::op_ld>(regs.a);
|
||||
case 0xe5: return op_read_addr<&SMPcore::op_ld>(regs.a);
|
||||
case 0xe6: return op_read_ix<&SMPcore::op_ld>();
|
||||
case 0xe7: return op_read_idpx<&SMPcore::op_ld>();
|
||||
case 0xe8: return op_read_const<&SMPcore::op_ld>(regs.a);
|
||||
case 0xe9: return op_read_addr<&SMPcore::op_ld>(regs.x);
|
||||
case 0xea: return op_set_addr_bit();
|
||||
case 0xeb: return op_read_dp<&SMPcore::op_ld>(regs.y);
|
||||
case 0xec: return op_read_addr<&SMPcore::op_ld>(regs.y);
|
||||
case 0xed: return op_cmc();
|
||||
case 0xee: return op_pull(regs.y);
|
||||
case 0xef: return op_wait();
|
||||
case 0xf0: return op_branch(regs.p.z == 1);
|
||||
case 0xf1: return op_jst();
|
||||
case 0xf2: return op_set_bit();
|
||||
case 0xf3: return op_branch_bit();
|
||||
case 0xf4: return op_read_dpi<&SMPcore::op_ld>(regs.a, regs.x);
|
||||
case 0xf5: return op_read_addri<&SMPcore::op_ld>(regs.x);
|
||||
case 0xf6: return op_read_addri<&SMPcore::op_ld>(regs.y);
|
||||
case 0xf7: return op_read_idpy<&SMPcore::op_ld>();
|
||||
case 0xf8: return op_read_dp<&SMPcore::op_ld>(regs.x);
|
||||
case 0xf9: return op_read_dpi<&SMPcore::op_ld>(regs.x, regs.y);
|
||||
case 0xfa: return op_write_dp_dp<&SMPcore::op_st>();
|
||||
case 0xfb: return op_read_dpi<&SMPcore::op_ld>(regs.y, regs.x);
|
||||
case 0xfc: return op_adjust<&SMPcore::op_inc>(regs.y);
|
||||
case 0xfd: return op_transfer(regs.a, regs.y);
|
||||
case 0xfe: return op_bne_ydec();
|
||||
case 0xff: return op_wait();
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
#include "algorithms.cpp"
|
||||
#include "opcodes.cpp"
|
||||
#include "disassembler.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
void SMPcore::op_step() {
|
||||
switch(opcode = op_readpc()) {
|
||||
case 0x00: return op_nop();
|
||||
case 0x01: return op_jst();
|
||||
case 0x02: return op_set_bit();
|
||||
case 0x03: return op_branch_bit();
|
||||
case 0x04: return op_read_dp<&SMPcore::op_or>(regs.a);
|
||||
case 0x05: return op_read_addr<&SMPcore::op_or>(regs.a);
|
||||
case 0x06: return op_read_ix<&SMPcore::op_or>();
|
||||
case 0x07: return op_read_idpx<&SMPcore::op_or>();
|
||||
case 0x08: return op_read_const<&SMPcore::op_or>(regs.a);
|
||||
case 0x09: return op_write_dp_dp<&SMPcore::op_or>();
|
||||
case 0x0a: return op_set_addr_bit();
|
||||
case 0x0b: return op_adjust_dp<&SMPcore::op_asl>();
|
||||
case 0x0c: return op_adjust_addr<&SMPcore::op_asl>();
|
||||
case 0x0d: return op_push(regs.p);
|
||||
case 0x0e: return op_test_addr(1);
|
||||
case 0x0f: return op_brk();
|
||||
case 0x10: return op_branch(regs.p.n == 0);
|
||||
case 0x11: return op_jst();
|
||||
case 0x12: return op_set_bit();
|
||||
case 0x13: return op_branch_bit();
|
||||
case 0x14: return op_read_dpi<&SMPcore::op_or>(regs.a, regs.x);
|
||||
case 0x15: return op_read_addri<&SMPcore::op_or>(regs.x);
|
||||
case 0x16: return op_read_addri<&SMPcore::op_or>(regs.y);
|
||||
case 0x17: return op_read_idpy<&SMPcore::op_or>();
|
||||
case 0x18: return op_write_dp_const<&SMPcore::op_or>();
|
||||
case 0x19: return op_write_ix_iy<&SMPcore::op_or>();
|
||||
case 0x1a: return op_adjust_dpw(-1);
|
||||
case 0x1b: return op_adjust_dpx<&SMPcore::op_asl>();
|
||||
case 0x1c: return op_adjust<&SMPcore::op_asl>(regs.a);
|
||||
case 0x1d: return op_adjust<&SMPcore::op_dec>(regs.x);
|
||||
case 0x1e: return op_read_addr<&SMPcore::op_cmp>(regs.x);
|
||||
case 0x1f: return op_jmp_iaddrx();
|
||||
case 0x20: return op_set_flag(regs.p.p, 0);
|
||||
case 0x21: return op_jst();
|
||||
case 0x22: return op_set_bit();
|
||||
case 0x23: return op_branch_bit();
|
||||
case 0x24: return op_read_dp<&SMPcore::op_and>(regs.a);
|
||||
case 0x25: return op_read_addr<&SMPcore::op_and>(regs.a);
|
||||
case 0x26: return op_read_ix<&SMPcore::op_and>();
|
||||
case 0x27: return op_read_idpx<&SMPcore::op_and>();
|
||||
case 0x28: return op_read_const<&SMPcore::op_and>(regs.a);
|
||||
case 0x29: return op_write_dp_dp<&SMPcore::op_and>();
|
||||
case 0x2a: return op_set_addr_bit();
|
||||
case 0x2b: return op_adjust_dp<&SMPcore::op_rol>();
|
||||
case 0x2c: return op_adjust_addr<&SMPcore::op_rol>();
|
||||
case 0x2d: return op_push(regs.a);
|
||||
case 0x2e: return op_bne_dp();
|
||||
case 0x2f: return op_branch(true);
|
||||
case 0x30: return op_branch(regs.p.n == 1);
|
||||
case 0x31: return op_jst();
|
||||
case 0x32: return op_set_bit();
|
||||
case 0x33: return op_branch_bit();
|
||||
case 0x34: return op_read_dpi<&SMPcore::op_and>(regs.a, regs.x);
|
||||
case 0x35: return op_read_addri<&SMPcore::op_and>(regs.x);
|
||||
case 0x36: return op_read_addri<&SMPcore::op_and>(regs.y);
|
||||
case 0x37: return op_read_idpy<&SMPcore::op_and>();
|
||||
case 0x38: return op_write_dp_const<&SMPcore::op_and>();
|
||||
case 0x39: return op_write_ix_iy<&SMPcore::op_and>();
|
||||
case 0x3a: return op_adjust_dpw(+1);
|
||||
case 0x3b: return op_adjust_dpx<&SMPcore::op_rol>();
|
||||
case 0x3c: return op_adjust<&SMPcore::op_rol>(regs.a);
|
||||
case 0x3d: return op_adjust<&SMPcore::op_inc>(regs.x);
|
||||
case 0x3e: return op_read_dp<&SMPcore::op_cmp>(regs.x);
|
||||
case 0x3f: return op_jsr_addr();
|
||||
case 0x40: return op_set_flag(regs.p.p, 1);
|
||||
case 0x41: return op_jst();
|
||||
case 0x42: return op_set_bit();
|
||||
case 0x43: return op_branch_bit();
|
||||
case 0x44: return op_read_dp<&SMPcore::op_eor>(regs.a);
|
||||
case 0x45: return op_read_addr<&SMPcore::op_eor>(regs.a);
|
||||
case 0x46: return op_read_ix<&SMPcore::op_eor>();
|
||||
case 0x47: return op_read_idpx<&SMPcore::op_eor>();
|
||||
case 0x48: return op_read_const<&SMPcore::op_eor>(regs.a);
|
||||
case 0x49: return op_write_dp_dp<&SMPcore::op_eor>();
|
||||
case 0x4a: return op_set_addr_bit();
|
||||
case 0x4b: return op_adjust_dp<&SMPcore::op_lsr>();
|
||||
case 0x4c: return op_adjust_addr<&SMPcore::op_lsr>();
|
||||
case 0x4d: return op_push(regs.x);
|
||||
case 0x4e: return op_test_addr(0);
|
||||
case 0x4f: return op_jsp_dp();
|
||||
case 0x50: return op_branch(regs.p.v == 0);
|
||||
case 0x51: return op_jst();
|
||||
case 0x52: return op_set_bit();
|
||||
case 0x53: return op_branch_bit();
|
||||
case 0x54: return op_read_dpi<&SMPcore::op_eor>(regs.a, regs.x);
|
||||
case 0x55: return op_read_addri<&SMPcore::op_eor>(regs.x);
|
||||
case 0x56: return op_read_addri<&SMPcore::op_eor>(regs.y);
|
||||
case 0x57: return op_read_idpy<&SMPcore::op_eor>();
|
||||
case 0x58: return op_write_dp_const<&SMPcore::op_eor>();
|
||||
case 0x59: return op_write_ix_iy<&SMPcore::op_eor>();
|
||||
case 0x5a: return op_read_dpw<&SMPcore::op_cpw>();
|
||||
case 0x5b: return op_adjust_dpx<&SMPcore::op_lsr>();
|
||||
case 0x5c: return op_adjust<&SMPcore::op_lsr>(regs.a);
|
||||
case 0x5d: return op_transfer(regs.a, regs.x);
|
||||
case 0x5e: return op_read_addr<&SMPcore::op_cmp>(regs.y);
|
||||
case 0x5f: return op_jmp_addr();
|
||||
case 0x60: return op_set_flag(regs.p.c, 0);
|
||||
case 0x61: return op_jst();
|
||||
case 0x62: return op_set_bit();
|
||||
case 0x63: return op_branch_bit();
|
||||
case 0x64: return op_read_dp<&SMPcore::op_cmp>(regs.a);
|
||||
case 0x65: return op_read_addr<&SMPcore::op_cmp>(regs.a);
|
||||
case 0x66: return op_read_ix<&SMPcore::op_cmp>();
|
||||
case 0x67: return op_read_idpx<&SMPcore::op_cmp>();
|
||||
case 0x68: return op_read_const<&SMPcore::op_cmp>(regs.a);
|
||||
case 0x69: return op_write_dp_dp<&SMPcore::op_cmp>();
|
||||
case 0x6a: return op_set_addr_bit();
|
||||
case 0x6b: return op_adjust_dp<&SMPcore::op_ror>();
|
||||
case 0x6c: return op_adjust_addr<&SMPcore::op_ror>();
|
||||
case 0x6d: return op_push(regs.y);
|
||||
case 0x6e: return op_bne_dpdec();
|
||||
case 0x6f: return op_rts();
|
||||
case 0x70: return op_branch(regs.p.v == 1);
|
||||
case 0x71: return op_jst();
|
||||
case 0x72: return op_set_bit();
|
||||
case 0x73: return op_branch_bit();
|
||||
case 0x74: return op_read_dpi<&SMPcore::op_cmp>(regs.a, regs.x);
|
||||
case 0x75: return op_read_addri<&SMPcore::op_cmp>(regs.x);
|
||||
case 0x76: return op_read_addri<&SMPcore::op_cmp>(regs.y);
|
||||
case 0x77: return op_read_idpy<&SMPcore::op_cmp>();
|
||||
case 0x78: return op_write_dp_const<&SMPcore::op_cmp>();
|
||||
case 0x79: return op_write_ix_iy<&SMPcore::op_cmp>();
|
||||
case 0x7a: return op_read_dpw<&SMPcore::op_adw>();
|
||||
case 0x7b: return op_adjust_dpx<&SMPcore::op_ror>();
|
||||
case 0x7c: return op_adjust<&SMPcore::op_ror>(regs.a);
|
||||
case 0x7d: return op_transfer(regs.x, regs.a);
|
||||
case 0x7e: return op_read_dp<&SMPcore::op_cmp>(regs.y);
|
||||
case 0x7f: return op_rti();
|
||||
case 0x80: return op_set_flag(regs.p.c, 1);
|
||||
case 0x81: return op_jst();
|
||||
case 0x82: return op_set_bit();
|
||||
case 0x83: return op_branch_bit();
|
||||
case 0x84: return op_read_dp<&SMPcore::op_adc>(regs.a);
|
||||
case 0x85: return op_read_addr<&SMPcore::op_adc>(regs.a);
|
||||
case 0x86: return op_read_ix<&SMPcore::op_adc>();
|
||||
case 0x87: return op_read_idpx<&SMPcore::op_adc>();
|
||||
case 0x88: return op_read_const<&SMPcore::op_adc>(regs.a);
|
||||
case 0x89: return op_write_dp_dp<&SMPcore::op_adc>();
|
||||
case 0x8a: return op_set_addr_bit();
|
||||
case 0x8b: return op_adjust_dp<&SMPcore::op_dec>();
|
||||
case 0x8c: return op_adjust_addr<&SMPcore::op_dec>();
|
||||
case 0x8d: return op_read_const<&SMPcore::op_ld>(regs.y);
|
||||
case 0x8e: return op_plp();
|
||||
case 0x8f: return op_write_dp_const<&SMPcore::op_st>();
|
||||
case 0x90: return op_branch(regs.p.c == 0);
|
||||
case 0x91: return op_jst();
|
||||
case 0x92: return op_set_bit();
|
||||
case 0x93: return op_branch_bit();
|
||||
case 0x94: return op_read_dpi<&SMPcore::op_adc>(regs.a, regs.x);
|
||||
case 0x95: return op_read_addri<&SMPcore::op_adc>(regs.x);
|
||||
case 0x96: return op_read_addri<&SMPcore::op_adc>(regs.y);
|
||||
case 0x97: return op_read_idpy<&SMPcore::op_adc>();
|
||||
case 0x98: return op_write_dp_const<&SMPcore::op_adc>();
|
||||
case 0x99: return op_write_ix_iy<&SMPcore::op_adc>();
|
||||
case 0x9a: return op_read_dpw<&SMPcore::op_sbw>();
|
||||
case 0x9b: return op_adjust_dpx<&SMPcore::op_dec>();
|
||||
case 0x9c: return op_adjust<&SMPcore::op_dec>(regs.a);
|
||||
case 0x9d: return op_transfer(regs.s, regs.x);
|
||||
case 0x9e: return op_div_ya_x();
|
||||
case 0x9f: return op_xcn();
|
||||
case 0xa0: return op_set_flag(regs.p.i, 1);
|
||||
case 0xa1: return op_jst();
|
||||
case 0xa2: return op_set_bit();
|
||||
case 0xa3: return op_branch_bit();
|
||||
case 0xa4: return op_read_dp<&SMPcore::op_sbc>(regs.a);
|
||||
case 0xa5: return op_read_addr<&SMPcore::op_sbc>(regs.a);
|
||||
case 0xa6: return op_read_ix<&SMPcore::op_sbc>();
|
||||
case 0xa7: return op_read_idpx<&SMPcore::op_sbc>();
|
||||
case 0xa8: return op_read_const<&SMPcore::op_sbc>(regs.a);
|
||||
case 0xa9: return op_write_dp_dp<&SMPcore::op_sbc>();
|
||||
case 0xaa: return op_set_addr_bit();
|
||||
case 0xab: return op_adjust_dp<&SMPcore::op_inc>();
|
||||
case 0xac: return op_adjust_addr<&SMPcore::op_inc>();
|
||||
case 0xad: return op_read_const<&SMPcore::op_cmp>(regs.y);
|
||||
case 0xae: return op_pull(regs.a);
|
||||
case 0xaf: return op_sta_ixinc();
|
||||
case 0xb0: return op_branch(regs.p.c == 1);
|
||||
case 0xb1: return op_jst();
|
||||
case 0xb2: return op_set_bit();
|
||||
case 0xb3: return op_branch_bit();
|
||||
case 0xb4: return op_read_dpi<&SMPcore::op_sbc>(regs.a, regs.x);
|
||||
case 0xb5: return op_read_addri<&SMPcore::op_sbc>(regs.x);
|
||||
case 0xb6: return op_read_addri<&SMPcore::op_sbc>(regs.y);
|
||||
case 0xb7: return op_read_idpy<&SMPcore::op_sbc>();
|
||||
case 0xb8: return op_write_dp_const<&SMPcore::op_sbc>();
|
||||
case 0xb9: return op_write_ix_iy<&SMPcore::op_sbc>();
|
||||
case 0xba: return op_read_dpw<&SMPcore::op_ldw>();
|
||||
case 0xbb: return op_adjust_dpx<&SMPcore::op_inc>();
|
||||
case 0xbc: return op_adjust<&SMPcore::op_inc>(regs.a);
|
||||
case 0xbd: return op_transfer(regs.x, regs.s);
|
||||
case 0xbe: return op_das();
|
||||
case 0xbf: return op_lda_ixinc();
|
||||
case 0xc0: return op_set_flag(regs.p.i, 0);
|
||||
case 0xc1: return op_jst();
|
||||
case 0xc2: return op_set_bit();
|
||||
case 0xc3: return op_branch_bit();
|
||||
case 0xc4: return op_write_dp(regs.a);
|
||||
case 0xc5: return op_write_addr(regs.a);
|
||||
case 0xc6: return op_sta_ix();
|
||||
case 0xc7: return op_sta_idpx();
|
||||
case 0xc8: return op_read_const<&SMPcore::op_cmp>(regs.x);
|
||||
case 0xc9: return op_write_addr(regs.x);
|
||||
case 0xca: return op_set_addr_bit();
|
||||
case 0xcb: return op_write_dp(regs.y);
|
||||
case 0xcc: return op_write_addr(regs.y);
|
||||
case 0xcd: return op_read_const<&SMPcore::op_ld>(regs.x);
|
||||
case 0xce: return op_pull(regs.x);
|
||||
case 0xcf: return op_mul_ya();
|
||||
case 0xd0: return op_branch(regs.p.z == 0);
|
||||
case 0xd1: return op_jst();
|
||||
case 0xd2: return op_set_bit();
|
||||
case 0xd3: return op_branch_bit();
|
||||
case 0xd4: return op_write_dpi(regs.a, regs.x);
|
||||
case 0xd5: return op_write_addri(regs.x);
|
||||
case 0xd6: return op_write_addri(regs.y);
|
||||
case 0xd7: return op_sta_idpy();
|
||||
case 0xd8: return op_write_dp(regs.x);
|
||||
case 0xd9: return op_write_dpi(regs.x, regs.y);
|
||||
case 0xda: return op_stw_dp();
|
||||
case 0xdb: return op_write_dpi(regs.y, regs.x);
|
||||
case 0xdc: return op_adjust<&SMPcore::op_dec>(regs.y);
|
||||
case 0xdd: return op_transfer(regs.y, regs.a);
|
||||
case 0xde: return op_bne_dpx();
|
||||
case 0xdf: return op_daa();
|
||||
case 0xe0: return op_clv();
|
||||
case 0xe1: return op_jst();
|
||||
case 0xe2: return op_set_bit();
|
||||
case 0xe3: return op_branch_bit();
|
||||
case 0xe4: return op_read_dp<&SMPcore::op_ld>(regs.a);
|
||||
case 0xe5: return op_read_addr<&SMPcore::op_ld>(regs.a);
|
||||
case 0xe6: return op_read_ix<&SMPcore::op_ld>();
|
||||
case 0xe7: return op_read_idpx<&SMPcore::op_ld>();
|
||||
case 0xe8: return op_read_const<&SMPcore::op_ld>(regs.a);
|
||||
case 0xe9: return op_read_addr<&SMPcore::op_ld>(regs.x);
|
||||
case 0xea: return op_set_addr_bit();
|
||||
case 0xeb: return op_read_dp<&SMPcore::op_ld>(regs.y);
|
||||
case 0xec: return op_read_addr<&SMPcore::op_ld>(regs.y);
|
||||
case 0xed: return op_cmc();
|
||||
case 0xee: return op_pull(regs.y);
|
||||
case 0xef: return op_wait();
|
||||
case 0xf0: return op_branch(regs.p.z == 1);
|
||||
case 0xf1: return op_jst();
|
||||
case 0xf2: return op_set_bit();
|
||||
case 0xf3: return op_branch_bit();
|
||||
case 0xf4: return op_read_dpi<&SMPcore::op_ld>(regs.a, regs.x);
|
||||
case 0xf5: return op_read_addri<&SMPcore::op_ld>(regs.x);
|
||||
case 0xf6: return op_read_addri<&SMPcore::op_ld>(regs.y);
|
||||
case 0xf7: return op_read_idpy<&SMPcore::op_ld>();
|
||||
case 0xf8: return op_read_dp<&SMPcore::op_ld>(regs.x);
|
||||
case 0xf9: return op_read_dpi<&SMPcore::op_ld>(regs.x, regs.y);
|
||||
case 0xfa: return op_write_dp_dp<&SMPcore::op_st>();
|
||||
case 0xfb: return op_read_dpi<&SMPcore::op_ld>(regs.y, regs.x);
|
||||
case 0xfc: return op_adjust<&SMPcore::op_inc>(regs.y);
|
||||
case 0xfd: return op_transfer(regs.a, regs.y);
|
||||
case 0xfe: return op_bne_ydec();
|
||||
case 0xff: return op_wait();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,98 +1,96 @@
|
|||
struct SMPcore {
|
||||
virtual void op_io() = 0;
|
||||
virtual uint8 op_read(uint16 addr, eCDLog_Flags flags = eCDLog_Flags_CPUData) = 0;
|
||||
virtual void op_write(uint16 addr, uint8 data) = 0;
|
||||
void op_step();
|
||||
|
||||
#include "registers.hpp"
|
||||
#include "memory.hpp"
|
||||
|
||||
regs_t regs;
|
||||
word_t dp, sp, rd, wr, bit, ya;
|
||||
struct SMPcore {
|
||||
virtual void op_io() = 0;
|
||||
virtual uint8 op_read(uint16 addr, eCDLog_Flags flags = eCDLog_Flags_CPUData) = 0;
|
||||
virtual void op_write(uint16 addr, uint8 data) = 0;
|
||||
void op_step();
|
||||
|
||||
#include "registers.hpp"
|
||||
#include "memory.hpp"
|
||||
|
||||
regs_t regs;
|
||||
word_t dp, sp, rd, wr, bit, ya;
|
||||
uint8 opcode;
|
||||
|
||||
int uindex;
|
||||
|
||||
void core_serialize(serializer&);
|
||||
string disassemble_opcode(uint16 addr);
|
||||
|
||||
protected:
|
||||
uint8 op_adc(uint8, uint8);
|
||||
uint8 op_and(uint8, uint8);
|
||||
uint8 op_asl(uint8);
|
||||
uint8 op_cmp(uint8, uint8);
|
||||
uint8 op_dec(uint8);
|
||||
uint8 op_eor(uint8, uint8);
|
||||
uint8 op_inc(uint8);
|
||||
uint8 op_ld (uint8, uint8);
|
||||
uint8 op_lsr(uint8);
|
||||
uint8 op_or (uint8, uint8);
|
||||
uint8 op_rol(uint8);
|
||||
uint8 op_ror(uint8);
|
||||
uint8 op_sbc(uint8, uint8);
|
||||
uint8 op_st (uint8, uint8);
|
||||
uint16 op_adw(uint16, uint16);
|
||||
uint16 op_cpw(uint16, uint16);
|
||||
uint16 op_ldw(uint16, uint16);
|
||||
uint16 op_sbw(uint16, uint16);
|
||||
|
||||
template<uint8 (SMPcore::*op)(uint8)> void op_adjust(uint8&);
|
||||
template<uint8 (SMPcore::*op)(uint8)> void op_adjust_addr();
|
||||
template<uint8 (SMPcore::*op)(uint8)> void op_adjust_dp();
|
||||
void op_adjust_dpw(signed);
|
||||
template<uint8 (SMPcore::*op)(uint8)> void op_adjust_dpx();
|
||||
void op_branch(bool);
|
||||
void op_branch_bit();
|
||||
void op_pull(uint8&);
|
||||
void op_push(uint8);
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_read_addr(uint8&);
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_read_addri(uint8&);
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_read_const(uint8&);
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_read_dp(uint8&);
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_read_dpi(uint8&, uint8&);
|
||||
template<uint16 (SMPcore::*op)(uint16, uint16)> void op_read_dpw();
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_read_idpx();
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_read_idpy();
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_read_ix();
|
||||
void op_set_addr_bit();
|
||||
void op_set_bit();
|
||||
void op_set_flag(bool&, bool);
|
||||
void op_test_addr(bool);
|
||||
void op_transfer(uint8&, uint8&);
|
||||
void op_write_addr(uint8&);
|
||||
void op_write_addri(uint8&);
|
||||
void op_write_dp(uint8&);
|
||||
void op_write_dpi(uint8&, uint8&);
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_write_dp_const();
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_write_dp_dp();
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_write_ix_iy();
|
||||
|
||||
void op_bne_dp();
|
||||
void op_bne_dpdec();
|
||||
void op_bne_dpx();
|
||||
void op_bne_ydec();
|
||||
void op_brk();
|
||||
void op_clv();
|
||||
void op_cmc();
|
||||
void op_daa();
|
||||
void op_das();
|
||||
void op_div_ya_x();
|
||||
void op_jmp_addr();
|
||||
void op_jmp_iaddrx();
|
||||
void op_jsp_dp();
|
||||
void op_jsr_addr();
|
||||
void op_jst();
|
||||
void op_lda_ixinc();
|
||||
void op_mul_ya();
|
||||
void op_nop();
|
||||
void op_plp();
|
||||
void op_rti();
|
||||
void op_rts();
|
||||
void op_sta_idpx();
|
||||
void op_sta_idpy();
|
||||
void op_sta_ix();
|
||||
void op_sta_ixinc();
|
||||
void op_stw_dp();
|
||||
void op_wait();
|
||||
void op_xcn();
|
||||
};
|
||||
void core_serialize(serializer&);
|
||||
string disassemble_opcode(uint16 addr);
|
||||
|
||||
protected:
|
||||
uint8 op_adc(uint8, uint8);
|
||||
uint8 op_and(uint8, uint8);
|
||||
uint8 op_asl(uint8);
|
||||
uint8 op_cmp(uint8, uint8);
|
||||
uint8 op_dec(uint8);
|
||||
uint8 op_eor(uint8, uint8);
|
||||
uint8 op_inc(uint8);
|
||||
uint8 op_ld (uint8, uint8);
|
||||
uint8 op_lsr(uint8);
|
||||
uint8 op_or (uint8, uint8);
|
||||
uint8 op_rol(uint8);
|
||||
uint8 op_ror(uint8);
|
||||
uint8 op_sbc(uint8, uint8);
|
||||
uint8 op_st (uint8, uint8);
|
||||
uint16 op_adw(uint16, uint16);
|
||||
uint16 op_cpw(uint16, uint16);
|
||||
uint16 op_ldw(uint16, uint16);
|
||||
uint16 op_sbw(uint16, uint16);
|
||||
|
||||
template<uint8 (SMPcore::*op)(uint8)> void op_adjust(uint8&);
|
||||
template<uint8 (SMPcore::*op)(uint8)> void op_adjust_addr();
|
||||
template<uint8 (SMPcore::*op)(uint8)> void op_adjust_dp();
|
||||
void op_adjust_dpw(signed);
|
||||
template<uint8 (SMPcore::*op)(uint8)> void op_adjust_dpx();
|
||||
void op_branch(bool);
|
||||
void op_branch_bit();
|
||||
void op_pull(uint8&);
|
||||
void op_push(uint8);
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_read_addr(uint8&);
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_read_addri(uint8&);
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_read_const(uint8&);
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_read_dp(uint8&);
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_read_dpi(uint8&, uint8&);
|
||||
template<uint16 (SMPcore::*op)(uint16, uint16)> void op_read_dpw();
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_read_idpx();
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_read_idpy();
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_read_ix();
|
||||
void op_set_addr_bit();
|
||||
void op_set_bit();
|
||||
void op_set_flag(bool&, bool);
|
||||
void op_test_addr(bool);
|
||||
void op_transfer(uint8&, uint8&);
|
||||
void op_write_addr(uint8&);
|
||||
void op_write_addri(uint8&);
|
||||
void op_write_dp(uint8&);
|
||||
void op_write_dpi(uint8&, uint8&);
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_write_dp_const();
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_write_dp_dp();
|
||||
template<uint8 (SMPcore::*op)(uint8, uint8)> void op_write_ix_iy();
|
||||
|
||||
void op_bne_dp();
|
||||
void op_bne_dpdec();
|
||||
void op_bne_dpx();
|
||||
void op_bne_ydec();
|
||||
void op_brk();
|
||||
void op_clv();
|
||||
void op_cmc();
|
||||
void op_daa();
|
||||
void op_das();
|
||||
void op_div_ya_x();
|
||||
void op_jmp_addr();
|
||||
void op_jmp_iaddrx();
|
||||
void op_jsp_dp();
|
||||
void op_jsr_addr();
|
||||
void op_jst();
|
||||
void op_lda_ixinc();
|
||||
void op_mul_ya();
|
||||
void op_nop();
|
||||
void op_plp();
|
||||
void op_rti();
|
||||
void op_rts();
|
||||
void op_sta_idpx();
|
||||
void op_sta_idpy();
|
||||
void op_sta_ix();
|
||||
void op_sta_ixinc();
|
||||
void op_stw_dp();
|
||||
void op_wait();
|
||||
void op_xcn();
|
||||
};
|
||||
|
|
|
@ -20,10 +20,10 @@ alwaysinline uint8 op_readdp(uint8 addr) {
|
|||
|
||||
alwaysinline void op_writedp(uint8 addr, uint8 data) {
|
||||
return op_write((regs.p.p << 8) + addr, data);
|
||||
}
|
||||
|
||||
alwaysinline void op_next() {
|
||||
opcode = op_readpcfirst();
|
||||
uindex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
alwaysinline void op_next() {
|
||||
opcode = op_readpcfirst();
|
||||
uindex = -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -540,10 +540,6 @@ void SMPcore::op_stw_dp() {
|
|||
|
||||
void SMPcore::op_wait() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
regs.pc--; // repeat this opcode on next run
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
op_io();
|
||||
op_io();
|
||||
}
|
||||
|
|
|
@ -1,29 +1,27 @@
|
|||
#ifdef SMPCORE_CPP
|
||||
|
||||
void SMPcore::core_serialize(serializer &s) {
|
||||
s.integer(regs.pc);
|
||||
s.integer(regs.a);
|
||||
s.integer(regs.x);
|
||||
s.integer(regs.y);
|
||||
s.integer(regs.s);
|
||||
s.integer(regs.p.n);
|
||||
s.integer(regs.p.v);
|
||||
s.integer(regs.p.p);
|
||||
s.integer(regs.p.b);
|
||||
s.integer(regs.p.h);
|
||||
s.integer(regs.p.i);
|
||||
s.integer(regs.p.z);
|
||||
s.integer(regs.p.c);
|
||||
|
||||
s.integer(opcode);
|
||||
s.integer(dp.w);
|
||||
s.integer(sp.w);
|
||||
s.integer(rd.w);
|
||||
s.integer(wr.w);
|
||||
s.integer(bit.w);
|
||||
s.integer(ya.w);
|
||||
#ifdef SMPCORE_CPP
|
||||
|
||||
s.integer(uindex);
|
||||
}
|
||||
|
||||
#endif
|
||||
void SMPcore::core_serialize(serializer &s) {
|
||||
s.integer(regs.pc);
|
||||
s.integer(regs.a);
|
||||
s.integer(regs.x);
|
||||
s.integer(regs.y);
|
||||
s.integer(regs.s);
|
||||
s.integer(regs.p.n);
|
||||
s.integer(regs.p.v);
|
||||
s.integer(regs.p.p);
|
||||
s.integer(regs.p.b);
|
||||
s.integer(regs.p.h);
|
||||
s.integer(regs.p.i);
|
||||
s.integer(regs.p.z);
|
||||
s.integer(regs.p.c);
|
||||
|
||||
s.integer(opcode);
|
||||
s.integer(dp.w);
|
||||
s.integer(sp.w);
|
||||
s.integer(rd.w);
|
||||
s.integer(wr.w);
|
||||
s.integer(bit.w);
|
||||
s.integer(ya.w);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -40,7 +40,7 @@ uint8 SMP::op_busread(uint16 addr) {
|
|||
case 0xf5: //CPUIO1
|
||||
case 0xf6: //CPUIO2
|
||||
case 0xf7: //CPUIO3
|
||||
synchronize_cpu_force();
|
||||
synchronize_cpu();
|
||||
return cpu.port_read(addr);
|
||||
|
||||
case 0xf8: //RAM0
|
||||
|
@ -99,7 +99,7 @@ void SMP::op_buswrite(uint16 addr, uint8 data) {
|
|||
if(data & 0x30) {
|
||||
//one-time clearing of APU port read registers,
|
||||
//emulated by simulating CPU writes of 0x00
|
||||
synchronize_cpu_force();
|
||||
synchronize_cpu();
|
||||
if(data & 0x20) {
|
||||
cpu.port_write(2, 0x00);
|
||||
cpu.port_write(3, 0x00);
|
||||
|
@ -143,7 +143,7 @@ void SMP::op_buswrite(uint16 addr, uint8 data) {
|
|||
case 0xf5: //CPUIO1
|
||||
case 0xf6: //CPUIO2
|
||||
case 0xf7: //CPUIO3
|
||||
synchronize_cpu_force();
|
||||
synchronize_cpu();
|
||||
port_write(addr, data);
|
||||
break;
|
||||
|
||||
|
|
|
@ -16,23 +16,12 @@ void SMP::step(unsigned clocks) {
|
|||
}
|
||||
|
||||
void SMP::synchronize_cpu() {
|
||||
if(CPU::Threaded == true) {
|
||||
if(CPU::Threaded == true) {
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
||||
} else {
|
||||
while(clock >= 0) cpu.enter();
|
||||
}
|
||||
}
|
||||
|
||||
void SMP::synchronize_cpu_force() {
|
||||
if(CPU::Threaded == true) {
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All)
|
||||
co_switch(cpu.thread);
|
||||
else if(clock >= 0 && scheduler.sync == Scheduler::SynchronizeMode::All)
|
||||
interface()->message("SMP had to advance nondeterministically!");
|
||||
} else {
|
||||
while(clock >= 0) cpu.enter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SMP::synchronize_dsp() {
|
||||
if(DSP::Threaded == true) {
|
||||
|
@ -45,17 +34,10 @@ void SMP::synchronize_dsp() {
|
|||
void SMP::Enter() { smp.enter(); }
|
||||
|
||||
void SMP::enter() {
|
||||
while(true) {
|
||||
// see comment in timing.cpp
|
||||
if(clock > +(768 * 24 * (int64)24000000))
|
||||
synchronize_cpu();
|
||||
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::CPU) {
|
||||
synchronize_cpu(); // when in CPU sync mode, always switch back to CPU as soon as possible
|
||||
}
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
debugger.op_exec(regs.pc);
|
||||
if(interface()->wanttrace & TRACE_SMP_MASK)
|
||||
|
@ -81,11 +63,7 @@ void SMP::power() {
|
|||
void SMP::reset() {
|
||||
create(Enter, system.apu_frequency());
|
||||
|
||||
regs.pc = 0xffc0;
|
||||
// exact value doesn't matter much, so long as "fetch" is next
|
||||
opcode = 0; // NOP
|
||||
uindex = 1; // fetch phase
|
||||
|
||||
regs.pc = 0xffc0;
|
||||
regs.a = 0x00;
|
||||
regs.x = 0x00;
|
||||
regs.y = 0x00;
|
||||
|
|
|
@ -1,63 +1,62 @@
|
|||
struct SMP : public Processor, public SMPcore {
|
||||
static const uint8 iplrom[64];
|
||||
uint8* apuram; //[64 * 1024];
|
||||
|
||||
enum : bool { Threaded = true };
|
||||
alwaysinline void step(unsigned clocks);
|
||||
struct SMP : public Processor, public SMPcore {
|
||||
static const uint8 iplrom[64];
|
||||
uint8* apuram; //[64 * 1024];
|
||||
|
||||
enum : bool { Threaded = true };
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_cpu();
|
||||
alwaysinline void synchronize_cpu_force();
|
||||
alwaysinline void synchronize_dsp();
|
||||
|
||||
uint8 port_read(uint2 port) const;
|
||||
void port_write(uint2 port, uint8 data);
|
||||
|
||||
void enter();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
void serialize(serializer&);
|
||||
SMP();
|
||||
~SMP();
|
||||
void initialize();
|
||||
|
||||
privileged:
|
||||
#include "memory/memory.hpp"
|
||||
#include "timing/timing.hpp"
|
||||
|
||||
struct {
|
||||
//timing
|
||||
unsigned clock_counter;
|
||||
unsigned dsp_counter;
|
||||
unsigned timer_step;
|
||||
|
||||
//$00f0
|
||||
uint8 clock_speed;
|
||||
uint8 timer_speed;
|
||||
bool timers_enable;
|
||||
bool ram_disable;
|
||||
bool ram_writable;
|
||||
bool timers_disable;
|
||||
|
||||
//$00f1
|
||||
bool iplrom_enable;
|
||||
|
||||
//$00f2
|
||||
uint8 dsp_addr;
|
||||
|
||||
//$00f8,$00f9
|
||||
uint8 ram00f8;
|
||||
uint8 ram00f9;
|
||||
} status;
|
||||
|
||||
static void Enter();
|
||||
|
||||
friend class SMPcore;
|
||||
|
||||
struct Debugger {
|
||||
hook<void (uint16)> op_exec;
|
||||
hook<void (uint16)> op_read;
|
||||
hook<void (uint16, uint8)> op_write;
|
||||
} debugger;
|
||||
};
|
||||
|
||||
extern SMP smp;
|
||||
alwaysinline void synchronize_dsp();
|
||||
|
||||
uint8 port_read(uint2 port) const;
|
||||
void port_write(uint2 port, uint8 data);
|
||||
|
||||
void enter();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
void serialize(serializer&);
|
||||
SMP();
|
||||
~SMP();
|
||||
void initialize();
|
||||
|
||||
privileged:
|
||||
#include "memory/memory.hpp"
|
||||
#include "timing/timing.hpp"
|
||||
|
||||
struct {
|
||||
//timing
|
||||
unsigned clock_counter;
|
||||
unsigned dsp_counter;
|
||||
unsigned timer_step;
|
||||
|
||||
//$00f0
|
||||
uint8 clock_speed;
|
||||
uint8 timer_speed;
|
||||
bool timers_enable;
|
||||
bool ram_disable;
|
||||
bool ram_writable;
|
||||
bool timers_disable;
|
||||
|
||||
//$00f1
|
||||
bool iplrom_enable;
|
||||
|
||||
//$00f2
|
||||
uint8 dsp_addr;
|
||||
|
||||
//$00f8,$00f9
|
||||
uint8 ram00f8;
|
||||
uint8 ram00f9;
|
||||
} status;
|
||||
|
||||
static void Enter();
|
||||
|
||||
friend class SMPcore;
|
||||
|
||||
struct Debugger {
|
||||
hook<void (uint16)> op_exec;
|
||||
hook<void (uint16)> op_read;
|
||||
hook<void (uint16, uint8)> op_write;
|
||||
} debugger;
|
||||
};
|
||||
|
||||
extern SMP smp;
|
||||
|
|
|
@ -1,72 +1,62 @@
|
|||
#ifdef SMP_CPP
|
||||
|
||||
void SMP::add_clocks(unsigned clocks) {
|
||||
step(clocks);
|
||||
synchronize_dsp();
|
||||
|
||||
#ifdef SMP_CPP
|
||||
|
||||
void SMP::add_clocks(unsigned clocks) {
|
||||
step(clocks);
|
||||
synchronize_dsp();
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
#error -DDEBUGGER SMP runtosave() correctness not checked
|
||||
synchronize_cpu();
|
||||
#else
|
||||
//forcefully sync S-SMP to S-CPU in case chips are not communicating
|
||||
synchronize_cpu();
|
||||
#else
|
||||
//forcefully sync S-SMP to S-CPU in case chips are not communicating
|
||||
//sync if S-SMP is more than 24 samples ahead of S-CPU
|
||||
/*
|
||||
our new smp design guarantees that there is at most one required synchronize_cpu() per uop,
|
||||
inside an op_busread() or op_buswrite(). this extra synchronize can cause problems if we
|
||||
swap out of the SMP at the beginning of a uop with an add_clocks() call when there is an
|
||||
important op_busread() / op_buswrite() later on. the SMP will need to finish that uop in
|
||||
order to reach a savable state, but it might never get to do so until it's too late (ie,
|
||||
scheduler.sync == Scheduler.SynchronizeMode::All). so we remove this call and instead
|
||||
do catchup sync in the main Enter() loop.
|
||||
*/
|
||||
//if(clock > +(768 * 24 * (int64)24000000)) synchronize_cpu();
|
||||
#endif
|
||||
}
|
||||
|
||||
void SMP::cycle_edge() {
|
||||
timer0.tick();
|
||||
timer1.tick();
|
||||
timer2.tick();
|
||||
|
||||
//TEST register S-SMP speed control
|
||||
//24 clocks have already been added for this cycle at this point
|
||||
switch(status.clock_speed) {
|
||||
case 0: break; //100% speed
|
||||
case 1: add_clocks(24); break; // 50% speed
|
||||
case 2: while(true) add_clocks(24); // 0% speed -- locks S-SMP
|
||||
case 3: add_clocks(24 * 9); break; // 10% speed
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned timer_frequency>
|
||||
void SMP::Timer<timer_frequency>::tick() {
|
||||
//stage 0 increment
|
||||
stage0_ticks += smp.status.timer_step;
|
||||
if(stage0_ticks < timer_frequency) return;
|
||||
stage0_ticks -= timer_frequency;
|
||||
|
||||
//stage 1 increment
|
||||
stage1_ticks ^= 1;
|
||||
synchronize_stage1();
|
||||
}
|
||||
|
||||
template<unsigned timer_frequency>
|
||||
void SMP::Timer<timer_frequency>::synchronize_stage1() {
|
||||
bool new_line = stage1_ticks;
|
||||
if(smp.status.timers_enable == false) new_line = false;
|
||||
if(smp.status.timers_disable == true) new_line = false;
|
||||
|
||||
bool old_line = current_line;
|
||||
current_line = new_line;
|
||||
if(old_line != 1 || new_line != 0) return; //only pulse on 1->0 transition
|
||||
|
||||
//stage 2 increment
|
||||
if(enable == false) return;
|
||||
if(++stage2_ticks != target) return;
|
||||
|
||||
//stage 3 increment
|
||||
stage2_ticks = 0;
|
||||
stage3_ticks++;
|
||||
}
|
||||
|
||||
#endif
|
||||
if(clock > +(768 * 24 * (int64)24000000)) synchronize_cpu();
|
||||
#endif
|
||||
}
|
||||
|
||||
void SMP::cycle_edge() {
|
||||
timer0.tick();
|
||||
timer1.tick();
|
||||
timer2.tick();
|
||||
|
||||
//TEST register S-SMP speed control
|
||||
//24 clocks have already been added for this cycle at this point
|
||||
switch(status.clock_speed) {
|
||||
case 0: break; //100% speed
|
||||
case 1: add_clocks(24); break; // 50% speed
|
||||
case 2: while(true) add_clocks(24); // 0% speed -- locks S-SMP
|
||||
case 3: add_clocks(24 * 9); break; // 10% speed
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned timer_frequency>
|
||||
void SMP::Timer<timer_frequency>::tick() {
|
||||
//stage 0 increment
|
||||
stage0_ticks += smp.status.timer_step;
|
||||
if(stage0_ticks < timer_frequency) return;
|
||||
stage0_ticks -= timer_frequency;
|
||||
|
||||
//stage 1 increment
|
||||
stage1_ticks ^= 1;
|
||||
synchronize_stage1();
|
||||
}
|
||||
|
||||
template<unsigned timer_frequency>
|
||||
void SMP::Timer<timer_frequency>::synchronize_stage1() {
|
||||
bool new_line = stage1_ticks;
|
||||
if(smp.status.timers_enable == false) new_line = false;
|
||||
if(smp.status.timers_disable == true) new_line = false;
|
||||
|
||||
bool old_line = current_line;
|
||||
current_line = new_line;
|
||||
if(old_line != 1 || new_line != 0) return; //only pulse on 1->0 transition
|
||||
|
||||
//stage 2 increment
|
||||
if(enable == false) return;
|
||||
if(++stage2_ticks != target) return;
|
||||
|
||||
//stage 3 increment
|
||||
stage2_ticks = 0;
|
||||
stage3_ticks++;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue