diff --git a/bsnes/Makefile b/bsnes/Makefile new file mode 100644 index 00000000..c037c5e1 --- /dev/null +++ b/bsnes/Makefile @@ -0,0 +1,34 @@ +CC = cl +CFLAGS = /nologo /O2 +OBJS = main.obj timing.obj g65816.obj d65816.obj memory.obj mmio.obj gui.obj libstr.obj +LIBS = kernel32.lib user32.lib gdi32.lib comdlg32.lib ddraw.lib + +all: $(OBJS) + $(CC) /Febsnes.exe $(CFLAGS) $(OBJS) $(LIBS) + +clean: + del *.obj + +main.obj: main.cpp main.h + $(CC) $(CFLAGS) /c main.cpp + +timing.obj: timing/timing.cpp timing/timing.h + $(CC) $(CFLAGS) /c timing/timing.cpp + +g65816.obj: cpu/g65816*.cpp cpu/g65816.h + $(CC) $(CFLAGS) /c cpu/g65816.cpp + +d65816.obj: cpu/d65816.cpp + $(CC) $(CFLAGS) /c cpu/d65816.cpp + +memory.obj: mem/memory.cpp + $(CC) $(CFLAGS) /c mem/memory.cpp + +mmio.obj: ppu/mmio.cpp ppu/ppu*.cpp + $(CC) $(CFLAGS) /c ppu/mmio.cpp + +gui.obj: win/gui*.cpp win/render*.cpp + $(CC) $(CFLAGS) /c win/gui.cpp + +libstr.obj: misc/libstr.cpp + $(CC) $(CFLAGS) /c misc/libstr.cpp diff --git a/bsnes/base.h b/bsnes/base.h new file mode 100644 index 00000000..32dbfd6a --- /dev/null +++ b/bsnes/base.h @@ -0,0 +1,332 @@ +//#define PUBLIC_DOMAIN + +#include +#include +#include +#include + +#define null 0xffffffff +typedef unsigned char byte; +typedef unsigned short word; +typedef unsigned long ulong; +typedef void (*vfunc)(void); + +#define SH_2 1 +#define SH_4 2 +#define SH_8 3 +#define SH_16 4 +#define SH_32 5 +#define SH_64 6 +#define SH_128 7 +#define SH_256 8 + +/************************* + *** general functions *** + ************************/ + +void alert(char *s, ...); + +/************************ + *** joypad functions *** + ***********************/ + +void UpdateJoypad(void); + +typedef struct { + byte a, b, x, y; + byte l, r; + byte select, start; + byte up, down, left, right; + + byte read_pos; +}joypad_state; + +/****************** + *** deprecated *** + *****************/ + +typedef struct { + char rom_name[4096], sram_name[4096]; + ulong sram_save_tick_count; +}emustate; + +/*********************** + *** video functions *** + **********************/ + +void video_setmode(bool fullscreen, word width, word height); +void video_setsnesmode(void); + +//global export: render +typedef struct { + word width, height; + word snes_width, snes_height; + bool fullscreen; + bool show_menu; + + byte frame_skip; + byte frame_count; + + bool bg1_enabled[3], bg2_enabled[3], bg3_enabled[3], bg4_enabled[3], oam_enabled[5]; +}videostate; + +/*************************** + *** debugging functions *** + **************************/ + +#define DEBUGMODE_NOROM 0 +#define DEBUGMODE_DISABLED 1 +#define DEBUGMODE_WAIT 2 +#define DEBUGMODE_RUN 3 +#define DEBUGMODE_STEP 4 +#define DEBUGMODE_PROCEED 5 + +#define DEBUG_BGENABLED_ALL 0 +#define DEBUG_BGENABLED_PRI0 1 +#define DEBUG_BGENABLED_PRI1 2 +#define DEBUG_BGENABLED_PRI2 3 +#define DEBUG_BGENABLED_PRI3 4 + +void debug_set_state(byte state); +#define debug_get_state() debugger.mode +void dprintf(char *s, ...); +void debug_refresh_mem(void); +void debug_refresh_bp(void); +void debug_update_cycles(void); + +typedef struct { + byte mode; + + bool trace_enabled; + ulong mem_ptr; //position of wram ptr for debug window + bool disas_op; + bool refresh_mem; + bool refresh_bp; + + FILE *trace_fp; +}debugstate; + +/********************* + *** ppu functions *** + ********************/ + +#define BG1 0x00 +#define BG2 0x01 +#define BG3 0x02 +#define BG4 0x03 +#define OAM 0x04 +#define SS_BG1 0x80 +#define SS_BG2 0x81 +#define SS_BG3 0x82 +#define SS_BG4 0x83 +#define SS_OAM 0x84 +#define BACK 0x05 + +#define CLIPMODE_IN 0 +#define CLIPMODE_OUT 1 + +#define WINDOWMASK_OR 0 +#define WINDOWMASK_AND 1 +#define WINDOWMASK_XOR 2 +#define WINDOWMASK_XNOR 3 + +#define COLORMODE_ADD 0 +#define COLORMODE_SUB 1 + +typedef struct { + word *screen; //internal buffer used to render 512x448 screen + byte *vram; //65536 bytes + byte *cgram; //512 bytes + byte *oam; //544 bytes mirrored as 1024 bytes (512-543 are mirrored to 544-1023) + word *light_table; //16 * 32768 -- applies display_brightness to bgr555 color data +//ppu.mosaic_table[ppu.mosaic_size][x] == (x / (ppu.mosaic_size + 1)) * (ppu.mosaic_size + 1) + word *mosaic_table[16]; + + ulong ppu_cycles, ppu_prev_cycles; //used in ppu_update_scanline() + + bool display_disable; //$2100 bit 7 + byte display_brightness; //$2100 bits 0-3 + + byte visible_scanlines; //$2133 bit 2 (NTSC/PAL mode) -- value = 224 or 240 + byte toggle_visible_scanlines; //do not allow change midframe + + bool interlace; + byte interlace_frame; //0 or 1, used to alternate between scanlines rendered + + bool bg_enabled[5]; + bool ss_bg_enabled[5]; + byte mosaic_size; + bool mosaic_enabled[4]; + word bg_tilemap_loc[4]; + byte bg_tile_size[4]; + byte bg_tilemap_size[4]; + word bg_tiledata_loc[4]; + word oam_tiledata_loc; + byte bg_priority_mode; + byte oam_base_size; + byte oam_name_sel; + byte bg_mode; + + word hline_pos; //0-255: inside vblank, 256-339: outside vblank + word vline_pos; //0-223: inside vblank, 224-261: outside vblank, 180 cycles/scanline + bool irq_triggered; //for $4211 read + bool virq_triggered; //prevent recursive calling + bool hirq_triggered; //prevent recursive calling + word vram_write_pos; //holds value at $2116 + word vram_inc_size; //amount to increment vram_write_pos by + byte vram_inc_reg; //increment on 2118 (0) or 2119 (1) + word cgram_write_pos; //holds value at $2121 (multiplied by 2) + word oam_write_pos; //holds value at $2102/$2103 (multiplied by 2) + ulong wram_write_pos; //holds value at $2181-$2183 + + word bg_hscroll_pos[4]; //$210d-$2114 + word bg_vscroll_pos[4]; + word m7hofs, m7vofs; + + byte mul_a, mul_b; + word div_a; + byte div_b; + word r_4214, r_4216; + + word smul_a; + byte smul_b; + ulong smul_r; + + bool bg_window1_enabled[5]; + bool bg_window2_enabled[5]; + byte bg_window1_clipmode[5]; + byte bg_window2_clipmode[5]; + + byte window1_left, window1_right; + byte window2_left, window2_right; + + bool bg_windowing_enabled[5]; + bool ss_bg_windowing_enabled[5]; + byte bg_window_mask[5]; + + bool color_window1_enabled, color_window2_enabled; + bool color_window1_clipmode, color_window2_clipmode; + byte color_window_mask; + byte color_mask, ss_color_mask; + byte addsub_mode; + byte color_mode, color_halve; + bool bg_color_enabled[6]; + byte color_r, color_g, color_b; + + byte toggle_active_hdma_channels; + byte active_hdma_channels; + word hdma_scanlines_remaining[8]; + word hdma_index_pointer[8]; + bool hdma_completed[8]; + + bool vcounter_enabled, hcounter_enabled; + word hirq_pos, virq_pos; + + bool auto_joypad_read; + byte joypad_strobe_value; + + byte latch_toggle; + word latch_vpos, latch_hpos; + + word m7a, m7b, m7c, m7d, m7x, m7y; + + bool mode7_vflip, mode7_hflip; +}ppustate; + +/********************* + *** cpu functions *** + ********************/ + +#define MEMSPEED_SLOWROM 0 +#define MEMSPEED_FASTROM 1 + +#define PF_N 0x80 +#define PF_V 0x40 +#define PF_M 0x20 +#define PF_X 0x10 +#define PF_D 0x08 +#define PF_I 0x04 +#define PF_Z 0x02 +#define PF_C 0x01 + +#define BP_OFF 0 +#define BP_READ 1 +#define BP_WRITE 2 +#define BP_EXEC 4 +#define BP_VAL 8 + +/************************ + *** memory functions *** + ***********************/ + +#define MEMMAP_HIROM 0x01 +#define MEMMAP_LOROM 0x02 + +#define MEMACCESS_NORMAL 0 +#define MEMACCESS_CPU 1 +#define MEMACCESS_DEBUGGER 1 + +enum { + MEMMODE_NONE = 0, //(no address translation) + MEMMODE_DP, //dp + MEMMODE_DPX, //dp,x + MEMMODE_DPY, //dp,y + MEMMODE_IDP, //(dp) + MEMMODE_IDPX, //(dp,x) + MEMMODE_IDPY, //(dp),y + MEMMODE_ILDP, //[dp] + MEMMODE_ILDPY, //[dp],y + MEMMODE_ADDR, //addr + MEMMODE_ADDRX, //addr,x + MEMMODE_ADDRY, //addr,y + MEMMODE_IADDRX, //(addr,x) + MEMMODE_ILADDR, //[addr] + MEMMODE_LONG, //long + MEMMODE_LONGX, //long, x + MEMMODE_SR, //sr,s + MEMMODE_ISRY, //(sr,s),y +//exchanges pbr for dbr, disables address mirroring + MEMMODE_ADDR_PC, //addr + MEMMODE_IADDR_PC, //(addr) + MEMMODE_IADDRX_PC, //(addr,x) + MEMMODE_ILADDR_PC //[addr] +}; + +#define MEMSIZE_BYTE 1 +#define MEMSIZE_WORD 2 +#define MEMSIZE_LONG 3 + +/*********************** + *** misc. functions *** + **********************/ + +//main.cpp +void InitSNES(void); +extern vfunc RunSNES; +void RunSNES_NoDebug(void); +void RunSNES_Debug(void); + +//cpu/g65816_ops_stack.cpp +ulong g65816_stackread(byte size); +void g65816_stackwrite(byte size, ulong value); + +//cpu/d65816.cpp +void disas_g65816_op(void); + +//ppu/mmio.cpp +byte mmio_read(word addr); +void mmio_write(word addr, byte value); + +//ppu/ppu.cpp +void ppu_render_scanline(void); +void ppu_update_scanline(void); +byte oam_read(word addr); +void oam_write(word addr, byte value); +void PPUInit(byte first_time); + +//win/render.cpp +void UpdateDisplay(void); + +//misc/libstr.cpp +ulong strhex(char *str); +ulong strdec(char *str); diff --git a/bsnes/bsnes.exe b/bsnes/bsnes.exe new file mode 100644 index 00000000..551d2a4a Binary files /dev/null and b/bsnes/bsnes.exe differ diff --git a/bsnes/cc.bat b/bsnes/cc.bat new file mode 100644 index 00000000..5a1afd6a --- /dev/null +++ b/bsnes/cc.bat @@ -0,0 +1,2 @@ +@nmake /NOLOGO +@pause \ No newline at end of file diff --git a/bsnes/clean.bat b/bsnes/clean.bat new file mode 100644 index 00000000..02d7e1df --- /dev/null +++ b/bsnes/clean.bat @@ -0,0 +1 @@ +@nmake /NOLOGO clean \ No newline at end of file diff --git a/bsnes/cpu/d65816.cpp b/bsnes/cpu/d65816.cpp new file mode 100644 index 00000000..35f12cf2 --- /dev/null +++ b/bsnes/cpu/d65816.cpp @@ -0,0 +1,337 @@ +#include "../base.h" +#include "g65816.h" +extern g65816 *gx816; + +ulong _disas_relb(byte addr) { + return gx816->regs.pc + (signed char)(addr + 2); +} + +ulong _disas_relw(word addr) { + return gx816->regs.pc + (signed short)(addr + 3); +} + +char __disas_op_str[256]; +void __disas_op(byte op, byte op0, byte op1, byte op2) { +char *s = (char*)__disas_op_str; + switch(op) { + case 0x00:sprintf(s, "brk #$%0.2x ", op0);break; + case 0x01:sprintf(s, "ora ($%0.2x,x) [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDPX, op0));break; + case 0x02:sprintf(s, "cop #$%0.2x ", op0);break; + case 0x03:sprintf(s, "ora $%0.2x,s [$%0.6x]", op0, gx816->convert_offset(MEMMODE_SR, op0));break; + case 0x04:sprintf(s, "tsb $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0x05:sprintf(s, "ora $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0x06:sprintf(s, "asl $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0x07:sprintf(s, "ora [$%0.2x] [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ILDP, op0));break; + case 0x08:sprintf(s, "php ");break; + case 0x09: + if(gx816->regs.e == true || (gx816->regs.e == false && (gx816->regs.p & 0x20)))sprintf(s, "ora #$%0.2x ", op0); + else sprintf(s, "ora #$%0.4x ", op0|op1<<8);break; + case 0x0a:sprintf(s, "asl a ");break; + case 0x0b:sprintf(s, "phd ");break; + case 0x0c:sprintf(s, "tsb $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0x0d:sprintf(s, "ora $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0x0e:sprintf(s, "asl $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0x0f:sprintf(s, "ora $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, gx816->convert_offset(MEMMODE_LONG, (op0|op1<<8|op2<<16)));break; + case 0x10:sprintf(s, "bpl $%0.4x [$%0.6x]", _disas_relb(op0)&0xffff, _disas_relb(op0)&0xffffff);break; + case 0x11:sprintf(s, "ora ($%0.2x),y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDPY, op0));break; + case 0x12:sprintf(s, "ora ($%0.2x) [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDP, op0));break; + case 0x13:sprintf(s, "ora ($%0.2x,s),y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ISRY, op0));break; + case 0x14:sprintf(s, "trb $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0x15:sprintf(s, "ora $%0.2x,x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPX, op0));break; + case 0x16:sprintf(s, "asl $%0.2x,x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPX, op0));break; + case 0x17:sprintf(s, "ora [$%0.2x],y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ILDPY, op0));break; + case 0x18:sprintf(s, "clc ");break; + case 0x19:sprintf(s, "ora $%0.4x,y [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRY, (op0|op1<<8)));break; + case 0x1a:sprintf(s, "inc ");break; + case 0x1b:sprintf(s, "tcs ");break; + case 0x1c:sprintf(s, "trb $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0x1d:sprintf(s, "ora $%0.4x,x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRX, (op0|op1<<8)));break; + case 0x1e:sprintf(s, "asl $%0.4x,x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRX, (op0|op1<<8)));break; + case 0x1f:sprintf(s, "ora $%0.6x,x [$%0.6x]", op0|op1<<8|op2<<16, gx816->convert_offset(MEMMODE_LONGX, (op0|op1<<8|op2<<16)));break; + case 0x20:sprintf(s, "jsr $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR_PC, (op0|op1<<8)));break; + case 0x21:sprintf(s, "and ($%0.2x,x) [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDPX, op0));break; + case 0x22:sprintf(s, "jsl $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, gx816->convert_offset(MEMMODE_LONG, (op0|op1<<8|op2<<16)));break; + case 0x23:sprintf(s, "and $%0.2x,s [$%0.6x]", op0, gx816->convert_offset(MEMMODE_SR, op0));break; + case 0x24:sprintf(s, "bit $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0x25:sprintf(s, "and $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0x26:sprintf(s, "rol $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0x27:sprintf(s, "and [$%0.2x] [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ILDP, op0));break; + case 0x28:sprintf(s, "plp ");break; + case 0x29: + if(gx816->regs.e == true || (gx816->regs.e == false && (gx816->regs.p & 0x20)))sprintf(s, "and #$%0.2x ", op0); + else sprintf(s, "and #$%0.4x ", op0|op1<<8);break; + case 0x2a:sprintf(s, "rol a ");break; + case 0x2b:sprintf(s, "pld ");break; + case 0x2c:sprintf(s, "bit $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0x2d:sprintf(s, "and $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0x2e:sprintf(s, "rol $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0x2f:sprintf(s, "and $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, gx816->convert_offset(MEMMODE_LONG, (op0|op1<<8|op2<<16)));break; + case 0x30:sprintf(s, "bmi $%0.4x [$%0.6x]", _disas_relb(op0)&0xffff, _disas_relb(op0)&0xffffff);break; + case 0x31:sprintf(s, "and ($%0.2x),y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDPY, op0));break; + case 0x32:sprintf(s, "and ($%0.2x) [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDP, op0));break; + case 0x33:sprintf(s, "and ($%0.2x,s),y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ISRY, op0));break; + case 0x34:sprintf(s, "bit $%0.2x,x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPX, op0));break; + case 0x35:sprintf(s, "and $%0.2x,x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPX, op0));break; + case 0x36:sprintf(s, "rol $%0.2x,x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPX, op0));break; + case 0x37:sprintf(s, "and [$%0.2x],y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ILDPY, op0));break; + case 0x38:sprintf(s, "sec ");break; + case 0x39:sprintf(s, "and $%0.4x,y [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRY, (op0|op1<<8)));break; + case 0x3a:sprintf(s, "dec ");break; + case 0x3b:sprintf(s, "tsc ");break; + case 0x3c:sprintf(s, "bit $%0.4x,x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRX, (op0|op1<<8)));break; + case 0x3d:sprintf(s, "and $%0.4x,x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRX, (op0|op1<<8)));break; + case 0x3e:sprintf(s, "rol $%0.4x,x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRX, (op0|op1<<8)));break; + case 0x3f:sprintf(s, "and $%0.6x,x [$%0.6x]", op0|op1<<8|op2<<16, gx816->convert_offset(MEMMODE_LONGX, (op0|op1<<8|op2<<16)));break; + case 0x40:sprintf(s, "rti ");break; + case 0x41:sprintf(s, "eor ($%0.2x,x) [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDPX, op0));break; + case 0x42:sprintf(s, "wdm ");break; + case 0x43:sprintf(s, "eor $%0.2x,s [$%0.6x]", op0, gx816->convert_offset(MEMMODE_SR, op0));break; + case 0x44:sprintf(s, "mvp $%0.2x,$%0.2x ", op1, op0);break; + case 0x45:sprintf(s, "eor $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0x46:sprintf(s, "lsr $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0x47:sprintf(s, "eor [$%0.2x] [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ILDP, op0));break; + case 0x48:sprintf(s, "pha ");break; + case 0x49: + if(gx816->regs.e == true || (gx816->regs.e == false && (gx816->regs.p & 0x20)))sprintf(s, "eor #$%0.2x ", op0); + else sprintf(s, "eor #$%0.4x ", op0|op1<<8);break; + case 0x4a:sprintf(s, "lsr a ");break; + case 0x4b:sprintf(s, "phk ");break; + case 0x4c:sprintf(s, "jmp $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR_PC, (op0|op1<<8)));break; + case 0x4d:sprintf(s, "eor $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0x4e:sprintf(s, "lsr $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0x4f:sprintf(s, "eor $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, gx816->convert_offset(MEMMODE_LONG, (op0|op1<<8|op2<<16)));break; + case 0x50:sprintf(s, "bvc $%0.4x [$%0.6x]", _disas_relb(op0)&0xffff, _disas_relb(op0)&0xffffff);break; + case 0x51:sprintf(s, "eor ($%0.2x),y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDPY, op0));break; + case 0x52:sprintf(s, "eor ($%0.2x) [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDP, op0));break; + case 0x53:sprintf(s, "eor ($%0.2x,s),y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ISRY, op0));break; + case 0x54:sprintf(s, "mvn $%0.2x,$%0.2x ", op1, op0);break; + case 0x55:sprintf(s, "eor $%0.2x,x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPX, op0));break; + case 0x56:sprintf(s, "lsr $%0.2x,x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPX, op0));break; + case 0x57:sprintf(s, "eor [$%0.2x],y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ILDPY, op0));break; + case 0x58:sprintf(s, "cli ");break; + case 0x59:sprintf(s, "eor $%0.4x,y [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRY, (op0|op1<<8)));break; + case 0x5a:sprintf(s, "phy ");break; + case 0x5b:sprintf(s, "tcd ");break; + case 0x5c:sprintf(s, "jml $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, gx816->convert_offset(MEMMODE_LONG, (op0|op1<<8|op2<<16)));break; + case 0x5d:sprintf(s, "eor $%0.4x,x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRX, (op0|op1<<8)));break; + case 0x5e:sprintf(s, "lsr $%0.4x,x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRX, (op0|op1<<8)));break; + case 0x5f:sprintf(s, "eor $%0.6x,x [$%0.6x]", op0|op1<<8|op2<<16, gx816->convert_offset(MEMMODE_LONGX, (op0|op1<<8|op2<<16)));break; + case 0x60:sprintf(s, "rts ");break; + case 0x61:sprintf(s, "adc ($%0.2x,x) [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDPX, op0));break; + case 0x62:sprintf(s, "per $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0x63:sprintf(s, "adc $%0.2x,s [$%0.6x]", op0, gx816->convert_offset(MEMMODE_SR, op0));break; + case 0x64:sprintf(s, "stz $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0x65:sprintf(s, "adc $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0x66:sprintf(s, "ror $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0x67:sprintf(s, "adc [$%0.2x] [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ILDP, op0));break; + case 0x68:sprintf(s, "pla ");break; + case 0x69: + if(gx816->regs.e == true || (gx816->regs.e == false && (gx816->regs.p & 0x20)))sprintf(s, "adc #$%0.2x ", op0); + else sprintf(s, "adc #$%0.4x ", op0|op1<<8);break; + case 0x6a:sprintf(s, "ror a ");break; + case 0x6b:sprintf(s, "rtl ");break; + case 0x6c:sprintf(s, "jmp ($%0.4x) [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_IADDR_PC, (op0|op1<<8)));break; + case 0x6d:sprintf(s, "adc $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0x6e:sprintf(s, "ror $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0x6f:sprintf(s, "adc $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, gx816->convert_offset(MEMMODE_LONG, (op0|op1<<8|op2<<16)));break; + case 0x70:sprintf(s, "bvs $%0.4x [$%0.6x]", _disas_relb(op0)&0xffff, _disas_relb(op0)&0xffffff);break; + case 0x71:sprintf(s, "adc ($%0.2x),y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDPY, op0));break; + case 0x72:sprintf(s, "adc ($%0.2x) [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDP, op0));break; + case 0x73:sprintf(s, "adc ($%0.2x,s),y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ISRY, op0));break; + case 0x74:sprintf(s, "stz $%0.2x,x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPX, op0));break; + case 0x75:sprintf(s, "adc $%0.2x,x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPX, op0));break; + case 0x76:sprintf(s, "ror $%0.2x,x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPX, op0));break; + case 0x77:sprintf(s, "adc [$%0.2x],y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ILDPY, op0));break; + case 0x78:sprintf(s, "sei ");break; + case 0x79:sprintf(s, "adc $%0.4x,y [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRY, (op0|op1<<8)));break; + case 0x7a:sprintf(s, "ply ");break; + case 0x7b:sprintf(s, "tdc ");break; + case 0x7c:sprintf(s, "jmp ($%0.4x,x) [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_IADDRX_PC, (op0|op1<<8)));break; + case 0x7d:sprintf(s, "adc $%0.4x,x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRX, (op0|op1<<8)));break; + case 0x7e:sprintf(s, "ror $%0.4x,x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRX, (op0|op1<<8)));break; + case 0x7f:sprintf(s, "adc $%0.6x,x [$%0.6x]", op0|op1<<8|op2<<16, gx816->convert_offset(MEMMODE_LONGX, (op0|op1<<8|op2<<16)));break; + case 0x80:sprintf(s, "bra $%0.4x [$%0.6x]", _disas_relb(op0)&0xffff, _disas_relb(op0)&0xffffff);break; + case 0x81:sprintf(s, "sta ($%0.2x,x) [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDPX, op0));break; + case 0x82:sprintf(s, "brl $%0.4x [$%0.6x]", _disas_relw(op0|op1<<8)&0xffff, _disas_relw(op0|op1<<8)&0xffffff);break; + case 0x83:sprintf(s, "sta $%0.2x,s [$%0.6x]", op0, gx816->convert_offset(MEMMODE_SR, op0));break; + case 0x84:sprintf(s, "sty $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0x85:sprintf(s, "sta $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0x86:sprintf(s, "stx $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0x87:sprintf(s, "sta [$%0.2x] [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ILDP, op0));break; + case 0x88:sprintf(s, "dey ");break; + case 0x89: + if(gx816->regs.e == true || (gx816->regs.e == false && (gx816->regs.p & 0x20)))sprintf(s, "bit #$%0.2x ", op0); + else sprintf(s, "bit #$%0.4x ", op0|op1<<8);break; + case 0x8a:sprintf(s, "txa ");break; + case 0x8b:sprintf(s, "phb ");break; + case 0x8c:sprintf(s, "sty $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0x8d:sprintf(s, "sta $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0x8e:sprintf(s, "stx $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0x8f:sprintf(s, "sta $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, gx816->convert_offset(MEMMODE_LONG, (op0|op1<<8|op2<<16)));break; + case 0x90:sprintf(s, "bcc $%0.4x [$%0.6x]", _disas_relb(op0)&0xffff, _disas_relb(op0)&0xffffff);break; + case 0x91:sprintf(s, "sta ($%0.2x),y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDPY, op0));break; + case 0x92:sprintf(s, "sta ($%0.2x) [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDP, op0));break; + case 0x93:sprintf(s, "sta ($%0.2x,s),y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ISRY, op0));break; + case 0x94:sprintf(s, "sty $%0.2x,x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPX, op0));break; + case 0x95:sprintf(s, "sta $%0.2x,x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPX, op0));break; + case 0x96:sprintf(s, "stx $%0.2x,y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPY, op0));break; + case 0x97:sprintf(s, "sta [$%0.2x],y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ILDPY, op0));break; + case 0x98:sprintf(s, "tya ");break; + case 0x99:sprintf(s, "sta $%0.4x,y [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRY, (op0|op1<<8)));break; + case 0x9a:sprintf(s, "txs ");break; + case 0x9b:sprintf(s, "txy ");break; + case 0x9c:sprintf(s, "stz $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0x9d:sprintf(s, "sta $%0.4x,x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRX, (op0|op1<<8)));break; + case 0x9e:sprintf(s, "stz $%0.4x,x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRX, (op0|op1<<8)));break; + case 0x9f:sprintf(s, "sta $%0.6x,x [$%0.6x]", op0|op1<<8|op2<<16, gx816->convert_offset(MEMMODE_LONGX, (op0|op1<<8|op2<<16)));break; + case 0xa0: + if(gx816->regs.e == true || (gx816->regs.e == false && (gx816->regs.p & PF_X)))sprintf(s, "ldy #$%0.2x ", op0); + else sprintf(s, "ldy #$%0.4x ", op0|op1<<8);break; + case 0xa1:sprintf(s, "lda ($%0.2x,x) [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDPX, op0));break; + case 0xa2: + if(gx816->regs.e == true || (gx816->regs.e == false && (gx816->regs.p & PF_X)))sprintf(s, "ldx #$%0.2x ", op0); + else sprintf(s, "ldx #$%0.4x ", op0|op1<<8);break; + case 0xa3:sprintf(s, "lda $%0.2x,s [$%0.6x]", op0, gx816->convert_offset(MEMMODE_SR, op0));break; + case 0xa4:sprintf(s, "ldy $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0xa5:sprintf(s, "lda $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0xa6:sprintf(s, "ldx $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0xa7:sprintf(s, "lda [$%0.2x] [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ILDP, op0));break; + case 0xa8:sprintf(s, "tay ");break; + case 0xa9: + if(gx816->regs.e == true || (gx816->regs.e == false && (gx816->regs.p & 0x20)))sprintf(s, "lda #$%0.2x ", op0); + else sprintf(s, "lda #$%0.4x ", op0|op1<<8);break; + case 0xaa:sprintf(s, "tax ");break; + case 0xab:sprintf(s, "plb ");break; + case 0xac:sprintf(s, "ldy $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0xad:sprintf(s, "lda $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0xae:sprintf(s, "ldx $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0xaf:sprintf(s, "lda $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, gx816->convert_offset(MEMMODE_LONG, (op0|op1<<8|op2<<16)));break; + case 0xb0:sprintf(s, "bcs $%0.4x [$%0.6x]", _disas_relb(op0)&0xffff, _disas_relb(op0)&0xffffff);break; + case 0xb1:sprintf(s, "lda ($%0.2x),y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDPY, op0));break; + case 0xb2:sprintf(s, "lda ($%0.2x) [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDP, op0));break; + case 0xb3:sprintf(s, "lda ($%0.2x,s),y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ISRY, op0));break; + case 0xb4:sprintf(s, "ldy $%0.2x,x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPX, op0));break; + case 0xb5:sprintf(s, "lda $%0.2x,x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPX, op0));break; + case 0xb6:sprintf(s, "ldx $%0.2x,y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPY, op0));break; + case 0xb7:sprintf(s, "lda [$%0.2x],y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ILDPY, op0));break; + case 0xb8:sprintf(s, "clv ");break; + case 0xb9:sprintf(s, "lda $%0.4x,y [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRY, (op0|op1<<8)));break; + case 0xba:sprintf(s, "tsx ");break; + case 0xbb:sprintf(s, "tyx ");break; + case 0xbc:sprintf(s, "ldy $%0.4x,x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRX, (op0|op1<<8)));break; + case 0xbd:sprintf(s, "lda $%0.4x,x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRX, (op0|op1<<8)));break; + case 0xbe:sprintf(s, "ldx $%0.4x,y [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRY, (op0|op1<<8)));break; + case 0xbf:sprintf(s, "lda $%0.6x,x [$%0.6x]", op0|op1<<8|op2<<16, gx816->convert_offset(MEMMODE_LONGX, (op0|op1<<8|op2<<16)));break; + case 0xc0: + if(gx816->regs.e == true || (gx816->regs.e == false && (gx816->regs.p & PF_X)))sprintf(s, "cpy #$%0.2x ", op0); + else sprintf(s, "cpy #$%0.4x ", op0|op1<<8);break; + case 0xc1:sprintf(s, "cmp ($%0.2x,x) [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDPX, op0));break; + case 0xc2:sprintf(s, "rep #$%0.2x ", op0);break; + case 0xc3:sprintf(s, "cmp $%0.2x,s [$%0.6x]", op0, gx816->convert_offset(MEMMODE_SR, op0));break; + case 0xc4:sprintf(s, "cpy $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0xc5:sprintf(s, "cmp $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0xc6:sprintf(s, "dec $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0xc7:sprintf(s, "cmp [$%0.2x] [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ILDP, op0));break; + case 0xc8:sprintf(s, "iny ");break; + case 0xc9: + if(gx816->regs.e == true || (gx816->regs.e == false && (gx816->regs.p & 0x20)))sprintf(s, "cmp #$%0.2x ", op0); + else sprintf(s, "cmp #$%0.4x ", op0|op1<<8);break; + case 0xca:sprintf(s, "dex ");break; + case 0xcb:sprintf(s, "wai ");break; + case 0xcc:sprintf(s, "cpy $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0xcd:sprintf(s, "cmp $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0xce:sprintf(s, "dec $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0xcf:sprintf(s, "cmp $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, gx816->convert_offset(MEMMODE_LONG, (op0|op1<<8|op2<<16)));break; + case 0xd0:sprintf(s, "bne $%0.4x [$%0.6x]", _disas_relb(op0)&0xffff, _disas_relb(op0)&0xffffff);break; + case 0xd1:sprintf(s, "cmp ($%0.2x),y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDPY, op0));break; + case 0xd2:sprintf(s, "cmp ($%0.2x) [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDP, op0));break; + case 0xd3:sprintf(s, "cmp ($%0.2x,s),y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ISRY, op0));break; + case 0xd4:sprintf(s, "pei ($%0.2x) [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDP, op0));break; + case 0xd5:sprintf(s, "cmp $%0.2x,x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPX, op0));break; + case 0xd6:sprintf(s, "dec $%0.2x,x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPX, op0));break; + case 0xd7:sprintf(s, "cmp [$%0.2x],y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ILDPY, op0));break; + case 0xd8:sprintf(s, "cld ");break; + case 0xd9:sprintf(s, "cmp $%0.4x,y [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRY, (op0|op1<<8)));break; + case 0xda:sprintf(s, "phx ");break; + case 0xdb:sprintf(s, "stp ");break; + case 0xdc:sprintf(s, "jmp [$%0.4x] [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ILADDR_PC, (op0|op1<<8)));break; + case 0xdd:sprintf(s, "cmp $%0.4x,x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRX, (op0|op1<<8)));break; + case 0xde:sprintf(s, "dec $%0.4x,x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRX, (op0|op1<<8)));break; + case 0xdf:sprintf(s, "cmp $%0.6x,x [$%0.6x]", op0|op1<<8|op2<<16, gx816->convert_offset(MEMMODE_LONGX, (op0|op1<<8|op2<<16)));break; + case 0xe0: + if(gx816->regs.e == true || (gx816->regs.e == false && (gx816->regs.p & PF_X)))sprintf(s, "cpx #$%0.2x ", op0); + else sprintf(s, "cpx #$%0.4x ", op0|op1<<8);break; + case 0xe1:sprintf(s, "sbc ($%0.2x,x) [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDPX, op0));break; + case 0xe2:sprintf(s, "sep #$%0.2x ", op0);break; + case 0xe3:sprintf(s, "sbc $%0.2x,s [$%0.6x]", op0, gx816->convert_offset(MEMMODE_SR, op0));break; + case 0xe4:sprintf(s, "cpx $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0xe5:sprintf(s, "sbc $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0xe6:sprintf(s, "inc $%0.2x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DP, op0));break; + case 0xe7:sprintf(s, "sbc [$%0.2x] [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ILDP, op0));break; + case 0xe8:sprintf(s, "inx ");break; + case 0xe9: + if(gx816->regs.e == true || (gx816->regs.e == false && (gx816->regs.p & 0x20)))sprintf(s, "sbc #$%0.2x ", op0); + else sprintf(s, "sbc #$%0.4x ", op0|op1<<8);break; + case 0xea:sprintf(s, "nop ");break; + case 0xeb:sprintf(s, "xba ");break; + case 0xec:sprintf(s, "cpx $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0xed:sprintf(s, "sbc $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0xee:sprintf(s, "inc $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0xef:sprintf(s, "sbc $%0.6x [$%0.6x]", op0|op1<<8|op2<<16, gx816->convert_offset(MEMMODE_LONG, (op0|op1<<8|op2<<16)));break; + case 0xf0:sprintf(s, "beq $%0.4x [$%0.6x]", _disas_relb(op0)&0xffff, _disas_relb(op0)&0xffffff);break; + case 0xf1:sprintf(s, "sbc ($%0.2x),y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDPY, op0));break; + case 0xf2:sprintf(s, "sbc ($%0.2x) [$%0.6x]", op0, gx816->convert_offset(MEMMODE_IDP, op0));break; + case 0xf3:sprintf(s, "sbc ($%0.2x,s),y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ISRY, op0));break; + case 0xf4:sprintf(s, "pea $%0.4x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDR, (op0|op1<<8)));break; + case 0xf5:sprintf(s, "sbc $%0.2x,x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPX, op0));break; + case 0xf6:sprintf(s, "inc $%0.2x,x [$%0.6x]", op0, gx816->convert_offset(MEMMODE_DPX, op0));break; + case 0xf7:sprintf(s, "sbc [$%0.2x],y [$%0.6x]", op0, gx816->convert_offset(MEMMODE_ILDPY, op0));break; + case 0xf8:sprintf(s, "sed ");break; + case 0xf9:sprintf(s, "sbc $%0.4x,y [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRY, (op0|op1<<8)));break; + case 0xfa:sprintf(s, "plx ");break; + case 0xfb:sprintf(s, "xce ");break; + case 0xfc:sprintf(s, "jsr ($%0.4x,x) [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_IADDRX_PC, (op0|op1<<8)));break; + case 0xfd:sprintf(s, "sbc $%0.4x,x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRX, (op0|op1<<8)));break; + case 0xfe:sprintf(s, "inc $%0.4x,x [$%0.6x]", op0|op1<<8, gx816->convert_offset(MEMMODE_ADDRX, (op0|op1<<8)));break; + case 0xff:sprintf(s, "sbc $%0.6x,x [$%0.6x]", op0|op1<<8|op2<<16, gx816->convert_offset(MEMMODE_LONGX, (op0|op1<<8|op2<<16)));break; + } +} + +void disas_g65816_op(void) { +byte op = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, gx816->regs.pc, MEMACCESS_DEBUGGER); +byte op0 = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, gx816->regs.pc + 1, MEMACCESS_DEBUGGER), + op1 = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, gx816->regs.pc + 2, MEMACCESS_DEBUGGER), + op2 = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, gx816->regs.pc + 3, MEMACCESS_DEBUGGER); +char str0[256], str1[256], str2[256]; + + strcpy(__disas_op_str, "??? "); + __disas_op(op, op0, op1, op2); + + if(gx816->regs.e == true) { + sprintf(str1, "%c%c%c%c%c%c%c%c E", + (gx816->regs.p & 0x80)?'N':'n', + (gx816->regs.p & 0x40)?'V':'v', + (gx816->regs.p & 0x20)?'1':'0', + (gx816->regs.p & 0x10)?'B':'b', + (gx816->regs.p & 0x08)?'D':'d', + (gx816->regs.p & 0x04)?'I':'i', + (gx816->regs.p & 0x02)?'Z':'z', + (gx816->regs.p & 0x01)?'C':'c'); + } else { + sprintf(str1, "%c%c%c%c%c%c%c%c N", + (gx816->regs.p & 0x80)?'N':'n', + (gx816->regs.p & 0x40)?'V':'v', + (gx816->regs.p & 0x20)?'M':'m', + (gx816->regs.p & 0x10)?'X':'x', + (gx816->regs.p & 0x08)?'D':'d', + (gx816->regs.p & 0x04)?'I':'i', + (gx816->regs.p & 0x02)?'Z':'z', + (gx816->regs.p & 0x01)?'C':'c'); + } + + dprintf("%0.6x %s A:%0.4x X:%0.4x Y:%0.4x S:%0.4x D:%0.4x DB:%0.2x %s", gx816->regs.pc, __disas_op_str, + gx816->regs.a.w, gx816->regs.x, gx816->regs.y, gx816->regs.s, + gx816->regs.d, gx816->regs.db, str1); + + debug_update_cycles(); +} diff --git a/bsnes/cpu/g65816.cpp b/bsnes/cpu/g65816.cpp new file mode 100644 index 00000000..9d117b50 --- /dev/null +++ b/bsnes/cpu/g65816.cpp @@ -0,0 +1,234 @@ +#include "../base.h" +#include "../timing/timing.h" +#include "g65816.h" + +extern emustate emu_state; +extern debugstate debugger; +extern ppustate ppu; +extern snes_timer *snes_time; +g65816 *gx816; + +#include "g65816_ops.cpp" + +void g65816::LoadROM(void) { +FILE *fp; +ulong fsize; +word header_offset = 0; +word cksum, icksum; +byte t; +int i; + dprintf("* Loading [%s]...", emu_state.rom_name); + + fp = fopen(emu_state.rom_name, "rb"); + if(!fp)return; + + fseek(fp, 0, SEEK_END); + fsize = ftell(fp); + fseek(fp, 0, SEEK_SET); + + map = MEMMAP_LOROM; + + if((fsize & 0x000fff) == 0x000200)header_offset = 512; + + fseek(fp, 0x7fdc + header_offset, SEEK_SET); + cksum = fgetc(fp) | fgetc(fp) << 8; + icksum = fgetc(fp) | fgetc(fp) << 8; + if(cksum + icksum == 0xffff)map = MEMMAP_LOROM; + + fseek(fp, 0xffdc + header_offset, SEEK_SET); + cksum = fgetc(fp) | fgetc(fp) << 8; + icksum = fgetc(fp) | fgetc(fp) << 8; + if(cksum + icksum == 0xffff)map = MEMMAP_HIROM; + + fseek(fp, 0 + header_offset, SEEK_SET); + fsize -= header_offset; + + dprintf("* ROM detected as: %s", (map == MEMMAP_LOROM)?"LoROM":"HiROM"); + + InitializeROM(map); + + fread(rom, 1, fsize, fp); + + t = (mem_read(MEMMODE_NONE, MEMSIZE_BYTE, 0x00ffd8) & 7); + switch(t) { + case 0: sram_size = 0; break; + case 1: sram_size = 2 * 1024;break; + case 2: sram_size = 4 * 1024;break; + case 3: sram_size = 8 * 1024;break; + case 4: sram_size = 16 * 1024;break; + case 5: sram_size = 32 * 1024;break; + case 6: sram_size = 64 * 1024;break; + case 7: sram_size = 128 * 1024;break; + default:sram_size = 0; break; + } + dprintf("* SRAM Size: %dkb", sram_size / 1024); + +//pbr is loaded with 00, and 16-bit pc is loaded with reset vector at 0xfffc +//upon power on and at first reset + regs.pc = mem_read(MEMMODE_LONG, MEMSIZE_WORD, 0x00fffc); + + fclose(fp); + + if(sram_size != 0) { + fp = fopen(emu_state.sram_name, "rb"); + +//create sram file if it does not exist + if(!fp) { + fp = fopen(emu_state.sram_name, "wb"); + for(i=0;imaster_cycles = 0; + memory_speed = MEMSPEED_SLOWROM; + toggle_memory_speed = MEMSPEED_SLOWROM; + wai_interrupt_occurred = false; + + InitializeWRAM(0x00); + PPUInit(first_time); + UpdateDisplay(); +} + +void g65816::Reset(void) { + regs.x &= 0xff; + regs.y &= 0xff; + regs.s = 0x0100 | (regs.s & 0xff); + regs.d = 0x0000; + regs.db = 0x00; + regs.p = 0x34; + regs.e = true; + regs.pc = mem_read(MEMMODE_LONG, MEMSIZE_WORD, 0x00fffc); + snes_time->master_cycles = 0; + memory_speed = MEMSPEED_SLOWROM; + toggle_memory_speed = MEMSPEED_SLOWROM; + wai_interrupt_occurred = false; + + PPUInit(0); //0 blocks reallocating memory for vram, cgram, etc. + UpdateDisplay(); + + if(debug_get_state() == DEBUGMODE_WAIT)disas_g65816_op(); +} + +void g65816::InvokeIRQ(word addr) { + wai_interrupt_occurred = true; + snes_time->add_cpu_pcycles(1); + if(gx816->regs.e == true) { + snes_time->add_cpu_scycles(3); + g65816_stackwrite(MEMSIZE_WORD, gx816->regs.pc); + g65816_stackwrite(MEMSIZE_BYTE, gx816->regs.p); + } else { + snes_time->add_cpu_scycles(4); + g65816_stackwrite(MEMSIZE_LONG, gx816->regs.pc); + g65816_stackwrite(MEMSIZE_BYTE, gx816->regs.p); + } + snes_time->add_cpu_mcycles(2, addr); + snes_time->add_cpu_icycles(1); + gx816->regs.pc = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, addr); + gx816->regs.p |= PF_I; + + snes_time->update_timer(); +} + +void g65816::Run(void) { +FILE *fp; +byte op; +word h; +int i; +static ulong sram_save_tick = 0; + op = mem_read(MEMMODE_NONE, MEMSIZE_BYTE, gx816->regs.pc); + if(regs.e == true)g65816_optbl_e[op](); + else switch((regs.p & 0x30)) { + case 0x30:g65816_optbl_MX[op]();break; + case 0x20:g65816_optbl_Mx[op]();break; + case 0x10:g65816_optbl_mX[op]();break; + case 0x00:g65816_optbl_mx[op]();break; + } + + h = snes_time->hscan_pos; + snes_time->update_timer(); + if(snes_time->hscan_pos >= WRAM_REFRESH_DOT_POS && h < WRAM_REFRESH_DOT_POS) { + snes_time->add_cpu_cycles(40); + snes_time->update_timer(); + } + ppu_update_scanline(); + + memory_speed = toggle_memory_speed; + + if(debug_get_state() == DEBUGMODE_DISABLED)return; + + for(i=0;i<16;i++) { + if(gx816->bp_list[i].flags & BP_EXEC) { + if(gx816->bp_list[i].offset == gx816->regs.pc) { + dprintf("* breakpoint %d hit -- exec access", i); + gx816->bp_list[i].hit_count++; + debug_set_state(DEBUGMODE_WAIT); + disas_g65816_op(); + debugger.refresh_bp = true; + } + } + } + +//see if we need to backup sram to a file yet... + if(sram_size != 0) { + sram_save_tick++; + if(sram_save_tick >= emu_state.sram_save_tick_count) { + sram_save_tick = 0; + fp = fopen(emu_state.sram_name, "wb"); + fwrite(sram, 1, sram_size, fp); + fclose(fp); + } + } +} + +g65816::g65816() { + rom = (byte*)malloc(0x600000); + wram = (byte*)malloc(0x020000); + sram = (byte*)malloc(0x0e0000); + for(int i=0;i<16;i++) { + bp_list[i].offset = 0; + bp_list[i].flags = BP_OFF; + bp_list[i].value = 0; + bp_list[i].hit_count = 0; + } + nmi_enabled = false; + nmi_pin = 0; +} + +g65816::~g65816() { + if(rom)free(rom); + if(wram)free(wram); + if(sram)free(sram); +} diff --git a/bsnes/cpu/g65816.h b/bsnes/cpu/g65816.h new file mode 100644 index 00000000..f1e83a1b --- /dev/null +++ b/bsnes/cpu/g65816.h @@ -0,0 +1,69 @@ +/* + regs.dc is not a real register. it is used to store the data counter + for reading from / writing to memory locations. it is also needed + to emulate slowrom / fastrom, as the speed varies depending on the + location where the memory was accessed. +*/ + +class g65816 { +public: +//cpu declarations + struct { + ulong pc, dc; + union { + byte b; + word w; + struct { byte l, h; }p; + }a; + word x, y, d, s; + byte db, p; + bool e; + }regs; + byte memory_speed; + byte toggle_memory_speed; + bool index_bank_crossed; + + byte nmi_pin; + bool nmi_enabled; + + bool wai_interrupt_occurred; + +//memory declarations + byte *wram, *sram, *rom; + ulong map; + ulong sram_size; +//debug declarations + struct { + ulong offset; + byte flags; + byte value; + ulong hit_count; + }bp_list[16]; + +//cpu functions (cpu/g65816.cpp) + void Run(void); + void LoadROM(void); + void PowerOn(byte first_time); + void Reset(void); + void InvokeIRQ(word addr); + +//memory functions (mem/memory.cpp) + void InitializeROM(byte memory_map); + void InitializeWRAM(byte value); + ulong mirror_offset(ulong offset); + ulong convert_offset(byte read_mode, ulong addr, bool mirror = true); + ulong adjust_base_offset(byte read_mode, ulong addr); + ulong read_indirect_address(byte read_mode, ulong addr); + ulong get_dc(byte read_mode, ulong addr); + byte mem_getbyte_direct(ulong addr, byte access_mode = MEMACCESS_NORMAL); + byte mem_getbyte(ulong addr, byte access_mode = MEMACCESS_NORMAL); + void mem_putbyte_direct(ulong addr, byte value, byte access_mode = MEMACCESS_NORMAL); + void mem_putbyte(ulong addr, byte value, byte access_mode = MEMACCESS_NORMAL); + ulong mem_read(byte read_mode, byte read_size, ulong addr, byte access_mode = MEMACCESS_NORMAL); + void mem_write(byte write_mode, byte write_size, ulong addr, ulong value, byte access_mode = MEMACCESS_NORMAL); + ulong rom_read(ulong addr, byte read_size); + void rom_write(ulong addr, ulong v, byte write_size); + + g65816(); + ~g65816(); +}; diff --git a/bsnes/cpu/g65816_ops.cpp b/bsnes/cpu/g65816_ops.cpp new file mode 100644 index 00000000..02e036da --- /dev/null +++ b/bsnes/cpu/g65816_ops.cpp @@ -0,0 +1,161 @@ +#define g65816_setn() gx816->regs.p |= PF_N +#define g65816_clrn() gx816->regs.p &= ~PF_N +#define g65816_setv() gx816->regs.p |= PF_V +#define g65816_clrv() gx816->regs.p &= ~PF_V +#define g65816_setm() gx816->regs.p |= PF_M +#define g65816_clrm() gx816->regs.p &= ~PF_M +#define g65816_setx() gx816->regs.p |= PF_X +#define g65816_clrx() gx816->regs.p &= ~PF_X +#define g65816_setd() gx816->regs.p |= PF_D +#define g65816_clrd() gx816->regs.p &= ~PF_D +#define g65816_seti() gx816->regs.p |= PF_I +#define g65816_clri() gx816->regs.p &= ~PF_I +#define g65816_setz() gx816->regs.p |= PF_Z +#define g65816_clrz() gx816->regs.p &= ~PF_Z +#define g65816_setc() gx816->regs.p |= PF_C +#define g65816_clrc() gx816->regs.p &= ~PF_C +#define g65816_testn(x) if(x)g65816_setn(); else g65816_clrn() +#define g65816_testv(x) if(x)g65816_setv(); else g65816_clrv() +#define g65816_testd(x) if(x)g65816_setd(); else g65816_clrd() +#define g65816_testi(x) if(x)g65816_seti(); else g65816_clri() +#define g65816_testz(x) if(x)g65816_setz(); else g65816_clrz() +#define g65816_testc(x) if(x)g65816_setc(); else g65816_clrc() + +//read opcode argument +#define g65816_prefetch(__size) ulong arg = gx816->mem_read(MEMMODE_NONE, __size, gx816->regs.pc + 1, MEMACCESS_CPU) +//get destination address, do not mirror +#define g65816_getaddr(__mode) ulong dest_addr = gx816->get_dc(__mode, arg) +//get indirect destination address + destination address, do not mirror +#define g65816_getiaddr(__mode) ulong base_addr = gx816->adjust_base_offset(__mode, arg);ulong dest_addr = gx816->read_indirect_address(__mode, base_addr) +//increment program counter, wrap around pbr +#define g65816_incpc(__n) gx816->regs.pc = (gx816->regs.pc & 0xff0000) | ((gx816->regs.pc + __n) & 0xffff) + +//opcode functions +#include "g65816_ops_adc.cpp" +#include "g65816_ops_and.cpp" +#include "g65816_ops_cmp.cpp" +#include "g65816_ops_eor.cpp" +#include "g65816_ops_lda.cpp" +#include "g65816_ops_ora.cpp" +#include "g65816_ops_sbc.cpp" +#include "g65816_ops_sta.cpp" +#include "g65816_ops_incdec.cpp" +#include "g65816_ops_shift.cpp" +#include "g65816_ops_stack.cpp" +#include "g65816_ops_pc.cpp" +#include "g65816_ops_misc.cpp" + +vfunc g65816_optbl_e[256] = { // g65816_optbl_e, g65816_optbl_e, g65816_optbl_e, + // ----------------------x0, ----------------------x1, ----------------------x2, ----------------------x3, -------- ----------------------x4, ----------------------x5, ----------------------x6, ----------------------x7, -------- ----------------------x8, ----------------------x9, ----------------------xa, ----------------------xb, -------- ----------------------xc, ----------------------xd, ----------------------xe, ----------------------xf, +/* 0x */ g65816_op_brke, g65816_op_ora_idpxb, g65816_op_cope, g65816_op_ora_srb, /* 0x */ g65816_op_tsb_dpb, g65816_op_ora_dpb, g65816_op_asl_dpb, g65816_op_ora_ildpb, /* 0x */ g65816_op_php, g65816_op_ora_constb, g65816_op_aslb, g65816_op_phd, /* 0x */ g65816_op_tsb_addrb, g65816_op_ora_addrb, g65816_op_asl_addrb, g65816_op_ora_longb, +/* 1x */ g65816_op_bpl, g65816_op_ora_idpyb, g65816_op_ora_idpb, g65816_op_ora_isryb, /* 1x */ g65816_op_trb_dpb, g65816_op_ora_dpxb, g65816_op_asl_dpxb, g65816_op_ora_ildpyb, /* 1x */ g65816_op_clc, g65816_op_ora_addryb, g65816_op_incb, g65816_op_tcse, /* 1x */ g65816_op_trb_addrb, g65816_op_ora_addrxb, g65816_op_asl_addrxb, g65816_op_ora_longxb, +/* 2x */ g65816_op_jsr_addr, g65816_op_and_idpxb, g65816_op_jsr_long, g65816_op_and_srb, /* 2x */ g65816_op_bit_dpb, g65816_op_and_dpb, g65816_op_rol_dpb, g65816_op_and_ildpb, /* 2x */ g65816_op_plp, g65816_op_and_constb, g65816_op_rolb, g65816_op_pld, /* 2x */ g65816_op_bit_addrb, g65816_op_and_addrb, g65816_op_rol_addrb, g65816_op_and_longb, +/* 3x */ g65816_op_bmi, g65816_op_and_idpyb, g65816_op_and_idpb, g65816_op_and_isryb, /* 3x */ g65816_op_bit_dpxb, g65816_op_and_dpxb, g65816_op_rol_dpxb, g65816_op_and_ildpyb, /* 3x */ g65816_op_sec, g65816_op_and_addryb, g65816_op_decb, g65816_op_tsce, /* 3x */ g65816_op_bit_addrxb, g65816_op_and_addrxb, g65816_op_rol_addrxb, g65816_op_and_longxb, + +/* 4x */ g65816_op_rtie, g65816_op_eor_idpxb, g65816_op_wdm, g65816_op_eor_srb, /* 4x */ g65816_op_mvp, g65816_op_eor_dpb, g65816_op_lsr_dpb, g65816_op_eor_ildpb, /* 4x */ g65816_op_phab, g65816_op_eor_constb, g65816_op_lsrb, g65816_op_phk, /* 4x */ g65816_op_jmp_addr, g65816_op_eor_addrb, g65816_op_lsr_addrb, g65816_op_eor_longb, +/* 5x */ g65816_op_bvc, g65816_op_eor_idpyb, g65816_op_eor_idpb, g65816_op_eor_isryb, /* 5x */ g65816_op_mvn, g65816_op_eor_dpxb, g65816_op_lsr_dpxb, g65816_op_eor_ildpyb, /* 5x */ g65816_op_cli, g65816_op_eor_addryb, g65816_op_phyb, g65816_op_tcd, /* 5x */ g65816_op_jmp_long, g65816_op_eor_addrxb, g65816_op_lsr_addrxb, g65816_op_eor_longxb, +/* 6x */ g65816_op_rts, g65816_op_adc_idpxb, g65816_op_per, g65816_op_adc_srb, /* 6x */ g65816_op_stz_dpb, g65816_op_adc_dpb, g65816_op_ror_dpb, g65816_op_adc_ildpb, /* 6x */ g65816_op_plab, g65816_op_adc_constb, g65816_op_rorb, g65816_op_rtl, /* 6x */ g65816_op_jmp_iaddr, g65816_op_adc_addrb, g65816_op_ror_addrb, g65816_op_adc_longb, +/* 7x */ g65816_op_bvs, g65816_op_adc_idpyb, g65816_op_adc_idpb, g65816_op_adc_isryb, /* 7x */ g65816_op_stz_dpxb, g65816_op_adc_dpxb, g65816_op_ror_dpxb, g65816_op_adc_ildpyb, /* 7x */ g65816_op_sei, g65816_op_adc_addryb, g65816_op_plyb, g65816_tdc, /* 7x */ g65816_op_jmp_iaddrx, g65816_op_adc_addrxb, g65816_op_ror_addrxb, g65816_op_adc_longxb, + +/* 8x */ g65816_op_bra, g65816_op_sta_idpxb, g65816_op_brl, g65816_op_sta_srb, /* 8x */ g65816_op_sty_dpb, g65816_op_sta_dpb, g65816_op_stx_dpb, g65816_op_sta_ildpb, /* 8x */ g65816_op_deyb, g65816_op_bit_constb, g65816_op_txab, g65816_op_phb, /* 8x */ g65816_op_sty_addrb, g65816_op_sta_addrb, g65816_op_stx_addrb, g65816_op_sta_longb, +/* 9x */ g65816_op_bcc, g65816_op_sta_idpyb, g65816_op_sta_idpb, g65816_op_sta_isryb, /* 9x */ g65816_op_sty_dpxb, g65816_op_sta_dpxb, g65816_op_stx_dpyb, g65816_op_sta_ildpyb, /* 9x */ g65816_op_tyab, g65816_op_sta_addryb, g65816_op_txsb, g65816_op_txyb, /* 9x */ g65816_op_stz_addrb, g65816_op_sta_addrxb, g65816_op_stz_addrxb, g65816_op_sta_longxb, +/* ax */ g65816_op_ldy_constb, g65816_op_lda_idpxb, g65816_op_ldx_constb, g65816_op_lda_srb, /* ax */ g65816_op_ldy_dpb, g65816_op_lda_dpb, g65816_op_ldx_dpb, g65816_op_lda_ildpb, /* ax */ g65816_op_tayb, g65816_op_lda_constb, g65816_op_taxb, g65816_op_plb, /* ax */ g65816_op_ldy_addrb, g65816_op_lda_addrb, g65816_op_ldx_addrb, g65816_op_lda_longb, +/* bx */ g65816_op_bcs, g65816_op_lda_idpyb, g65816_op_lda_idpb, g65816_op_lda_isryb, /* bx */ g65816_op_ldy_dpxb, g65816_op_lda_dpxb, g65816_op_ldx_dpyb, g65816_op_lda_ildpyb, /* bx */ g65816_op_clv, g65816_op_lda_addryb, g65816_op_tsxb, g65816_op_tyxb, /* bx */ g65816_op_ldy_addrxb, g65816_op_lda_addrxb, g65816_op_ldx_addryb, g65816_op_lda_longxb, + +/* cx */ g65816_op_cpy_constb, g65816_op_cmp_idpxb, g65816_op_rep, g65816_op_cmp_srb, /* cx */ g65816_op_cpy_dpb, g65816_op_cmp_dpb, g65816_op_dec_dpb, g65816_op_cmp_ildpb, /* cx */ g65816_op_inyb, g65816_op_cmp_constb, g65816_op_dexb, g65816_op_wai, /* cx */ g65816_op_cpy_addrb, g65816_op_cmp_addrb, g65816_op_dec_addrb, g65816_op_cmp_longb, +/* dx */ g65816_op_bne, g65816_op_cmp_idpyb, g65816_op_cmp_idpb, g65816_op_cmp_isryb, /* dx */ g65816_op_pei, g65816_op_cmp_dpxb, g65816_op_dec_dpxb, g65816_op_cmp_ildpyb, /* dx */ g65816_op_cld, g65816_op_cmp_addryb, g65816_op_phxb, g65816_op_stp, /* dx */ g65816_op_jmp_iladdr, g65816_op_cmp_addrxb, g65816_op_dec_addrxb, g65816_op_cmp_longxb, +/* ex */ g65816_op_cpx_constb, g65816_op_sbc_idpxb, g65816_op_sep, g65816_op_sbc_srb, /* ex */ g65816_op_cpx_dpb, g65816_op_sbc_dpb, g65816_op_inc_dpb, g65816_op_sbc_ildpb, /* ex */ g65816_op_inxb, g65816_op_sbc_constb, g65816_op_nop, g65816_op_xba, /* ex */ g65816_op_cpx_addrb, g65816_op_sbc_addrb, g65816_op_inc_addrb, g65816_op_sbc_longb, +/* fx */ g65816_op_beq, g65816_op_sbc_idpyb, g65816_op_sbc_idpb, g65816_op_sbc_isryb, /* fx */ g65816_op_pea, g65816_op_sbc_dpxb, g65816_op_inc_dpxb, g65816_op_sbc_ildpyb, /* fx */ g65816_op_sed, g65816_op_sbc_addryb, g65816_op_plxb, g65816_op_xce, /* fx */ g65816_op_jsr_iaddrx, g65816_op_sbc_addrxb, g65816_op_inc_addrxb, g65816_op_sbc_longxb +}; + +vfunc g65816_optbl_MX[256] = { // g65816_optbl_MX, g65816_optbl_MX, g65816_optbl_MX, + // ----------------------x0, ----------------------x1, ----------------------x2, ----------------------x3, -------- ----------------------x4, ----------------------x5, ----------------------x6, ----------------------x7, -------- ----------------------x8, ----------------------x9, ----------------------xa, ----------------------xb, -------- ----------------------xc, ----------------------xd, ----------------------xe, ----------------------xf, +/* 0x */ g65816_op_brkn, g65816_op_ora_idpxb, g65816_op_copn, g65816_op_ora_srb, /* 0x */ g65816_op_tsb_dpb, g65816_op_ora_dpb, g65816_op_asl_dpb, g65816_op_ora_ildpb, /* 0x */ g65816_op_php, g65816_op_ora_constb, g65816_op_aslb, g65816_op_phd, /* 0x */ g65816_op_tsb_addrb, g65816_op_ora_addrb, g65816_op_asl_addrb, g65816_op_ora_longb, +/* 1x */ g65816_op_bpl, g65816_op_ora_idpyb, g65816_op_ora_idpb, g65816_op_ora_isryb, /* 1x */ g65816_op_trb_dpb, g65816_op_ora_dpxb, g65816_op_asl_dpxb, g65816_op_ora_ildpyb, /* 1x */ g65816_op_clc, g65816_op_ora_addryb, g65816_op_incb, g65816_op_tcsn, /* 1x */ g65816_op_trb_addrb, g65816_op_ora_addrxb, g65816_op_asl_addrxb, g65816_op_ora_longxb, +/* 2x */ g65816_op_jsr_addr, g65816_op_and_idpxb, g65816_op_jsr_long, g65816_op_and_srb, /* 2x */ g65816_op_bit_dpb, g65816_op_and_dpb, g65816_op_rol_dpb, g65816_op_and_ildpb, /* 2x */ g65816_op_plp, g65816_op_and_constb, g65816_op_rolb, g65816_op_pld, /* 2x */ g65816_op_bit_addrb, g65816_op_and_addrb, g65816_op_rol_addrb, g65816_op_and_longb, +/* 3x */ g65816_op_bmi, g65816_op_and_idpyb, g65816_op_and_idpb, g65816_op_and_isryb, /* 3x */ g65816_op_bit_dpxb, g65816_op_and_dpxb, g65816_op_rol_dpxb, g65816_op_and_ildpyb, /* 3x */ g65816_op_sec, g65816_op_and_addryb, g65816_op_decb, g65816_op_tscn, /* 3x */ g65816_op_bit_addrxb, g65816_op_and_addrxb, g65816_op_rol_addrxb, g65816_op_and_longxb, + +/* 4x */ g65816_op_rtin, g65816_op_eor_idpxb, g65816_op_wdm, g65816_op_eor_srb, /* 4x */ g65816_op_mvp, g65816_op_eor_dpb, g65816_op_lsr_dpb, g65816_op_eor_ildpb, /* 4x */ g65816_op_phab, g65816_op_eor_constb, g65816_op_lsrb, g65816_op_phk, /* 4x */ g65816_op_jmp_addr, g65816_op_eor_addrb, g65816_op_lsr_addrb, g65816_op_eor_longb, +/* 5x */ g65816_op_bvc, g65816_op_eor_idpyb, g65816_op_eor_idpb, g65816_op_eor_isryb, /* 5x */ g65816_op_mvn, g65816_op_eor_dpxb, g65816_op_lsr_dpxb, g65816_op_eor_ildpyb, /* 5x */ g65816_op_cli, g65816_op_eor_addryb, g65816_op_phyb, g65816_op_tcd, /* 5x */ g65816_op_jmp_long, g65816_op_eor_addrxb, g65816_op_lsr_addrxb, g65816_op_eor_longxb, +/* 6x */ g65816_op_rts, g65816_op_adc_idpxb, g65816_op_per, g65816_op_adc_srb, /* 6x */ g65816_op_stz_dpb, g65816_op_adc_dpb, g65816_op_ror_dpb, g65816_op_adc_ildpb, /* 6x */ g65816_op_plab, g65816_op_adc_constb, g65816_op_rorb, g65816_op_rtl, /* 6x */ g65816_op_jmp_iaddr, g65816_op_adc_addrb, g65816_op_ror_addrb, g65816_op_adc_longb, +/* 7x */ g65816_op_bvs, g65816_op_adc_idpyb, g65816_op_adc_idpb, g65816_op_adc_isryb, /* 7x */ g65816_op_stz_dpxb, g65816_op_adc_dpxb, g65816_op_ror_dpxb, g65816_op_adc_ildpyb, /* 7x */ g65816_op_sei, g65816_op_adc_addryb, g65816_op_plyb, g65816_tdc, /* 7x */ g65816_op_jmp_iaddrx, g65816_op_adc_addrxb, g65816_op_ror_addrxb, g65816_op_adc_longxb, + +/* 8x */ g65816_op_bra, g65816_op_sta_idpxb, g65816_op_brl, g65816_op_sta_srb, /* 8x */ g65816_op_sty_dpb, g65816_op_sta_dpb, g65816_op_stx_dpb, g65816_op_sta_ildpb, /* 8x */ g65816_op_deyb, g65816_op_bit_constb, g65816_op_txab, g65816_op_phb, /* 8x */ g65816_op_sty_addrb, g65816_op_sta_addrb, g65816_op_stx_addrb, g65816_op_sta_longb, +/* 9x */ g65816_op_bcc, g65816_op_sta_idpyb, g65816_op_sta_idpb, g65816_op_sta_isryb, /* 9x */ g65816_op_sty_dpxb, g65816_op_sta_dpxb, g65816_op_stx_dpyb, g65816_op_sta_ildpyb, /* 9x */ g65816_op_tyab, g65816_op_sta_addryb, g65816_op_txsb, g65816_op_txyb, /* 9x */ g65816_op_stz_addrb, g65816_op_sta_addrxb, g65816_op_stz_addrxb, g65816_op_sta_longxb, +/* ax */ g65816_op_ldy_constb, g65816_op_lda_idpxb, g65816_op_ldx_constb, g65816_op_lda_srb, /* ax */ g65816_op_ldy_dpb, g65816_op_lda_dpb, g65816_op_ldx_dpb, g65816_op_lda_ildpb, /* ax */ g65816_op_tayb, g65816_op_lda_constb, g65816_op_taxb, g65816_op_plb, /* ax */ g65816_op_ldy_addrb, g65816_op_lda_addrb, g65816_op_ldx_addrb, g65816_op_lda_longb, +/* bx */ g65816_op_bcs, g65816_op_lda_idpyb, g65816_op_lda_idpb, g65816_op_lda_isryb, /* bx */ g65816_op_ldy_dpxb, g65816_op_lda_dpxb, g65816_op_ldx_dpyb, g65816_op_lda_ildpyb, /* bx */ g65816_op_clv, g65816_op_lda_addryb, g65816_op_tsxb, g65816_op_tyxb, /* bx */ g65816_op_ldy_addrxb, g65816_op_lda_addrxb, g65816_op_ldx_addryb, g65816_op_lda_longxb, + +/* cx */ g65816_op_cpy_constb, g65816_op_cmp_idpxb, g65816_op_rep, g65816_op_cmp_srb, /* cx */ g65816_op_cpy_dpb, g65816_op_cmp_dpb, g65816_op_dec_dpb, g65816_op_cmp_ildpb, /* cx */ g65816_op_inyb, g65816_op_cmp_constb, g65816_op_dexb, g65816_op_wai, /* cx */ g65816_op_cpy_addrb, g65816_op_cmp_addrb, g65816_op_dec_addrb, g65816_op_cmp_longb, +/* dx */ g65816_op_bne, g65816_op_cmp_idpyb, g65816_op_cmp_idpb, g65816_op_cmp_isryb, /* dx */ g65816_op_pei, g65816_op_cmp_dpxb, g65816_op_dec_dpxb, g65816_op_cmp_ildpyb, /* dx */ g65816_op_cld, g65816_op_cmp_addryb, g65816_op_phxb, g65816_op_stp, /* dx */ g65816_op_jmp_iladdr, g65816_op_cmp_addrxb, g65816_op_dec_addrxb, g65816_op_cmp_longxb, +/* ex */ g65816_op_cpx_constb, g65816_op_sbc_idpxb, g65816_op_sep, g65816_op_sbc_srb, /* ex */ g65816_op_cpx_dpb, g65816_op_sbc_dpb, g65816_op_inc_dpb, g65816_op_sbc_ildpb, /* ex */ g65816_op_inxb, g65816_op_sbc_constb, g65816_op_nop, g65816_op_xba, /* ex */ g65816_op_cpx_addrb, g65816_op_sbc_addrb, g65816_op_inc_addrb, g65816_op_sbc_longb, +/* fx */ g65816_op_beq, g65816_op_sbc_idpyb, g65816_op_sbc_idpb, g65816_op_sbc_isryb, /* fx */ g65816_op_pea, g65816_op_sbc_dpxb, g65816_op_inc_dpxb, g65816_op_sbc_ildpyb, /* fx */ g65816_op_sed, g65816_op_sbc_addryb, g65816_op_plxb, g65816_op_xce, /* fx */ g65816_op_jsr_iaddrx, g65816_op_sbc_addrxb, g65816_op_inc_addrxb, g65816_op_sbc_longxb +}; + +vfunc g65816_optbl_Mx[256] = { // g65816_optbl_Mx, g65816_optbl_Mx, g65816_optbl_Mx, + // ----------------------x0, ----------------------x1, ----------------------x2, ----------------------x3, -------- ----------------------x4, ----------------------x5, ----------------------x6, ----------------------x7, -------- ----------------------x8, ----------------------x9, ----------------------xa, ----------------------xb, -------- ----------------------xc, ----------------------xd, ----------------------xe, ----------------------xf, +/* 0x */ g65816_op_brkn, g65816_op_ora_idpxb, g65816_op_copn, g65816_op_ora_srb, /* 0x */ g65816_op_tsb_dpb, g65816_op_ora_dpb, g65816_op_asl_dpb, g65816_op_ora_ildpb, /* 0x */ g65816_op_php, g65816_op_ora_constb, g65816_op_aslb, g65816_op_phd, /* 0x */ g65816_op_tsb_addrb, g65816_op_ora_addrb, g65816_op_asl_addrb, g65816_op_ora_longb, +/* 1x */ g65816_op_bpl, g65816_op_ora_idpyb, g65816_op_ora_idpb, g65816_op_ora_isryb, /* 1x */ g65816_op_trb_dpb, g65816_op_ora_dpxb, g65816_op_asl_dpxb, g65816_op_ora_ildpyb, /* 1x */ g65816_op_clc, g65816_op_ora_addryb, g65816_op_incb, g65816_op_tcsn, /* 1x */ g65816_op_trb_addrb, g65816_op_ora_addrxb, g65816_op_asl_addrxb, g65816_op_ora_longxb, +/* 2x */ g65816_op_jsr_addr, g65816_op_and_idpxb, g65816_op_jsr_long, g65816_op_and_srb, /* 2x */ g65816_op_bit_dpb, g65816_op_and_dpb, g65816_op_rol_dpb, g65816_op_and_ildpb, /* 2x */ g65816_op_plp, g65816_op_and_constb, g65816_op_rolb, g65816_op_pld, /* 2x */ g65816_op_bit_addrb, g65816_op_and_addrb, g65816_op_rol_addrb, g65816_op_and_longb, +/* 3x */ g65816_op_bmi, g65816_op_and_idpyb, g65816_op_and_idpb, g65816_op_and_isryb, /* 3x */ g65816_op_bit_dpxb, g65816_op_and_dpxb, g65816_op_rol_dpxb, g65816_op_and_ildpyb, /* 3x */ g65816_op_sec, g65816_op_and_addryb, g65816_op_decb, g65816_op_tscn, /* 3x */ g65816_op_bit_addrxb, g65816_op_and_addrxb, g65816_op_rol_addrxb, g65816_op_and_longxb, + +/* 4x */ g65816_op_rtin, g65816_op_eor_idpxb, g65816_op_wdm, g65816_op_eor_srb, /* 4x */ g65816_op_mvp, g65816_op_eor_dpb, g65816_op_lsr_dpb, g65816_op_eor_ildpb, /* 4x */ g65816_op_phab, g65816_op_eor_constb, g65816_op_lsrb, g65816_op_phk, /* 4x */ g65816_op_jmp_addr, g65816_op_eor_addrb, g65816_op_lsr_addrb, g65816_op_eor_longb, +/* 5x */ g65816_op_bvc, g65816_op_eor_idpyb, g65816_op_eor_idpb, g65816_op_eor_isryb, /* 5x */ g65816_op_mvn, g65816_op_eor_dpxb, g65816_op_lsr_dpxb, g65816_op_eor_ildpyb, /* 5x */ g65816_op_cli, g65816_op_eor_addryb, g65816_op_phyw, g65816_op_tcd, /* 5x */ g65816_op_jmp_long, g65816_op_eor_addrxb, g65816_op_lsr_addrxb, g65816_op_eor_longxb, +/* 6x */ g65816_op_rts, g65816_op_adc_idpxb, g65816_op_per, g65816_op_adc_srb, /* 6x */ g65816_op_stz_dpb, g65816_op_adc_dpb, g65816_op_ror_dpb, g65816_op_adc_ildpb, /* 6x */ g65816_op_plab, g65816_op_adc_constb, g65816_op_rorb, g65816_op_rtl, /* 6x */ g65816_op_jmp_iaddr, g65816_op_adc_addrb, g65816_op_ror_addrb, g65816_op_adc_longb, +/* 7x */ g65816_op_bvs, g65816_op_adc_idpyb, g65816_op_adc_idpb, g65816_op_adc_isryb, /* 7x */ g65816_op_stz_dpxb, g65816_op_adc_dpxb, g65816_op_ror_dpxb, g65816_op_adc_ildpyb, /* 7x */ g65816_op_sei, g65816_op_adc_addryb, g65816_op_plyw, g65816_tdc, /* 7x */ g65816_op_jmp_iaddrx, g65816_op_adc_addrxb, g65816_op_ror_addrxb, g65816_op_adc_longxb, + +/* 8x */ g65816_op_bra, g65816_op_sta_idpxb, g65816_op_brl, g65816_op_sta_srb, /* 8x */ g65816_op_sty_dpw, g65816_op_sta_dpb, g65816_op_stx_dpw, g65816_op_sta_ildpb, /* 8x */ g65816_op_deyw, g65816_op_bit_constb, g65816_op_txab, g65816_op_phb, /* 8x */ g65816_op_sty_addrw, g65816_op_sta_addrb, g65816_op_stx_addrw, g65816_op_sta_longb, +/* 9x */ g65816_op_bcc, g65816_op_sta_idpyb, g65816_op_sta_idpb, g65816_op_sta_isryb, /* 9x */ g65816_op_sty_dpxw, g65816_op_sta_dpxb, g65816_op_stx_dpyw, g65816_op_sta_ildpyb, /* 9x */ g65816_op_tyab, g65816_op_sta_addryb, g65816_op_txsw, g65816_op_txyw, /* 9x */ g65816_op_stz_addrb, g65816_op_sta_addrxb, g65816_op_stz_addrxb, g65816_op_sta_longxb, +/* ax */ g65816_op_ldy_constw, g65816_op_lda_idpxb, g65816_op_ldx_constw, g65816_op_lda_srb, /* ax */ g65816_op_ldy_dpw, g65816_op_lda_dpb, g65816_op_ldx_dpw, g65816_op_lda_ildpb, /* ax */ g65816_op_tayw, g65816_op_lda_constb, g65816_op_taxw, g65816_op_plb, /* ax */ g65816_op_ldy_addrw, g65816_op_lda_addrb, g65816_op_ldx_addrw, g65816_op_lda_longb, +/* bx */ g65816_op_bcs, g65816_op_lda_idpyb, g65816_op_lda_idpb, g65816_op_lda_isryb, /* bx */ g65816_op_ldy_dpxw, g65816_op_lda_dpxb, g65816_op_ldx_dpyw, g65816_op_lda_ildpyb, /* bx */ g65816_op_clv, g65816_op_lda_addryb, g65816_op_tsxw, g65816_op_tyxw, /* bx */ g65816_op_ldy_addrxw, g65816_op_lda_addrxb, g65816_op_ldx_addryw, g65816_op_lda_longxb, + +/* cx */ g65816_op_cpy_constw, g65816_op_cmp_idpxb, g65816_op_rep, g65816_op_cmp_srb, /* cx */ g65816_op_cpy_dpw, g65816_op_cmp_dpb, g65816_op_dec_dpb, g65816_op_cmp_ildpb, /* cx */ g65816_op_inyw, g65816_op_cmp_constb, g65816_op_dexw, g65816_op_wai, /* cx */ g65816_op_cpy_addrw, g65816_op_cmp_addrb, g65816_op_dec_addrb, g65816_op_cmp_longb, +/* dx */ g65816_op_bne, g65816_op_cmp_idpyb, g65816_op_cmp_idpb, g65816_op_cmp_isryb, /* dx */ g65816_op_pei, g65816_op_cmp_dpxb, g65816_op_dec_dpxb, g65816_op_cmp_ildpyb, /* dx */ g65816_op_cld, g65816_op_cmp_addryb, g65816_op_phxw, g65816_op_stp, /* dx */ g65816_op_jmp_iladdr, g65816_op_cmp_addrxb, g65816_op_dec_addrxb, g65816_op_cmp_longxb, +/* ex */ g65816_op_cpx_constw, g65816_op_sbc_idpxb, g65816_op_sep, g65816_op_sbc_srb, /* ex */ g65816_op_cpx_dpw, g65816_op_sbc_dpb, g65816_op_inc_dpb, g65816_op_sbc_ildpb, /* ex */ g65816_op_inxw, g65816_op_sbc_constb, g65816_op_nop, g65816_op_xba, /* ex */ g65816_op_cpx_addrw, g65816_op_sbc_addrb, g65816_op_inc_addrb, g65816_op_sbc_longb, +/* fx */ g65816_op_beq, g65816_op_sbc_idpyb, g65816_op_sbc_idpb, g65816_op_sbc_isryb, /* fx */ g65816_op_pea, g65816_op_sbc_dpxb, g65816_op_inc_dpxb, g65816_op_sbc_ildpyb, /* fx */ g65816_op_sed, g65816_op_sbc_addryb, g65816_op_plxw, g65816_op_xce, /* fx */ g65816_op_jsr_iaddrx, g65816_op_sbc_addrxb, g65816_op_inc_addrxb, g65816_op_sbc_longxb +}; + +vfunc g65816_optbl_mX[256] = { // g65816_optbl_mX, g65816_optbl_mX, g65816_optbl_mX, + // ----------------------x0, ----------------------x1, ----------------------x2, ----------------------x3, -------- ----------------------x4, ----------------------x5, ----------------------x6, ----------------------x7, -------- ----------------------x8, ----------------------x9, ----------------------xa, ----------------------xb, -------- ----------------------xc, ----------------------xd, ----------------------xe, ----------------------xf, +/* 0x */ g65816_op_brkn, g65816_op_ora_idpxw, g65816_op_copn, g65816_op_ora_srw, /* 0x */ g65816_op_tsb_dpw, g65816_op_ora_dpw, g65816_op_asl_dpw, g65816_op_ora_ildpw, /* 0x */ g65816_op_php, g65816_op_ora_constw, g65816_op_aslw, g65816_op_phd, /* 0x */ g65816_op_tsb_addrw, g65816_op_ora_addrw, g65816_op_asl_addrw, g65816_op_ora_longw, +/* 1x */ g65816_op_bpl, g65816_op_ora_idpyw, g65816_op_ora_idpw, g65816_op_ora_isryw, /* 1x */ g65816_op_trb_dpw, g65816_op_ora_dpxw, g65816_op_asl_dpxw, g65816_op_ora_ildpyw, /* 1x */ g65816_op_clc, g65816_op_ora_addryw, g65816_op_incw, g65816_op_tcsn, /* 1x */ g65816_op_trb_addrw, g65816_op_ora_addrxw, g65816_op_asl_addrxw, g65816_op_ora_longxw, +/* 2x */ g65816_op_jsr_addr, g65816_op_and_idpxw, g65816_op_jsr_long, g65816_op_and_srw, /* 2x */ g65816_op_bit_dpw, g65816_op_and_dpw, g65816_op_rol_dpw, g65816_op_and_ildpw, /* 2x */ g65816_op_plp, g65816_op_and_constw, g65816_op_rolw, g65816_op_pld, /* 2x */ g65816_op_bit_addrw, g65816_op_and_addrw, g65816_op_rol_addrw, g65816_op_and_longw, +/* 3x */ g65816_op_bmi, g65816_op_and_idpyw, g65816_op_and_idpw, g65816_op_and_isryw, /* 3x */ g65816_op_bit_dpxw, g65816_op_and_dpxw, g65816_op_rol_dpxw, g65816_op_and_ildpyw, /* 3x */ g65816_op_sec, g65816_op_and_addryw, g65816_op_decw, g65816_op_tscn, /* 3x */ g65816_op_bit_addrxw, g65816_op_and_addrxw, g65816_op_rol_addrxw, g65816_op_and_longxw, + +/* 4x */ g65816_op_rtin, g65816_op_eor_idpxw, g65816_op_wdm, g65816_op_eor_srw, /* 4x */ g65816_op_mvp, g65816_op_eor_dpw, g65816_op_lsr_dpw, g65816_op_eor_ildpw, /* 4x */ g65816_op_phaw, g65816_op_eor_constw, g65816_op_lsrw, g65816_op_phk, /* 4x */ g65816_op_jmp_addr, g65816_op_eor_addrw, g65816_op_lsr_addrw, g65816_op_eor_longw, +/* 5x */ g65816_op_bvc, g65816_op_eor_idpyw, g65816_op_eor_idpw, g65816_op_eor_isryw, /* 5x */ g65816_op_mvn, g65816_op_eor_dpxw, g65816_op_lsr_dpxw, g65816_op_eor_ildpyw, /* 5x */ g65816_op_cli, g65816_op_eor_addryw, g65816_op_phyb, g65816_op_tcd, /* 5x */ g65816_op_jmp_long, g65816_op_eor_addrxw, g65816_op_lsr_addrxw, g65816_op_eor_longxw, +/* 6x */ g65816_op_rts, g65816_op_adc_idpxw, g65816_op_per, g65816_op_adc_srw, /* 6x */ g65816_op_stz_dpw, g65816_op_adc_dpw, g65816_op_ror_dpw, g65816_op_adc_ildpw, /* 6x */ g65816_op_plaw, g65816_op_adc_constw, g65816_op_rorw, g65816_op_rtl, /* 6x */ g65816_op_jmp_iaddr, g65816_op_adc_addrw, g65816_op_ror_addrw, g65816_op_adc_longw, +/* 7x */ g65816_op_bvs, g65816_op_adc_idpyw, g65816_op_adc_idpw, g65816_op_adc_isryw, /* 7x */ g65816_op_stz_dpxw, g65816_op_adc_dpxw, g65816_op_ror_dpxw, g65816_op_adc_ildpyw, /* 7x */ g65816_op_sei, g65816_op_adc_addryw, g65816_op_plyb, g65816_tdc, /* 7x */ g65816_op_jmp_iaddrx, g65816_op_adc_addrxw, g65816_op_ror_addrxw, g65816_op_adc_longxw, + +/* 8x */ g65816_op_bra, g65816_op_sta_idpxw, g65816_op_brl, g65816_op_sta_srw, /* 8x */ g65816_op_sty_dpb, g65816_op_sta_dpw, g65816_op_stx_dpb, g65816_op_sta_ildpw, /* 8x */ g65816_op_deyb, g65816_op_bit_constw, g65816_op_txaw, g65816_op_phb, /* 8x */ g65816_op_sty_addrb, g65816_op_sta_addrw, g65816_op_stx_addrb, g65816_op_sta_longw, +/* 9x */ g65816_op_bcc, g65816_op_sta_idpyw, g65816_op_sta_idpw, g65816_op_sta_isryw, /* 9x */ g65816_op_sty_dpxb, g65816_op_sta_dpxw, g65816_op_stx_dpyb, g65816_op_sta_ildpyw, /* 9x */ g65816_op_tyaw, g65816_op_sta_addryw, g65816_op_txsb, g65816_op_txyb, /* 9x */ g65816_op_stz_addrw, g65816_op_sta_addrxw, g65816_op_stz_addrxw, g65816_op_sta_longxw, +/* ax */ g65816_op_ldy_constb, g65816_op_lda_idpxw, g65816_op_ldx_constb, g65816_op_lda_srw, /* ax */ g65816_op_ldy_dpb, g65816_op_lda_dpw, g65816_op_ldx_dpb, g65816_op_lda_ildpw, /* ax */ g65816_op_tayb, g65816_op_lda_constw, g65816_op_taxb, g65816_op_plb, /* ax */ g65816_op_ldy_addrb, g65816_op_lda_addrw, g65816_op_ldx_addrb, g65816_op_lda_longw, +/* bx */ g65816_op_bcs, g65816_op_lda_idpyw, g65816_op_lda_idpw, g65816_op_lda_isryw, /* bx */ g65816_op_ldy_dpxb, g65816_op_lda_dpxw, g65816_op_ldx_dpyb, g65816_op_lda_ildpyw, /* bx */ g65816_op_clv, g65816_op_lda_addryw, g65816_op_tsxb, g65816_op_tyxb, /* bx */ g65816_op_ldy_addrxb, g65816_op_lda_addrxw, g65816_op_ldx_addryb, g65816_op_lda_longxw, + +/* cx */ g65816_op_cpy_constb, g65816_op_cmp_idpxw, g65816_op_rep, g65816_op_cmp_srw, /* cx */ g65816_op_cpy_dpb, g65816_op_cmp_dpw, g65816_op_dec_dpw, g65816_op_cmp_ildpw, /* cx */ g65816_op_inyb, g65816_op_cmp_constw, g65816_op_dexb, g65816_op_wai, /* cx */ g65816_op_cpy_addrb, g65816_op_cmp_addrw, g65816_op_dec_addrw, g65816_op_cmp_longw, +/* dx */ g65816_op_bne, g65816_op_cmp_idpyw, g65816_op_cmp_idpw, g65816_op_cmp_isryw, /* dx */ g65816_op_pei, g65816_op_cmp_dpxw, g65816_op_dec_dpxw, g65816_op_cmp_ildpyw, /* dx */ g65816_op_cld, g65816_op_cmp_addryw, g65816_op_phxb, g65816_op_stp, /* dx */ g65816_op_jmp_iladdr, g65816_op_cmp_addrxw, g65816_op_dec_addrxw, g65816_op_cmp_longxw, +/* ex */ g65816_op_cpx_constb, g65816_op_sbc_idpxw, g65816_op_sep, g65816_op_sbc_srw, /* ex */ g65816_op_cpx_dpb, g65816_op_sbc_dpw, g65816_op_inc_dpw, g65816_op_sbc_ildpw, /* ex */ g65816_op_inxb, g65816_op_sbc_constw, g65816_op_nop, g65816_op_xba, /* ex */ g65816_op_cpx_addrb, g65816_op_sbc_addrw, g65816_op_inc_addrw, g65816_op_sbc_longw, +/* fx */ g65816_op_beq, g65816_op_sbc_idpyw, g65816_op_sbc_idpw, g65816_op_sbc_isryw, /* fx */ g65816_op_pea, g65816_op_sbc_dpxw, g65816_op_inc_dpxw, g65816_op_sbc_ildpyw, /* fx */ g65816_op_sed, g65816_op_sbc_addryw, g65816_op_plxb, g65816_op_xce, /* fx */ g65816_op_jsr_iaddrx, g65816_op_sbc_addrxw, g65816_op_inc_addrxw, g65816_op_sbc_longxw +}; + +vfunc g65816_optbl_mx[256] = { // g65816_optbl_mx, g65816_optbl_mx, g65816_optbl_mx, + // ----------------------x0, ----------------------x1, ----------------------x2, ----------------------x3, -------- ----------------------x4, ----------------------x5, ----------------------x6, ----------------------x7, -------- ----------------------x8, ----------------------x9, ----------------------xa, ----------------------xb, -------- ----------------------xc, ----------------------xd, ----------------------xe, ----------------------xf, +/* 0x */ g65816_op_brkn, g65816_op_ora_idpxw, g65816_op_copn, g65816_op_ora_srw, /* 0x */ g65816_op_tsb_dpw, g65816_op_ora_dpw, g65816_op_asl_dpw, g65816_op_ora_ildpw, /* 0x */ g65816_op_php, g65816_op_ora_constw, g65816_op_aslw, g65816_op_phd, /* 0x */ g65816_op_tsb_addrw, g65816_op_ora_addrw, g65816_op_asl_addrw, g65816_op_ora_longw, +/* 1x */ g65816_op_bpl, g65816_op_ora_idpyw, g65816_op_ora_idpw, g65816_op_ora_isryw, /* 1x */ g65816_op_trb_dpw, g65816_op_ora_dpxw, g65816_op_asl_dpxw, g65816_op_ora_ildpyw, /* 1x */ g65816_op_clc, g65816_op_ora_addryw, g65816_op_incw, g65816_op_tcsn, /* 1x */ g65816_op_trb_addrw, g65816_op_ora_addrxw, g65816_op_asl_addrxw, g65816_op_ora_longxw, +/* 2x */ g65816_op_jsr_addr, g65816_op_and_idpxw, g65816_op_jsr_long, g65816_op_and_srw, /* 2x */ g65816_op_bit_dpw, g65816_op_and_dpw, g65816_op_rol_dpw, g65816_op_and_ildpw, /* 2x */ g65816_op_plp, g65816_op_and_constw, g65816_op_rolw, g65816_op_pld, /* 2x */ g65816_op_bit_addrw, g65816_op_and_addrw, g65816_op_rol_addrw, g65816_op_and_longw, +/* 3x */ g65816_op_bmi, g65816_op_and_idpyw, g65816_op_and_idpw, g65816_op_and_isryw, /* 3x */ g65816_op_bit_dpxw, g65816_op_and_dpxw, g65816_op_rol_dpxw, g65816_op_and_ildpyw, /* 3x */ g65816_op_sec, g65816_op_and_addryw, g65816_op_decw, g65816_op_tscn, /* 3x */ g65816_op_bit_addrxw, g65816_op_and_addrxw, g65816_op_rol_addrxw, g65816_op_and_longxw, + +/* 4x */ g65816_op_rtin, g65816_op_eor_idpxw, g65816_op_wdm, g65816_op_eor_srw, /* 4x */ g65816_op_mvp, g65816_op_eor_dpw, g65816_op_lsr_dpw, g65816_op_eor_ildpw, /* 4x */ g65816_op_phaw, g65816_op_eor_constw, g65816_op_lsrw, g65816_op_phk, /* 4x */ g65816_op_jmp_addr, g65816_op_eor_addrw, g65816_op_lsr_addrw, g65816_op_eor_longw, +/* 5x */ g65816_op_bvc, g65816_op_eor_idpyw, g65816_op_eor_idpw, g65816_op_eor_isryw, /* 5x */ g65816_op_mvn, g65816_op_eor_dpxw, g65816_op_lsr_dpxw, g65816_op_eor_ildpyw, /* 5x */ g65816_op_cli, g65816_op_eor_addryw, g65816_op_phyw, g65816_op_tcd, /* 5x */ g65816_op_jmp_long, g65816_op_eor_addrxw, g65816_op_lsr_addrxw, g65816_op_eor_longxw, +/* 6x */ g65816_op_rts, g65816_op_adc_idpxw, g65816_op_per, g65816_op_adc_srw, /* 6x */ g65816_op_stz_dpw, g65816_op_adc_dpw, g65816_op_ror_dpw, g65816_op_adc_ildpw, /* 6x */ g65816_op_plaw, g65816_op_adc_constw, g65816_op_rorw, g65816_op_rtl, /* 6x */ g65816_op_jmp_iaddr, g65816_op_adc_addrw, g65816_op_ror_addrw, g65816_op_adc_longw, +/* 7x */ g65816_op_bvs, g65816_op_adc_idpyw, g65816_op_adc_idpw, g65816_op_adc_isryw, /* 7x */ g65816_op_stz_dpxw, g65816_op_adc_dpxw, g65816_op_ror_dpxw, g65816_op_adc_ildpyw, /* 7x */ g65816_op_sei, g65816_op_adc_addryw, g65816_op_plyw, g65816_tdc, /* 7x */ g65816_op_jmp_iaddrx, g65816_op_adc_addrxw, g65816_op_ror_addrxw, g65816_op_adc_longxw, + +/* 8x */ g65816_op_bra, g65816_op_sta_idpxw, g65816_op_brl, g65816_op_sta_srw, /* 8x */ g65816_op_sty_dpw, g65816_op_sta_dpw, g65816_op_stx_dpw, g65816_op_sta_ildpw, /* 8x */ g65816_op_deyw, g65816_op_bit_constw, g65816_op_txaw, g65816_op_phb, /* 8x */ g65816_op_sty_addrw, g65816_op_sta_addrw, g65816_op_stx_addrw, g65816_op_sta_longw, +/* 9x */ g65816_op_bcc, g65816_op_sta_idpyw, g65816_op_sta_idpw, g65816_op_sta_isryw, /* 9x */ g65816_op_sty_dpxw, g65816_op_sta_dpxw, g65816_op_stx_dpyw, g65816_op_sta_ildpyw, /* 9x */ g65816_op_tyaw, g65816_op_sta_addryw, g65816_op_txsw, g65816_op_txyw, /* 9x */ g65816_op_stz_addrw, g65816_op_sta_addrxw, g65816_op_stz_addrxw, g65816_op_sta_longxw, +/* ax */ g65816_op_ldy_constw, g65816_op_lda_idpxw, g65816_op_ldx_constw, g65816_op_lda_srw, /* ax */ g65816_op_ldy_dpw, g65816_op_lda_dpw, g65816_op_ldx_dpw, g65816_op_lda_ildpw, /* ax */ g65816_op_tayw, g65816_op_lda_constw, g65816_op_taxw, g65816_op_plb, /* ax */ g65816_op_ldy_addrw, g65816_op_lda_addrw, g65816_op_ldx_addrw, g65816_op_lda_longw, +/* bx */ g65816_op_bcs, g65816_op_lda_idpyw, g65816_op_lda_idpw, g65816_op_lda_isryw, /* bx */ g65816_op_ldy_dpxw, g65816_op_lda_dpxw, g65816_op_ldx_dpyw, g65816_op_lda_ildpyw, /* bx */ g65816_op_clv, g65816_op_lda_addryw, g65816_op_tsxw, g65816_op_tyxw, /* bx */ g65816_op_ldy_addrxw, g65816_op_lda_addrxw, g65816_op_ldx_addryw, g65816_op_lda_longxw, + +/* cx */ g65816_op_cpy_constw, g65816_op_cmp_idpxw, g65816_op_rep, g65816_op_cmp_srw, /* cx */ g65816_op_cpy_dpw, g65816_op_cmp_dpw, g65816_op_dec_dpw, g65816_op_cmp_ildpw, /* cx */ g65816_op_inyw, g65816_op_cmp_constw, g65816_op_dexw, g65816_op_wai, /* cx */ g65816_op_cpy_addrw, g65816_op_cmp_addrw, g65816_op_dec_addrw, g65816_op_cmp_longw, +/* dx */ g65816_op_bne, g65816_op_cmp_idpyw, g65816_op_cmp_idpw, g65816_op_cmp_isryw, /* dx */ g65816_op_pei, g65816_op_cmp_dpxw, g65816_op_dec_dpxw, g65816_op_cmp_ildpyw, /* dx */ g65816_op_cld, g65816_op_cmp_addryw, g65816_op_phxw, g65816_op_stp, /* dx */ g65816_op_jmp_iladdr, g65816_op_cmp_addrxw, g65816_op_dec_addrxw, g65816_op_cmp_longxw, +/* ex */ g65816_op_cpx_constw, g65816_op_sbc_idpxw, g65816_op_sep, g65816_op_sbc_srw, /* ex */ g65816_op_cpx_dpw, g65816_op_sbc_dpw, g65816_op_inc_dpw, g65816_op_sbc_ildpw, /* ex */ g65816_op_inxw, g65816_op_sbc_constw, g65816_op_nop, g65816_op_xba, /* ex */ g65816_op_cpx_addrw, g65816_op_sbc_addrw, g65816_op_inc_addrw, g65816_op_sbc_longw, +/* fx */ g65816_op_beq, g65816_op_sbc_idpyw, g65816_op_sbc_idpw, g65816_op_sbc_isryw, /* fx */ g65816_op_pea, g65816_op_sbc_dpxw, g65816_op_inc_dpxw, g65816_op_sbc_ildpyw, /* fx */ g65816_op_sed, g65816_op_sbc_addryw, g65816_op_plxw, g65816_op_xce, /* fx */ g65816_op_jsr_iaddrx, g65816_op_sbc_addrxw, g65816_op_inc_addrxw, g65816_op_sbc_longxw +}; diff --git a/bsnes/cpu/g65816_ops_adc.cpp b/bsnes/cpu/g65816_ops_adc.cpp new file mode 100644 index 00000000..06134a76 --- /dev/null +++ b/bsnes/cpu/g65816_ops_adc.cpp @@ -0,0 +1,345 @@ +#define bcd_add_adjust_byte() \ + if(gx816->regs.p & PF_D) { \ + if(((r ) & 15) > 9)r += 6; \ + if(((r >> 4) & 15) > 9)r += 6 << 4; \ + } + +#define bcd_add_adjust_word() \ + if(gx816->regs.p & PF_D) { \ + if(((r ) & 15) > 9)r += 6; \ + if(((r >> 4) & 15) > 9)r += 6 << 4; \ + if(((r >> 8) & 15) > 9)r += 6 << 8; \ + if(((r >> 12) & 15) > 9)r += 6 << 12; \ + } + +#define g65816_if_adc_b() \ +byte c = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); \ +int r = gx816->regs.a.b + c + (gx816->regs.p & PF_C); \ + bcd_add_adjust_byte() \ + g65816_testn(r & 0x80); \ + g65816_testv(~(gx816->regs.a.b ^ c) & (gx816->regs.a.b ^ (byte)r) & 0x80); \ + g65816_testz((byte)r == 0); \ + g65816_testc(r > 0xff); \ + gx816->regs.a.b = r + +#define g65816_if_adc_w() \ +word c = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); \ +int r = gx816->regs.a.w + c + (gx816->regs.p & PF_C); \ + bcd_add_adjust_word() \ + g65816_testn(r & 0x8000); \ + g65816_testv(~(gx816->regs.a.w ^ c) & (gx816->regs.a.w ^ (word)r) & 0x8000); \ + g65816_testz((word)r == 0); \ + g65816_testc(r > 0xffff); \ + gx816->regs.a.w = r + +void g65816_op_adc_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + g65816_if_adc_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_adc_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + g65816_if_adc_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_adc_addrxb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + g65816_if_adc_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_adc_addrxw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + g65816_if_adc_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_adc_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + g65816_if_adc_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_adc_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + g65816_if_adc_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_adc_idpb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDP); + g65816_if_adc_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_adc_idpw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDP); + g65816_if_adc_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_adc_ildpb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDP); + g65816_if_adc_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_adc_ildpw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDP); + g65816_if_adc_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_adc_longb(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONG); + g65816_if_adc_b(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_adc_longw(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONG); + g65816_if_adc_w(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_adc_longxb(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONGX); + g65816_if_adc_b(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_adc_longxw(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONGX); + g65816_if_adc_w(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_adc_addryb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRY); + g65816_if_adc_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_adc_addryw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRY); + g65816_if_adc_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_adc_dpxb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + g65816_if_adc_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_adc_dpxw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + g65816_if_adc_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_adc_idpxb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPX); + g65816_if_adc_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_adc_idpxw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPX); + g65816_if_adc_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_adc_idpyb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPY); + g65816_if_adc_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2 | TIMING_CONDITION4); +} + +void g65816_op_adc_idpyw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPY); + g65816_if_adc_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2 | TIMING_CONDITION4); +} + +void g65816_op_adc_ildpyb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDPY); + g65816_if_adc_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_adc_ildpyw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDPY); + g65816_if_adc_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_adc_srb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_SR); + g65816_if_adc_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_adc_srw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_SR); + g65816_if_adc_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_adc_isryb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_ISRY); + g65816_if_adc_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_adc_isryw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_ISRY); + g65816_if_adc_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_adc_constb(void) { +g65816_prefetch(1); +int r = gx816->regs.a.b + arg + (gx816->regs.p & PF_C); + bcd_add_adjust_byte() + g65816_testn(r & 0x80); + g65816_testv(~(gx816->regs.a.b ^ arg) & (gx816->regs.a.b ^ (byte)r) & 0x80); + g65816_testz((byte)r == 0); + g65816_testc(r > 0xff); + gx816->regs.a.b = r; + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); +} + +void g65816_op_adc_constw(void) { +g65816_prefetch(2); +int r = gx816->regs.a.w + arg + (gx816->regs.p & PF_C); + bcd_add_adjust_word() + g65816_testn(r & 0x8000); + g65816_testv(~(gx816->regs.a.w ^ arg) & (gx816->regs.a.w ^ (word)r) & 0x8000); + g65816_testz((word)r == 0); + g65816_testc(r > 0xffff); + gx816->regs.a.w = r; + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); +} diff --git a/bsnes/cpu/g65816_ops_and.cpp b/bsnes/cpu/g65816_ops_and.cpp new file mode 100644 index 00000000..4ea42256 --- /dev/null +++ b/bsnes/cpu/g65816_ops_and.cpp @@ -0,0 +1,335 @@ +#define g65816_flags_and_b() g65816_testn(gx816->regs.a.b & 0x80); g65816_testz(gx816->regs.a.b == 0) +#define g65816_flags_and_w() g65816_testn(gx816->regs.a.w & 0x8000); g65816_testz(gx816->regs.a.w == 0) + +#define g65816_inst_and_b() gx816->regs.a.b &= gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr) +#define g65816_inst_and_w() gx816->regs.a.w &= gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr) + +void g65816_op_and_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + g65816_inst_and_b(); + g65816_flags_and_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_and_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + g65816_inst_and_w(); + g65816_flags_and_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_and_addrxb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + g65816_inst_and_b(); + g65816_flags_and_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_and_addrxw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + g65816_inst_and_w(); + g65816_flags_and_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_and_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + g65816_inst_and_b(); + g65816_flags_and_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_and_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + g65816_inst_and_w(); + g65816_flags_and_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_and_idpb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDP); + g65816_inst_and_b(); + g65816_flags_and_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_and_idpw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDP); + g65816_inst_and_w(); + g65816_flags_and_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_and_ildpb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDP); + g65816_inst_and_b(); + g65816_flags_and_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_and_ildpw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDP); + g65816_inst_and_w(); + g65816_flags_and_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_and_longb(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONG); + g65816_inst_and_b(); + g65816_flags_and_b(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_and_longw(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONG); + g65816_inst_and_w(); + g65816_flags_and_w(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_and_longxb(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONGX); + g65816_inst_and_b(); + g65816_flags_and_b(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_and_longxw(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONGX); + g65816_inst_and_w(); + g65816_flags_and_w(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_and_addryb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRY); + g65816_inst_and_b(); + g65816_flags_and_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_and_addryw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRY); + g65816_inst_and_w(); + g65816_flags_and_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_and_dpxb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + g65816_inst_and_b(); + g65816_flags_and_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_and_dpxw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + g65816_inst_and_w(); + g65816_flags_and_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_and_idpxb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPX); + g65816_inst_and_b(); + g65816_flags_and_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_and_idpxw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPX); + g65816_inst_and_w(); + g65816_flags_and_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_and_idpyb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPY); + g65816_inst_and_b(); + g65816_flags_and_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2 | TIMING_CONDITION4); +} + +void g65816_op_and_idpyw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPY); + g65816_inst_and_w(); + g65816_flags_and_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2 | TIMING_CONDITION4); +} + +void g65816_op_and_ildpyb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDPY); + g65816_inst_and_b(); + g65816_flags_and_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_and_ildpyw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDPY); + g65816_inst_and_w(); + g65816_flags_and_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_and_srb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_SR); + g65816_inst_and_b(); + g65816_flags_and_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_and_srw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_SR); + g65816_inst_and_w(); + g65816_flags_and_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_and_isryb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_ISRY); + g65816_inst_and_b(); + g65816_flags_and_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_and_isryw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_ISRY); + g65816_inst_and_w(); + g65816_flags_and_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_and_constb(void) { +g65816_prefetch(1); + gx816->regs.a.b &= arg; + g65816_flags_and_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); +} + +void g65816_op_and_constw(void) { +g65816_prefetch(2); + gx816->regs.a.w &= arg; + g65816_flags_and_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); +} diff --git a/bsnes/cpu/g65816_ops_cmp.cpp b/bsnes/cpu/g65816_ops_cmp.cpp new file mode 100644 index 00000000..9eabc22a --- /dev/null +++ b/bsnes/cpu/g65816_ops_cmp.cpp @@ -0,0 +1,321 @@ +#define g65816_flags_cmp_b() \ +byte c = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); \ +int r = gx816->regs.a.b - c; \ + g65816_testn(r & 0x80); \ + g65816_testz((byte)r == 0); \ + g65816_testc(r >= 0) + +#define g65816_flags_cmp_w() \ +word c = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); \ +int r = gx816->regs.a.w - c; \ + g65816_testn(r & 0x8000); \ + g65816_testz((word)r == 0); \ + g65816_testc(r >= 0) + +void g65816_op_cmp_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + g65816_flags_cmp_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_cmp_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + g65816_flags_cmp_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_cmp_addrxb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + g65816_flags_cmp_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_cmp_addrxw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + g65816_flags_cmp_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_cmp_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + g65816_flags_cmp_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_cmp_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + g65816_flags_cmp_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_cmp_idpb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDP); + g65816_flags_cmp_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_cmp_idpw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDP); + g65816_flags_cmp_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_cmp_ildpb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDP); + g65816_flags_cmp_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_cmp_ildpw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDP); + g65816_flags_cmp_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_cmp_longb(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONG); + g65816_flags_cmp_b(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_cmp_longw(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONG); + g65816_flags_cmp_w(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_cmp_longxb(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONGX); + g65816_flags_cmp_b(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_cmp_longxw(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONGX); + g65816_flags_cmp_w(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_cmp_addryb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRY); + g65816_flags_cmp_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_cmp_addryw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRY); + g65816_flags_cmp_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_cmp_dpxb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + g65816_flags_cmp_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_cmp_dpxw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + g65816_flags_cmp_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_cmp_idpxb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPX); + g65816_flags_cmp_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_cmp_idpxw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPX); + g65816_flags_cmp_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_cmp_idpyb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPY); + g65816_flags_cmp_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2 | TIMING_CONDITION4); +} + +void g65816_op_cmp_idpyw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPY); + g65816_flags_cmp_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2 | TIMING_CONDITION4); +} + +void g65816_op_cmp_ildpyb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDPY); + g65816_flags_cmp_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_cmp_ildpyw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDPY); + g65816_flags_cmp_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_cmp_srb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_SR); + g65816_flags_cmp_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_cmp_srw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_SR); + g65816_flags_cmp_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_cmp_isryb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_ISRY); + g65816_flags_cmp_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_cmp_isryw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_ISRY); + g65816_flags_cmp_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_cmp_constb(void) { +g65816_prefetch(1); +int r; + r = gx816->regs.a.b - arg; + g65816_testn(r & 0x80); + g65816_testz((byte)r == 0); + g65816_testc(r >= 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); +} + +void g65816_op_cmp_constw(void) { +g65816_prefetch(2); +int r; + r = gx816->regs.a.w - arg; + g65816_testn(r & 0x8000); + g65816_testz((word)r == 0); + g65816_testc(r >= 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); +} diff --git a/bsnes/cpu/g65816_ops_eor.cpp b/bsnes/cpu/g65816_ops_eor.cpp new file mode 100644 index 00000000..80932ee4 --- /dev/null +++ b/bsnes/cpu/g65816_ops_eor.cpp @@ -0,0 +1,335 @@ +#define g65816_flags_eor_b() g65816_testn(gx816->regs.a.b & 0x80); g65816_testz(gx816->regs.a.b == 0) +#define g65816_flags_eor_w() g65816_testn(gx816->regs.a.w & 0x8000); g65816_testz(gx816->regs.a.w == 0) + +#define g65816_inst_eor_b() gx816->regs.a.b ^= gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr) +#define g65816_inst_eor_w() gx816->regs.a.w ^= gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr) + +void g65816_op_eor_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + g65816_inst_eor_b(); + g65816_flags_eor_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_eor_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + g65816_inst_eor_w(); + g65816_flags_eor_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_eor_addrxb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + g65816_inst_eor_b(); + g65816_flags_eor_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_eor_addrxw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + g65816_inst_eor_w(); + g65816_flags_eor_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_eor_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + g65816_inst_eor_b(); + g65816_flags_eor_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_eor_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + g65816_inst_eor_w(); + g65816_flags_eor_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_eor_idpb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDP); + g65816_inst_eor_b(); + g65816_flags_eor_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_eor_idpw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDP); + g65816_inst_eor_w(); + g65816_flags_eor_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_eor_ildpb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDP); + g65816_inst_eor_b(); + g65816_flags_eor_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_eor_ildpw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDP); + g65816_inst_eor_w(); + g65816_flags_eor_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_eor_longb(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONG); + g65816_inst_eor_b(); + g65816_flags_eor_b(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_eor_longw(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONG); + g65816_inst_eor_w(); + g65816_flags_eor_w(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_eor_longxb(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONGX); + g65816_inst_eor_b(); + g65816_flags_eor_b(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_eor_longxw(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONGX); + g65816_inst_eor_w(); + g65816_flags_eor_w(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_eor_addryb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRY); + g65816_inst_eor_b(); + g65816_flags_eor_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_eor_addryw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRY); + g65816_inst_eor_w(); + g65816_flags_eor_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_eor_dpxb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + g65816_inst_eor_b(); + g65816_flags_eor_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_eor_dpxw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + g65816_inst_eor_w(); + g65816_flags_eor_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_eor_idpxb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPX); + g65816_inst_eor_b(); + g65816_flags_eor_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_eor_idpxw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPX); + g65816_inst_eor_w(); + g65816_flags_eor_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_eor_idpyb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPY); + g65816_inst_eor_b(); + g65816_flags_eor_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2 | TIMING_CONDITION4); +} + +void g65816_op_eor_idpyw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPY); + g65816_inst_eor_w(); + g65816_flags_eor_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2 | TIMING_CONDITION4); +} + +void g65816_op_eor_ildpyb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDPY); + g65816_inst_eor_b(); + g65816_flags_eor_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_eor_ildpyw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDPY); + g65816_inst_eor_w(); + g65816_flags_eor_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_eor_srb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_SR); + g65816_inst_eor_b(); + g65816_flags_eor_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_eor_srw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_SR); + g65816_inst_eor_w(); + g65816_flags_eor_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_eor_isryb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_ISRY); + g65816_inst_eor_b(); + g65816_flags_eor_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_eor_isryw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_ISRY); + g65816_inst_eor_w(); + g65816_flags_eor_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_eor_constb(void) { +g65816_prefetch(1); + gx816->regs.a.b ^= arg; + g65816_flags_eor_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); +} + +void g65816_op_eor_constw(void) { +g65816_prefetch(2); + gx816->regs.a.w ^= arg; + g65816_flags_eor_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); +} diff --git a/bsnes/cpu/g65816_ops_incdec.cpp b/bsnes/cpu/g65816_ops_incdec.cpp new file mode 100644 index 00000000..5abaa9c7 --- /dev/null +++ b/bsnes/cpu/g65816_ops_incdec.cpp @@ -0,0 +1,355 @@ +/*********** + *** inc *** + **********/ + +void g65816_op_incb(void) { + gx816->regs.a.b++; + g65816_testn(gx816->regs.a.b & 0x80); + g65816_testz(gx816->regs.a.b == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_incw(void) { + gx816->regs.a.w++; + g65816_testn(gx816->regs.a.w & 0x8000); + g65816_testz(gx816->regs.a.w == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_inc_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + m++; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_testn(m & 0x80); + g65816_testz(m == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_inc_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + m++; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_inc_addrxb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + m++; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_testn(m & 0x80); + g65816_testz(m == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_inc_addrxw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + m++; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_inc_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + m++; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_testn(m & 0x80); + g65816_testz(m == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_REGD); +} + +void g65816_op_inc_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + m++; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_REGD); +} + +void g65816_op_inc_dpxb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + m++; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_testn(m & 0x80); + g65816_testz(m == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2, TIMING_REGD); +} + +void g65816_op_inc_dpxw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + m++; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(2, TIMING_REGD); +} + +/*********** + *** inx *** + **********/ + +void g65816_op_inxb(void) { + gx816->regs.x = (gx816->regs.x + 1) & 0xff; + g65816_testn(gx816->regs.x & 0x80); + g65816_testz((gx816->regs.x & 0xff) == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_inxw(void) { + gx816->regs.x += 1; + g65816_testn(gx816->regs.x & 0x8000); + g65816_testz(gx816->regs.x == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +/*********** + *** iny *** + **********/ + +void g65816_op_inyb(void) { + gx816->regs.y = (gx816->regs.y + 1) & 0xff; + g65816_testn(gx816->regs.y & 0x80); + g65816_testz((gx816->regs.y & 0xff) == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_inyw(void) { + gx816->regs.y += 1; + g65816_testn(gx816->regs.y & 0x8000); + g65816_testz(gx816->regs.y == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +/*********** + *** dec *** + **********/ + +void g65816_op_decb(void) { + gx816->regs.a.b--; + g65816_testn(gx816->regs.a.b & 0x80); + g65816_testz(gx816->regs.a.b == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_decw(void) { + gx816->regs.a.w--; + g65816_testn(gx816->regs.a.w & 0x8000); + g65816_testz(gx816->regs.a.w == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_dec_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + m--; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_testn(m & 0x80); + g65816_testz(m == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_dec_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + m--; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_dec_addrxb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + m--; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_testn(m & 0x80); + g65816_testz(m == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_dec_addrxw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + m--; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_dec_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + m--; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_testn(m & 0x80); + g65816_testz(m == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_REGD); +} + +void g65816_op_dec_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + m--; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_REGD); +} + +void g65816_op_dec_dpxb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + m--; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_testn(m & 0x80); + g65816_testz(m == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2, TIMING_REGD); +} + +void g65816_op_dec_dpxw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + m--; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(2, TIMING_REGD); +} + +/*********** + *** dex *** + **********/ + +void g65816_op_dexb(void) { + gx816->regs.x = (gx816->regs.x - 1) & 0xff; + g65816_testn(gx816->regs.x & 0x80); + g65816_testz((gx816->regs.x & 0xff) == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_dexw(void) { + gx816->regs.x -= 1; + g65816_testn(gx816->regs.x & 0x8000); + g65816_testz(gx816->regs.x == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +/*********** + *** dey *** + **********/ + +void g65816_op_deyb(void) { + gx816->regs.y = (gx816->regs.y - 1) & 0xff; + g65816_testn(gx816->regs.y & 0x80); + g65816_testz((gx816->regs.y & 0xff) == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_deyw(void) { + gx816->regs.y -= 1; + g65816_testn(gx816->regs.y & 0x8000); + g65816_testz(gx816->regs.y == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} diff --git a/bsnes/cpu/g65816_ops_lda.cpp b/bsnes/cpu/g65816_ops_lda.cpp new file mode 100644 index 00000000..289285cd --- /dev/null +++ b/bsnes/cpu/g65816_ops_lda.cpp @@ -0,0 +1,335 @@ +#define g65816_flags_lda_b() g65816_testn(gx816->regs.a.b & 0x80); g65816_testz(gx816->regs.a.b == 0) +#define g65816_flags_lda_w() g65816_testn(gx816->regs.a.w & 0x8000); g65816_testz(gx816->regs.a.w == 0) + +#define g65816_set_lda_b() gx816->regs.a.b = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr) +#define g65816_set_lda_w() gx816->regs.a.w = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr) + +void g65816_op_lda_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + g65816_set_lda_b(); + g65816_flags_lda_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_lda_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + g65816_set_lda_w(); + g65816_flags_lda_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_lda_addrxb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + g65816_set_lda_b(); + g65816_flags_lda_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_lda_addrxw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + g65816_set_lda_w(); + g65816_flags_lda_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_lda_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + g65816_set_lda_b(); + g65816_flags_lda_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_lda_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + g65816_set_lda_w(); + g65816_flags_lda_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_lda_idpb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDP); + g65816_set_lda_b(); + g65816_flags_lda_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_lda_idpw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDP); + g65816_set_lda_w(); + g65816_flags_lda_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_lda_ildpb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDP); + g65816_set_lda_b(); + g65816_flags_lda_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_lda_ildpw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDP); + g65816_set_lda_w(); + g65816_flags_lda_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_lda_longb(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONG); + g65816_set_lda_b(); + g65816_flags_lda_b(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_lda_longw(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONG); + g65816_set_lda_w(); + g65816_flags_lda_w(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_lda_longxb(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONGX); + g65816_set_lda_b(); + g65816_flags_lda_b(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_lda_longxw(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONGX); + g65816_set_lda_w(); + g65816_flags_lda_w(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_lda_addryb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRY); + g65816_set_lda_b(); + g65816_flags_lda_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_lda_addryw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRY); + g65816_set_lda_w(); + g65816_flags_lda_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_lda_dpxb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + g65816_set_lda_b(); + g65816_flags_lda_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_lda_dpxw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + g65816_set_lda_w(); + g65816_flags_lda_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_lda_idpxb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPX); + g65816_set_lda_b(); + g65816_flags_lda_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_lda_idpxw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPX); + g65816_set_lda_w(); + g65816_flags_lda_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_lda_idpyb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPY); + g65816_set_lda_b(); + g65816_flags_lda_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2 | TIMING_CONDITION4); +} + +void g65816_op_lda_idpyw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPY); + g65816_set_lda_w(); + g65816_flags_lda_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2 | TIMING_CONDITION4); +} + +void g65816_op_lda_ildpyb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDPY); + g65816_set_lda_b(); + g65816_flags_lda_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_lda_ildpyw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDPY); + g65816_set_lda_w(); + g65816_flags_lda_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_lda_srb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_SR); + g65816_set_lda_b(); + g65816_flags_lda_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_lda_srw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_SR); + g65816_set_lda_w(); + g65816_flags_lda_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_lda_isryb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_ISRY); + g65816_set_lda_b(); + g65816_flags_lda_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_lda_isryw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_ISRY); + g65816_set_lda_w(); + g65816_flags_lda_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_lda_constb(void) { +g65816_prefetch(1); + gx816->regs.a.b = arg; + g65816_flags_lda_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); +} + +void g65816_op_lda_constw(void) { +g65816_prefetch(2); + gx816->regs.a.w = arg; + g65816_flags_lda_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); +} diff --git a/bsnes/cpu/g65816_ops_misc.cpp b/bsnes/cpu/g65816_ops_misc.cpp new file mode 100644 index 00000000..6737a35f --- /dev/null +++ b/bsnes/cpu/g65816_ops_misc.cpp @@ -0,0 +1,1294 @@ +/*********** + *** bit *** + **********/ + +void g65816_op_bit_constb(void) { +g65816_prefetch(1); + g65816_testn(arg & 0x80); + g65816_testv(arg & 0x40); + g65816_testz((arg & gx816->regs.a.b) == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); +} + +void g65816_op_bit_constw(void) { +g65816_prefetch(2); + g65816_testn(arg & 0x8000); + g65816_testv(arg & 0x4000); + g65816_testz((arg & gx816->regs.a.w) == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); +} + +void g65816_op_bit_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + arg = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testn(arg & 0x80); + g65816_testv(arg & 0x40); + g65816_testz((arg & gx816->regs.a.b) == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_bit_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + arg = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testn(arg & 0x8000); + g65816_testv(arg & 0x4000); + g65816_testz((arg & gx816->regs.a.w) == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_bit_addrxb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + arg = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testn(arg & 0x80); + g65816_testv(arg & 0x40); + g65816_testz((arg & gx816->regs.a.b) == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_bit_addrxw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + arg = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testn(arg & 0x8000); + g65816_testv(arg & 0x4000); + g65816_testz((arg & gx816->regs.a.w) == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_bit_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + arg = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testn(arg & 0x80); + g65816_testv(arg & 0x40); + g65816_testz((arg & gx816->regs.a.b) == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_bit_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + arg = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testn(arg & 0x8000); + g65816_testv(arg & 0x4000); + g65816_testz((arg & gx816->regs.a.w) == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_bit_dpxb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + arg = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testn(arg & 0x80); + g65816_testv(arg & 0x40); + g65816_testz((arg & gx816->regs.a.b) == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_bit_dpxw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + arg = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testn(arg & 0x8000); + g65816_testv(arg & 0x4000); + g65816_testz((arg & gx816->regs.a.w) == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +/*********** + *** cpx *** + **********/ + +void g65816_op_cpx_constb(void) { +g65816_prefetch(1); +int r = gx816->regs.x - arg; + g65816_testn(r & 0x80); + g65816_testz((byte)r == 0); + g65816_testc(r >= 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); +} + +void g65816_op_cpx_constw(void) { +g65816_prefetch(2); +int r = gx816->regs.x - arg; + g65816_testn(r & 0x8000); + g65816_testz((word)r == 0); + g65816_testc(r >= 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); +} + +void g65816_op_cpx_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +int r = gx816->regs.x - gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testn(r & 0x80); + g65816_testz((byte)r == 0); + g65816_testc(r >= 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_cpx_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +int r = gx816->regs.x - gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testn(r & 0x8000); + g65816_testz((word)r == 0); + g65816_testc(r >= 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_cpx_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +int r = gx816->regs.x - gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testn(r & 0x80); + g65816_testz((byte)r == 0); + g65816_testc(r >= 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_cpx_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +int r = gx816->regs.x - gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testn(r & 0x8000); + g65816_testz((word)r == 0); + g65816_testc(r >= 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +/*********** + *** cpy *** + **********/ + +void g65816_op_cpy_constb(void) { +g65816_prefetch(1); +int r = gx816->regs.y - arg; + g65816_testn(r & 0x80); + g65816_testz((byte)r == 0); + g65816_testc(r >= 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); +} + +void g65816_op_cpy_constw(void) { +g65816_prefetch(2); +int r = gx816->regs.y - arg; + g65816_testn(r & 0x8000); + g65816_testz((word)r == 0); + g65816_testc(r >= 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); +} + +void g65816_op_cpy_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +int r = gx816->regs.y - gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testn(r & 0x80); + g65816_testz((byte)r == 0); + g65816_testc(r >= 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_cpy_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +int r = gx816->regs.y - gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testn(r & 0x8000); + g65816_testz((word)r == 0); + g65816_testc(r >= 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_cpy_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +int r = gx816->regs.y - gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testn(r & 0x80); + g65816_testz((byte)r == 0); + g65816_testc(r >= 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_cpy_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +int r = gx816->regs.y - gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testn(r & 0x8000); + g65816_testz((word)r == 0); + g65816_testc(r >= 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +/*********** + *** ldx *** + **********/ + +void g65816_op_ldx_constb(void) { +g65816_prefetch(1); + gx816->regs.x = arg; + g65816_testn(gx816->regs.x & 0x80); + g65816_testz(gx816->regs.x == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); +} + +void g65816_op_ldx_constw(void) { +g65816_prefetch(2); + gx816->regs.x = arg; + g65816_testn(gx816->regs.x & 0x8000); + g65816_testz(gx816->regs.x == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); +} + +void g65816_op_ldx_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + gx816->regs.x = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testn(gx816->regs.x & 0x80); + g65816_testz(gx816->regs.x == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_ldx_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + gx816->regs.x = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testn(gx816->regs.x & 0x8000); + g65816_testz(gx816->regs.x == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_ldx_addryb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRY); + gx816->regs.x = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testn(gx816->regs.x & 0x80); + g65816_testz(gx816->regs.x == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_ldx_addryw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRY); + gx816->regs.x = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testn(gx816->regs.x & 0x8000); + g65816_testz(gx816->regs.x == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_ldx_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + gx816->regs.x = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testn(gx816->regs.x & 0x80); + g65816_testz(gx816->regs.x == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_ldx_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + gx816->regs.x = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testn(gx816->regs.x & 0x8000); + g65816_testz(gx816->regs.x == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_ldx_dpyb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPY); + gx816->regs.x = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testn(gx816->regs.x & 0x80); + g65816_testz(gx816->regs.x == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_ldx_dpyw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPY); + gx816->regs.x = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testn(gx816->regs.x & 0x8000); + g65816_testz(gx816->regs.x == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +/*********** + *** ldy *** + **********/ + +void g65816_op_ldy_constb(void) { +g65816_prefetch(1); + gx816->regs.y = (gx816->regs.y & 0xff00) | arg; + g65816_testn(gx816->regs.y & 0x80); + g65816_testz(gx816->regs.y == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); +} + +void g65816_op_ldy_constw(void) { +g65816_prefetch(2); + gx816->regs.y = arg; + g65816_testn(gx816->regs.y & 0x8000); + g65816_testz(gx816->regs.y == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); +} + +void g65816_op_ldy_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + gx816->regs.y = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testn(gx816->regs.y & 0x80); + g65816_testz(gx816->regs.y == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_ldy_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + gx816->regs.y = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testn(gx816->regs.y & 0x8000); + g65816_testz(gx816->regs.y == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_ldy_addrxb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + gx816->regs.y = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testn(gx816->regs.y & 0x80); + g65816_testz(gx816->regs.y == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_ldy_addrxw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + gx816->regs.y = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testn(gx816->regs.y & 0x8000); + g65816_testz(gx816->regs.y == 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_ldy_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + gx816->regs.y = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testn(gx816->regs.y & 0x80); + g65816_testz(gx816->regs.y == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_ldy_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + gx816->regs.y = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testn(gx816->regs.y & 0x8000); + g65816_testz(gx816->regs.y == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_ldy_dpxb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + gx816->regs.y = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testn(gx816->regs.y & 0x80); + g65816_testz(gx816->regs.y == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_ldy_dpxw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + gx816->regs.y = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testn(gx816->regs.y & 0x8000); + g65816_testz(gx816->regs.y == 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +/*********** + *** stx *** + **********/ + +void g65816_op_stx_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, gx816->regs.x); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_stx_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, gx816->regs.x); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_stx_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, gx816->regs.x); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_stx_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, gx816->regs.x); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_stx_dpyb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPY); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, gx816->regs.x); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_stx_dpyw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPY); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, gx816->regs.x); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +/*********** + *** sty *** + **********/ + +void g65816_op_sty_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, gx816->regs.y); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_sty_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, gx816->regs.y); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_sty_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, gx816->regs.y); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_sty_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, gx816->regs.y); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_sty_dpxb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, gx816->regs.y); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_sty_dpxw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, gx816->regs.y); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +/*********** + *** stz *** + **********/ + +void g65816_op_stz_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_stz_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_stz_addrxb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_stz_addrxw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, 0); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_stz_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_stz_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_stz_dpxb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_stz_dpxw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, 0); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +/*********** + *** xba *** + **********/ + +void g65816_op_xba(void) { + gx816->regs.a.p.l ^= gx816->regs.a.p.h; + gx816->regs.a.p.h ^= gx816->regs.a.p.l; + gx816->regs.a.p.l ^= gx816->regs.a.p.h; + g65816_testn(gx816->regs.a.b & 0x80); + g65816_testz(gx816->regs.a.b == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(2); +} + +/*********** + *** trb *** + **********/ + +void g65816_op_trb_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testz((m & gx816->regs.a.b) == 0); + m &= ~gx816->regs.a.b; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_trb_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testz((m & gx816->regs.a.w) == 0); + m &= ~gx816->regs.a.w; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_trb_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testz((m & gx816->regs.a.b) == 0); + m &= ~gx816->regs.a.b; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_REGD); +} + +void g65816_op_trb_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testz((m & gx816->regs.a.w) == 0); + m &= ~gx816->regs.a.w; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_REGD); +} + +/*********** + *** tsb *** + **********/ + +void g65816_op_tsb_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testz((m & gx816->regs.a.b) == 0); + m |= gx816->regs.a.b; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_tsb_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testz((m & gx816->regs.a.w) == 0); + m |= gx816->regs.a.w; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_tsb_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testz((m & gx816->regs.a.b) == 0); + m |= gx816->regs.a.b; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_REGD); +} + +void g65816_op_tsb_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testz((m & gx816->regs.a.w) == 0); + m |= gx816->regs.a.w; + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_REGD); +} + +/*********** + *** mvn *** + **********/ + +void g65816_op_mvn(void) { +g65816_prefetch(2); +ulong sp, dp; +byte m; + if(gx816->regs.a.w != 0xffff) { + gx816->regs.a.w--; + dp = (arg) & 0xff; + sp = (arg >> 8) & 0xff; + dp = (dp << 16) | gx816->regs.y; + sp = (sp << 16) | gx816->regs.x; + m = gx816->mem_read(MEMMODE_LONG, MEMSIZE_BYTE, sp); + gx816->mem_write(MEMMODE_LONG, MEMSIZE_BYTE, dp, m); + gx816->regs.x++; + gx816->regs.y++; + if(gx816->regs.e == true || (gx816->regs.e == false && (gx816->regs.p & PF_X))) { + gx816->regs.x &= 0xff; + gx816->regs.y &= 0xff; + } + } + if(gx816->regs.a.w == 0xffff) { + g65816_incpc(3); + } + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, sp); + snes_time->add_cpu_mcycles(1, dp); + snes_time->add_cpu_icycles(2); +} + +/*********** + *** mvp *** + **********/ + +void g65816_op_mvp(void) { +g65816_prefetch(2); +ulong sp, dp; +byte m; + if(gx816->regs.a.w != 0xffff) { + gx816->regs.a.w--; + dp = (arg) & 0xff; + sp = (arg >> 8) & 0xff; + dp = (dp << 16) | gx816->regs.y; + sp = (sp << 16) | gx816->regs.x; + m = gx816->mem_read(MEMMODE_LONG, MEMSIZE_BYTE, sp); + gx816->mem_write(MEMMODE_LONG, MEMSIZE_BYTE, dp, m); + gx816->regs.x--; + gx816->regs.y--; + if(gx816->regs.e == true || (gx816->regs.e == false && (gx816->regs.p & PF_X))) { + gx816->regs.x &= 0xff; + gx816->regs.y &= 0xff; + } + } + if(gx816->regs.a.w == 0xffff) { + g65816_incpc(3); + } + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, sp); + snes_time->add_cpu_mcycles(1, dp); + snes_time->add_cpu_icycles(2); +} + +/*********** + *** brk *** + **********/ + +void g65816_op_brke(void) { + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(3); + snes_time->add_cpu_mcycles(2, 0x00ffe6); + g65816_incpc(2); + g65816_stackwrite(MEMSIZE_WORD, gx816->regs.pc); + g65816_stackwrite(MEMSIZE_BYTE, gx816->regs.p); + g65816_seti(); + g65816_clrd(); + gx816->regs.pc = gx816->mem_read(MEMMODE_LONG, MEMSIZE_WORD, 0x00ffe6); +} + +void g65816_op_brkn(void) { + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(4); + snes_time->add_cpu_mcycles(2, 0x00ffe6); + g65816_incpc(2); + g65816_stackwrite(MEMSIZE_LONG, gx816->regs.pc); + g65816_stackwrite(MEMSIZE_BYTE, gx816->regs.p); + g65816_seti(); + g65816_clrd(); + gx816->regs.pc = gx816->mem_read(MEMMODE_LONG, MEMSIZE_WORD, 0x00ffe6); +} + +/*********** + *** cop *** + **********/ + +void g65816_op_cope(void) { + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(3); + snes_time->add_cpu_mcycles(2, 0x00fff4); + g65816_incpc(2); + g65816_stackwrite(MEMSIZE_WORD, gx816->regs.pc); + g65816_stackwrite(MEMSIZE_BYTE, gx816->regs.p); + g65816_seti(); + g65816_clrd(); + gx816->regs.pc = gx816->mem_read(MEMMODE_LONG, MEMSIZE_WORD, 0x00fff4); +} + +void g65816_op_copn(void) { + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(4); + snes_time->add_cpu_mcycles(2, 0x00fff4); + g65816_incpc(2); + g65816_stackwrite(MEMSIZE_LONG, gx816->regs.pc); + g65816_stackwrite(MEMSIZE_BYTE, gx816->regs.p); + g65816_seti(); + g65816_clrd(); + gx816->regs.pc = gx816->mem_read(MEMMODE_LONG, MEMSIZE_WORD, 0x00fff4); +} + +/*********** + *** stp *** + **********/ + +void g65816_op_stp(void) { + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(2); + dprintf("* stp not implemented"); +} + +/*********** + *** wai *** + **********/ + +void g65816_op_wai(void) { +byte i = 0; + if(gx816->nmi_enabled == true)i = 1; + if((ppu.vcounter_enabled == true || ppu.hcounter_enabled == true) && !(gx816->regs.p & PF_I))i = 1; + if(gx816->wai_interrupt_occurred == true || i == 0) { + gx816->wai_interrupt_occurred = false; + g65816_incpc(1); + } + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(2); +} + +/*********** + *** xce *** + **********/ + +void g65816_op_xce(void) { +bool t = gx816->regs.e; + if(gx816->regs.p & PF_C)gx816->regs.e = true; + else gx816->regs.e = false; + g65816_setm(); + g65816_setx(); + if(t == true)g65816_setc(); + else g65816_clrc(); + + if(gx816->regs.e == true)gx816->regs.s = 0x0100 | (gx816->regs.s & 0xff); + + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +/*********** + *** nop *** + **********/ + +void g65816_op_nop(void) { + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +/*********** + *** wdm *** + **********/ + +void g65816_op_wdm(void) { + g65816_incpc(2); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +/***************************** + *** clear/set bit opcodes *** + ****************************/ + +void g65816_op_clc(void) { + g65816_clrc(); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_cld(void) { + g65816_clrd(); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_cli(void) { + g65816_clri(); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_clv(void) { + g65816_clrv(); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_sec(void) { + g65816_setc(); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_sed(void) { + g65816_setd(); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_sei(void) { + g65816_seti(); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_rep(void) { +g65816_prefetch(1); + gx816->regs.p &= ~arg; + g65816_incpc(2); + snes_time->add_cpu_pcycles(3); + + if(gx816->regs.e == true)gx816->regs.p |= 0x30; +} + +void g65816_op_sep(void) { +g65816_prefetch(1); + gx816->regs.p |= arg; + if(arg & 0x10) { + gx816->regs.x &= 0xff; + gx816->regs.y &= 0xff; + } + g65816_incpc(2); + snes_time->add_cpu_pcycles(3); +} + +/************************ + *** transfer opcodes *** + ***********************/ + +void g65816_op_taxb(void) { + gx816->regs.x = gx816->regs.a.b; + g65816_testn(gx816->regs.a.b & 0x80); + g65816_testz(gx816->regs.a.b == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_taxw(void) { + gx816->regs.x = gx816->regs.a.w; + g65816_testn(gx816->regs.a.w & 0x8000); + g65816_testz(gx816->regs.a.w == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_tayb(void) { + gx816->regs.y = gx816->regs.a.b; + g65816_testn(gx816->regs.a.b & 0x80); + g65816_testz(gx816->regs.a.b == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_tayw(void) { + gx816->regs.y = gx816->regs.a.w; + g65816_testn(gx816->regs.a.w & 0x8000); + g65816_testz(gx816->regs.a.w == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_tcd(void) { + gx816->regs.d = gx816->regs.a.w; + g65816_testn(gx816->regs.a.w & 0x8000); + g65816_testz(gx816->regs.a.w == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_tcse(void) { + gx816->regs.s = 0x0100 | gx816->regs.a.b; + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_tcsn(void) { + gx816->regs.s = gx816->regs.a.w; + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_tdc(void) { + gx816->regs.a.w = gx816->regs.d; + g65816_testn(gx816->regs.d & 0x8000); + g65816_testz(gx816->regs.d == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_tsce(void) { + gx816->regs.a.w = gx816->regs.s; + g65816_testn(gx816->regs.a.b & 0x80); + g65816_testz(gx816->regs.a.b == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_tscn(void) { + gx816->regs.a.w = gx816->regs.s; + g65816_testn(gx816->regs.a.w & 0x8000); + g65816_testz(gx816->regs.a.w == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_tsxb(void) { + gx816->regs.x = gx816->regs.s & 0xff; + g65816_testn(gx816->regs.s & 0x80); + g65816_testz((gx816->regs.s & 0xff) == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_tsxw(void) { + gx816->regs.x = gx816->regs.s; + g65816_testn(gx816->regs.s & 0x8000); + g65816_testz(gx816->regs.s == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_txab(void) { + gx816->regs.a.b = gx816->regs.x; + g65816_testn(gx816->regs.a.b & 0x80); + g65816_testz(gx816->regs.a.b == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_txaw(void) { + gx816->regs.a.w = gx816->regs.x; + g65816_testn(gx816->regs.a.w & 0x8000); + g65816_testz(gx816->regs.a.w == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_txsb(void) { + gx816->regs.s = gx816->regs.x; + g65816_testn(gx816->regs.x & 0x80); + g65816_testz((gx816->regs.x & 0xff) == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_txsw(void) { + gx816->regs.s = gx816->regs.x; + g65816_testn(gx816->regs.x & 0x8000); + g65816_testz(gx816->regs.x == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_txyb(void) { + gx816->regs.y = gx816->regs.x; + g65816_testn(gx816->regs.x & 0x80); + g65816_testz((gx816->regs.x & 0xff) == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_txyw(void) { + gx816->regs.y = gx816->regs.x; + g65816_testn(gx816->regs.x & 0x8000); + g65816_testz(gx816->regs.x == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_tyab(void) { + gx816->regs.a.b = gx816->regs.y; + g65816_testn(gx816->regs.a.b & 0x80); + g65816_testz(gx816->regs.a.b == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_tyaw(void) { + gx816->regs.a.w = gx816->regs.y; + g65816_testn(gx816->regs.a.w & 0x8000); + g65816_testz(gx816->regs.a.w == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_tyxb(void) { + gx816->regs.x = gx816->regs.y; + g65816_testn(gx816->regs.y & 0x80); + g65816_testz((gx816->regs.y & 0xff) == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_tyxw(void) { + gx816->regs.x = gx816->regs.y; + g65816_testn(gx816->regs.y & 0x8000); + g65816_testz(gx816->regs.y == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} diff --git a/bsnes/cpu/g65816_ops_ora.cpp b/bsnes/cpu/g65816_ops_ora.cpp new file mode 100644 index 00000000..f6aa2d75 --- /dev/null +++ b/bsnes/cpu/g65816_ops_ora.cpp @@ -0,0 +1,335 @@ +#define g65816_flags_ora_b() g65816_testn(gx816->regs.a.b & 0x80); g65816_testz(gx816->regs.a.b == 0) +#define g65816_flags_ora_w() g65816_testn(gx816->regs.a.w & 0x8000); g65816_testz(gx816->regs.a.w == 0) + +#define g65816_inst_ora_b() gx816->regs.a.b |= gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr) +#define g65816_inst_ora_w() gx816->regs.a.w |= gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr) + +void g65816_op_ora_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + g65816_inst_ora_b(); + g65816_flags_ora_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_ora_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + g65816_inst_ora_w(); + g65816_flags_ora_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_ora_addrxb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + g65816_inst_ora_b(); + g65816_flags_ora_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_ora_addrxw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + g65816_inst_ora_w(); + g65816_flags_ora_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_ora_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + g65816_inst_ora_b(); + g65816_flags_ora_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_ora_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + g65816_inst_ora_w(); + g65816_flags_ora_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_ora_idpb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDP); + g65816_inst_ora_b(); + g65816_flags_ora_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_ora_idpw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDP); + g65816_inst_ora_w(); + g65816_flags_ora_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_ora_ildpb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDP); + g65816_inst_ora_b(); + g65816_flags_ora_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_ora_ildpw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDP); + g65816_inst_ora_w(); + g65816_flags_ora_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_ora_longb(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONG); + g65816_inst_ora_b(); + g65816_flags_ora_b(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_ora_longw(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONG); + g65816_inst_ora_w(); + g65816_flags_ora_w(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_ora_longxb(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONGX); + g65816_inst_ora_b(); + g65816_flags_ora_b(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_ora_longxw(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONGX); + g65816_inst_ora_w(); + g65816_flags_ora_w(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_ora_addryb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRY); + g65816_inst_ora_b(); + g65816_flags_ora_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_ora_addryw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRY); + g65816_inst_ora_w(); + g65816_flags_ora_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_ora_dpxb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + g65816_inst_ora_b(); + g65816_flags_ora_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_ora_dpxw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + g65816_inst_ora_w(); + g65816_flags_ora_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_ora_idpxb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPX); + g65816_inst_ora_b(); + g65816_flags_ora_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_ora_idpxw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPX); + g65816_inst_ora_w(); + g65816_flags_ora_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_ora_idpyb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPY); + g65816_inst_ora_b(); + g65816_flags_ora_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2 | TIMING_CONDITION4); +} + +void g65816_op_ora_idpyw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPY); + g65816_inst_ora_w(); + g65816_flags_ora_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2 | TIMING_CONDITION4); +} + +void g65816_op_ora_ildpyb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDPY); + g65816_inst_ora_b(); + g65816_flags_ora_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_ora_ildpyw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDPY); + g65816_inst_ora_w(); + g65816_flags_ora_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_ora_srb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_SR); + g65816_inst_ora_b(); + g65816_flags_ora_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_ora_srw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_SR); + g65816_inst_ora_w(); + g65816_flags_ora_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_ora_isryb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_ISRY); + g65816_inst_ora_b(); + g65816_flags_ora_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_ora_isryw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_ISRY); + g65816_inst_ora_w(); + g65816_flags_ora_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_ora_constb(void) { +g65816_prefetch(1); + gx816->regs.a.b |= arg; + g65816_flags_ora_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); +} + +void g65816_op_ora_constw(void) { +g65816_prefetch(2); + gx816->regs.a.w |= arg; + g65816_flags_ora_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); +} diff --git a/bsnes/cpu/g65816_ops_pc.cpp b/bsnes/cpu/g65816_ops_pc.cpp new file mode 100644 index 00000000..efa52755 --- /dev/null +++ b/bsnes/cpu/g65816_ops_pc.cpp @@ -0,0 +1,223 @@ +/*********** + *** jmp *** + **********/ + +void g65816_op_jmp_addr(void) { +g65816_prefetch(2); + snes_time->add_cpu_pcycles(3); + gx816->regs.pc = (gx816->regs.pc & 0xff0000) | arg; +} + +void g65816_op_jmp_long(void) { +g65816_prefetch(3); + snes_time->add_cpu_pcycles(4); + gx816->regs.pc = arg; +} + +void g65816_op_jmp_iaddr(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_IADDR_PC); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + gx816->regs.pc = (gx816->regs.pc & 0xff0000) | gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); +} + +void g65816_op_jmp_iaddrx(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_IADDRX_PC); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1); + gx816->regs.pc = (gx816->regs.pc & 0xff0000) | gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); +} + +void g65816_op_jmp_iladdr(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ILADDR_PC); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(3, dest_addr); + gx816->regs.pc = gx816->mem_read(MEMMODE_NONE, MEMSIZE_LONG, dest_addr); +} + +/*********** + *** jsr *** + **********/ + +//Note: The address pushed onto the stack is one byte less than the operand size. +//Upon returning, the address counter is incremented one more to move to the next +//instruction. The third/fourth cycles store the pc address on the stack, before +//the second operand byte is read in. + +void g65816_op_jsr_addr(void) { +g65816_prefetch(2); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(1); + g65816_stackwrite(MEMSIZE_WORD, gx816->regs.pc + 2); + gx816->regs.pc = (gx816->regs.pc & 0xff0000) | arg; +} + +void g65816_op_jsr_long(void) { +g65816_prefetch(3); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_scycles(3); + snes_time->add_cpu_icycles(1); + g65816_stackwrite(MEMSIZE_LONG, gx816->regs.pc + 3); + gx816->regs.pc = arg; +} + +void g65816_op_jsr_iaddrx(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_IADDRX_PC); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(1); + g65816_stackwrite(MEMSIZE_WORD, gx816->regs.pc + 2); + gx816->regs.pc = (gx816->regs.pc & 0xff0000) | gx816->mem_read(MEMMODE_IADDRX_PC, MEMSIZE_WORD, arg); + snes_time->add_cpu_pcycles(2); +} + +/*********** + *** ret *** + **********/ + +void g65816_op_rtie(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(3); + gx816->regs.p = g65816_stackread(MEMSIZE_BYTE); + gx816->regs.pc = (gx816->regs.pc & 0xff0000) | g65816_stackread(MEMSIZE_WORD); + if(gx816->regs.p & PF_X) { gx816->regs.x &= 0xff; gx816->regs.y &= 0xff; } + gx816->regs.p &= ~ PF_I; + snes_time->add_cpu_icycles(2); +} + +void g65816_op_rtin(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(4); + gx816->regs.p = g65816_stackread(MEMSIZE_BYTE); + gx816->regs.pc = g65816_stackread(MEMSIZE_LONG); + if(gx816->regs.p & PF_X) { gx816->regs.x &= 0xff; gx816->regs.y &= 0xff; } + snes_time->add_cpu_icycles(2); +} + +void g65816_op_rts(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(3); + gx816->regs.pc = ((gx816->regs.pc & 0xff0000) | g65816_stackread(MEMSIZE_WORD)) + 1; +} + +void g65816_op_rtl(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(3); + snes_time->add_cpu_icycles(2); + gx816->regs.pc = g65816_stackread(MEMSIZE_LONG) + 1; +} + +/*********** + *** bra *** + **********/ + +//Need to add condition (5) to cycle counts: if e=1, add one (i)cycle if page boundary crossed + +void g65816_op_bra(void) { +g65816_prefetch(1); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_icycles(1); + gx816->regs.pc += (signed char)(arg + 2); +} + +void g65816_op_brl(void) { +g65816_prefetch(2); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_icycles(1); + gx816->regs.pc += (signed short)(arg + 3); +} + +void g65816_op_bcc(void) { +g65816_prefetch(1); + snes_time->add_cpu_pcycles(2); + if(!(gx816->regs.p & PF_C)) { + snes_time->add_cpu_icycles(1); + gx816->regs.pc += (signed char)(arg + 2); + } else { + g65816_incpc(2); + } +} + +void g65816_op_bcs(void) { +g65816_prefetch(1); + snes_time->add_cpu_pcycles(2); + if(gx816->regs.p & PF_C) { + snes_time->add_cpu_icycles(1); + gx816->regs.pc += (signed char)(arg + 2); + } else { + g65816_incpc(2); + } +} + +void g65816_op_bne(void) { +g65816_prefetch(1); + snes_time->add_cpu_pcycles(2); + if(!(gx816->regs.p & PF_Z)) { + snes_time->add_cpu_icycles(1); + gx816->regs.pc += (signed char)(arg + 2); + } else { + g65816_incpc(2); + } +} + +void g65816_op_beq(void) { +g65816_prefetch(1); + snes_time->add_cpu_pcycles(2); + if(gx816->regs.p & PF_Z) { + snes_time->add_cpu_icycles(1); + gx816->regs.pc += (signed char)(arg + 2); + } else { + g65816_incpc(2); + } +} + +void g65816_op_bpl(void) { +g65816_prefetch(1); + snes_time->add_cpu_pcycles(2); + if(!(gx816->regs.p & PF_N)) { + snes_time->add_cpu_icycles(1); + gx816->regs.pc += (signed char)(arg + 2); + } else { + g65816_incpc(2); + } +} + +void g65816_op_bmi(void) { +g65816_prefetch(1); + snes_time->add_cpu_pcycles(2); + if(gx816->regs.p & PF_N) { + snes_time->add_cpu_icycles(1); + gx816->regs.pc += (signed char)(arg + 2); + } else { + g65816_incpc(2); + } +} + +void g65816_op_bvc(void) { +g65816_prefetch(1); + snes_time->add_cpu_pcycles(2); + if(!(gx816->regs.p & PF_V)) { + snes_time->add_cpu_icycles(1); + gx816->regs.pc += (signed char)(arg + 2); + } else { + g65816_incpc(2); + } +} + +void g65816_op_bvs(void) { +g65816_prefetch(1); + snes_time->add_cpu_pcycles(2); + if(gx816->regs.p & PF_V) { + snes_time->add_cpu_icycles(1); + gx816->regs.pc += (signed char)(arg + 2); + } else { + g65816_incpc(2); + } +} diff --git a/bsnes/cpu/g65816_ops_sbc.cpp b/bsnes/cpu/g65816_ops_sbc.cpp new file mode 100644 index 00000000..f5f3c076 --- /dev/null +++ b/bsnes/cpu/g65816_ops_sbc.cpp @@ -0,0 +1,345 @@ +#define bcd_sub_adjust_byte() \ + if(gx816->regs.p & PF_D) { \ + if(((r ) & 15) > 9)r -= 6; \ + if(((r >> 4) & 15) > 9)r -= 6 << 4; \ + } + +#define bcd_sub_adjust_word() \ + if(gx816->regs.p & PF_D) { \ + if(((r ) & 15) > 9)r -= 6; \ + if(((r >> 4) & 15) > 9)r -= 6 << 4; \ + if(((r >> 8) & 15) > 9)r -= 6 << 8; \ + if(((r >> 12) & 15) > 9)r -= 6 << 12; \ + } + +#define g65816_if_sbc_b() \ +byte c = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); \ +int r = gx816->regs.a.b - c - !(gx816->regs.p & PF_C); \ + bcd_sub_adjust_byte() \ + g65816_testn(r & 0x80); \ + g65816_testv((gx816->regs.a.b ^ c) & (gx816->regs.a.b ^ (byte)r) & 0x80); \ + g65816_testz((byte)r == 0); \ + g65816_testc(r >= 0); \ + gx816->regs.a.b = r + +#define g65816_if_sbc_w() \ +word c = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); \ +int r = gx816->regs.a.w - c - !(gx816->regs.p & PF_C); \ + bcd_sub_adjust_word() \ + g65816_testn(r & 0x8000); \ + g65816_testv((gx816->regs.a.w ^ c) & (gx816->regs.a.w ^ (word)r) & 0x8000); \ + g65816_testz((word)r == 0); \ + g65816_testc(r >= 0); \ + gx816->regs.a.w = r + +void g65816_op_sbc_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + g65816_if_sbc_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_sbc_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + g65816_if_sbc_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_sbc_addrxb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + g65816_if_sbc_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_sbc_addrxw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + g65816_if_sbc_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_sbc_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + g65816_if_sbc_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_sbc_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + g65816_if_sbc_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_sbc_idpb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDP); + g65816_if_sbc_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_sbc_idpw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDP); + g65816_if_sbc_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_sbc_ildpb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDP); + g65816_if_sbc_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_sbc_ildpw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDP); + g65816_if_sbc_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_sbc_longb(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONG); + g65816_if_sbc_b(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_sbc_longw(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONG); + g65816_if_sbc_w(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_sbc_longxb(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONGX); + g65816_if_sbc_b(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_sbc_longxw(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONGX); + g65816_if_sbc_w(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_sbc_addryb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRY); + g65816_if_sbc_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_sbc_addryw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRY); + g65816_if_sbc_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_sbc_dpxb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + g65816_if_sbc_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_sbc_dpxw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + g65816_if_sbc_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_sbc_idpxb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPX); + g65816_if_sbc_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_sbc_idpxw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPX); + g65816_if_sbc_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_sbc_idpyb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPY); + g65816_if_sbc_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2 | TIMING_CONDITION4); +} + +void g65816_op_sbc_idpyw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPY); + g65816_if_sbc_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2 | TIMING_CONDITION4); +} + +void g65816_op_sbc_ildpyb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDPY); + g65816_if_sbc_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_sbc_ildpyw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDPY); + g65816_if_sbc_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_sbc_srb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_SR); + g65816_if_sbc_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_sbc_srw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_SR); + g65816_if_sbc_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_sbc_isryb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_ISRY); + g65816_if_sbc_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_sbc_isryw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_ISRY); + g65816_if_sbc_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_sbc_constb(void) { +g65816_prefetch(1); +int r = gx816->regs.a.b - arg - !(gx816->regs.p & PF_C); + bcd_sub_adjust_byte() + g65816_testn(r & 0x80); + g65816_testv((gx816->regs.a.b ^ arg) & (gx816->regs.a.b ^ (byte)r) & 0x80); + g65816_testz((byte)r == 0); + g65816_testc(r >= 0); + gx816->regs.a.b = r; + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); +} + +void g65816_op_sbc_constw(void) { +g65816_prefetch(2); +int r = gx816->regs.a.w - arg - !(gx816->regs.p & PF_C); + bcd_sub_adjust_word() + g65816_testn(r & 0x8000); + g65816_testv((gx816->regs.a.w ^ arg) & (gx816->regs.a.w ^ (word)r) & 0x8000); + g65816_testz((word)r == 0); + g65816_testc(r >= 0); + gx816->regs.a.w = r; + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); +} diff --git a/bsnes/cpu/g65816_ops_shift.cpp b/bsnes/cpu/g65816_ops_shift.cpp new file mode 100644 index 00000000..2e61d5f8 --- /dev/null +++ b/bsnes/cpu/g65816_ops_shift.cpp @@ -0,0 +1,595 @@ +/********** +*** asl *** +**********/ + +void g65816_op_aslb(void) { + g65816_testc(gx816->regs.a.b & 0x80); + gx816->regs.a.b <<= 1; + g65816_testn(gx816->regs.a.b & 0x80); + g65816_testz(gx816->regs.a.b == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_aslw(void) { + g65816_testc(gx816->regs.a.w & 0x8000); + gx816->regs.a.w <<= 1; + g65816_testn(gx816->regs.a.w & 0x8000); + g65816_testz(gx816->regs.a.w == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_asl_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testc(m & 0x80); + m <<= 1; + g65816_testn(m & 0x80); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_asl_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testc(m & 0x8000); + m <<= 1; + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_asl_addrxb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testc(m & 0x80); + m <<= 1; + g65816_testn(m & 0x80); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_asl_addrxw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testc(m & 0x8000); + m <<= 1; + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_asl_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testc(m & 0x80); + m <<= 1; + g65816_testn(m & 0x80); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_REGD); +} + +void g65816_op_asl_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testc(m & 0x8000); + m <<= 1; + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_REGD); +} + +void g65816_op_asl_dpxb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testc(m & 0x80); + m <<= 1; + g65816_testn(m & 0x80); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2, TIMING_REGD); +} + +void g65816_op_asl_dpxw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testc(m & 0x8000); + m <<= 1; + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(2, TIMING_REGD); +} + +/********** +*** lsr *** +**********/ + +void g65816_op_lsrb(void) { + g65816_testc(gx816->regs.a.b & 0x01); + gx816->regs.a.b >>= 1; + g65816_clrn(); + g65816_testz(gx816->regs.a.b == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_lsrw(void) { + g65816_testc(gx816->regs.a.w & 0x0001); + gx816->regs.a.w >>= 1; + g65816_clrn(); + g65816_testz(gx816->regs.a.w == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_lsr_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testc(m & 0x01); + m >>= 1; + g65816_clrn(); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_lsr_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testc(m & 0x0001); + m >>= 1; + g65816_clrn(); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_lsr_addrxb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testc(m & 0x01); + m >>= 1; + g65816_clrn(); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_lsr_addrxw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testc(m & 0x0001); + m >>= 1; + g65816_clrn(); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_lsr_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testc(m & 0x01); + m >>= 1; + g65816_clrn(); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_REGD); +} + +void g65816_op_lsr_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testc(m & 0x0001); + m >>= 1; + g65816_clrn(); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_REGD); +} + +void g65816_op_lsr_dpxb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testc(m & 0x01); + m >>= 1; + g65816_clrn(); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2, TIMING_REGD); +} + +void g65816_op_lsr_dpxw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testc(m & 0x0001); + m >>= 1; + g65816_clrn(); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(2, TIMING_REGD); +} + +/********** +*** rol *** +**********/ + +void g65816_op_rolb(void) { +byte c = gx816->regs.p & PF_C; + g65816_testc(gx816->regs.a.b & 0x80); + gx816->regs.a.b = (gx816->regs.a.b << 1) | c; + g65816_testn(gx816->regs.a.b & 0x80); + g65816_testz(gx816->regs.a.b == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_rolw(void) { +byte c = gx816->regs.p & PF_C; + g65816_testc(gx816->regs.a.w & 0x8000); + gx816->regs.a.w = (gx816->regs.a.w << 1) | c; + g65816_testn(gx816->regs.a.w & 0x8000); + g65816_testz(gx816->regs.a.w == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_rol_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +byte c = gx816->regs.p & PF_C; +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testc(m & 0x80); + m = (m << 1) | c; + g65816_testn(m & 0x80); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_rol_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +byte c = gx816->regs.p & PF_C; +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testc(m & 0x8000); + m = (m << 1) | c; + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_rol_addrxb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); +byte c = gx816->regs.p & PF_C; +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testc(m & 0x80); + m = (m << 1) | c; + g65816_testn(m & 0x80); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_rol_addrxw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); +byte c = gx816->regs.p & PF_C; +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testc(m & 0x8000); + m = (m << 1) | c; + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_rol_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +byte c = gx816->regs.p & PF_C; +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testc(m & 0x80); + m = (m << 1) | c; + g65816_testn(m & 0x80); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_REGD); +} + +void g65816_op_rol_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +byte c = gx816->regs.p & PF_C; +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testc(m & 0x8000); + m = (m << 1) | c; + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_REGD); +} + +void g65816_op_rol_dpxb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); +byte c = gx816->regs.p & PF_C; +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testc(m & 0x80); + m = (m << 1) | c; + g65816_testn(m & 0x80); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2, TIMING_REGD); +} + +void g65816_op_rol_dpxw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); +byte c = gx816->regs.p & PF_C; +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, arg); + g65816_testc(m & 0x8000); + m = (m << 1) | c; + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, arg, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(2, TIMING_REGD); +} + +/********** +*** ror *** +**********/ + +void g65816_op_rorb(void) { +byte c = (gx816->regs.p & PF_C)?0x80:0x00; + g65816_testc(gx816->regs.a.b & 0x01); + gx816->regs.a.b = (gx816->regs.a.b >> 1) | c; + g65816_testn(gx816->regs.a.b & 0x80); + g65816_testz(gx816->regs.a.b == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_rorw(void) { +word c = (gx816->regs.p & PF_C)?0x8000:0x0000; + g65816_testc(gx816->regs.a.w & 0x0001); + gx816->regs.a.w = (gx816->regs.a.w >> 1) | c; + g65816_testn(gx816->regs.a.w & 0x8000); + g65816_testz(gx816->regs.a.w == 0); + g65816_incpc(1); + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_ror_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +byte c = (gx816->regs.p & PF_C)?0x80:0x00; +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testc(m & 0x01); + m = (m >> 1) | c; + g65816_testn(m & 0x80); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_ror_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); +word c = (gx816->regs.p & PF_C)?0x8000:0x0000; +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testc(m & 0x0001); + m = (m >> 1) | c; + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_ror_addrxb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); +byte c = (gx816->regs.p & PF_C)?0x80:0x00; +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testc(m & 0x01); + m = (m >> 1) | c; + g65816_testn(m & 0x80); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_ror_addrxw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); +word c = (gx816->regs.p & PF_C)?0x8000:0x0000; +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testc(m & 0x0001); + m = (m >> 1) | c; + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_ror_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +byte c = (gx816->regs.p & PF_C)?0x80:0x00; +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testc(m & 0x01); + m = (m >> 1) | c; + g65816_testn(m & 0x80); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_REGD); +} + +void g65816_op_ror_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); +word c = (gx816->regs.p & PF_C)?0x8000:0x0000; +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testc(m & 0x0001); + m = (m >> 1) | c; + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_REGD); +} + +void g65816_op_ror_dpxb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); +byte c = (gx816->regs.p & PF_C)?0x80:0x00; +byte m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr); + g65816_testc(m & 0x01); + m = (m >> 1) | c; + g65816_testn(m & 0x80); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2, TIMING_REGD); +} + +void g65816_op_ror_dpxw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); +word c = (gx816->regs.p & PF_C)?0x8000:0x0000; +word m = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr); + g65816_testc(m & 0x0001); + m = (m >> 1) | c; + g65816_testn(m & 0x8000); + g65816_testz(m == 0); + gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, m); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(4, dest_addr); + snes_time->add_cpu_icycles(2, TIMING_REGD); +} diff --git a/bsnes/cpu/g65816_ops_sta.cpp b/bsnes/cpu/g65816_ops_sta.cpp new file mode 100644 index 00000000..5f2069cc --- /dev/null +++ b/bsnes/cpu/g65816_ops_sta.cpp @@ -0,0 +1,288 @@ +#define g65816_sta_data_b() gx816->mem_write(MEMMODE_NONE, MEMSIZE_BYTE, dest_addr, gx816->regs.a.b) +#define g65816_sta_data_w() gx816->mem_write(MEMMODE_NONE, MEMSIZE_WORD, dest_addr, gx816->regs.a.w) + +void g65816_op_sta_addrb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + g65816_sta_data_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_sta_addrw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDR); + g65816_sta_data_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_sta_addrxb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + g65816_sta_data_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_sta_addrxw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRX); + g65816_sta_data_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_sta_dpb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + g65816_sta_data_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_sta_dpw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + g65816_sta_data_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_sta_idpb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDP); + g65816_sta_data_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_sta_idpw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDP); + g65816_sta_data_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_sta_ildpb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDP); + g65816_sta_data_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_sta_ildpw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDP); + g65816_sta_data_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_sta_longb(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONG); + g65816_sta_data_b(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_sta_longw(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONG); + g65816_sta_data_w(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_sta_longxb(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONGX); + g65816_sta_data_b(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(1, dest_addr); +} + +void g65816_op_sta_longxw(void) { +g65816_prefetch(3); +g65816_getaddr(MEMMODE_LONGX); + g65816_sta_data_w(); + g65816_incpc(4); + snes_time->add_cpu_pcycles(4); + snes_time->add_cpu_mcycles(2, dest_addr); +} + +void g65816_op_sta_addryb(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRY); + g65816_sta_data_b(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_sta_addryw(void) { +g65816_prefetch(2); +g65816_getaddr(MEMMODE_ADDRY); + g65816_sta_data_w(); + g65816_incpc(3); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION4); +} + +void g65816_op_sta_dpxb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + g65816_sta_data_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_sta_dpxw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DPX); + g65816_sta_data_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_sta_idpxb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPX); + g65816_sta_data_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_sta_idpxw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPX); + g65816_sta_data_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(1, TIMING_CONDITION2); +} + +void g65816_op_sta_idpyb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPY); + g65816_sta_data_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2 | TIMING_CONDITION4); +} + +void g65816_op_sta_idpyw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_IDPY); + g65816_sta_data_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2 | TIMING_CONDITION4); +} + +void g65816_op_sta_ildpyb(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDPY); + g65816_sta_data_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_sta_ildpyw(void) { +g65816_prefetch(1); +g65816_getiaddr(MEMMODE_ILDPY); + g65816_sta_data_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(3, base_addr); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(0, TIMING_CONDITION2); +} + +void g65816_op_sta_srb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_SR); + g65816_sta_data_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_sta_srw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_SR); + g65816_sta_data_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(1); +} + +void g65816_op_sta_isryb(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_ISRY); + g65816_sta_data_b(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_mcycles(1, dest_addr); + snes_time->add_cpu_icycles(2); +} + +void g65816_op_sta_isryw(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_ISRY); + g65816_sta_data_w(); + g65816_incpc(2); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_icycles(2); +} diff --git a/bsnes/cpu/g65816_ops_stack.cpp b/bsnes/cpu/g65816_ops_stack.cpp new file mode 100644 index 00000000..a126db5c --- /dev/null +++ b/bsnes/cpu/g65816_ops_stack.cpp @@ -0,0 +1,243 @@ +ulong g65816_stackread(byte size) { +ulong r = 0; + if(size == MEMSIZE_BYTE) { + gx816->regs.s++; + r = gx816->mem_read(MEMMODE_LONG, MEMSIZE_BYTE, gx816->regs.s); + } else if(size == MEMSIZE_WORD) { + gx816->regs.s++; + r = gx816->mem_read(MEMMODE_LONG, MEMSIZE_BYTE, gx816->regs.s); + gx816->regs.s++; + r |= gx816->mem_read(MEMMODE_LONG, MEMSIZE_BYTE, gx816->regs.s) << 8; + } else if(size == MEMSIZE_LONG) { + gx816->regs.s++; + r = gx816->mem_read(MEMMODE_LONG, MEMSIZE_BYTE, gx816->regs.s); + gx816->regs.s++; + r |= gx816->mem_read(MEMMODE_LONG, MEMSIZE_BYTE, gx816->regs.s) << 8; + gx816->regs.s++; + r |= gx816->mem_read(MEMMODE_LONG, MEMSIZE_BYTE, gx816->regs.s) << 16; + } + if(gx816->regs.e == true) { + gx816->regs.s = 0x0100 | (gx816->regs.s & 0xff); + } + return r; +} + +void g65816_stackwrite(byte size, ulong value) { + if(size == MEMSIZE_BYTE) { + gx816->mem_write(MEMMODE_LONG, MEMSIZE_BYTE, gx816->regs.s, value); + gx816->regs.s--; + } else if(size == MEMSIZE_WORD) { + gx816->mem_write(MEMMODE_LONG, MEMSIZE_BYTE, gx816->regs.s, value >> 8); + gx816->regs.s--; + gx816->mem_write(MEMMODE_LONG, MEMSIZE_BYTE, gx816->regs.s, value); + gx816->regs.s--; + } else if(size == MEMSIZE_LONG) { + gx816->mem_write(MEMMODE_LONG, MEMSIZE_BYTE, gx816->regs.s, value >> 16); + gx816->regs.s--; + gx816->mem_write(MEMMODE_LONG, MEMSIZE_BYTE, gx816->regs.s, value >> 8); + gx816->regs.s--; + gx816->mem_write(MEMMODE_LONG, MEMSIZE_BYTE, gx816->regs.s, value); + gx816->regs.s--; + } + if(gx816->regs.e == true) { + gx816->regs.s = 0x0100 | (gx816->regs.s & 0xff); + } +} + +void g65816_op_phab(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(1); + g65816_stackwrite(MEMSIZE_BYTE, gx816->regs.a.b); + g65816_incpc(1); +} + +void g65816_op_phaw(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(1); + g65816_stackwrite(MEMSIZE_WORD, gx816->regs.a.w); + g65816_incpc(1); +} + +void g65816_op_phb(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(1); + g65816_stackwrite(MEMSIZE_BYTE, gx816->regs.db); + g65816_incpc(1); +} + +void g65816_op_phd(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(1); + g65816_stackwrite(MEMSIZE_WORD, gx816->regs.d); + g65816_incpc(1); +} + +void g65816_op_phk(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(1); + g65816_stackwrite(MEMSIZE_BYTE, gx816->regs.pc >> 16); + g65816_incpc(1); +} + +void g65816_op_php(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(1); + g65816_stackwrite(MEMSIZE_BYTE, gx816->regs.p); + g65816_incpc(1); +} + +void g65816_op_phxb(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(1); + g65816_stackwrite(MEMSIZE_BYTE, gx816->regs.x); + g65816_incpc(1); +} + +void g65816_op_phxw(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(1); + g65816_stackwrite(MEMSIZE_WORD, gx816->regs.x); + g65816_incpc(1); +} + +void g65816_op_phyb(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(1); + g65816_stackwrite(MEMSIZE_BYTE, gx816->regs.y); + g65816_incpc(1); +} + +void g65816_op_phyw(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(1); + g65816_stackwrite(MEMSIZE_WORD, gx816->regs.y); + g65816_incpc(1); +} + +void g65816_op_plab(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(2); + gx816->regs.a.b = g65816_stackread(MEMSIZE_BYTE); + g65816_testn(gx816->regs.a.b & 0x80); + g65816_testz(gx816->regs.a.b == 0); + g65816_incpc(1); +} + +void g65816_op_plaw(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(2); + gx816->regs.a.w = g65816_stackread(MEMSIZE_WORD); + g65816_testn(gx816->regs.a.w & 0x8000); + g65816_testz(gx816->regs.a.w == 0); + g65816_incpc(1); +} + +void g65816_op_plb(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(2); + gx816->regs.db = g65816_stackread(MEMSIZE_BYTE); + g65816_testn(gx816->regs.db & 0x80); + g65816_testz(gx816->regs.db == 0); + g65816_incpc(1); +} + +void g65816_op_pld(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(2); + gx816->regs.d = g65816_stackread(MEMSIZE_WORD); + g65816_testn(gx816->regs.d & 0x8000); + g65816_testz(gx816->regs.d == 0); + g65816_incpc(1); +} + +void g65816_op_plp(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(2); + gx816->regs.p = g65816_stackread(MEMSIZE_BYTE); + g65816_incpc(1); + if(gx816->regs.e == true)gx816->regs.p |= 0x30; + if(gx816->regs.p & PF_X) { gx816->regs.x &= 0xff; gx816->regs.y &= 0xff; } +} + +void g65816_op_plxb(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(2); + gx816->regs.x = g65816_stackread(MEMSIZE_BYTE); + g65816_testn(gx816->regs.x & 0x80); + g65816_testz((gx816->regs.x & 0xff) == 0); + g65816_incpc(1); +} + +void g65816_op_plxw(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(2); + gx816->regs.x = g65816_stackread(MEMSIZE_WORD); + g65816_testn(gx816->regs.x & 0x8000); + g65816_testz(gx816->regs.x == 0); + g65816_incpc(1); +} + +void g65816_op_plyb(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(1); + snes_time->add_cpu_icycles(2); + gx816->regs.y = g65816_stackread(MEMSIZE_BYTE); + g65816_testn(gx816->regs.y & 0x80); + g65816_testz((gx816->regs.y & 0xff) == 0); + g65816_incpc(1); +} + +void g65816_op_plyw(void) { + snes_time->add_cpu_pcycles(1); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(2); + gx816->regs.y = g65816_stackread(MEMSIZE_WORD); + g65816_testn(gx816->regs.y & 0x8000); + g65816_testz(gx816->regs.y == 0); + g65816_incpc(1); +} + +void g65816_op_pea(void) { +g65816_prefetch(2); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_scycles(2); + g65816_stackwrite(MEMSIZE_WORD, arg); + g65816_incpc(3); +} + +void g65816_op_pei(void) { +g65816_prefetch(1); +g65816_getaddr(MEMMODE_DP); + snes_time->add_cpu_pcycles(2); + snes_time->add_cpu_mcycles(2, dest_addr); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(0, TIMING_REGD); + g65816_stackwrite(MEMSIZE_WORD, gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dest_addr)); + g65816_incpc(2); +} + +void g65816_op_per(void) { +g65816_prefetch(2); + snes_time->add_cpu_pcycles(3); + snes_time->add_cpu_scycles(2); + snes_time->add_cpu_icycles(1); + g65816_stackwrite(MEMSIZE_WORD, gx816->regs.pc + arg + 3); + g65816_incpc(3); +} diff --git a/bsnes/d65816.obj b/bsnes/d65816.obj new file mode 100644 index 00000000..e685f195 Binary files /dev/null and b/bsnes/d65816.obj differ diff --git a/bsnes/demo.smc b/bsnes/demo.smc new file mode 100644 index 00000000..4abad79c Binary files /dev/null and b/bsnes/demo.smc differ diff --git a/bsnes/demo.srm b/bsnes/demo.srm new file mode 100644 index 00000000..6d17cf9d Binary files /dev/null and b/bsnes/demo.srm differ diff --git a/bsnes/demo_mode1.smc b/bsnes/demo_mode1.smc new file mode 100644 index 00000000..687d1749 Binary files /dev/null and b/bsnes/demo_mode1.smc differ diff --git a/bsnes/demo_mode1.srm b/bsnes/demo_mode1.srm new file mode 100644 index 00000000..6d17cf9d Binary files /dev/null and b/bsnes/demo_mode1.srm differ diff --git a/bsnes/demo_mode4.smc b/bsnes/demo_mode4.smc new file mode 100644 index 00000000..a1811a01 Binary files /dev/null and b/bsnes/demo_mode4.smc differ diff --git a/bsnes/demo_mode4.srm b/bsnes/demo_mode4.srm new file mode 100644 index 00000000..6d17cf9d Binary files /dev/null and b/bsnes/demo_mode4.srm differ diff --git a/bsnes/g65816.obj b/bsnes/g65816.obj new file mode 100644 index 00000000..f333479d Binary files /dev/null and b/bsnes/g65816.obj differ diff --git a/bsnes/gui.obj b/bsnes/gui.obj new file mode 100644 index 00000000..6d84676e Binary files /dev/null and b/bsnes/gui.obj differ diff --git a/bsnes/libstr.obj b/bsnes/libstr.obj new file mode 100644 index 00000000..7518ffe9 Binary files /dev/null and b/bsnes/libstr.obj differ diff --git a/bsnes/main.cpp b/bsnes/main.cpp new file mode 100644 index 00000000..b01c7881 --- /dev/null +++ b/bsnes/main.cpp @@ -0,0 +1,97 @@ +/* bsnes + project started 10/14/2004 + author byuu */ + +#include "base.h" +#include "main.h" +#include "timing/timing.h" +#include "cpu/g65816.h" +extern snes_timer *snes_time; +extern g65816 *gx816; +extern ppustate ppu; + +vfunc RunSNES; + +void RunSNES_NoDebug(void) { +byte l = 64; + while(l--) { + gx816->Run(); + gx816->Run(); + gx816->Run(); + gx816->Run(); + gx816->Run(); + gx816->Run(); + gx816->Run(); + gx816->Run(); + } +} + +void RunSNES_Debug(void) { + if(debug_get_state() == DEBUGMODE_NOROM)return; + + if(debug_get_state() == DEBUGMODE_RUN) { + gx816->Run(); + if(debugger.trace_enabled == true) { + disas_g65816_op(); + } + } else { + if(debugger.disas_op == true) { + disas_g65816_op(); + debugger.disas_op = false; + } + if(debugger.refresh_mem == true) { + debug_refresh_mem(); + debugger.refresh_mem = false; + } + if(debugger.refresh_bp == true) { + debug_refresh_bp(); + debugger.refresh_bp = false; + } + if(debug_get_state() == DEBUGMODE_WAIT)return; + + if(debug_get_state() == DEBUGMODE_STEP) { + gx816->Run(); + disas_g65816_op(); + debug_set_state(DEBUGMODE_WAIT); + } + } +} + +void InitSNES(void) { + snes_time = new snes_timer(); + gx816 = new g65816(); + gx816->PowerOn(1); + if(*emu_state.rom_name == 0) { + debug_set_state(DEBUGMODE_NOROM); + } else { + gx816->LoadROM(); + } + + if(debug_get_state() == DEBUGMODE_DISABLED) { + RunSNES = RunSNES_NoDebug; + } else { + RunSNES = RunSNES_Debug; + } +} + +#include +int __stdcall WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) { +char fn[MAX_PATH]; + strcpy(fn, lpcmdline); +//remove quotes from filename, if neccesary (if path contains spaces, quotes will be around command line arg) + if(*fn == '\"') { + strcpy(emu_state.rom_name, fn + 1); + emu_state.rom_name[strlen(emu_state.rom_name) - 1] = 0; + } else { + strcpy(emu_state.rom_name, fn); + } +//create save ram file name + strcpy(emu_state.sram_name, emu_state.rom_name); + if(strlen(emu_state.sram_name) > 4) { + emu_state.sram_name[strlen(emu_state.sram_name) - 4] = 0; + } + strcat(emu_state.sram_name, ".srm"); +//located in win/gui.cpp + __winmain(); + return 0; +} diff --git a/bsnes/main.h b/bsnes/main.h new file mode 100644 index 00000000..21446257 --- /dev/null +++ b/bsnes/main.h @@ -0,0 +1,34 @@ +void __winmain(void); + +/* + *1 - how many instructions to execute before saving sram data + to emu_state.sram_name +*/ +emustate emu_state = { + "", "", //rom name, sram name + 1000000 //sram save tick count *1 +}; + +debugstate debugger = { + DEBUGMODE_DISABLED, //default debug mode + false, //trace enabled + 0x7e0000, //debugger memory start pos + true, //debugger disassemble op + true, //debugger refresh mem + true, //debugger refresh breakpoints + 0 //tracelog file pointer +}; + +videostate render = { + 512, 448, //resolution + 256, 224, //snes internal resolution + false, //fullscreen + true, //show menu + 1, //frame skip + 0, //frame count + { true, true, true }, //bg1 enable + { true, true, true }, //bg2 enable + { true, true, true }, //bg3 enable + { true, true, true }, //bg4 enable + { true, true, true, true, true } //oam enable +}; diff --git a/bsnes/main.obj b/bsnes/main.obj new file mode 100644 index 00000000..e04557fb Binary files /dev/null and b/bsnes/main.obj differ diff --git a/bsnes/mem/memory.cpp b/bsnes/mem/memory.cpp new file mode 100644 index 00000000..5d2072dc --- /dev/null +++ b/bsnes/mem/memory.cpp @@ -0,0 +1,516 @@ +#include "../base.h" +#include "../cpu/g65816.h" +extern g65816 *gx816; +extern emustate emu_state; +extern debugstate debugger; + +void g65816::InitializeROM(byte memory_map) { + memset(rom, 0, 0x600000); + map = memory_map; +} + +void g65816::InitializeWRAM(byte value) { + memset(wram, value, 0x020000); + memset(sram, 0x00, 0x0e0000); +} + +/*********************** + *** SNES Memory Map *** + ************************************************** + *** 00-3f 0000-1fff First 8k WRAM *** + *** 2000-5fff MMIO *** + *** 6000-7fff Expansion RAM (Unmapped) *** + *** 8000-ffff Cartridge ROM *** + *** 40-7d 0000-ffff Cartridge ROM *** + *** 7e-7f 0000-ffff 128k WRAM *** + *** 80-bf 0000-1fff First 8k WRAM *** + *** 2000-5fff MMIO *** + *** 6000-7fff Expansion RAM (Unmapped) *** + *** 8000-ffff Cartridge ROM *** + *** c0-ff 0000-ffff Cartridge ROM *** +**************************************************/ + +ulong g65816::mirror_offset(ulong addr) { +byte db; +word a; +ulong r = 0; + db = (addr >> 16) & 0xff; + a = (addr & 0xffff); + if(db >= 0x00 && db <= 0x3f) { + if(a >= 0x0000 && a <= 0x1fff) { + r = 0x7e0000 | (a & 0x1fff); + } else if(a >= 0x2000 && a <= 0x5fff) { + r = a; + } else if(a >= 0x6000 && a <= 0x7fff) { + r = (db << 16) | a; + } else if(a >= 0x8000 && a <= 0xffff) { + r = (db << 16) | a; + } + } else if(db >= 0x40 && db <= 0x7d) { + r = (db << 16) | a; + } else if(db >= 0x7e && db <= 0x7f) { + r = addr; + } else if(db >= 0x80 && db <= 0xbf) { + if(a >= 0x0000 && a <= 0x1fff) { + r = 0x7e0000 | (a & 0x1fff); + } else if(a >= 0x2000 && a <= 0x5fff) { + r = a; + } else if(a >= 0x6000 && a <= 0x7fff) { + r = (db << 16) | a; + } else if(a >= 0x8000 && a <= 0xffff) { + r = ((db & 0x7f) << 16) | a; + } + } else if(db >= 0xc0 && db <= 0xff) { + r = addr; + } + + return r; +} + +ulong g65816::convert_offset(byte read_mode, ulong addr, bool mirror) { +byte db; + switch(read_mode) { + case MEMMODE_DP: + addr = (regs.d + (addr & 0xff)) & 0xffff; + break; + case MEMMODE_DPX: + addr = (regs.d + regs.x + (addr & 0xff)) & 0xffff; + break; + case MEMMODE_DPY: + addr = (regs.d + regs.y + (addr & 0xff)) & 0xffff; + break; + case MEMMODE_IDP: + addr = (regs.d + (addr & 0xff)) & 0xffff; + addr = mem_read(MEMMODE_LONG, MEMSIZE_WORD, addr); + addr |= (regs.db << 16); + break; + case MEMMODE_IDPX: + addr = (regs.d + regs.x + (addr & 0xff)) & 0xffff; + addr = mem_read(MEMMODE_LONG, MEMSIZE_WORD, addr); + addr |= (regs.db << 16); + break; + case MEMMODE_IDPY: + addr = (regs.d + (addr & 0xff)) & 0xffff; + addr = mem_read(MEMMODE_LONG, MEMSIZE_WORD, addr); + addr += (regs.db << 16) + regs.y; + if((addr >> 16) != regs.db)index_bank_crossed = true; + else index_bank_crossed = false; + break; + case MEMMODE_ILDP: + addr = (regs.d + (addr & 0xff)); + addr = mem_read(MEMMODE_LONG, MEMSIZE_LONG, addr); + break; + case MEMMODE_ILDPY: + addr = (regs.d + (addr & 0xff)); + addr = mem_read(MEMMODE_LONG, MEMSIZE_LONG, addr); + addr += regs.y; + break; + case MEMMODE_ADDR: + addr = addr & 0xffff; + addr |= (regs.db << 16); + break; + case MEMMODE_ADDR_PC: + addr = addr & 0xffff; + addr |= (regs.pc & 0xff0000); + break; + case MEMMODE_ADDRX: + addr = (regs.db << 16) + (addr & 0xffff); + addr += regs.x; + if((addr >> 16) != regs.db)index_bank_crossed = true; + else index_bank_crossed = false; + break; + case MEMMODE_ADDRY: + addr = (regs.db << 16) + (addr & 0xffff); + addr += regs.y; + if((addr >> 16) != regs.db)index_bank_crossed = true; + else index_bank_crossed = false; + break; + case MEMMODE_IADDRX: + addr += regs.x; + addr = mem_read(MEMMODE_LONG, MEMSIZE_WORD, (addr & 0x00ffff)); + addr |= (regs.pc & 0xff0000); + break; + case MEMMODE_ILADDR: + addr = mem_read(MEMMODE_LONG, MEMSIZE_LONG, addr); + break; + case MEMMODE_IADDR_PC: + addr |= (regs.pc & 0xff0000); + break; + case MEMMODE_IADDRX_PC: + addr += regs.x; + addr |= (regs.pc & 0xff0000); + break; + case MEMMODE_ILADDR_PC: + break; + case MEMMODE_LONG: + break; + case MEMMODE_LONGX: + addr += regs.x; + break; + case MEMMODE_SR: + addr = (regs.s + (addr & 0xff)) & 0xffff; + break; + case MEMMODE_ISRY: + addr = (regs.s + (addr & 0xff)) & 0xffff; + addr = mem_read(MEMMODE_LONG, MEMSIZE_WORD, addr); + addr += (regs.db << 16) + regs.y; + break; + } + + if(mirror == true) { + return mirror_offset(addr); + } else { + return addr; + } +} + +ulong g65816::adjust_base_offset(byte read_mode, ulong addr) { +byte db; + switch(read_mode) { + case MEMMODE_DP: + addr = (regs.d + (addr & 0xff)) & 0xffff; + break; + case MEMMODE_DPX: + addr = (regs.d + regs.x + (addr & 0xff)) & 0xffff; + break; + case MEMMODE_DPY: + addr = (regs.d + regs.y + (addr & 0xff)) & 0xffff; + break; + case MEMMODE_IDP: + addr = (regs.d + (addr & 0xff)) & 0xffff; + break; + case MEMMODE_IDPX: + addr = (regs.d + regs.x + (addr & 0xff)) & 0xffff; + break; + case MEMMODE_IDPY: + addr = (regs.d + (addr & 0xff)) & 0xffff; + break; + case MEMMODE_ILDP: + addr = (regs.d + (addr & 0xff)); + break; + case MEMMODE_ILDPY: + addr = (regs.d + (addr & 0xff)); + break; + case MEMMODE_ADDR: + addr = addr & 0xffff; + addr |= (regs.db << 16); + break; + case MEMMODE_ADDR_PC: + addr = addr & 0xffff; + addr |= (regs.pc & 0xff0000); + break; + case MEMMODE_ADDRX: + addr = (regs.db << 16) | (addr & 0xffff); + addr += regs.x; + if((addr >> 16) != regs.db)index_bank_crossed = true; + else index_bank_crossed = false; + break; + case MEMMODE_ADDRY: + addr = (regs.db << 16) + (addr & 0xffff); + addr += regs.y; + if((addr >> 16) != regs.db)index_bank_crossed = true; + else index_bank_crossed = false; + break; + case MEMMODE_IADDRX: + addr += regs.x; + addr &= 0xffff; + break; + case MEMMODE_ILADDR: + addr &= 0xffff; + break; + case MEMMODE_IADDR_PC: + addr |= (regs.pc & 0xff0000); + break; + case MEMMODE_IADDRX_PC: + addr += regs.x; + addr |= (regs.pc & 0xff0000); + break; + case MEMMODE_ILADDR_PC: + break; + case MEMMODE_LONG: + break; + case MEMMODE_LONGX: + addr += regs.x; + break; + case MEMMODE_SR: + addr = (regs.s + (addr & 0xff)) & 0xffff; + break; + case MEMMODE_ISRY: + addr = (regs.s + (addr & 0xff)) & 0xffff; + break; + } + return addr; +} + +ulong g65816::read_indirect_address(byte read_mode, ulong addr) { +byte db; + switch(read_mode) { + case MEMMODE_IDP: + addr = mem_read(MEMMODE_LONG, MEMSIZE_WORD, addr); + addr |= (regs.db << 16); + break; + case MEMMODE_IDPX: + addr = mem_read(MEMMODE_LONG, MEMSIZE_WORD, addr); + addr |= (regs.db << 16); + break; + case MEMMODE_IDPY: + addr = mem_read(MEMMODE_LONG, MEMSIZE_WORD, addr); + addr += (regs.db << 16) + regs.y; + if((addr >> 16) != regs.db)index_bank_crossed = true; + else index_bank_crossed = false; + break; + case MEMMODE_ILDP: + addr = mem_read(MEMMODE_LONG, MEMSIZE_LONG, addr); + break; + case MEMMODE_ILDPY: + addr = mem_read(MEMMODE_LONG, MEMSIZE_LONG, addr); + addr += regs.y; + break; + case MEMMODE_IADDRX: + addr = mem_read(MEMMODE_LONG, MEMSIZE_WORD, (addr & 0x00ffff)); + addr |= (regs.pc & 0xff0000); + break; + case MEMMODE_ILADDR: + addr = mem_read(MEMMODE_LONG, MEMSIZE_LONG, addr); + break; + case MEMMODE_ISRY: + addr = mem_read(MEMMODE_LONG, MEMSIZE_WORD, addr); + addr += (regs.db << 16) + regs.y; + break; + default: + dprintf("* Error: Invalid read_mode for g65816::read_indirect_address [%d]", read_mode); + break; + } + return addr; +} + +ulong g65816::get_dc(byte read_mode, ulong addr) { + regs.dc = convert_offset(read_mode, addr, false); + return regs.dc; +} + +byte g65816::mem_getbyte_direct(ulong addr, byte access_mode) { +byte db; +word a; + db = (addr >> 16) & 0xff; + a = (addr & 0xffff); + if(db == 0x00 && a >= 0x2000 && a <= 0x5fff) { + return mmio_read(addr); + } + + if(db == 0x7e || db == 0x7f) { + return wram[addr & 0x01ffff]; + } else if(db != 0x7e && db != 0x7f && a >= 0x8000 && a <= 0xffff) { + return rom_read(addr, MEMSIZE_BYTE); + } else if(db >= 0x30 && db <= 0x3f) { + if(a >= 0x6000 && a <= 0x7fff) { + addr = ((db - 0x30) * 0x2000) + (a - 0x6000); + addr &= (sram_size - 1); + return sram[addr]; + } + } else if(db >= 0x70 && db <= 0x7d) { + addr -= 0x700000; + addr &= (sram_size - 1); + return sram[addr]; + } else if(db >= 0xc0 && db <= 0xff) { + return rom_read(addr, MEMSIZE_BYTE); + } + return 0; +} + +byte g65816::mem_getbyte(ulong addr, byte access_mode) { +int i; +byte r; + r = mem_getbyte_direct(addr, access_mode); + + if(debug_get_state() == DEBUGMODE_DISABLED)return r; + + if(access_mode == MEMACCESS_DEBUGGER)return r; //don't report breakpoint hits from debugger + + for(i=0;i<16;i++) { + if(bp_list[i].flags & BP_READ) { + if(bp_list[i].offset == addr) { + if(bp_list[i].flags & BP_VAL) { + if(bp_list[i].value == r) { + dprintf("* breakpoint %d hit -- read match access [%0.2x]", i, r); + bp_list[i].hit_count++; + debugger.refresh_bp = true; + debug_set_state(DEBUGMODE_WAIT); + disas_g65816_op(); + } + } else { + dprintf("* breakpoint %d hit -- read access", i); + bp_list[i].hit_count++; + debugger.refresh_bp = true; + debug_set_state(DEBUGMODE_WAIT); + disas_g65816_op(); + } + } + } + } + return r; +} + +void g65816::mem_putbyte_direct(ulong addr, byte value, byte access_mode) { +byte db; +word a; + db = (addr >> 16) & 0xff; + a = (addr & 0xffff); + if(db == 0x00 && a >= 0x2000 && a <= 0x5fff) { + mmio_write(a, value); + } else if(db == 0x7e || db == 0x7f) { + wram[addr & 0x01ffff] = value; + } else if(db >= 0x30 && db <= 0x3f) { + if(a >= 0x6000 && a <= 0x7fff) { + addr = ((db - 0x30) * 0x2000) + (a - 0x6000); + addr &= (sram_size - 1); + sram[addr] = value; + } + } else if(db >= 0x70 && db <= 0x7d) { + addr -= 0x700000; + addr &= (sram_size - 1); + sram[addr] = value; + } + + if(access_mode == MEMACCESS_DEBUGGER) { + if(gx816->map == MEMMAP_LOROM) { + if((db >= 0x00 && db <= 0x5f) || (db >= 0x80 && db <= 0xdf)) { + if(addr >= 0x8000 && addr <= 0xffff) { + rom_write(addr, value, MEMSIZE_BYTE); + } + } + } else if(gx816->map == MEMMAP_HIROM) { + if(db >= 0xc0 && db <= 0xff) { + rom_write(addr, value, MEMSIZE_BYTE); + } + } + } +} + +void g65816::mem_putbyte(ulong addr, byte value, byte access_mode) { +int i; + mem_putbyte_direct(addr, value, access_mode); + + if(debug_get_state() == DEBUGMODE_DISABLED)return; + + if(access_mode == MEMACCESS_DEBUGGER)return; //don't report breakpoint hits from debugger + + for(i=0;i<16;i++) { + if(bp_list[i].flags & BP_WRITE) { + if(bp_list[i].offset == addr) { + if(bp_list[i].flags & BP_VAL) { + if(bp_list[i].value == value) { + dprintf("* breakpoint %d hit -- write match access [%0.2x]", i, value); + bp_list[i].hit_count++; + debugger.refresh_bp = true; + debug_set_state(DEBUGMODE_WAIT); + disas_g65816_op(); + } + } else { + dprintf("* breakpoint %d hit -- write access", i); + bp_list[i].hit_count++; + debugger.refresh_bp = true; + debug_set_state(DEBUGMODE_WAIT); + disas_g65816_op(); + } + } + } + } +} + +ulong g65816::mem_read(byte read_mode, byte read_size, ulong addr, byte access_mode) { +ulong r; + addr = convert_offset(read_mode, addr); + + switch(read_size) { + case MEMSIZE_BYTE: + r = mem_getbyte(addr, access_mode); + break; + case MEMSIZE_WORD: + r = mem_getbyte(addr, access_mode) | + mem_getbyte(addr + 1, access_mode)<<8; + break; + case MEMSIZE_LONG: + r = mem_getbyte(addr, access_mode) | + mem_getbyte(addr + 1, access_mode)<<8 | + mem_getbyte(addr + 2, access_mode)<<16; + break; + } + + return r; +} + +void g65816::mem_write(byte write_mode, byte write_size, ulong addr, ulong value, byte access_mode) { + addr = convert_offset(write_mode, addr); + + switch(write_size) { + case MEMSIZE_BYTE: + mem_putbyte(addr, value, access_mode); + break; + case MEMSIZE_WORD: + mem_putbyte(addr, value, access_mode); + mem_putbyte(addr+1, value>>8, access_mode); + break; + case MEMSIZE_LONG: + mem_putbyte(addr, value, access_mode); + mem_putbyte(addr+1, value>>8, access_mode); + mem_putbyte(addr+2, value>>16, access_mode); + break; + } + + debugger.refresh_mem = true; +} + +ulong g65816::rom_read(ulong addr, byte read_size) { +ulong r; + if(map == MEMMAP_LOROM) { + if(read_size == MEMSIZE_BYTE) { + r = rom[((addr & 0x7f0000) >> 1) | (addr & 0x7fff)]; + } else if(read_size == MEMSIZE_WORD) { + r = rom[((addr & 0x7f0000) >> 1) | (addr & 0x7fff)] | + rom[(((addr + 1) & 0x7f0000) >> 1) | ((addr + 1) & 0x7fff)] << 8; + } else if(read_size == MEMSIZE_LONG) { + r = rom[((addr & 0x7f0000) >> 1) | (addr & 0x7fff)] | + rom[(((addr + 1) & 0x7f0000) >> 1) | ((addr + 1) & 0x7fff)] << 8 | + rom[(((addr + 2) & 0x7f0000) >> 1) | ((addr + 2) & 0x7fff)] << 16; + } + } else if(map == MEMMAP_HIROM) { + if(read_size == MEMSIZE_BYTE) { + r = rom[addr & 0x3fffff]; + } else if(read_size == MEMSIZE_WORD) { + r = rom[addr & 0x3fffff] | + rom[(addr + 1) & 0x3fffff] << 8; + } else if(read_size == MEMSIZE_LONG) { + r = rom[addr & 0x3fffff] | + rom[(addr + 1) & 0x3fffff] << 8 | + rom[(addr + 2) & 0x3fffff] << 16; + } + } + return r; +} + +void g65816::rom_write(ulong addr, ulong v, byte write_size) { + if(map == MEMMAP_LOROM) { + if(write_size == MEMSIZE_BYTE) { + rom[((addr & 0x7f0000) >> 1) | (addr & 0x7fff)] = v; + } else if(write_size == MEMSIZE_WORD) { + rom[((addr & 0x7f0000) >> 1) | (addr & 0x7fff)] = v; + rom[(((addr + 1) & 0x7f0000) >> 1) | ((addr + 1) & 0x7fff)] = v >> 8; + } else if(write_size == MEMSIZE_LONG) { + rom[((addr & 0x7f0000) >> 1) | (addr & 0x7fff)] = v; + rom[(((addr + 1) & 0x7f0000) >> 1) | ((addr + 1) & 0x7fff)] = v >> 8; + rom[(((addr + 2) & 0x7f0000) >> 1) | ((addr + 2) & 0x7fff)] = v >> 16; + } + } else if(map == MEMMAP_HIROM) { + if(write_size == MEMSIZE_BYTE) { + rom[addr & 0x3fffff] = v; + } else if(write_size == MEMSIZE_WORD) { + rom[addr & 0x3fffff] = v; + rom[(addr + 1) & 0x3fffff] = v >> 8; + } else if(write_size == MEMSIZE_LONG) { + rom[addr & 0x3fffff] = v; + rom[(addr + 1) & 0x3fffff] = v >> 8; + rom[(addr + 2) & 0x3fffff] = v >> 16; + } + } +} diff --git a/bsnes/memory.obj b/bsnes/memory.obj new file mode 100644 index 00000000..ca0afd4a Binary files /dev/null and b/bsnes/memory.obj differ diff --git a/bsnes/misc/libstr.cpp b/bsnes/misc/libstr.cpp new file mode 100644 index 00000000..a9ba0b40 --- /dev/null +++ b/bsnes/misc/libstr.cpp @@ -0,0 +1,393 @@ +#include "../base.h" +#include "libvlist.cpp" + +typedef struct { +char *s; +ulong size; +}string; + +typedef struct { +vectorlist list; +ulong count; +}stringlist; + +/*********************** +string library functions +***********************/ + +void strresize(string *str, ulong size) { +char *t; +int sl; + if(str->size == size)return; + sl = strlen(str->s); + t = (char*)malloc(size + 1); + strncpy(t, str->s, size); + free(str->s); + str->s = t; + str->size = size; +} + +string *newstr(void) { +string *s; + s = (string*)malloc(sizeof(string)); + s->size = 16; + s->s = (char*)malloc(s->size + 1); + *s->s = 0; + return s; +} + +void memfree(string *s) { + if(s->s)free(s->s); + free(s); +} + +/*************************** +stringlist library functions +***************************/ + +void stradd(stringlist *sl, ulong num) { +int i; +string *s; + while(sl->count < (num + 1)) { + s = newstr(); + sl->list.add((ulong)s); + sl->count++; + } +} + +string *strget(stringlist *sl, ulong num) { +string *s; + if(sl->count < (num + 1)) { stradd(sl, num); } + s = (string*)sl->list.get(num); + return s; +} + +stringlist *newstrlist(void) { +stringlist *sl; + sl = (stringlist*)malloc(sizeof(stringlist)); + sl->count = 0; + stradd(sl, 1); + return sl; +} + +ulong count(stringlist *sl) { + return sl->count; +} + +/**************************** +string manipulation functions +****************************/ + +char *strptr(string *s) { return s->s; } +char *strptr(stringlist *sl, ulong num) { return strget(sl, num)->s; } + +void strcpy(string *dest, char *src) { +int srclen = strlen(src); + if(srclen > dest->size) { strresize(dest, srclen); } + strncpy(dest->s, src, dest->size); +} +void strcpy(string *dest, string *src) { strcpy(dest, src->s); } +void strcpy(stringlist *dest, ulong num, char *src) { strcpy(strget(dest, num), src); } +void strcpy(stringlist *dest, ulong num, string *src) { strcpy(strget(dest, num), src->s); } +void strcpy(stringlist *dest, ulong destnum, stringlist *src, ulong srcnum) { strcpy(strget(dest, destnum), strptr(src, srcnum)); } + +void strset(string *dest, ulong pos, byte c) { +char *s; + if(pos > dest->size) { strresize(dest, pos); } + dest->s[pos] = c; +} +void strset(stringlist *dest, ulong num, ulong pos, byte c) { strset(strget(dest, num), pos, c); } + +void strcat(string *dest, char *src) { +int srclen, destlen; + srclen = strlen(src); + destlen = strlen(dest->s); + if(srclen + destlen > dest->size) { strresize(dest, srclen + destlen); } + strncat(dest->s, src, srclen + destlen); +} +void strcat(string *dest, string *src) { strcat(dest, src->s); } +void strcat(stringlist *dest, ulong num, char *src) { strcat(strget(dest, num), src); } +void strcat(stringlist *dest, ulong num, string *src) { strcat(strget(dest, num), src->s); } +void strcat(stringlist *dest, ulong destnum, stringlist *src, ulong srcnum) { strcat(strget(dest, destnum), strptr(src, srcnum)); } + +ulong strlen(string *s) { return strlen(s->s); } +ulong strlen(stringlist *sl, ulong num) { return strlen(strget(sl, num)->s); } + +void strinsert(string *dest, char *src, ulong pos) { +string *s = newstr(); + strcpy(s, strptr(dest)+pos); + strset(dest, pos, 0); + strcat(dest, src); + strcat(dest, s); + memfree(s); +} +void strinsert(string *dest, string *src, ulong pos) { strinsert(dest, src->s, pos); } +void strinsert(stringlist *dest, ulong num, char *src, ulong pos) { strinsert(strget(dest, num), src, pos); } +void strinsert(stringlist *dest, ulong num, string *src, ulong pos) { strinsert(strget(dest, num), src->s, pos); } +void strinsert(stringlist *dest, ulong destnum, stringlist *src, ulong srcnum, ulong pos) { strinsert(strget(dest, destnum), strptr(src, srcnum), pos); } + +void strremove(string *dest, ulong start, ulong length = 0) { +int destlen; +char *s; +int i, sl = strlen(dest->s); + if(start > dest->size) { strresize(dest, start); } + if(!length) { + strset(dest, start, 0); + return; + } + s = strptr(dest); + for(i=start;is, src); } +ulong strcmp(string *dest, string *src) { return strcmp(dest->s, src->s); } +ulong strcmp(stringlist *dest, ulong num, char *src) { return strcmp(strget(dest, num)->s, src); } +ulong strcmp(stringlist *dest, ulong num, string *src) { return strcmp(strget(dest, num)->s, src->s); } +ulong strcmp(stringlist *dest, ulong destnum, stringlist *src, ulong srcnum) { return strcmp(strget(dest, destnum)->s, strptr(src, srcnum)); } + +ulong stricmp(char *dest, char *src) { +int i, sl = strlen(dest); + if(sl != strlen(src))return 1; + for(i=0;i= 'A' && dest[i] <= 'Z') { + if(dest[i]!=src[i] && dest[i]+0x20!=src[i])return 1; + } else if(dest[i] >='a' && dest[i] <= 'z') { + if(dest[i]!=src[i] && dest[i]-0x20!=src[i])return 1; + } else { + if(dest[i] != src[i])return 1; + } + } + return 0; +} +ulong stricmp(string *dest, char *src) { return stricmp(dest->s, src); } +ulong stricmp(string *dest, string *src) { return stricmp(dest->s, src->s); } +ulong stricmp(stringlist *dest, ulong num, char *src) { return stricmp(strget(dest, num)->s, src); } +ulong stricmp(stringlist *dest, ulong num, string *src) { return stricmp(strget(dest, num)->s, src->s); } +ulong stricmp(stringlist *dest, ulong destnum, stringlist *src, ulong srcnum) { return stricmp(strget(dest, destnum)->s, strptr(src, srcnum)); } + +void strlower(char *str) { +int i, sl = strlen(str); + for(i=0;i= 'A' && str[i] <= 'Z')str[i] += 0x20; } +} +void strlower(string *str) { strlower(str->s); } +void strlower(stringlist *sl, ulong num) { strlower(strptr(sl, num)); } + +void strupper(char *str) { +int i, sl = strlen(str); + for(i=0;i='a' && str[i] <='z')str[i] -= 0x20; } +} +void strupper(string *str) { strupper(str->s); } +void strupper(stringlist *sl, ulong num) { strupper(strptr(sl, num)); } + +ulong strpos(char *str, char *key) { +int i, ssl = strlen(str), ksl = strlen(key); + if(ksl > ssl)return null; + for(i=0;i<=ssl-ksl;i++) { + if(!memcmp(str+i, key, ksl))return i; + } + return null; +} +ulong strpos(string *dest, char *src) { return strpos(dest->s, src); } +ulong strpos(string *dest, string *src) { return strpos(dest->s, src->s); } +ulong strpos(stringlist *dest, ulong num, char *src) { return strpos(strget(dest, num)->s, src); } +ulong strpos(stringlist *dest, ulong num, string *src) { return strpos(strget(dest, num)->s, src->s); } +ulong strpos(stringlist *dest, ulong destnum, stringlist *src, ulong srcnum) { return strpos(strget(dest, destnum)->s, strptr(src, srcnum)); } + +ulong strpos_q(char *str, char *key) { +int i, z, ssl = strlen(str), ksl = strlen(key); +byte x; + if(ksl > ssl)return null; + for(i=0;i<=ssl-ksl;) { + x = str[i]; + if(x == '\"' || x == '\'') { + z = i++; + while(str[i] != x && i < ssl)i++; + if(i >= ssl)i = z; + } + if(!memcmp(str+i, key, ksl)) { + return i; + } else { + i++; + } + } + return null; +} +ulong strpos_q(string *dest, char *src) { return strpos_q(dest->s, src); } +ulong strpos_q(string *dest, string *src) { return strpos_q(dest->s, src->s); } +ulong strpos_q(stringlist *dest, ulong num, char *src) { return strpos_q(strget(dest, num)->s, src); } +ulong strpos_q(stringlist *dest, ulong num, string *src) { return strpos_q(strget(dest, num)->s, src->s); } +ulong strpos_q(stringlist *dest, ulong destnum, stringlist *src, ulong srcnum) { return strpos_q(strget(dest, destnum)->s, strptr(src, srcnum)); } + +void strtr(char *dest, char *before, char *after) { +int i, l, sl = strlen(dest), bsl = strlen(before), asl = strlen(after); + if((bsl != asl) || bsl == 0)return; + for(i=0;is, before, after); } +void strtr(stringlist *dest, ulong num, char *before, char *after) { strtr(strptr(dest, num), before, after); } + +ulong strbegin(char *str, char *key) { +int i, ssl = strlen(str), ksl = strlen(key); + if(ksl > ssl)return 1; + if(!memcmp(str, key, ksl))return 0; + return 1; +} +ulong strbegin(string *str, char *key) { return strbegin(str->s, key); } +ulong strbegin(stringlist *str, ulong num, char *key) { return strbegin(strptr(str, num), key); } + +ulong stribegin(char *str, char *key) { +int i, ssl = strlen(str), ksl = strlen(key); + if(ksl > ssl)return 1; + for(i=0;i= 'A' && str[i] <= 'Z') { + if(str[i] != key[i] && str[i]+0x20 != key[i])return 1; + } else if(str[i] >= 'a' && str[i] <= 'z') { + if(str[i] != key[i] && str[i]-0x20 != key[i])return 1; + } else { + if(str[i] != key[i])return 1; + } + } + return 0; +} +ulong stribegin(string *str, char *key) { return stribegin(str->s, key); } +ulong stribegin(stringlist *str, ulong num, char *key) { return stribegin(strptr(str, num), key); } + +ulong strend(char *str, char *key) { +int i, ssl = strlen(str), ksl = strlen(key); + if(ksl > ssl)return 1; + if(!memcmp(str + ssl - ksl, key, ksl))return 0; + return 1; +} +ulong strend(string *str, char *key) { return strend(str->s, key); } +ulong strend(stringlist *str, ulong num, char *key) { return strend(strptr(str, num), key); } + +ulong striend(char *str, char *key) { +int i, z, ssl = strlen(str), ksl = strlen(key); + if(ksl > ssl)return 1; + for(i=ssl-ksl, z=0;i= 'A' && str[i] <= 'Z') { + if(str[i] != key[z] && str[i]+0x20 != key[z])return 1; + } else if(str[i] >= 'a' && str[i] <= 'z') { + if(str[i] != key[z] && str[i]-0x20 != key[z])return 1; + } else { + if(str[i] != key[z])return 1; + } + } + return 0; +} +ulong striend(string *str, char *key) { return striend(str->s, key); } +ulong striend(stringlist *str, ulong num, char *key) { return striend(strptr(str, num), key); } + +void strltrim(char *str, char *key) { +int i, ssl = strlen(str), ksl = strlen(key); + if(ksl > ssl)return; + if(!strbegin(str, key)) { + for(i=0;is, key); } +void strltrim(stringlist *str, ulong num, char *key) { strltrim(strptr(str, num), key); } + +void striltrim(char *str, char *key) { +int i, ssl = strlen(str), ksl = strlen(key); + if(ksl > ssl)return; + if(!stribegin(str, key)) { + for(i=0;is, key); } +void striltrim(stringlist *str, ulong num, char *key) { striltrim(strptr(str, num), key); } + +void strrtrim(char *str, char *key) { +int ssl = strlen(str), ksl = strlen(key); + if(ksl > ssl)return; + if(!strend(str, key)) { + str[ssl - ksl] = 0; + } +} +void strrtrim(string *str, char *key) { strrtrim(str->s, key); } +void strrtrim(stringlist *str, ulong num, char *key) { strrtrim(strptr(str, num), key); } + +void strirtrim(char *str, char *key) { +int ssl = strlen(str), ksl = strlen(key); + if(ksl > ssl)return; + if(!striend(str, key)) { + str[ssl - ksl] = 0; + } +} +void strirtrim(string *str, char *key) { strirtrim(str->s, key); } +void strirtrim(stringlist *str, ulong num, char *key) { strirtrim(strptr(str, num), key); } + +ulong strhex(char *str) { +ulong r = 0, m = 0; +int i, ssl = strlen(str); +byte x; + for(i=0;i= '0' && str[i] <= '9'); + else if(str[i] >= 'A' && str[i] <= 'F'); + else if(str[i] >= 'a' && str[i] <= 'f'); + else break; + } + for(--i;i>=0;i--, m+=4) { + x = str[i]; + if(x >= '0' && x <= '9')x -= '0'; + else if(x >= 'A' && x <= 'F')x -= 'A' - 0x0a; + else if(x >= 'a' && x <= 'f')x -= 'a' - 0x0a; + else return r; + r |= x << m; + } + return r; +} +ulong strhex(string *str) { return strhex(str->s); } +ulong strhex(stringlist *str, ulong num) { return strhex(strptr(str, num)); } + +ulong strdec(char *str) { +ulong r = 0, m = 1; +int i, ssl = strlen(str); +byte x; + for(i=0;i= '0' && str[i] <= '9'); + else break; + } + for(--i;i>=0;i--, m*=10) { + x = str[i]; + if(x >= '0' && x <= '9')x -= '0'; + else return r; + r += x * m; + } + return r; +} +ulong strdec(string *str) { return strdec(str->s); } +ulong strdec(stringlist *str, ulong num) { return strdec(strptr(str, num)); } + +ulong strbin(char *str) { +ulong r = 0, m = 0; +int i, ssl = strlen(str); +byte x; + for(i=0;i=0;i--, m++) { + x = str[i]; + if(str[i] == '0' || str[i] == '1')x -= '0'; + else return r; + r |= x << m; + } + return r; +} +ulong strbin(string *str) { return strbin(str->s); } +ulong strbin(stringlist *str, ulong num) { return strbin(strptr(str, num)); } + +#include "libstr_math.cpp" +#include "libstr_split.cpp" +#include "libstr_replace.cpp" +#include "libstr_sprintf.cpp" diff --git a/bsnes/misc/libstr_math.cpp b/bsnes/misc/libstr_math.cpp new file mode 100644 index 00000000..7bfedea5 --- /dev/null +++ b/bsnes/misc/libstr_math.cpp @@ -0,0 +1,181 @@ +#define STRMATH_ADD 1 +#define STRMATH_SUB 2 +#define STRMATH_MUL 3 +#define STRMATH_DIV 4 +#define STRMATH_MOD 5 +#define STRMATH_AND 6 +#define STRMATH_OR 7 +#define STRMATH_XOR 8 +#define STRMATH_SHL 9 +#define STRMATH_SHR 10 + +#define STRMATH_LINKED 64 + +#define STRMATHMODE_NEG 1 +#define STRMATHMODE_NOT 2 + +#define __strunktonum() \ + if (s1[0] == '0' && s1[1] == 'x')r = strhex(s1 + 2); \ + else if(s1[0] == '0' && s1[1] == 'b')r = strbin(s1 + 2); \ + else r = strdec(s1) + +#define __strmath_setmode() \ + if (str[i] == '-') { mode = STRMATHMODE_NEG; i++; } \ + else if(str[i] == '~') { mode = STRMATHMODE_NOT; i++; } \ + else if(str[i] == '+') { i++; } \ + else mode=0 + +#define __strmath_modeset() \ + if (mode == STRMATHMODE_NEG)r *= -1; \ + else if(mode == STRMATHMODE_NOT)r =~ r + +#define __strmath_set(__x) \ + s1[z] = 0; \ + z = 0; \ + __strunktonum(); \ + __strmath_modeset(); \ + array[array_size++] = r; \ + array_gate[array_size] = __x + +/*************************************** +strmath(str) + resolves all math entities from within + str, and returns numerical result + example: strmath("5+5")=10 +***************************************/ +ulong p_strmath(char *str) { +int i = 0, ssl = strlen(str); +byte x, mode = 0; +ulong r, array[128], array_size = 0, z = 0; +byte array_gate[128]; +char *s1; + if(!ssl)return 0; + s1 = (char*)malloc(ssl + 1); + __strmath_setmode(); + while(i < ssl) { + x = str[i++]; + if (x == '+') { __strmath_set(STRMATH_ADD); __strmath_setmode(); } + else if(x == '-') { __strmath_set(STRMATH_SUB); __strmath_setmode(); } + else if(x == '*') { __strmath_set(STRMATH_MUL); __strmath_setmode(); } + else if(x == '/') { __strmath_set(STRMATH_DIV); __strmath_setmode(); } + else if(x == '%') { __strmath_set(STRMATH_MOD); __strmath_setmode(); } + else if(x == '&') { __strmath_set(STRMATH_AND); __strmath_setmode(); } + else if(x == '|') { __strmath_set(STRMATH_OR ); __strmath_setmode(); } + else if(x == '^') { __strmath_set(STRMATH_XOR); __strmath_setmode(); } + else if(x == '<' && str[i] == '<') { __strmath_set(STRMATH_SHL); i++; __strmath_setmode(); } + else if(x == '>' && str[i] == '>') { __strmath_set(STRMATH_SHR); i++; __strmath_setmode(); } + else s1[z++] = x; + } + s1[z] = 0; + __strunktonum(); + __strmath_modeset(); + array[array_size++] = r; + free(s1); + + for(i=1;i>= array[i]; array_gate[i] = STRMATH_LINKED; } + } + + for(i=1;i maxpdepth)maxpdepth = pdepth; + } else if(str[i]==')') { + if(pdepth == 0) { + free(str); + return null; //error! too many )'s + } + pdepth --; + } + } + + if(pdepth != 0) { + free(str); + return null; //error! unequal ('s to )'s + } + + pdepth = maxpdepth; + while(pdepth) { + cpdepth = 0; + for(i=0;is); } +ulong strmath(stringlist *str, ulong num) { return strmath(strptr(str, num)); } + +ulong strmathentity(char *str) { +int i, ssl = strlen(str); + for(i=0;i' && str[i+1] == '>'))return 1; + } + return 0; +} +ulong strmathentity(string *str) { return strmathentity(str->s); } +ulong strmathentity(stringlist *str, ulong num) { return strmathentity(strptr(str, num)); } diff --git a/bsnes/misc/libstr_replace.cpp b/bsnes/misc/libstr_replace.cpp new file mode 100644 index 00000000..415ea3d4 --- /dev/null +++ b/bsnes/misc/libstr_replace.cpp @@ -0,0 +1,82 @@ +void replace(string *str, char *key, char *token) { +int i, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str); +ulong replace_count = 0, size; +char *data; + if(ksl > ssl)return; + if(tsl > ksl) { //the new string may be longer than the old string... + for(i=0;i<=ssl-ksl;) { //so let's find out how big of a string we'll need... + if(!memcmp(str->s + i, key, ksl)) { + replace_count++; + i += ksl; + } else i++; + } + size = ssl + ((tsl - ksl) * replace_count); + if(size > str->size)strresize(str, size); + } + data = (char*)malloc(size + 1); + for(i=z=0;is + i, key, ksl)) { + memcpy(data + z, token, tsl); + z += tsl; + i += ksl; + } else data[z++] = str->s[i++]; + } else data[z++] = str->s[i++]; + } + data[z] = 0; + strcpy(str, data); + free(data); +} + +void replace_q(string *str, char *key, char *token) { +int i, l, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str); +byte x; +ulong replace_count = 0, size; +char *data; + if(ksl > ssl)return; + if(tsl > ksl) { + for(i=0;i<=ssl-ksl;) { + x = str->s[i]; + if(x == '\"' || x == '\'') { + l = i; + i++; + while(str->s[i++] != x) { + if(i == ssl) { + i = l; + break; + } + } + } + if(!memcmp(str->s + i, key, ksl)) { + replace_count++; + i += ksl; + } else i++; + } + size = ssl + ((tsl - ksl) * replace_count); + if(size > str->size)strresize(str, size); + } + data = (char*)malloc(size + 1); + for(i=z=0;is[i]; + if(x == '\"' || x == '\'') { + l = i++; + while(str->s[i] != x && i < ssl)i++; + if(i >= ssl)i = l; + else { + memcpy(data + z, str->s + l, i - l); + z += i - l; + } + } + if(i <= ssl - ksl) { + if(!memcmp(str->s + i, key, ksl)) { + memcpy(data + z, token, tsl); + z += tsl; + i += ksl; + replace_count++; + } else data[z++] = str->s[i++]; + } else data[z++] = str->s[i++]; + } + data[z] = 0; + strcpy(str, data); + free(data); +} diff --git a/bsnes/misc/libstr_split.cpp b/bsnes/misc/libstr_split.cpp new file mode 100644 index 00000000..91f9ff1e --- /dev/null +++ b/bsnes/misc/libstr_split.cpp @@ -0,0 +1,41 @@ +void split(stringlist *dest, char *key, char *src) { +int i, ssl = strlen(src), ksl = strlen(key); +byte x; +ulong lp = 0, split_count = 0; + for(i=0;i<=ssl-ksl;) { + if(!memcmp(src + i, key, ksl)) { + x = src[i]; + src[i] = 0; + strcpy(dest, split_count++, src + lp); + src[i] = x; + i += ksl; + lp = i; + } else i++; + } + strcpy(dest, split_count++, src + lp); +} +void split(stringlist *dest, char *key, string *src) { split(dest, key, src->s); } + +void split_q(stringlist *dest, char *key, char *src) { +int i, z, ssl = strlen(src), ksl = strlen(key); +byte x; +ulong lp = 0, split_count = 0; + for(i=0;i<=ssl-ksl;) { + x = src[i]; + if(x=='\"' || x=='\'') { + z = i++; + while(src[i] != x && i < ssl)i++; + if(i >= ssl)i = z; + } + if(!memcmp(src + i, key, ksl)) { + x = src[i]; + src[i] = 0; + strcpy(dest, split_count++, src + lp); + src[i] = x; + i += ksl; + lp = i; + } else i++; + } + strcpy(dest, split_count++, src + lp); +} +void split_q(stringlist *dest, char *key, string *src) { split_q(dest, key, src->s); } diff --git a/bsnes/misc/libstr_sprintf.cpp b/bsnes/misc/libstr_sprintf.cpp new file mode 100644 index 00000000..30a67a2d --- /dev/null +++ b/bsnes/misc/libstr_sprintf.cpp @@ -0,0 +1,130 @@ +void numtobin(char *s, ulong num) { +ulong mask = 0x80000000, len = 0, z = 0; + for(;mask;mask>>=1,len++) { if(num&mask)break; } + len = 32 - len; + do { + if(num&(1<<(len-1)))s[z++] = '1'; + else s[z++] = '0'; + }while(--len); + s[z] = 0; +} + +void sprintf(string *str, char *s, ...) { +va_list args; +char t[2], n[256]; +int i, l, sl, z; +byte pad_type, pad_len; +ulong num; +char *r; + va_start(args, s); + strcpy(str, ""); + for(i=0;i= '0' && s[i+2] <= '9')) { + pad_type = 1; + if(s[i+3] >= '0' && s[i+3] <= '9') { pad_len = (s[i+2]-'0')*10 + (s[i+3]-'0'); i+=4; } + else { pad_len = (s[i+2]-'0'); i+=3; } + } + else if(s[i] >= '0' && s[i] <= '9') { + pad_type = 2; + if(s[i+1] >= '0' && s[i+1] <= '9') { pad_len = (s[i]-'0')*10 + (s[i+1]-'0'); i+=2; } + else { pad_len = (s[i]-'0'); i+=1; } + } + else { pad_type = 0; } + + if(s[i] == 'd') { + num = va_arg(args, ulong); + sprintf(n, "%d", num); + } else if(s[i] == 'x') { + num = va_arg(args, ulong); + sprintf(n, "%x", num); + } else if(s[i] == 'b') { + num = va_arg(args, ulong); + numtobin(n, num); + } else if(s[i] == 's') { + r = va_arg(args, char*); + } + + if(pad_type != 0) { + if(s[i] == 's')sl = strlen(r); + else sl = strlen(n); + if(sl < pad_len) { + while(sl < pad_len) { + strcat(str, (pad_type == 1)?"0":" "); + sl++; + } + } + } + + if(s[i] == 's')strcat(str, r); + else strcat(str, n); + } else { + t[0] = s[i]; + t[1] = 0; + strcat(str, t); + } + } + va_end(args); +} + + +void sprintf(stringlist *str_list, ulong str_num, char *s, ...) { +va_list args; +char t[2], n[256]; +int i, l, sl, z; +byte pad_type, pad_len; +ulong num; +char *r; +string *str = strget(str_list, str_num); + va_start(args, s); + strcpy(str, ""); + for(i=0;i= '0' && s[i+2] <= '9')) { + pad_type = 1; + if(s[i+3] >= '0' && s[i+3] <= '9') { pad_len = (s[i+2]-'0')*10 + (s[i+3]-'0'); i+=4; } + else { pad_len = (s[i+2]-'0'); i+=3; } + } + else if(s[i] >= '0' && s[i] <= '9') { + pad_type = 2; + if(s[i+1] >= '0' && s[i+1] <= '9') { pad_len = (s[i]-'0')*10 + (s[i+1]-'0'); i+=2; } + else { pad_len = (s[i]-'0'); i+=1; } + } + else { pad_type = 0; } + + if(s[i] == 'd') { + num = va_arg(args, ulong); + sprintf(n, "%d", num); + } else if(s[i] == 'x') { + num = va_arg(args, ulong); + sprintf(n, "%x", num); + } else if(s[i] == 'b') { + num = va_arg(args, ulong); + numtobin(n, num); + } else if(s[i] == 's') { + r = va_arg(args, char*); + } + + if(pad_type != 0) { + if(s[i] == 's')sl = strlen(r); + else sl = strlen(n); + if(sl < pad_len) { + while(sl < pad_len) { + strcat(str, (pad_type == 1)?"0":" "); + sl++; + } + } + } + + if(s[i] == 's')strcat(str, r); + else strcat(str, n); + } else { + t[0] = s[i]; + t[1] = 0; + strcat(str, t); + } + } + va_end(args); +} diff --git a/bsnes/misc/libvlist.cpp b/bsnes/misc/libvlist.cpp new file mode 100644 index 00000000..d5825364 --- /dev/null +++ b/bsnes/misc/libvlist.cpp @@ -0,0 +1,55 @@ +ulong __vector_resize(ulong val) +{ +int i; + for(i=0;i<32;i++) { + if((1<= val)break; + } +//if the value is >2 million, this will fail, in which case, +//just use value. otherwise, use the power of 2. + if((1< val)val = 1< max_size)alloc(size + 1); + list[size - 1] = val; + } + + void set(ulong num, ulong val) { + if(num >= max_size)alloc(num + 1); + list[num] = val; + if(++num > size)size = num; + } + + ulong get(ulong num) { + if(num >= max_size)return 0; + return list[num]; + } + + vectorlist() { + list = 0; + size = 0; + max_size = 8; + list = (ulong*)malloc(8*4); + } + + ~vectorlist() { + if(list)free(list); + } + +}; diff --git a/bsnes/mmio.obj b/bsnes/mmio.obj new file mode 100644 index 00000000..090d59ad Binary files /dev/null and b/bsnes/mmio.obj differ diff --git a/bsnes/ppu/mmio.cpp b/bsnes/ppu/mmio.cpp new file mode 100644 index 00000000..4a515a37 --- /dev/null +++ b/bsnes/ppu/mmio.cpp @@ -0,0 +1,198 @@ +#include "../base.h" +#include "../timing/timing.h" +#include "../cpu/g65816.h" +extern g65816 *gx816; +extern snes_timer *snes_time; +extern videostate render; + +ppustate ppu; + +#include "ppu_cache.cpp" + +#include "ppu_dma.cpp" +#include "ppu_screen.cpp" +#include "ppu_vram.cpp" +#include "ppu_palette.cpp" +#include "ppu_timing.cpp" +#include "ppu_oam.cpp" +#include "ppu_wram.cpp" +#include "ppu_mode7.cpp" +#include "ppu_scroll.cpp" +#include "ppu_muldiv.cpp" +#include "ppu_window.cpp" +#include "ppu_addsub.cpp" +#include "ppu_joypad.cpp" +#include "ppu_misc.cpp" + +#include "ppu.cpp" + +byte mmio_read(word addr) { +static word counter = 0; + switch(addr) { + case 0x2134:return mmio_r2134(); + case 0x2135:return mmio_r2135(); + case 0x2136:return mmio_r2136(); + case 0x2137:return mmio_r2137(); + case 0x2138:return mmio_r2138(); + case 0x2139:return mmio_r2139(); + case 0x213a:return mmio_r213a(); + case 0x213b:return mmio_r213b(); + case 0x213c:return mmio_r213c(); + case 0x213d:return mmio_r213d(); + case 0x213e:return mmio_r213e(); + case 0x213f:return mmio_r213f(); + + case 0x2140:case 0x2141:case 0x2142:case 0x2143: + case 0x2144:case 0x2145:case 0x2146:case 0x2147: + case 0x2148:case 0x2149:case 0x214a:case 0x214b: + case 0x214c:case 0x214d:case 0x214e:case 0x214f: + case 0x2150:case 0x2151:case 0x2152:case 0x2153: + case 0x2154:case 0x2155:case 0x2156:case 0x2157: + case 0x2158:case 0x2159:case 0x215a:case 0x215b: + case 0x215c:case 0x215d:case 0x215e:case 0x215f: + case 0x2160:case 0x2161:case 0x2162:case 0x2163: + case 0x2164:case 0x2165:case 0x2166:case 0x2167: + case 0x2168:case 0x2169:case 0x216a:case 0x216b: + case 0x216c:case 0x216d:case 0x216e:case 0x216f: + case 0x2170:case 0x2171:case 0x2172:case 0x2173: + case 0x2174:case 0x2175:case 0x2176:case 0x2177: + case 0x2178:case 0x2179:case 0x217a:case 0x217b: + case 0x217c:case 0x217d:case 0x217e:case 0x217f: + byte x; + x = rand() & 3; + if(x == 0)return gx816->regs.a.b; + if(x == 1)return gx816->regs.x; + if(x == 2)return gx816->regs.y; + if(x == 3) { counter++; return counter >> 1; } + break; + + case 0x21c2:return mmio_r21c2(); + case 0x21c3:return mmio_r21c3(); + + case 0x4016:return mmio_r4016(); + case 0x4210:return mmio_r4210(); + case 0x4211:return mmio_r4211(); + case 0x4212:return mmio_r4212(); + case 0x4214:return mmio_r4214(); + case 0x4215:return mmio_r4215(); + case 0x4216:return mmio_r4216(); + case 0x4217:return mmio_r4217(); + case 0x4218:return mmio_r4218(); + case 0x4219:return mmio_r4219(); + default: +/* + dprintf("* mmio: unknown read [%0.4x]", addr); + debug_set_state(DEBUGMODE_WAIT); + disas_g65816_op(); +*/ + break; + } + return 0x00; +} + +void mmio_write(word addr, byte value) { + switch(addr) { + case 0x2100:mmio_w2100(value);break; + case 0x2101:mmio_w2101(value);break; + case 0x2102:mmio_w2102(value);break; + case 0x2103:mmio_w2103(value);break; + case 0x2104:mmio_w2104(value);break; + case 0x2105:mmio_w2105(value);break; + case 0x2106:mmio_w2106(value);break; + case 0x2107:mmio_w2107(value);break; + case 0x2108:mmio_w2108(value);break; + case 0x2109:mmio_w2109(value);break; + case 0x210a:mmio_w210a(value);break; + case 0x210b:mmio_w210b(value);break; + case 0x210c:mmio_w210c(value);break; + case 0x210d:mmio_w210d(value);break; + case 0x210e:mmio_w210e(value);break; + case 0x210f:mmio_w210f(value);break; + case 0x2110:mmio_w2110(value);break; + case 0x2111:mmio_w2111(value);break; + case 0x2112:mmio_w2112(value);break; + case 0x2113:mmio_w2113(value);break; + case 0x2114:mmio_w2114(value);break; + case 0x2115:mmio_w2115(value);break; + case 0x2116:mmio_w2116(value);break; + case 0x2117:mmio_w2117(value);break; + case 0x2118:mmio_w2118(value);break; + case 0x2119:mmio_w2119(value);break; + case 0x211a:mmio_w211a(value);break; + case 0x211b:mmio_w211b(value);break; + case 0x211c:mmio_w211c(value);break; + case 0x211d:mmio_w211d(value);break; + case 0x211e:mmio_w211e(value);break; + case 0x211f:mmio_w211f(value);break; + case 0x2120:mmio_w2120(value);break; + case 0x2121:mmio_w2121(value);break; + case 0x2122:mmio_w2122(value);break; + case 0x2123:mmio_w2123(value);break; + case 0x2124:mmio_w2124(value);break; + case 0x2125:mmio_w2125(value);break; + case 0x2126:mmio_w2126(value);break; + case 0x2127:mmio_w2127(value);break; + case 0x2128:mmio_w2128(value);break; + case 0x2129:mmio_w2129(value);break; + case 0x212a:mmio_w212a(value);break; + case 0x212b:mmio_w212b(value);break; + case 0x212c:mmio_w212c(value);break; + case 0x212d:mmio_w212d(value);break; + case 0x212e:mmio_w212e(value);break; + case 0x212f:mmio_w212f(value);break; + case 0x2130:mmio_w2130(value);break; + case 0x2131:mmio_w2131(value);break; + case 0x2132:mmio_w2132(value);break; + case 0x2133:mmio_w2133(value);break; + case 0x2180:mmio_w2180(value);break; + case 0x2181:mmio_w2181(value);break; + case 0x2182:mmio_w2182(value);break; + case 0x2183:mmio_w2183(value);break; + case 0x4016:mmio_w4016(value);break; + case 0x4200:mmio_w4200(value);break; + case 0x4202:mmio_w4202(value);break; + case 0x4203:mmio_w4203(value);break; + case 0x4204:mmio_w4204(value);break; + case 0x4205:mmio_w4205(value);break; + case 0x4206:mmio_w4206(value);break; + case 0x4207:mmio_w4207(value);break; + case 0x4208:mmio_w4208(value);break; + case 0x4209:mmio_w4209(value);break; + case 0x420a:mmio_w420a(value);break; + case 0x420b:mmio_w420b(value);break; + case 0x420c:mmio_w420c(value);break; + case 0x420d:mmio_w420d(value);break; + + case 0x4300:case 0x4310:case 0x4320:case 0x4330: + case 0x4340:case 0x4350:case 0x4360:case 0x4370: + mmio_w43x0((addr >> 4) & 7, value);break; + + case 0x4301:case 0x4311:case 0x4321:case 0x4331: + case 0x4341:case 0x4351:case 0x4361:case 0x4371: + mmio_w43x1((addr >> 4) & 7, value);break; + + case 0x4302:case 0x4312:case 0x4322:case 0x4332: + case 0x4342:case 0x4352:case 0x4362:case 0x4372: + mmio_w43x2((addr >> 4) & 7, value);break; + + case 0x4303:case 0x4313:case 0x4323:case 0x4333: + case 0x4343:case 0x4353:case 0x4363:case 0x4373: + mmio_w43x3((addr >> 4) & 7, value);break; + + case 0x4304:case 0x4314:case 0x4324:case 0x4334: + case 0x4344:case 0x4354:case 0x4364:case 0x4374: + mmio_w43x4((addr >> 4) & 7, value);break; + + case 0x4305:case 0x4315:case 0x4325:case 0x4335: + case 0x4345:case 0x4355:case 0x4365:case 0x4375: + mmio_w43x5((addr >> 4) & 7, value);break; + + case 0x4306:case 0x4316:case 0x4326:case 0x4336: + case 0x4346:case 0x4356:case 0x4366:case 0x4376: + mmio_w43x6((addr >> 4) & 7, value);break; + + case 0x4307:case 0x4317:case 0x4327:case 0x4337: + case 0x4347:case 0x4357:case 0x4367:case 0x4377: + mmio_w43x7((addr >> 4) & 7, value);break; + } +} diff --git a/bsnes/ppu/ppu.cpp b/bsnes/ppu/ppu.cpp new file mode 100644 index 00000000..a2745ecf --- /dev/null +++ b/bsnes/ppu/ppu.cpp @@ -0,0 +1,476 @@ +#define RENDER_MAIN 0 +#define RENDER_SUB 1 + +#include "ppu_render.cpp" + +/********************** + *** priority table *** + ********************************* + *** p = $2105 bit 3 *** + *** o = tile priority bit *** + *** s = sprite priority (0-3) *** + ********************************* + *** p = 0 : p = 1 *** + *** bg4(o = 0) : bg4(o = 0) *** + *** bg3(o = 0) : bg3(o = 0) *** + *** oam(s = 0) : oam(s = 0) *** + *** bg4(o = 1) : bg4(o = 1) *** + *** bg3(o = 1) : oam(s = 1) *** + *** oam(s = 1) : bg2(o = 0) *** + *** bg2(o = 0) : bg1(o = 0) *** + *** bg1(o = 0) : oam(s = 2) *** + *** oam(s = 2) : bg2(o = 1) *** + *** bg2(o = 1) : bg1(o = 1) *** + *** bg1(o = 1) : oam(s = 3) *** + *** oam(s = 3) : bg3(o = 1) *** + ********************************/ + +#define debug_ppu_render_line_bg(bgnum, depth, bg, pri) \ + if(render.##bgnum##_enabled[DEBUG_BGENABLED_ALL] == true) { \ + if(render.##bgnum##_enabled[DEBUG_BGENABLED_PRI##pri##] == true) { \ + ppu_render_line_bg(depth, bg, pri); \ + } \ + } +#define debug_ppu_render_line_oam(bgnum, pri) \ + if(render.##bgnum##_enabled[DEBUG_BGENABLED_ALL] == true) { \ + if(render.##bgnum##_enabled[DEBUG_BGENABLED_PRI##pri##] == true) { \ + ppu_render_line_oam(pri); \ + } \ + } + +void ppu_render_line_mode0(void) { + if(ppu.bg_priority_mode == 0) { + debug_ppu_render_line_bg (bg4, COLORDEPTH_4, BG4, 0); + debug_ppu_render_line_bg (bg3, COLORDEPTH_4, BG3, 0); + debug_ppu_render_line_oam(oam, 0); + debug_ppu_render_line_bg (bg4, COLORDEPTH_4, BG4, 1); + debug_ppu_render_line_bg (bg3, COLORDEPTH_4, BG3, 1); + debug_ppu_render_line_oam(oam, 1); + debug_ppu_render_line_bg (bg2, COLORDEPTH_4, BG2, 0); + debug_ppu_render_line_bg (bg1, COLORDEPTH_4, BG1, 0); + debug_ppu_render_line_oam(oam, 2); + debug_ppu_render_line_bg (bg2, COLORDEPTH_4, BG2, 1); + debug_ppu_render_line_bg (bg1, COLORDEPTH_4, BG1, 1); + debug_ppu_render_line_oam(oam, 3); + } else { + debug_ppu_render_line_bg (bg4, COLORDEPTH_4, BG4, 0); + debug_ppu_render_line_bg (bg3, COLORDEPTH_4, BG3, 0); + debug_ppu_render_line_oam(oam, 0); + debug_ppu_render_line_bg (bg4, COLORDEPTH_4, BG4, 1); + debug_ppu_render_line_oam(oam, 1); + debug_ppu_render_line_bg (bg2, COLORDEPTH_4, BG2, 0); + debug_ppu_render_line_bg (bg1, COLORDEPTH_4, BG1, 0); + debug_ppu_render_line_oam(oam, 2); + debug_ppu_render_line_bg (bg2, COLORDEPTH_4, BG2, 1); + debug_ppu_render_line_bg (bg1, COLORDEPTH_4, BG1, 1); + debug_ppu_render_line_oam(oam, 3); + debug_ppu_render_line_bg (bg3, COLORDEPTH_4, BG3, 1); + } +} + +void ppu_render_line_mode1(void) { + if(ppu.bg_priority_mode == 0) { + debug_ppu_render_line_bg (bg3, COLORDEPTH_4, BG3, 0); + debug_ppu_render_line_oam(oam, 0); + debug_ppu_render_line_bg (bg3, COLORDEPTH_4, BG3, 1); + debug_ppu_render_line_oam(oam, 1); + debug_ppu_render_line_bg (bg2, COLORDEPTH_16, BG2, 0); + debug_ppu_render_line_bg (bg1, COLORDEPTH_16, BG1, 0); + debug_ppu_render_line_oam(oam, 2); + debug_ppu_render_line_bg (bg2, COLORDEPTH_16, BG2, 1); + debug_ppu_render_line_bg (bg1, COLORDEPTH_16, BG1, 1); + debug_ppu_render_line_oam(oam, 3); + } else { + debug_ppu_render_line_bg (bg3, COLORDEPTH_4, BG3, 0); + debug_ppu_render_line_oam(oam, 0); + debug_ppu_render_line_oam(oam, 1); + debug_ppu_render_line_bg (bg2, COLORDEPTH_16, BG2, 0); + debug_ppu_render_line_bg (bg1, COLORDEPTH_16, BG1, 0) + debug_ppu_render_line_oam(oam, 2); + debug_ppu_render_line_bg (bg2, COLORDEPTH_16, BG2, 1); + debug_ppu_render_line_bg (bg1, COLORDEPTH_16, BG1, 1) + debug_ppu_render_line_oam(oam, 3); + debug_ppu_render_line_bg (bg3, COLORDEPTH_4, BG3, 1); + } +} + +void ppu_render_line_mode2(void) { + if(ppu.bg_priority_mode == 0) { + debug_ppu_render_line_oam(oam, 0); + debug_ppu_render_line_oam(oam, 1); + debug_ppu_render_line_bg (bg2, COLORDEPTH_16, BG2, 0); + debug_ppu_render_line_bg (bg1, COLORDEPTH_16, BG1, 0); + debug_ppu_render_line_oam(oam, 2); + debug_ppu_render_line_bg (bg2, COLORDEPTH_16, BG2, 1); + debug_ppu_render_line_bg (bg1, COLORDEPTH_16, BG1, 1); + debug_ppu_render_line_oam(oam, 3); + } else { + debug_ppu_render_line_oam(oam, 0); + debug_ppu_render_line_oam(oam, 1); + debug_ppu_render_line_bg (bg2, COLORDEPTH_16, BG2, 0); + debug_ppu_render_line_bg (bg1, COLORDEPTH_16, BG1, 0) + debug_ppu_render_line_oam(oam, 2); + debug_ppu_render_line_bg (bg2, COLORDEPTH_16, BG2, 1); + debug_ppu_render_line_bg (bg1, COLORDEPTH_16, BG1, 1) + debug_ppu_render_line_oam(oam, 3); + } +} + +void ppu_render_line_mode3(void) { + if(ppu.bg_priority_mode == 0) { + debug_ppu_render_line_oam(oam, 0); + debug_ppu_render_line_oam(oam, 1); + debug_ppu_render_line_bg(bg2, COLORDEPTH_16, BG2, 0); + debug_ppu_render_line_bg(bg1, COLORDEPTH_256, BG1, 0); + debug_ppu_render_line_oam(oam, 2); + debug_ppu_render_line_bg(bg2, COLORDEPTH_16, BG2, 1); + debug_ppu_render_line_bg(bg1, COLORDEPTH_256, BG1, 1); + debug_ppu_render_line_oam(oam, 3); + } else { + debug_ppu_render_line_oam(oam, 0); + debug_ppu_render_line_oam(oam, 1); + debug_ppu_render_line_bg(bg2, COLORDEPTH_16, BG2, 0); + debug_ppu_render_line_bg(bg1, COLORDEPTH_256, BG1, 0); + debug_ppu_render_line_oam(oam, 2); + debug_ppu_render_line_bg(bg2, COLORDEPTH_16, BG2, 1); + debug_ppu_render_line_bg(bg1, COLORDEPTH_256, BG1, 1); + debug_ppu_render_line_oam(oam, 3); + } +} + +void ppu_render_line_mode4(void) { + if(ppu.bg_priority_mode == 0) { + debug_ppu_render_line_oam(oam, 0); + debug_ppu_render_line_oam(oam, 1); + debug_ppu_render_line_bg(bg2, COLORDEPTH_4, BG2, 0); + debug_ppu_render_line_bg(bg1, COLORDEPTH_256, BG1, 0); + debug_ppu_render_line_oam(oam, 2); + debug_ppu_render_line_bg(bg2, COLORDEPTH_4, BG2, 1); + debug_ppu_render_line_bg(bg1, COLORDEPTH_256, BG1, 1); + debug_ppu_render_line_oam(oam, 3); + } else { + debug_ppu_render_line_oam(oam, 0); + debug_ppu_render_line_oam(oam, 1); + debug_ppu_render_line_bg(bg2, COLORDEPTH_4, BG2, 0); + debug_ppu_render_line_bg(bg1, COLORDEPTH_256, BG1, 0); + debug_ppu_render_line_oam(oam, 2); + debug_ppu_render_line_bg(bg2, COLORDEPTH_4, BG2, 1); + debug_ppu_render_line_bg(bg1, COLORDEPTH_256, BG1, 1); + debug_ppu_render_line_oam(oam, 3); + } +} + +void ppu_render_line_mode5(void) { + debug_ppu_render_line_bg(bg2, COLORDEPTH_4, BG2, 0); + debug_ppu_render_line_bg(bg1, COLORDEPTH_16, BG1, 0); + debug_ppu_render_line_bg(bg2, COLORDEPTH_4, BG2, 0); + debug_ppu_render_line_bg(bg1, COLORDEPTH_16, BG1, 1); +} + +void ppu_render_line_mode6(void) { + debug_ppu_render_line_bg(bg1, COLORDEPTH_16, BG1, 0); + debug_ppu_render_line_bg(bg1, COLORDEPTH_16, BG1, 1); +} + +void ppu_render_line_mode7(void) { + if(ppu.bg_priority_mode == 0) { + debug_ppu_render_line_oam(oam, 0); + debug_ppu_render_line_oam(oam, 1); + ppu_render_line_m7(); + debug_ppu_render_line_oam(oam, 2); + debug_ppu_render_line_oam(oam, 3); + } else { + debug_ppu_render_line_oam(oam, 0); + debug_ppu_render_line_oam(oam, 1); + ppu_render_line_m7(); + debug_ppu_render_line_oam(oam, 2); + debug_ppu_render_line_oam(oam, 3); + } +} + +void ppu_render_scanline(void) { +int x, y; + ppu.hirq_triggered = false; + ppu.vline_pos++; + if(ppu.vline_pos > 261)ppu.vline_pos = 0; + +//new screen initialize + if(ppu.vline_pos == 0) { + ppu.virq_triggered = false; + ppu.active_hdma_channels = ppu.toggle_active_hdma_channels; + if(ppu.visible_scanlines != ppu.toggle_visible_scanlines) { + ppu.visible_scanlines = ppu.toggle_visible_scanlines; + video_setsnesmode(); + video_setmode(false, 512, ppu.visible_scanlines * 2); + } + gx816->nmi_pin = 1; + } + +//screen refresh + if(ppu.vline_pos == ppu.visible_scanlines) { + if(render.frame_count == 0) { + UpdateDisplay(); + } + render.frame_count++; + if(render.frame_count >= render.frame_skip) { + render.frame_count = 0; + } + ppu.interlace_frame ^= 1; + } + +//automatic joypad read + if(ppu.vline_pos == (ppu.visible_scanlines + 1) && ppu.auto_joypad_read == true) { + UpdateJoypad(); + } + +//nmi + if(ppu.vline_pos == (ppu.visible_scanlines + 8) && gx816->nmi_pin == 1) { + gx816->nmi_pin = 0; + if(gx816->nmi_enabled == true) { + gx816->InvokeIRQ(0xffea); + } + } + + UpdateHDMA(); //found in ppu_dma.cpp + y = ppu.vline_pos; + if(y < ppu.visible_scanlines && (render.frame_skip == 0 || render.frame_count == 0)) { + if(ppu.display_disable == true) { + memset(ppu.screen + y * 512, 0, 1024); + } else { + ppu_clear_pixel_cache(); + switch(ppu.bg_mode) { + case 0:ppu_render_line_mode0();break; + case 1:ppu_render_line_mode1();break; + case 2:ppu_render_line_mode2();break; + case 3:ppu_render_line_mode3();break; + case 4:ppu_render_line_mode4();break; + case 5:ppu_render_line_mode5();break; + case 6:ppu_render_line_mode6();break; + case 7:ppu_render_line_mode7();break; + } + ppu_render_line_to_screen(); + } + } +} + +void ppu_update_scanline(void) { +//starting a new screen? + if(ppu.vline_pos > snes_time->vscan_pos) { + while(ppu.vline_pos != 0) { + ppu_render_scanline(); + } + } + + while(snes_time->vscan_pos > ppu.vline_pos) { + ppu_render_scanline(); + } + + if(!(gx816->regs.p & PF_I)) { + if(ppu.vcounter_enabled == true && ppu.hcounter_enabled == true) { + if(snes_time->vscan_pos == ppu.virq_pos && ppu.virq_triggered == false) { + if(snes_time->hscan_pos >= ppu.hirq_pos && ppu.hirq_triggered == false) { + ppu.irq_triggered = true; + ppu.virq_triggered = true; + ppu.hirq_triggered = true; + gx816->InvokeIRQ(0xffee); + } + } + } else if(ppu.vcounter_enabled == true) { + if(snes_time->vscan_pos == ppu.virq_pos && ppu.virq_triggered == false) { + ppu.irq_triggered = true; + ppu.virq_triggered = true; + gx816->InvokeIRQ(0xffee); + } + } else if(ppu.hcounter_enabled == true) { + if(snes_time->hscan_pos >= ppu.hirq_pos && ppu.hirq_triggered == false) { + ppu.irq_triggered = true; + ppu.hirq_triggered = true; + gx816->InvokeIRQ(0xffee); + } + } + } +} + +byte oam_read(word addr) { + addr &= 1023; + if(addr >= 512) { + addr &= 31; + return ppu.oam[addr + 512]; + } else { + return ppu.oam[addr]; + } +} + +void oam_write(word addr, byte value) { + addr &= 1023; + if(addr >= 512) { + addr &= 31; + ppu.oam[addr + 512] = value; + } else { + ppu.oam[addr] = value; + } +} + +void PPUInit(byte first_time) { +int i, l; +byte r, g, b; +double m; +word *ptr; + if(first_time == 1) { + ppu.screen = (word*)malloc(512 * 480 * 2); + ppu.vram = (byte*)malloc(0x10000); + ppu.cgram = (byte*)malloc(512); + ppu.oam = (byte*)malloc(544); + ppu.light_table = (word*)malloc(16 * 65536 * 2); + ppu_init_tiledata_cache(); + + for(l=0;l<16;l++) { + ppu.mosaic_table[l] = (word*)malloc(4096 * 2); + for(i=0;i<4096;i++) { + ppu.mosaic_table[l][i] = (i / (l + 1)) * (l + 1); + } + } + + ptr = (word*)ppu.light_table; + for(l=0;l<16;l++) { + m = (double)l / 15.0; + for(i=0;i<65536;i++) { + r = (i ) & 31; + g = (i >> 5) & 31; + b = (i >> 10) & 31; + if(l == 0) { r = g = b = 0; } + else if(l == 15); + else { + r = (double)r * m; + g = (double)g * m; + b = (double)b * m; + } + *ptr++ = (r) | (g << 5) | (b << 10); + } + } + } + ppu_clear_pixel_cache(); + memset(ppu.screen, 0, 512 * 480 * 2); + memset(ppu.vram, 0, 0x10000); + memset(ppu.cgram, 0, 512); + memset(ppu.oam, 0, 544); + ppu.ppu_cycles = 0; + ppu.ppu_prev_cycles = 0; + ppu.display_disable = true; + ppu.display_brightness = 15; + ppu.visible_scanlines = 224; + ppu.toggle_visible_scanlines = 224; + + ppu.interlace = false; + ppu.interlace_frame = 0; + ppu.hline_pos = 0; + ppu.vline_pos = 261; + ppu.irq_triggered = false; + ppu.virq_triggered = false; + ppu.hirq_triggered = false; + ppu.vram_write_pos = 0; + ppu.cgram_write_pos = 0; + ppu.wram_write_pos = 0; + ppu.vram_inc_size = 2; + ppu.vram_inc_reg = 0; + ppu.oam_write_pos = 0; + ppu.oam_tiledata_loc = 0; + + ppu.bg_enabled[OAM] = false; + ppu.ss_bg_enabled[OAM] = false; + ppu.mosaic_size = 0; + ppu.mosaic_enabled[BG4] = false; + ppu.mosaic_enabled[BG3] = false; + ppu.mosaic_enabled[BG2] = false; + ppu.mosaic_enabled[BG1] = false; + ppu.bg_windowing_enabled[OAM] = false; + ppu.ss_bg_windowing_enabled[OAM] = false; + ppu.bg_window1_enabled[OAM] = false; + ppu.bg_window2_enabled[OAM] = false; + ppu.bg_window1_clipmode[OAM] = false; + ppu.bg_window2_clipmode[OAM] = false; + ppu.bg_window_mask[OAM] = false; + + for(i=0;i<4;i++) { + ppu.bg_enabled[i] = false; + ppu.ss_bg_enabled[i] = false; + ppu.bg_window1_enabled[i] = false; + ppu.bg_window2_enabled[i] = false; + ppu.bg_windowing_enabled[i] = false; + ppu.ss_bg_windowing_enabled[i] = false; + ppu.bg_window1_clipmode[i] = 0; + ppu.bg_window2_clipmode[i] = 0; + ppu.bg_window_mask[i] = 0; + ppu.bg_tilemap_loc[i] = 0; + ppu.bg_tiledata_loc[i] = 0; + ppu.bg_hscroll_pos[i] = 0; + ppu.bg_vscroll_pos[i] = 0; + } + ppu.bg_priority_mode = 0; + ppu.oam_base_size = 0; + ppu.oam_name_sel = 0; + ppu.bg_mode = 0; + + ppu.mul_a = 0; + ppu.mul_b = 0; + ppu.div_a = 0; + ppu.div_b = 0; + ppu.r_4214 = 0; + ppu.r_4216 = 0; + + ppu.smul_a = 0; + ppu.smul_b = 0; + ppu.smul_r = 0; + + ppu.window1_left = 0; + ppu.window1_right = 0; + ppu.window2_left = 0; + ppu.window2_right = 0; + + ppu.color_window1_enabled = 0; + ppu.color_window2_enabled = 0; + ppu.color_window1_clipmode = 0; + ppu.color_window2_clipmode = 0; + ppu.color_window_mask = 0; + ppu.color_mask = 0; + ppu.ss_color_mask = 0; + ppu.addsub_mode = 0; + ppu.color_mode = 0; + ppu.color_halve = 0; + for(i=0;i<6;i++) { + ppu.bg_color_enabled[i] = false; + } + ppu.color_r = 0; + ppu.color_g = 0; + ppu.color_b = 0; + + ppu.toggle_active_hdma_channels = 0; + ppu.active_hdma_channels = 0; + for(i=0;i<8;i++) { + memset(&dma_channel[i], 0, sizeof(dmachannel)); + ppu.hdma_completed[i] = false; + ppu.hdma_scanlines_remaining[i] = 0; + ppu.hdma_index_pointer[i] = 0; + } + + ppu.vcounter_enabled = false; + ppu.hcounter_enabled = false; + ppu.hirq_pos = 0; + ppu.virq_pos = 0; + + ppu.auto_joypad_read = false; + ppu.joypad_strobe_value = 0; + + ppu.latch_toggle = 0; + ppu.latch_vpos = 0; + ppu.latch_hpos = 0; + + ppu.m7a = ppu.m7b = + ppu.m7c = ppu.m7d = + ppu.m7x = ppu.m7y = 0; + + ppu.m7hofs = ppu.m7vofs = 0x0000; + + ppu.mode7_hflip = false; + ppu.mode7_vflip = false; +} diff --git a/bsnes/ppu/ppu_addsub.cpp b/bsnes/ppu/ppu_addsub.cpp new file mode 100644 index 00000000..bd711235 --- /dev/null +++ b/bsnes/ppu/ppu_addsub.cpp @@ -0,0 +1,60 @@ +/* + $2130 : fixed color / screen add sub + abcd--ef + + ab: main + cd: subscreen + 00: all the time + 01: inside window only + 10: outside window only + 11: all the time + e: 0 = enable addsub for fixed color + 1 = enable addsub for sub screen + f: color / chardata = direct color + (mode3, 4, 7 only) +*/ +void mmio_w2130(byte value) { + ppu.color_mask = (value >> 6) & 3; + ppu.ss_color_mask = (value >> 4) & 3; + ppu.addsub_mode = (value & 0x02)?1:0; +} + +/* + $2131 : addsub designation + mrgsdcba + + m: 0 = enable add color data mode + 1 = enable sub color data mode + r: 1/2 color mode + g: Backarea enable + s: OAM enable + d: BG4 enable + c: BG3 enable + b: BG2 enable + a: BG1 enable +*/ +void mmio_w2131(byte value) { + ppu.color_mode = (value & 0x80)?COLORMODE_SUB:COLORMODE_ADD; + ppu.color_halve = (value & 0x40)?1:0; + ppu.bg_color_enabled[BACK] = (value & 0x20)?true:false; + ppu.bg_color_enabled[OAM] = (value & 0x10)?true:false; + ppu.bg_color_enabled[BG4] = (value & 0x08)?true:false; + ppu.bg_color_enabled[BG3] = (value & 0x04)?true:false; + ppu.bg_color_enabled[BG2] = (value & 0x02)?true:false; + ppu.bg_color_enabled[BG1] = (value & 0x01)?true:false; +} + +/* + $2132 : addsub settings + bgrddddd + + b: affect blue + g: affect green + r: affect red + d: color constant +*/ +void mmio_w2132(byte value) { + if(value & 0x80)ppu.color_b = (value & 0x1f); + if(value & 0x40)ppu.color_g = (value & 0x1f); + if(value & 0x20)ppu.color_r = (value & 0x1f); +} diff --git a/bsnes/ppu/ppu_cache.cpp b/bsnes/ppu/ppu_cache.cpp new file mode 100644 index 00000000..591db059 --- /dev/null +++ b/bsnes/ppu/ppu_cache.cpp @@ -0,0 +1,49 @@ +#define BLENDTYPE_BACK 0 +#define BLENDTYPE_MAIN 1 +#define BLENDTYPE_SUB 2 +#define BLENDTYPE_COMBINE 3 + +#define COLORDEPTH_4 0 +#define COLORDEPTH_16 1 +#define COLORDEPTH_256 2 + +struct { + byte color_main, color_sub; + byte src_main, src_sub; + byte blend_type; +}ppu_pixel_cache[512]; + +#define TILE_2BIT 0 +#define TILE_4BIT 1 +#define TILE_8BIT 2 + +byte *ppu_bg_tiledata[3]; +byte *ppu_bg_tiledata_state[3]; + +//this should be reset once every scanline +void ppu_clear_pixel_cache(void) { +int i; + for(i=0;i<512;i++) { + ppu_pixel_cache[i].color_main = + ppu_pixel_cache[i].color_sub = 0; + ppu_pixel_cache[i].src_main = + ppu_pixel_cache[i].src_sub = BACK; + ppu_pixel_cache[i].blend_type = BLENDTYPE_BACK; + } +} + +void ppu_init_tiledata_cache(void) { +int i; + ppu_bg_tiledata[TILE_2BIT] = (byte*)malloc(262144); + ppu_bg_tiledata[TILE_4BIT] = (byte*)malloc(131072); + ppu_bg_tiledata[TILE_8BIT] = (byte*)malloc( 65536); + ppu_bg_tiledata_state[TILE_2BIT] = (byte*)malloc( 4096); + ppu_bg_tiledata_state[TILE_4BIT] = (byte*)malloc( 2048); + ppu_bg_tiledata_state[TILE_8BIT] = (byte*)malloc( 1024); + memset(ppu_bg_tiledata[TILE_2BIT], 0, 262144); + memset(ppu_bg_tiledata[TILE_4BIT], 0, 131072); + memset(ppu_bg_tiledata[TILE_4BIT], 0, 65536); + memset(ppu_bg_tiledata_state[TILE_2BIT], 0, 4096); + memset(ppu_bg_tiledata_state[TILE_4BIT], 0, 2048); + memset(ppu_bg_tiledata_state[TILE_8BIT], 0, 1024); +} diff --git a/bsnes/ppu/ppu_dma.cpp b/bsnes/ppu/ppu_dma.cpp new file mode 100644 index 00000000..66f2812f --- /dev/null +++ b/bsnes/ppu/ppu_dma.cpp @@ -0,0 +1,485 @@ +#define DMATRANSFER_CPUTOMMIO 0 +#define DMATRANSFER_MMIOTOCPU 1 + +#define DMAINDEX_ABSOLUTE 0 +#define DMAINDEX_INDIRECT 1 + +#define DMAWRITE_INC 0 +#define DMAWRITE_DEC 1 + +#define HDMAMODE_NORMAL 0 +#define HDMAMODE_CONTINUOUS 1 + +typedef struct { + byte transfer_mode; + byte index_mode; + bool fixed_address; + byte write_dir; + byte transfer_type; + word dest_addr; + ulong src_addr; + word transfer_size; + byte indirect_bank_address; + byte hdma_mode; + word hdma_indirect_pointer; +}dmachannel; + +dmachannel dma_channel[8]; + +/* + $43x0 : DMA control + da-ifttt + + d: (dma only) + 0=read from cpu mem, write to $21?? + 1=read from $21??, write to cpu mem + a: (hdma only) + 0=absolute addressing + 1=indirect addressing + f: 1=fixed address, 0=inc/dec address + i: 0=increment address, 1=decrement address + t: transfer type + 000: 1 reg 1 write (01->2118 23->2118 45->2118 67->2118 89->2118) + 001: 2 regs 1 write (01->2118 23->2119 45->2118 67->2119 89->2118) + 010: 1 reg 2 writes (01->2118 23->2118 45->2118 67->2118 89->2118) + 011: 2 regs 2 writes (01->2118 23->2118 45->2119 67->2119 89->2118) + 100: 4 regs 1 write (01->2118 23->2119 45->211a 67->211b 89->2118) + 101-111: unknown +*/ +void mmio_w43x0(byte c, byte value) { + dma_channel[c].transfer_mode = (value & 0x80)?DMATRANSFER_MMIOTOCPU:DMATRANSFER_CPUTOMMIO; + dma_channel[c].index_mode = (value & 0x40)?DMAINDEX_INDIRECT:DMAINDEX_ABSOLUTE; + dma_channel[c].write_dir = (value & 0x10)?DMAWRITE_DEC:DMAWRITE_INC; + dma_channel[c].fixed_address = (value & 0x08)?true:false; + dma_channel[c].transfer_type = (value & 0x07); +} + +/* + $43x1 : DMA destination address + bbbbbbbb + + b: $2100 | b = destination register - limited to $21xx regs only +*/ +void mmio_w43x1(byte c, byte value) { + dma_channel[c].dest_addr = 0x2100 | value; +} + +/* + $43x2-$43x4 : 24-bit DMA source address + + after a dma transfer, this address must be incremented +*/ +void mmio_w43x2(byte c, byte value) { + dma_channel[c].src_addr = (dma_channel[c].src_addr & 0xffff00) | value; +} + +void mmio_w43x3(byte c, byte value) { + dma_channel[c].src_addr = (dma_channel[c].src_addr & 0xff00ff) | (value << 8); +} + +void mmio_w43x4(byte c, byte value) { + dma_channel[c].src_addr = (dma_channel[c].src_addr & 0x00ffff) | (value << 16); +} + +/* + $43x5/$43x6 : DMA transfer size +*/ +void mmio_w43x5(byte c, byte value) { + dma_channel[c].transfer_size = (dma_channel[c].transfer_size & 0xff00) | value; +} + +void mmio_w43x6(byte c, byte value) { + dma_channel[c].transfer_size = (dma_channel[c].transfer_size & 0x00ff) | (value << 8); +} + +/* + $43x7 : HDMA indirect bank address +*/ +void mmio_w43x7(byte c, byte value) { + dma_channel[c].indirect_bank_address = value; +} + +void dma_cputommio(byte c, byte a) { +byte x; + x = gx816->mem_read(MEMMODE_LONG, MEMSIZE_BYTE, dma_channel[c].src_addr); + mmio_write(dma_channel[c].dest_addr + a, x); + if(dma_channel[c].fixed_address == false) { + if(dma_channel[c].write_dir == DMAWRITE_INC)dma_channel[c].src_addr++; + if(dma_channel[c].write_dir == DMAWRITE_DEC)dma_channel[c].src_addr--; + } + dma_channel[c].transfer_size--; +} + +void dma_mmiotocpu(byte c, byte a) { +byte x; + x = mmio_read(dma_channel[c].dest_addr + a); + gx816->mem_write(MEMMODE_LONG, MEMSIZE_BYTE, dma_channel[c].src_addr, x); + if(dma_channel[c].fixed_address == false) { + if(dma_channel[c].write_dir == DMAWRITE_INC)dma_channel[c].src_addr++; + if(dma_channel[c].write_dir == DMAWRITE_DEC)dma_channel[c].src_addr--; + } + dma_channel[c].transfer_size--; +} + +void dma_transfer_type0(byte c) { + if(dma_channel[c].transfer_mode == DMATRANSFER_CPUTOMMIO) { + while(1) { + dma_cputommio(c, 0); if(dma_channel[c].transfer_size == 0)break; + } + } else if(dma_channel[c].transfer_mode == DMATRANSFER_MMIOTOCPU) { + while(1) { + dma_mmiotocpu(c, 0); if(dma_channel[c].transfer_size == 0)break; + } + } +} + +void dma_transfer_type1(byte c) { + if(dma_channel[c].transfer_mode == DMATRANSFER_CPUTOMMIO) { + while(1) { + dma_cputommio(c, 0); if(dma_channel[c].transfer_size == 0)break; + dma_cputommio(c, 1); if(dma_channel[c].transfer_size == 0)break; + } + } else if(dma_channel[c].transfer_mode == DMATRANSFER_MMIOTOCPU) { + while(1) { + dma_mmiotocpu(c, 0); if(dma_channel[c].transfer_size == 0)break; + dma_mmiotocpu(c, 1); if(dma_channel[c].transfer_size == 0)break; + } + } +} + +void dma_transfer_type2(byte c) { + if(dma_channel[c].transfer_mode == DMATRANSFER_CPUTOMMIO) { + while(1) { + dma_cputommio(c, 0); if(dma_channel[c].transfer_size == 0)break; + } + } else if(dma_channel[c].transfer_mode == DMATRANSFER_MMIOTOCPU) { + while(1) { + dma_mmiotocpu(c, 0); if(dma_channel[c].transfer_size == 0)break; + } + } +} + +void dma_transfer_type3(byte c) { + if(dma_channel[c].transfer_mode == DMATRANSFER_CPUTOMMIO) { + while(1) { + dma_cputommio(c, 0); if(dma_channel[c].transfer_size == 0)break; + dma_cputommio(c, 0); if(dma_channel[c].transfer_size == 0)break; + dma_cputommio(c, 1); if(dma_channel[c].transfer_size == 0)break; + dma_cputommio(c, 1); if(dma_channel[c].transfer_size == 0)break; + } + } else if(dma_channel[c].transfer_mode == DMATRANSFER_MMIOTOCPU) { + while(1) { + dma_mmiotocpu(c, 0); if(dma_channel[c].transfer_size == 0)break; + dma_mmiotocpu(c, 0); if(dma_channel[c].transfer_size == 0)break; + dma_mmiotocpu(c, 1); if(dma_channel[c].transfer_size == 0)break; + dma_mmiotocpu(c, 1); if(dma_channel[c].transfer_size == 0)break; + } + } +} + +void dma_transfer_type4(byte c) { + if(dma_channel[c].transfer_mode == DMATRANSFER_CPUTOMMIO) { + while(1) { + dma_cputommio(c, 0); if(dma_channel[c].transfer_size == 0)break; + dma_cputommio(c, 1); if(dma_channel[c].transfer_size == 0)break; + dma_cputommio(c, 2); if(dma_channel[c].transfer_size == 0)break; + dma_cputommio(c, 3); if(dma_channel[c].transfer_size == 0)break; + } + } else if(dma_channel[c].transfer_mode == DMATRANSFER_MMIOTOCPU) { + while(1) { + dma_mmiotocpu(c, 0); if(dma_channel[c].transfer_size == 0)break; + dma_mmiotocpu(c, 1); if(dma_channel[c].transfer_size == 0)break; + dma_mmiotocpu(c, 2); if(dma_channel[c].transfer_size == 0)break; + dma_mmiotocpu(c, 3); if(dma_channel[c].transfer_size == 0)break; + } + } +} + +/* + $420b : DMA enable + $420c : HDMA enable + + each bit corresponds to the respecting DMA channel (7,6,5,4,3,2,1,0) + setting a bit in this register will perform the DMA transfer. multiple + transfers can be done at once. requires one cycle per byte transferred + hdma bits are sticky (they are not cleared automatically after write) +*/ +void mmio_w420b(byte value) { +int i; + for(i=0;i<8;i++) { + if(value & (1 << i)) { + snes_time->add_cpu_cycles(dma_channel[i].transfer_size * 6); + if (dma_channel[i].transfer_type == 0)dma_transfer_type0(i); + else if(dma_channel[i].transfer_type == 1)dma_transfer_type1(i); + else if(dma_channel[i].transfer_type == 2)dma_transfer_type2(i); + else if(dma_channel[i].transfer_type == 3)dma_transfer_type3(i); + else if(dma_channel[i].transfer_type == 4)dma_transfer_type4(i); + else dprintf("* mmio_w420b(): Unknown DMA transfer type: %d", dma_channel[i].transfer_type); + } + } +} + +void mmio_w420c(byte value) { +//don't actually enable hdma channels until the start of the next frame + ppu.toggle_active_hdma_channels = value; +} + +byte hdma_read_absolute(byte c) { +ulong x; + x = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dma_channel[c].src_addr + ppu.hdma_index_pointer[c]); + ppu.hdma_index_pointer[c]++; + return x; +} + +byte hdma_read_indirect(byte c) { +ulong x; + x = gx816->mem_read(MEMMODE_NONE, MEMSIZE_WORD, dma_channel[c].src_addr + ppu.hdma_index_pointer[c]); + x += dma_channel[c].hdma_indirect_pointer; + x = (dma_channel[c].indirect_bank_address << 16) | (x & 0xffff); + x = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, x); + dma_channel[c].hdma_indirect_pointer++; + return x; +} + +void hdma_transfer_type0_absolute(byte c) { + mmio_write(dma_channel[c].dest_addr, hdma_read_absolute(c)); +} + +void hdma_transfer_type0_indirect(byte c) { + mmio_write(dma_channel[c].dest_addr, hdma_read_indirect(c)); + if(dma_channel[c].hdma_mode == HDMAMODE_NORMAL)dma_channel[c].hdma_indirect_pointer -= 1; +} + +void hdma_transfer_type1_absolute(byte c) { + mmio_write(dma_channel[c].dest_addr, hdma_read_absolute(c)); + mmio_write(dma_channel[c].dest_addr + 1, hdma_read_absolute(c)); +} + +void hdma_transfer_type1_indirect(byte c) { + mmio_write(dma_channel[c].dest_addr, hdma_read_indirect(c)); + mmio_write(dma_channel[c].dest_addr + 1, hdma_read_indirect(c)); + if(dma_channel[c].hdma_mode == HDMAMODE_NORMAL)dma_channel[c].hdma_indirect_pointer -= 2; +} + +void hdma_transfer_type2_absolute(byte c) { + mmio_write(dma_channel[c].dest_addr, hdma_read_absolute(c)); + mmio_write(dma_channel[c].dest_addr, hdma_read_absolute(c)); +} + +void hdma_transfer_type2_indirect(byte c) { + mmio_write(dma_channel[c].dest_addr, hdma_read_indirect(c)); + mmio_write(dma_channel[c].dest_addr, hdma_read_indirect(c)); + if(dma_channel[c].hdma_mode == HDMAMODE_NORMAL)dma_channel[c].hdma_indirect_pointer -= 2; +} + +void hdma_transfer_type3_absolute(byte c) { + mmio_write(dma_channel[c].dest_addr, hdma_read_absolute(c)); + mmio_write(dma_channel[c].dest_addr, hdma_read_absolute(c)); + mmio_write(dma_channel[c].dest_addr + 1, hdma_read_absolute(c)); + mmio_write(dma_channel[c].dest_addr + 1, hdma_read_absolute(c)); +} + +void hdma_transfer_type3_indirect(byte c) { + mmio_write(dma_channel[c].dest_addr, hdma_read_indirect(c)); + mmio_write(dma_channel[c].dest_addr, hdma_read_indirect(c)); + mmio_write(dma_channel[c].dest_addr + 1, hdma_read_indirect(c)); + mmio_write(dma_channel[c].dest_addr + 1, hdma_read_indirect(c)); + if(dma_channel[c].hdma_mode == HDMAMODE_NORMAL)dma_channel[c].hdma_indirect_pointer -= 4; +} + +void hdma_transfer_type4_absolute(byte c) { + mmio_write(dma_channel[c].dest_addr, hdma_read_absolute(c)); + mmio_write(dma_channel[c].dest_addr + 1, hdma_read_absolute(c)); + mmio_write(dma_channel[c].dest_addr + 2, hdma_read_absolute(c)); + mmio_write(dma_channel[c].dest_addr + 3, hdma_read_absolute(c)); +} + +void hdma_transfer_type4_indirect(byte c) { + mmio_write(dma_channel[c].dest_addr, hdma_read_indirect(c)); + mmio_write(dma_channel[c].dest_addr + 1, hdma_read_indirect(c)); + mmio_write(dma_channel[c].dest_addr + 2, hdma_read_indirect(c)); + mmio_write(dma_channel[c].dest_addr + 3, hdma_read_indirect(c)); + if(dma_channel[c].hdma_mode == HDMAMODE_NORMAL)dma_channel[c].hdma_indirect_pointer -= 4; +} + +byte hdma_transfer_type_size_table[8] = { 1, 2, 2, 4, 4, 0, 0, 0 }; + +void HDMAFirstWrite(byte c) { + if(dma_channel[c].hdma_mode == HDMAMODE_NORMAL && ppu.hdma_scanlines_remaining[c] == 0x00) { + return; + } + if(dma_channel[c].hdma_mode == HDMAMODE_CONTINUOUS && ppu.hdma_scanlines_remaining[c] == 0x80) { + return; + } + + if(dma_channel[c].index_mode == DMAINDEX_ABSOLUTE) { + if (dma_channel[c].transfer_type == 0)hdma_transfer_type0_absolute(c); + else if(dma_channel[c].transfer_type == 1)hdma_transfer_type1_absolute(c); + else if(dma_channel[c].transfer_type == 2)hdma_transfer_type2_absolute(c); + else if(dma_channel[c].transfer_type == 3)hdma_transfer_type3_absolute(c); + else if(dma_channel[c].transfer_type == 4)hdma_transfer_type4_absolute(c); + else dprintf("* mmio_w420c(): Unknown HDMA transfer type: %d", dma_channel[c].transfer_type); + } else { //indirect + if (dma_channel[c].transfer_type == 0)hdma_transfer_type0_indirect(c); + else if(dma_channel[c].transfer_type == 1)hdma_transfer_type1_indirect(c); + else if(dma_channel[c].transfer_type == 2)hdma_transfer_type2_indirect(c); + else if(dma_channel[c].transfer_type == 3)hdma_transfer_type3_indirect(c); + else if(dma_channel[c].transfer_type == 4)hdma_transfer_type4_indirect(c); + else dprintf("* mmio_w420c(): Unknown HDMA transfer type: %d", dma_channel[c].transfer_type); + } +} + +void UpdateHDMAAbsoluteNormal(byte c) { + if(ppu.hdma_scanlines_remaining[c] == 0x00) { + ppu.hdma_scanlines_remaining[c] = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dma_channel[c].src_addr + ppu.hdma_index_pointer[c]); + + if(ppu.hdma_scanlines_remaining[c] == 0) { + ppu.hdma_completed[c] = true; + return; + } + + dma_channel[c].hdma_indirect_pointer = 0; + if(ppu.hdma_scanlines_remaining[c] > 0x80) { + dma_channel[c].hdma_mode = HDMAMODE_CONTINUOUS; + } else { + dma_channel[c].hdma_mode = HDMAMODE_NORMAL; + } + + ppu.hdma_index_pointer[c]++; + HDMAFirstWrite(c); + } + + ppu.hdma_scanlines_remaining[c]--; +} + +void UpdateHDMAAbsoluteContinuous(byte c) { + if(ppu.hdma_scanlines_remaining[c] == 0x80) { + ppu.hdma_scanlines_remaining[c] = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dma_channel[c].src_addr + ppu.hdma_index_pointer[c]); + + if(ppu.hdma_scanlines_remaining[c] == 0) { + ppu.hdma_completed[c] = true; + return; + } + + dma_channel[c].hdma_indirect_pointer = 0; + if(ppu.hdma_scanlines_remaining[c] > 0x80) { + dma_channel[c].hdma_mode = HDMAMODE_CONTINUOUS; + } else { + dma_channel[c].hdma_mode = HDMAMODE_NORMAL; + } + + ppu.hdma_index_pointer[c]++; + HDMAFirstWrite(c); + ppu.hdma_scanlines_remaining[c]--; + } else { + if (dma_channel[c].transfer_type == 0)hdma_transfer_type0_absolute(c); + else if(dma_channel[c].transfer_type == 1)hdma_transfer_type1_absolute(c); + else if(dma_channel[c].transfer_type == 2)hdma_transfer_type2_absolute(c); + else if(dma_channel[c].transfer_type == 3)hdma_transfer_type3_absolute(c); + else if(dma_channel[c].transfer_type == 4)hdma_transfer_type4_absolute(c); + else dprintf("* mmio_w420c(): Unknown HDMA transfer type: %d", dma_channel[c].transfer_type); + + ppu.hdma_scanlines_remaining[c]--; + } +} + +void UpdateHDMAIndirectNormal(byte c) { + if(ppu.hdma_scanlines_remaining[c] == 0x00) { + ppu.hdma_index_pointer[c] += 2; + ppu.hdma_scanlines_remaining[c] = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dma_channel[c].src_addr + ppu.hdma_index_pointer[c]); + + if(ppu.hdma_scanlines_remaining[c] == 0) { + ppu.hdma_completed[c] = true; + return; + } + + dma_channel[c].hdma_indirect_pointer = 0; + if(ppu.hdma_scanlines_remaining[c] > 0x80) { + dma_channel[c].hdma_mode = HDMAMODE_CONTINUOUS; + } else { + dma_channel[c].hdma_mode = HDMAMODE_NORMAL; + } + + ppu.hdma_index_pointer[c]++; + HDMAFirstWrite(c); + } + + ppu.hdma_scanlines_remaining[c]--; +} + +void UpdateHDMAIndirectContinuous(byte c) { + if(ppu.hdma_scanlines_remaining[c] == 0x80) { + ppu.hdma_index_pointer[c] += 2; + ppu.hdma_scanlines_remaining[c] = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dma_channel[c].src_addr + ppu.hdma_index_pointer[c]); + + if(ppu.hdma_scanlines_remaining[c] == 0) { + ppu.hdma_completed[c] = true; + return; + } + + dma_channel[c].hdma_indirect_pointer = 0; + if(ppu.hdma_scanlines_remaining[c] > 0x80) { + dma_channel[c].hdma_mode = HDMAMODE_CONTINUOUS; + } else { + dma_channel[c].hdma_mode = HDMAMODE_NORMAL; + } + ppu.hdma_index_pointer[c]++; + HDMAFirstWrite(c); + ppu.hdma_scanlines_remaining[c]--; + } else { + if (dma_channel[c].transfer_type == 0)hdma_transfer_type0_indirect(c); + else if(dma_channel[c].transfer_type == 1)hdma_transfer_type1_indirect(c); + else if(dma_channel[c].transfer_type == 2)hdma_transfer_type2_indirect(c); + else if(dma_channel[c].transfer_type == 3)hdma_transfer_type3_indirect(c); + else if(dma_channel[c].transfer_type == 4)hdma_transfer_type4_indirect(c); + else dprintf("* mmio_w420c(): Unknown HDMA transfer type: %d", dma_channel[c].transfer_type); + + ppu.hdma_scanlines_remaining[c]--; + } +} + +void UpdateHDMA(void) { +int c; + for(c=0;c<8;c++) { + if(ppu.active_hdma_channels & (1 << c)) { + if(ppu.vline_pos == 0)continue; + if(ppu.vline_pos == 1) { + ppu.hdma_completed[c] = false; + ppu.hdma_index_pointer[c] = 0; + ppu.hdma_scanlines_remaining[c] = gx816->mem_read(MEMMODE_NONE, MEMSIZE_BYTE, dma_channel[c].src_addr); + ppu.hdma_index_pointer[c]++; + + if(ppu.hdma_scanlines_remaining[c] == 0) { + ppu.hdma_completed[c] = true; + continue; + } + + dma_channel[c].hdma_indirect_pointer = 0; + if(ppu.hdma_scanlines_remaining[c] > 0x80) { + dma_channel[c].hdma_mode = HDMAMODE_CONTINUOUS; + } else { + dma_channel[c].hdma_mode = HDMAMODE_NORMAL; + } + + HDMAFirstWrite(c); + ppu.hdma_scanlines_remaining[c]--; + } else { + if(ppu.hdma_completed[c] == true)continue; + + if(dma_channel[c].index_mode == DMAINDEX_ABSOLUTE) { + if(dma_channel[c].hdma_mode == HDMAMODE_NORMAL) { + UpdateHDMAAbsoluteNormal(c); + } else { + UpdateHDMAAbsoluteContinuous(c); + } + } else { //indirect + if(dma_channel[c].hdma_mode == HDMAMODE_NORMAL) { + UpdateHDMAIndirectNormal(c); + } else { + UpdateHDMAIndirectContinuous(c); + } + } + } + } + } +} diff --git a/bsnes/ppu/ppu_joypad.cpp b/bsnes/ppu/ppu_joypad.cpp new file mode 100644 index 00000000..082325d0 --- /dev/null +++ b/bsnes/ppu/ppu_joypad.cpp @@ -0,0 +1,67 @@ +joypad_state joypad1; + +/* + *1 - The joypad contains a small bit shifter that has 16 bits. + Reading from 4016 reads one bit from this buffer, then moves + the buffer left one, and adds a '1' to the rightmost bit. + Writing a one to $4016 will fill the buffer with the current + joypad button states, and lock the bit shifter at position + zero. All reads will be the first buffer state, or 'B'. + A zero must be written back to $4016 to unlock the buffer, + so that reads will increment the bit shifting position. +*/ +byte mmio_r4016(void) { +byte r = 0; + if(ppu.joypad_strobe_value == 1) { //*1 + r |= joypad1.b; + } else { + if (joypad1.read_pos == 0)r |= joypad1.b; + else if(joypad1.read_pos == 1)r |= joypad1.y; + else if(joypad1.read_pos == 2)r |= joypad1.select; + else if(joypad1.read_pos == 3)r |= joypad1.start; + else if(joypad1.read_pos == 4)r |= joypad1.up; + else if(joypad1.read_pos == 5)r |= joypad1.down; + else if(joypad1.read_pos == 6)r |= joypad1.left; + else if(joypad1.read_pos == 7)r |= joypad1.right; + else if(joypad1.read_pos == 8)r |= joypad1.a; + else if(joypad1.read_pos == 9)r |= joypad1.x; + else if(joypad1.read_pos == 10)r |= joypad1.l; + else if(joypad1.read_pos == 11)r |= joypad1.r; + else if(joypad1.read_pos == 16)r |= 1; //joypad connected bit (1=yes, 0=no) + else r |= 1; //after 16th read, all subsequent reads return 1 + if(++joypad1.read_pos > 17)joypad1.read_pos = 17; + } + return r; +} + +byte mmio_r4218(void) { +byte r; + if(ppu.auto_joypad_read == false) return 0x00; //cannot read joypad if auto joypad read not enabled + if(ppu.vline_pos >= 225 && ppu.vline_pos <= 227)return 0x00; //cannot read joypad while SNES is polling the joypad data + r = joypad1.a << 7 | + joypad1.x << 6 | + joypad1.l << 5 | + joypad1.r << 4; + return r; +} + +byte mmio_r4219(void) { +byte r; + if(ppu.auto_joypad_read == false) return 0x00; //cannot read joypad if auto joypad read not enabled + if(ppu.vline_pos >= 225 && ppu.vline_pos <= 227)return 0x00; //cannot read joypad while SNES is polling the joypad data + r = joypad1.b << 7 | + joypad1.y << 6 | + joypad1.select << 5 | + joypad1.start << 4 | + joypad1.up << 3 | + joypad1.down << 2 | + joypad1.left << 1 | + joypad1.right; + return r; +} + +void mmio_w4016(byte value) { + ppu.joypad_strobe_value = value; + if(value == 1)UpdateJoypad(); + if(value == 0)joypad1.read_pos = 0; +} diff --git a/bsnes/ppu/ppu_misc.cpp b/bsnes/ppu/ppu_misc.cpp new file mode 100644 index 00000000..80d1cf91 --- /dev/null +++ b/bsnes/ppu/ppu_misc.cpp @@ -0,0 +1,15 @@ +/* + $21c2/$21c3 + + These seem to be version information registers... I don't know + what their purpose is, but I do know that the SNES demo rom + expects these values to be returned in order to proceed through + the character test. +*/ +byte mmio_r21c2(void) { + return 0x20; +} + +byte mmio_r21c3(void) { + return 0x00; +} diff --git a/bsnes/ppu/ppu_mode7.cpp b/bsnes/ppu/ppu_mode7.cpp new file mode 100644 index 00000000..302eed08 --- /dev/null +++ b/bsnes/ppu/ppu_mode7.cpp @@ -0,0 +1,74 @@ +/* + $211a : mode7 settings register + ab0000yx + + ab: + 00 = use screen repetition if outside screen area + 01 = ??? + 10 = use character 0x00 repetition if outside screen area + 11 = use back color if outside screen area + y: vertical screen flip + x: horizontal screen flip +*/ +void mmio_w211a(byte value) { + ppu.mode7_vflip = (value & 0x02)?true:false; + ppu.mode7_hflip = (value & 0x01)?true:false; +} + +byte m7_latch = 0x00; + +/* + $211b : m7a / 16-bit source operand for signed multiplication +*/ +void mmio_w211b(byte value) { +static byte latch = 0; + ppu.m7a = (value << 8) | m7_latch; + m7_latch = value; + + if(!latch) { ppu.smul_a = (ppu.smul_a & 0xff00) | value; } + else { ppu.smul_a = (ppu.smul_a & 0x00ff) | (value << 8); } + + latch ^= 1; +} + +/* + $211c : m7b / 8-bit source operand for signed multiplication +*/ +void mmio_w211c(byte value) { + ppu.m7b = (value << 8) | m7_latch; + m7_latch = value; + + ppu.smul_b = value; +} + +/* + $211d : m7c +*/ +void mmio_w211d(byte value) { + ppu.m7c = (value << 8) | m7_latch; + m7_latch = value; +} + +/* + $211e : m7d +*/ +void mmio_w211e(byte value) { + ppu.m7d = (value << 8) | m7_latch; + m7_latch = value; +} + +/* + $211f : m7x +*/ +void mmio_w211f(byte value) { + ppu.m7x = (value << 8) | m7_latch; + m7_latch = value; +} + +/* + $2120 : m7y +*/ +void mmio_w2120(byte value) { + ppu.m7y = (value << 8) | m7_latch; + m7_latch = value; +} diff --git a/bsnes/ppu/ppu_muldiv.cpp b/bsnes/ppu/ppu_muldiv.cpp new file mode 100644 index 00000000..731be27b --- /dev/null +++ b/bsnes/ppu/ppu_muldiv.cpp @@ -0,0 +1,57 @@ +byte mmio_r2134(void) { +ulong r; + r = (signed short)ppu.smul_a * (signed char)ppu.smul_b; + return r & 0xff; +} + +byte mmio_r2135(void) { +ulong r; + r = (signed short)ppu.smul_a * (signed char)ppu.smul_b; + return (r >> 8) & 0xff; +} + +byte mmio_r2136(void) { +ulong r; + r = (signed short)ppu.smul_a * (signed char)ppu.smul_b; + return (r >> 16) & 0xff; +} + +void mmio_w4202(byte value) { + ppu.mul_a = value; +} + +void mmio_w4203(byte value) { + ppu.mul_b = value; + ppu.r_4216 = ppu.mul_a * ppu.mul_b; +} + +void mmio_w4204(byte value) { + ppu.div_a = (ppu.div_a & 0xff00) | value; +} + +void mmio_w4205(byte value) { + ppu.div_a = (ppu.div_a & 0x00ff) | (value << 8); +} + +void mmio_w4206(byte value) { + ppu.div_b = value; + + ppu.r_4214 = (ppu.div_b)?ppu.div_a / ppu.div_b : 0; + ppu.r_4216 = (ppu.div_b)?ppu.div_a % ppu.div_b : 0; +} + +byte mmio_r4214(void) { + return ppu.r_4214; +} + +byte mmio_r4215(void) { + return ppu.r_4214 >> 8; +} + +byte mmio_r4216(void) { + return ppu.r_4216; +} + +byte mmio_r4217(void) { + return ppu.r_4216 >> 8; +} diff --git a/bsnes/ppu/ppu_oam.cpp b/bsnes/ppu/ppu_oam.cpp new file mode 100644 index 00000000..162c6d83 --- /dev/null +++ b/bsnes/ppu/ppu_oam.cpp @@ -0,0 +1,86 @@ +/* + $2101 : OAM settings + sssnnbbb + + s: base sprite size + small : large + 000: 8x8 : 16x16 + 001: 8x8 : 32x32 + 010: 8x8 : 64x64 + 011: 16x16 : 32x32 + 100: 16x16 : 64x64 + 101: 32x32 : 64x64 + 110: 16x32 : 32x64 + 111: 16x32 : 32x32 + small/large is determined by oam size bit + n: name selection (0-3) + b: oam tiledata location (>>14) -- highest bit ignored +*/ +void mmio_w2101(byte value) { + ppu.oam_base_size = (value >> 5); + ppu.oam_name_sel = (value >> 3) & 3; + ppu.oam_tiledata_loc = (value & 3) << 14; +} + +/* + $2102/$2103 : OAM access address + $2102: llllllll + $2103: ???????h + + 9-bit address, h = bit 8, l = bits 7-0 +*/ +byte ppu_oam_write_posl = 0x00, ppu_oam_write_posh = 0x00; + +void mmio_w2102(byte value) { + ppu_oam_write_posl = value; + ppu.oam_write_pos = ((ppu_oam_write_posh << 8) | (ppu_oam_write_posl)) * 2; +} + +void mmio_w2103(byte value) { + ppu_oam_write_posh = value & 0x01; + ppu.oam_write_pos = ((ppu_oam_write_posh << 8) | (ppu_oam_write_posl)) * 2; +} + +byte ppu_oam_latch_data = 0; + +/* + $2104 : OAM write + + write one byte to OAM data. even writes (bit 0 = 0) are cached + to the OAM latch, and no data is transferred to OAM ram. odd writes + (bit 0 = 1) write the latch value, and then the requested value (2 bytes) + to oam data. writes to OAM address 0x0200 and above (priority / x bit 8 table) + always write, but even writes still update the latch data. +*/ +void mmio_w2104(byte value) { + if(ppu.oam_write_pos >= 0x0200) { + if((ppu.oam_write_pos & 1) == 0) { + ppu_oam_latch_data = value; + } + oam_write(ppu.oam_write_pos, value); + } else if((ppu.oam_write_pos & 1) == 0) { + ppu_oam_latch_data = value; + } else { + oam_write((ppu.oam_write_pos & 0x03fe), ppu_oam_latch_data); + oam_write((ppu.oam_write_pos & 0x03fe) + 1, value); + } + ppu.oam_write_pos++; + ppu.oam_write_pos &= 0x03ff; +} + +/* + $2138 : OAM read + + read one byte from OAM data. if address is even (bit 0 = 0), + latch data is updated. +*/ +byte mmio_r2138(void) { +byte r; + r = oam_read(ppu.oam_write_pos); + if((ppu.oam_write_pos & 1) == 0) { + ppu_oam_latch_data = r; + } + ppu.oam_write_pos++; + ppu.oam_write_pos &= 0x03ff; + return r; +} diff --git a/bsnes/ppu/ppu_palette.cpp b/bsnes/ppu/ppu_palette.cpp new file mode 100644 index 00000000..f8f3b142 --- /dev/null +++ b/bsnes/ppu/ppu_palette.cpp @@ -0,0 +1,36 @@ +/* + $2121 : cgram write position + + takes an 8-bit value that indexes into color palette cgram data. + multiply value by 2 to get actual offset into ppu.cgram +*/ +void mmio_w2121(byte value) { +//if(ppu.vline_pos < 224 && ppu.display_disable == false)return; + ppu.cgram_write_pos = value << 1; +} + +/* + $2122 : cgram write + + writes to cgram using cgram_write_pos * 2 as an index +*/ +void mmio_w2122(byte val) { +//if(ppu.vline_pos < 224 && ppu.display_disable == false)return; + ppu.cgram[ppu.cgram_write_pos] = val; + ppu.cgram_write_pos++; + ppu.cgram_write_pos &= 0x01ff; +} + +/* + $213b : cgram read + + read from cgram using cgram_write_pos * 2 as an index +*/ +byte mmio_r213b(void) { +byte r; +//if(ppu.vline_pos < 224 && ppu.display_disable == false)return; + r = ppu.cgram[ppu.cgram_write_pos]; + ppu.cgram_write_pos++; + ppu.cgram_write_pos &= 0x01ff; + return r; +} diff --git a/bsnes/ppu/ppu_render.cpp b/bsnes/ppu/ppu_render.cpp new file mode 100644 index 00000000..648760ee --- /dev/null +++ b/bsnes/ppu/ppu_render.cpp @@ -0,0 +1,753 @@ +byte ppu_addsub_adjust_buffer[96] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 +}; + +#define ppu_pal_pixel(__i) \ + (*((word*)ppu.cgram + __i)) + +word ppu_addsub_pixels(byte x, byte cdest_index, byte cdest_bg, byte csrc_index, byte csrc_bg) { +int r, g, b; +byte hd = 0, hs = 0; +word cdest = ppu_pal_pixel(cdest_index); +word csrc = ppu_pal_pixel(csrc_index); +//oam palettes 0-3 are not affected by color add/sub + if(cdest_bg == OAM) { + if(cdest_index < 192) { + return cdest; + } + } + if(ppu.bg_color_enabled[cdest_bg] == true) { + hd = hs = ppu.color_halve; + } + switch(ppu.color_mode) { + case COLORMODE_ADD: + r = *(ppu_addsub_adjust_buffer + 32 + (( ((cdest ) & 31) >> hd) + ( ((csrc ) & 31) >> hs) )); + g = *(ppu_addsub_adjust_buffer + 32 + (( ((cdest >> 5) & 31) >> hd) + ( ((csrc >> 5) & 31) >> hs) )); + b = *(ppu_addsub_adjust_buffer + 32 + (( ((cdest >> 10) & 31) >> hd) + ( ((csrc >> 10) & 31) >> hs) )); + break; + case COLORMODE_SUB: + r = *(ppu_addsub_adjust_buffer + 32 + (( ((cdest ) & 31) >> hd) - ( ((csrc ) & 31) >> hs) )); + g = *(ppu_addsub_adjust_buffer + 32 + (( ((cdest >> 5) & 31) >> hd) - ( ((csrc >> 5) & 31) >> hs) )); + b = *(ppu_addsub_adjust_buffer + 32 + (( ((cdest >> 10) & 31) >> hd) - ( ((csrc >> 10) & 31) >> hs) )); + break; + } + return ((r) | (g << 5) | (b << 10)); +} + +word ppu_addsub_pixel(byte x, byte cdest_index, byte cdest_bg) { +int r, g, b; +byte hd = 0; +word cdest = ppu_pal_pixel(cdest_index); +//only oam palettes 4-7 are affected by color add/sub + if(cdest_bg == OAM) { + if(cdest_index < 192) { + return cdest; + } + } + if(ppu.bg_color_enabled[cdest_bg] == true) { + hd = ppu.color_halve; + } + switch(ppu.color_mode) { + case COLORMODE_ADD: + r = *(ppu_addsub_adjust_buffer + 32 + (( ((cdest ) & 31) >> hd) + (ppu.color_r >> hd) )); + g = *(ppu_addsub_adjust_buffer + 32 + (( ((cdest >> 5) & 31) >> hd) + (ppu.color_g >> hd) )); + b = *(ppu_addsub_adjust_buffer + 32 + (( ((cdest >> 10) & 31) >> hd) + (ppu.color_b >> hd) )); + break; + case COLORMODE_SUB: + r = *(ppu_addsub_adjust_buffer + 32 + (( ((cdest ) & 31) >> hd) - (ppu.color_r >> hd) )); + g = *(ppu_addsub_adjust_buffer + 32 + (( ((cdest >> 5) & 31) >> hd) - (ppu.color_g >> hd) )); + b = *(ppu_addsub_adjust_buffer + 32 + (( ((cdest >> 10) & 31) >> hd) - (ppu.color_b >> hd) )); + break; + } + return ((r) | (g << 5) | (b << 10)); +} + +#define ppu_render_bg_tile_line_4(__m) \ + col = 0; \ + if(d0 & __m)col += 1; \ + if(d1 & __m)col += 2; \ + *dest++ = col +#define ppu_render_bg_tile_line_16(__m) \ + col = 0; \ + if(d0 & __m)col += 1; \ + if(d1 & __m)col += 2; \ + if(d2 & __m)col += 4; \ + if(d3 & __m)col += 8; \ + *dest++ = col +#define ppu_render_bg_tile_line_256(__m) \ + col = 0; \ + if(d0 & __m)col += 1; \ + if(d1 & __m)col += 2; \ + if(d2 & __m)col += 4; \ + if(d3 & __m)col += 8; \ + if(d4 & __m)col += 16; \ + if(d5 & __m)col += 32; \ + if(d6 & __m)col += 64; \ + if(d7 & __m)col += 128; \ + *dest++ = col + +void ppu_render_bg_tile(byte color_depth, byte bg, word tile_num) { +byte mask, d0, d1, d2, d3, d4, d5, d6, d7, col; +int x, y; +ulong pos; +byte *dest; + switch(color_depth) { + case COLORDEPTH_4: + dest = (byte*)ppu_bg_tiledata[TILE_2BIT] + tile_num * 64; + pos = tile_num * 16; + y = 8; + while(y--) { + d0 = ppu.vram[pos ]; + d1 = ppu.vram[pos + 1]; + ppu_render_bg_tile_line_4(0x80); + ppu_render_bg_tile_line_4(0x40); + ppu_render_bg_tile_line_4(0x20); + ppu_render_bg_tile_line_4(0x10); + ppu_render_bg_tile_line_4(0x08); + ppu_render_bg_tile_line_4(0x04); + ppu_render_bg_tile_line_4(0x02); + ppu_render_bg_tile_line_4(0x01); + pos += 2; + } + ppu_bg_tiledata_state[TILE_2BIT][tile_num] = 0; + break; + case COLORDEPTH_16: + dest = (byte*)ppu_bg_tiledata[TILE_4BIT] + tile_num * 64; + pos = tile_num * 32; + y = 8; + while(y--) { + d0 = ppu.vram[pos ]; + d1 = ppu.vram[pos + 1]; + d2 = ppu.vram[pos + 16]; + d3 = ppu.vram[pos + 17]; + ppu_render_bg_tile_line_16(0x80); + ppu_render_bg_tile_line_16(0x40); + ppu_render_bg_tile_line_16(0x20); + ppu_render_bg_tile_line_16(0x10); + ppu_render_bg_tile_line_16(0x08); + ppu_render_bg_tile_line_16(0x04); + ppu_render_bg_tile_line_16(0x02); + ppu_render_bg_tile_line_16(0x01); + pos += 2; + } + ppu_bg_tiledata_state[TILE_4BIT][tile_num] = 0; + break; + case COLORDEPTH_256: + dest = (byte*)ppu_bg_tiledata[TILE_8BIT] + tile_num * 64; + pos = tile_num * 64; + y = 8; + while(y--) { + d0 = ppu.vram[pos ]; + d1 = ppu.vram[pos + 1]; + d2 = ppu.vram[pos + 16]; + d3 = ppu.vram[pos + 17]; + d4 = ppu.vram[pos + 32]; + d5 = ppu.vram[pos + 33]; + d6 = ppu.vram[pos + 48]; + d7 = ppu.vram[pos + 49]; + ppu_render_bg_tile_line_256(0x80); + ppu_render_bg_tile_line_256(0x40); + ppu_render_bg_tile_line_256(0x20); + ppu_render_bg_tile_line_256(0x10); + ppu_render_bg_tile_line_256(0x08); + ppu_render_bg_tile_line_256(0x04); + ppu_render_bg_tile_line_256(0x02); + ppu_render_bg_tile_line_256(0x01); + pos += 2; + } + ppu_bg_tiledata_state[TILE_8BIT][tile_num] = 0; + break; + } +} + +#define PPU_MAIN 0 +#define PPU_SUB 1 + +bool windows_not_obstructing(byte layer, byte bg, byte x); +bool color_windows_not_obstructing(byte x, byte color_mask_type); + +//light table is mirrored twice so that the high bit (bit 15) in the color +//is ignored, and does not cause color to reach into next light table. +#define ppu_write_pixel() \ + *(ptr + x) = *(light_table + cx) + +void ppu_render_line_to_screen(void) { +int x; +word *ptr, *light_table; +word c, cx, cy; +word screen_width = render.snes_width; + ptr = (word*)ppu.screen; + light_table = (word*)ppu.light_table + (ppu.display_brightness * 65536); + if(ppu.interlace == true) { + ptr += ((ppu.vline_pos * 2) + ppu.interlace_frame) * 512; + } else { + ptr += ppu.vline_pos * 512; + } + for(x=0;x= 192)) { + if(ppu.bg_color_enabled[ppu_pixel_cache[x].src_main] == true) { + ppu_pixel_cache[x].blend_type = BLENDTYPE_COMBINE; + } + } + } + } +} + +struct { + byte num; + byte width, height; + word x, y; + word character; + byte v_flip, h_flip; + byte palette; + byte priority; +}current_sprite; + +void ppu_set_sprite_attributes(byte sprite_num) { +ulong t; +byte size, b; +word x; + t = ppu.oam[(sprite_num << 2) ] | + ppu.oam[(sprite_num << 2) + 1] << 8 | + ppu.oam[(sprite_num << 2) + 2] << 16 | + ppu.oam[(sprite_num << 2) + 3] << 24; + b = ppu.oam[512 + (sprite_num >> 2)]; + + if ((sprite_num & 3) == 0) { size = (b & 0x02)?1:0; x = (b & 0x01)?0x100:0; } + else if((sprite_num & 3) == 1) { size = (b & 0x08)?1:0; x = (b & 0x04)?0x100:0; } + else if((sprite_num & 3) == 2) { size = (b & 0x20)?1:0; x = (b & 0x10)?0x100:0; } + else if((sprite_num & 3) == 3) { size = (b & 0x80)?1:0; x = (b & 0x40)?0x100:0; } + + current_sprite.num = sprite_num; + current_sprite.priority = (t >> 28) & 3; + current_sprite.x = x | (t & 0xff); + current_sprite.y = (t >> 8) & 0xff; + current_sprite.v_flip = (t & 0x80000000)?1:0; + current_sprite.h_flip = (t & 0x40000000)?1:0; + current_sprite.palette = (t >> 25) & 7; + current_sprite.character = (t >> 16) & 0x01ff; + +//size: 0 = small, 1 = large + switch(ppu.oam_base_size) { + case 0: + if(!size) { current_sprite.width = 8; current_sprite.height = 8; } + else { current_sprite.width = 16; current_sprite.height = 16; } + break; + case 1: + if(!size) { current_sprite.width = 8; current_sprite.height = 8; } + else { current_sprite.width = 32; current_sprite.height = 32; } + break; + case 2: + if(!size) { current_sprite.width = 8; current_sprite.height = 8; } + else { current_sprite.width = 64; current_sprite.height = 64; } + break; + case 3: + if(!size) { current_sprite.width = 16; current_sprite.height = 16; } + else { current_sprite.width = 32; current_sprite.height = 32; } + break; + case 4: + if(!size) { current_sprite.width = 16; current_sprite.height = 16; } + else { current_sprite.width = 64; current_sprite.height = 64; } + break; + case 5: + if(!size) { current_sprite.width = 32; current_sprite.height = 32; } + else { current_sprite.width = 64; current_sprite.height = 64; } + break; + case 6: + if(!size) { current_sprite.width = 16; current_sprite.height = 32; } + else { current_sprite.width = 32; current_sprite.height = 64; } + break; + case 7: + if(!size) { current_sprite.width = 16; current_sprite.height = 32; } + else { current_sprite.width = 32; current_sprite.height = 32; } + break; + } +} + +bool windows_not_obstructing(byte layer, byte bg, byte x) { +byte w1_mask, w2_mask; //1 = masked, 0 = not masked + if(layer == PPU_MAIN) { + if(ppu.bg_windowing_enabled[bg] == false)return true; + } else if(layer == PPU_SUB) { + if(ppu.ss_bg_windowing_enabled[bg] == false)return true; + } + + if(ppu.bg_window1_enabled[bg] == true && ppu.bg_window2_enabled[bg] == false) { + if(ppu.bg_window1_clipmode[bg] == CLIPMODE_IN) { + if(x >= ppu.window1_left && x <= ppu.window1_right)return false; + return true; + } else { + if(x <= ppu.window1_left || x >= ppu.window1_right)return false; + return true; + } + } else if(ppu.bg_window2_enabled[bg] == true && ppu.bg_window1_enabled[bg] == false) { + if(ppu.bg_window2_clipmode[bg] == CLIPMODE_IN) { + if(x >= ppu.window2_left && x <= ppu.window2_right)return false; + return true; + } else { + if(x <= ppu.window2_left || x >= ppu.window2_right)return false; + return true; + } + } else if(ppu.bg_window1_enabled[bg] == true && ppu.bg_window2_enabled[bg] == true) { + if(ppu.bg_window1_clipmode[bg] == CLIPMODE_IN) { + if(x >= ppu.window1_left && x <= ppu.window1_right)w1_mask = 1; + else w1_mask = 0; + } else { + if(x <= ppu.window1_left || x >= ppu.window1_right)w1_mask = 1; + else w1_mask = 0; + } + + if(ppu.bg_window2_clipmode[bg] == CLIPMODE_IN) { + if(x >= ppu.window2_left && x <= ppu.window2_right)w2_mask = 1; + else w2_mask = 0; + } else { + if(x <= ppu.window2_left || x >= ppu.window2_right)w2_mask = 1; + else w2_mask = 0; + } + + switch(ppu.bg_window_mask[bg]) { + case WINDOWMASK_OR: + if((w1_mask | w2_mask) == 1)return false; + return true; + case WINDOWMASK_AND: + if((w1_mask & w2_mask) == 1)return false; + return true; + case WINDOWMASK_XOR: + if((w1_mask ^ w2_mask) == 1)return false; + return true; + case WINDOWMASK_XNOR: + if((w1_mask ^ w2_mask) == 0)return false; + return true; + } + } + return true; +} + +bool color_windows_not_obstructing(byte x, byte color_mask_type) { +byte w1_mask, w2_mask; //1 = masked, 0 = not masked +byte color_mask; +bool r; + if(color_mask_type == PPU_MAIN)color_mask = ppu.color_mask; + else color_mask = ppu.ss_color_mask; + + if(color_mask == 0)return false; + if(color_mask == 3)return true; + + if(ppu.color_window1_enabled == false && ppu.color_window2_enabled == false) { + r = true; + } else if(ppu.color_window1_enabled == true && ppu.color_window2_enabled == false) { + if(ppu.color_window1_clipmode == CLIPMODE_IN) { + if(x >= ppu.window1_left && x <= ppu.window1_right)r = false; + else r = true; + } else { + if(x <= ppu.window1_left || x >= ppu.window1_right)r = false; + else r = true; + } + } else if(ppu.color_window1_enabled == false && ppu.color_window2_enabled == true) { + if(ppu.color_window2_clipmode == CLIPMODE_IN) { + if(x >= ppu.window2_left && x <= ppu.window2_right)r = false; + else r = true; + } else { + if(x <= ppu.window2_left || x >= ppu.window2_right)r = false; + else r = true; + } + } else if(ppu.color_window1_enabled == true && ppu.color_window2_enabled == true) { + if(ppu.color_window1_clipmode == CLIPMODE_IN) { + if(x >= ppu.window1_left && x <= ppu.window1_right)w1_mask = 1; + else w1_mask = 0; + } else { + if(x <= ppu.window1_left || x >= ppu.window1_right)w1_mask = 1; + else w1_mask = 0; + } + + if(ppu.color_window2_clipmode == CLIPMODE_IN) { + if(x >= ppu.window2_left && x <= ppu.window2_right)w2_mask = 1; + else w2_mask = 0; + } else { + if(x <= ppu.window2_left || x >= ppu.window2_right)w2_mask = 1; + else w2_mask = 0; + } + + switch(ppu.color_window_mask) { + case WINDOWMASK_OR: + if((w1_mask | w2_mask) == 1)r = false; + else r = true; + break; + case WINDOWMASK_AND: + if((w1_mask & w2_mask) == 1)r = false; + else r = true; + break; + case WINDOWMASK_XOR: + if((w1_mask ^ w2_mask) == 1)r = false; + else r = true; + break; + case WINDOWMASK_XNOR: + if((w1_mask ^ w2_mask) == 0)r = false; + else r = true; + break; + } + } + + if(color_mask == 2) { + r = (r == true)?false:true; + } + + return r; +} + +/* + *1 - When bit 8 of a sprite's character number is set, such that character data + is read from the upper half (upper 8k) of sprite vram, bits 4-3 of $2101 + are added to bits 14-13 of the tiledata location. The address wraps around + the 64k bank. Why this happens, or what it's for, I have no idea. + *2 - The sprite tiledata is stored with 16 tiles making up the first row, followed + by 16 tiles making up the second row, and so on. Therefore, to get the + correct y tile, y / 8 * 1 row (16 tiles) must be used. +*/ + +#define ppu_render_oam_tile_line(__m) \ + x &= 511; \ + if(x < 256) { \ + col = 0; \ + if(d0 & __m)col += 1; \ + if(d1 & __m)col += 2; \ + if(d2 & __m)col += 4; \ + if(d3 & __m)col += 8; \ + if(col) { \ + col += pal_index; \ + col += 128; \ + ppu_set_pixel(OAM, x, col); \ + } \ + } \ + x++ + +void ppu_render_oam_sprite(void) { +word pos, col, chr, tiledata_inc; +byte d0, d1, d2, d3, pal_index; +int x, y, z, x1, mx, mask, p; +int tile_width; + if(ppu.bg_enabled[OAM] == false && ppu.ss_bg_enabled[OAM] == false)return; + + tile_width = current_sprite.width >> SH_8; //e.x. 16x16 sprite = 2x2 tiles + + y = ppu.vline_pos; + x = current_sprite.x; + if(current_sprite.v_flip) { + y = (current_sprite.height - 1) - (ppu.vline_pos - current_sprite.y); + } else { + y = ppu.vline_pos - current_sprite.y; + } + y &= 255; + + chr = current_sprite.character; + tiledata_inc = (chr & 0x100)?(ppu.oam_name_sel << 13):0; //*1 + chr += (y >> SH_8) << SH_16; //*2 + pal_index = (current_sprite.palette << SH_16); + for(x1=0;x1= current_sprite.y && ppu.vline_pos < (current_sprite.y + current_sprite.height)) { + ppu_render_oam_sprite(); +//or if the sprite is so close to the bottom of the screen that the bottom of it actually wraps back around to the top... + } else if((current_sprite.y + current_sprite.height) >= 256 && ppu.vline_pos < ((current_sprite.y + current_sprite.height) & 255)) { + ppu_render_oam_sprite(); + } + } + } +} + +/* + *1 - map_index + The tilemap can be 32x32, 64x32, 32x64, or 64x64. Rather than expanding the width + and height of the tilemap, the game instead stores duplicate tilemaps immediately + following the previous ones. For example, if you were in 64x64 mode, there would + be four tilemaps. Each tilemap would be 2048 bytes in size + (32 tiles * 32 tiles * 2 bytes/tile), the first tilemap would make the top left + corner, the second the top right, the third the bottom left, and the fourth, the + bottom right. Because x / y are divided by the tile size, the tile size setting + (8x8 or 16x16) does not affect the result. + *2 - pos = ppu.bg_tilemap_loc[bg] + map_index + ((y1 / tile_size) & 31) * 64 + ( ((x / tile_size) & 31) * 2); + Format: tilemap start location + + map index (either map 0 or map 1; see *1) + + ((y tile #) mapped to tilemap boundary) * # of bytes per tilemap line + + (((x tile #) mapped to tilemap boundary) * 2 (# of bytes per tilemap entry)); +*/ + +void ppu_render_line_bg(byte color_depth, byte bg, byte priority) { +int x, y, z, x1, y1; +int mirror_x, mirror_y, p; +int screen_x, screen_y; +int bg_x, bg_y; +int xpos, ypos, mosaic_x, mosaic_y; +word t, base_xpos, base_pos, pos, ppos = 0; +word col; +byte *src, *bg_tiledata, *bg_tiledata_state; +byte tiledata_size; +byte tile_size, tile_width, tile_height; +byte mask, pal_index, pal_size; +word tile_num, screen_width, screen_height, screen_width_mask, screen_height_mask, map_index; +word *mosaic_table; + if(ppu.bg_enabled[bg] == false && ppu.ss_bg_enabled[bg] == false)return; + + switch(color_depth) { + case COLORDEPTH_4: + pal_size = 4; + tiledata_size = SH_16; + break; + case COLORDEPTH_16: + pal_size = 16; + tiledata_size = SH_32; + break; + case COLORDEPTH_256: + pal_size = 256; + tiledata_size = SH_64; + break; + } + bg_tiledata = (byte*)ppu_bg_tiledata[color_depth]; + bg_tiledata_state = (byte*)ppu_bg_tiledata_state[color_depth]; + + screen_width = render.snes_width; + screen_height = render.snes_width; //this is correct -- ppu tilemap is based around 256x256, etc. + tile_size = (ppu.bg_tile_size[bg])?SH_16:SH_8; + tile_width = tile_size; + tile_height = tile_size; + + if(ppu.interlace == true && (ppu.bg_mode == 5 || ppu.bg_mode == 6)) { + screen_y = (ppu.vline_pos << SH_2) + ppu.interlace_frame; + } else { + screen_y = ppu.vline_pos; + } + +//Not sure why, but modes 5 and 6 seem to force 16-width tiles. +//The tile size attribute in $2105 has no effect on tile width. + if(ppu.bg_mode == 5 || ppu.bg_mode == 6) { + tile_width = SH_16; + } + + if(tile_size == SH_16) { + screen_width <<= SH_2; + screen_height <<= SH_2; + } + + if(ppu.bg_tilemap_size[bg] & 0x01)screen_width <<= SH_2; + if(ppu.bg_tilemap_size[bg] & 0x02)screen_height <<= SH_2; + + screen_width_mask = screen_width - 1; + screen_height_mask = screen_height - 1; + + if(render.snes_width == 512) { + bg_x = (ppu.bg_hscroll_pos[bg] << SH_2) & screen_width_mask; + } else { + bg_x = ppu.bg_hscroll_pos[bg] & screen_width_mask; + } + if(render.snes_height == 448) { + bg_y = (screen_y + ((ppu.bg_vscroll_pos[bg] << SH_2) & screen_height_mask)) & screen_height_mask; + } else { + bg_y = (screen_y + (ppu.bg_vscroll_pos[bg] & screen_height_mask)) & screen_height_mask; + } + + mosaic_table = (word*)ppu.mosaic_table[ppu.mosaic_size]; + mosaic_y = mosaic_table[bg_y]; + + for(screen_x=0;screen_x> tile_size) > 31)?32*32*2:0; + break; + case 2: + map_index = ((bg_y >> tile_size) > 31)?32*32*2:0; + break; + case 3: + map_index = ((bg_x >> tile_size) > 31)?32*32*2:0; + map_index += ((bg_y >> tile_size) > 31)?32*32*2*2:0; + break; + } + + mosaic_x = mosaic_table[bg_x]; + + base_xpos = ((mosaic_x >> SH_8) & 31); + base_pos = (((mosaic_y >> tile_height) & 31) << SH_32) + ((mosaic_x >> tile_width) & 31); + pos = ppu.bg_tilemap_loc[bg] + map_index + (base_pos << SH_2); + t = *((word*)ppu.vram + (pos >> SH_2)); + mirror_y = (t & 0x8000)?1:0; + mirror_x = (t & 0x4000)?1:0; + if(((t >> 13) & 1) == priority) { + tile_num = t & 0x03ff; + if(tile_width == SH_16) { + if((mosaic_x & 15) >= 8)tile_num++; + if(mirror_x) { + if((mosaic_x & 15) >= 8)tile_num--; + else tile_num++; + } + tile_num &= 0x03ff; + } + if(tile_height == SH_16) { + if((mosaic_y & 15) >= 8)tile_num += 16; + if(mirror_y) { + if((mosaic_y & 15) >= 8)tile_num -= 16; + else tile_num += 16; + } + tile_num &= 0x03ff; + } + tile_num += (ppu.bg_tiledata_loc[bg] >> tiledata_size); + + if(bg_tiledata_state[tile_num] == 1) { + ppu_render_bg_tile(color_depth, bg, tile_num); + } + + pal_index = ((t >> 10) & 7) * pal_size; + + if(mirror_y) { ypos = (7 - (mosaic_y & 7)); } + else { ypos = ( (mosaic_y & 7)); } + +//loop while we are rendering from the same tile, as there's no need to do all of the above work +//unless we have rendered all of the visible tile, taking mosaic into account. + while(1) { + if(mirror_x) { xpos = (7 - (mosaic_x & 7)); } + else { xpos = ( (mosaic_x & 7)); } + col = *(bg_tiledata + (tile_num << SH_64) + (ypos << SH_8) + (xpos)); + if(col) { + ppu_set_pixel(bg, screen_x, col + pal_index); + } + + bg_x++; + bg_x &= screen_width_mask; + mosaic_x = mosaic_table[bg_x]; + + if(base_xpos != ((mosaic_x >> SH_8) & 31))break; + screen_x++; + if(screen_x >= render.snes_width)break; + } + } else { + while(1) { + bg_x++; + bg_x &= screen_width_mask; + mosaic_x = mosaic_table[bg_x]; + + if(base_xpos != ((mosaic_x >> SH_8) & 31))break; + screen_x++; + if(screen_x >= render.snes_width)break; + } + } + } +} + +#ifdef PUBLIC_DOMAIN + #include "ppu_render_mode7f.cpp" +#else + #include "ppu_render_mode7i.cpp" +#endif diff --git a/bsnes/ppu/ppu_render_mode7f.cpp b/bsnes/ppu/ppu_render_mode7f.cpp new file mode 100644 index 00000000..3fd66357 --- /dev/null +++ b/bsnes/ppu/ppu_render_mode7f.cpp @@ -0,0 +1,74 @@ +/* + This mode7 code was derived from my own research, assisted by + information in the public domain. It is therefore redistributed + to the public domain. This code is infinitesimally less accurate + than ppu_render_mode7i.cpp, but nearly twice as slow. + However, this file contains no licensing restrictions. + Please define the precompiler variable PUBLIC_DOMAIN to use this + code instead of mode7i. +*/ + +/* + *1 - converts 16-bit word value to float within the range -128/127. decimal + has range of 256 with steps of 0.00390625 + *2 - (int)float will turn anything from -0.999 to 0.999 to 0. this code will + check to see if the number is negative, and if the decimal place (.xxx) + is zero or not. If value is positive or the decimal place ends on .000, + the number is converted directly to an int. otherwise, one is subtracted + to make up for the rounding error of 1 mentioned above. + result is masked by 1023 (width / height of map is 1024) to prevent + negative values from causing an error with the division in the tile + calculation below. + *3 - mode7 vram consists of 32k of data. there are two 16k regions interleaved + in bytes. the low byte is the tile number, and the high byte is tile data. + the tile data directly indexes into the palette. the map is 128*128, and + there are 256 possible characters. each character is 64 bytes in length. +*/ +void ppu_render_line_m7(void) { +int x, y, sx, sy; +byte tile, palette; +float x_stepx, x_stepy, y_stepx, y_stepy; +float centerx, centery, scrollx, scrolly, startx, starty; + y = (ppu.mode7_vflip == true)?223 - ppu.vline_pos:ppu.vline_pos; + +//*1 + x_stepx = (float)((signed short)ppu.m7a) / 256.0; + x_stepy = (float)((signed short)ppu.m7b) / 256.0; + y_stepx = (float)((signed short)ppu.m7c) / 256.0; + y_stepy = (float)((signed short)ppu.m7d) / 256.0; + + centerx = (float)(1.0 - x_stepx) * (signed short)ppu.m7x - x_stepy * (signed short)ppu.m7y; + centery = (float)(1.0 - y_stepy) * (signed short)ppu.m7y - y_stepx * (signed short)ppu.m7x; + + scrollx = (float)((signed short)ppu.m7hofs); + scrolly = (float)((signed short)ppu.m7vofs); + + startx = centerx + ((scrollx) * x_stepx) + ((scrolly + y) * x_stepy); + starty = centery + ((scrollx) * y_stepx) + ((scrolly + y) * y_stepy); + + for(x=0;x<256;x++) { +//*2 + if(startx < 0.0 && (int)(startx * 32768) & 32767) { + sx = (int)(startx - 1) & 1023; + } else { + sx = (int)startx & 1023; + } + if(starty < 0.0 && (int)(starty * 32768) & 32767) { + sy = (int)(starty - 1) & 1023; + } else { + sy = (int)starty & 1023; + } +//*3 + tile = ppu.vram[(((sy / 8) & 127) * 128 + ((sx / 8) & 127)) << 1]; + palette = ppu.vram[((tile * 64 + (sy & 7) * 8 + (sx & 7)) << 1) + 1]; + if(palette) { + if(ppu.mode7_hflip == true) { + ppu_set_pixel(BG1, 255 - x, palette); + } else { + ppu_set_pixel(BG1, x, palette); + } + } + startx += x_stepx; + starty += y_stepx; + } +} diff --git a/bsnes/ppu/ppu_render_mode7i.cpp b/bsnes/ppu/ppu_render_mode7i.cpp new file mode 100644 index 00000000..6fc9dffe --- /dev/null +++ b/bsnes/ppu/ppu_render_mode7i.cpp @@ -0,0 +1,66 @@ +/* + The algorithm in this file was derived from the snes9x source code. + The snes9x source code is not public domain. If you wish to use this + code, you must abide by the terms of the snes9x license. If you do not + wish to abide by the snes9x licensing terms, please define the precompiler + variable PUBLIC_DOMAIN so that ppu_render_mode7f.cpp is used instead of + this file. You must also remove this file from any work that you release + that does not follow the snes9x license. + See license.txt for more info on the license of this software and snes9x. +*/ + +#define CLIP_10BIT_SIGNED(x) \ + ((x) & ((1 << 10) - 1)) + (((((x) & (1 << 13)) ^ (1 << 13)) - (1 << 13)) >> 3) + +#define CAST_WORDTOINT(x) \ + (int)(((x & 0x8000)?(x | 0xffff0000):(x & 0x00007fff))) + +void ppu_render_line_m7(void) { +int x; +int step_m7a, step_m7c, m7a, m7b, m7c, m7d; +int hoffset, voffset; +int centerx, centery; +int xx, yy; +int px, py; +int tile, palette; + hoffset = (CAST_WORDTOINT(ppu.m7hofs) << 7) >> 7; + voffset = (CAST_WORDTOINT(ppu.m7vofs) << 7) >> 7; + + centerx = (CAST_WORDTOINT(ppu.m7x) << 7) >> 7; + centery = (CAST_WORDTOINT(ppu.m7y) << 7) >> 7; + + if(ppu.mode7_vflip == true) { + yy = 223 - ppu.vline_pos; + } else { + yy = ppu.vline_pos; + } + yy += CLIP_10BIT_SIGNED(voffset - centery); + + m7b = CAST_WORDTOINT(ppu.m7b) * yy + (centerx << 8); + m7d = CAST_WORDTOINT(ppu.m7d) * yy + (centery << 8); + + step_m7a = CAST_WORDTOINT(ppu.m7a); + step_m7c = CAST_WORDTOINT(ppu.m7c); + + xx = CLIP_10BIT_SIGNED(hoffset - centerx); + + m7a = CAST_WORDTOINT(ppu.m7a) * xx; + m7c = CAST_WORDTOINT(ppu.m7c) * xx; + + for(x=0;x<256;x++) { + px = ((m7a + m7b) >> 8) & 1023; + py = ((m7c + m7d) >> 8) & 1023; + + tile = ppu.vram[(((py / 8) & 127) * 128 + ((px / 8) & 127)) << 1]; + palette = ppu.vram[((tile * 64 + (py & 7) * 8 + (px & 7)) << 1) + 1]; + + if(ppu.mode7_hflip == true) { + ppu_set_pixel(BG1, 255 - x, palette); + } else { + ppu_set_pixel(BG1, x, palette); + } + + m7a += step_m7a; + m7c += step_m7c; + } +} diff --git a/bsnes/ppu/ppu_screen.cpp b/bsnes/ppu/ppu_screen.cpp new file mode 100644 index 00000000..9b6c7990 --- /dev/null +++ b/bsnes/ppu/ppu_screen.cpp @@ -0,0 +1,92 @@ +/* + $2100 : screen brightness / enable + d---bbbb + + d: display (0=on, 1=off) + b: brightness (0-15) +*/ +extern emustate emu_state; + +void mmio_w2100(byte value) { + ppu.display_disable = (value & 0x80)?true:false; + ppu.display_brightness = (value & 0x0f); +} + +/* + $2105 : screen mode register + dcbapmmm + + d: bg4 tile size (0=8x8, 1=16x16) + c: bg3 tile size (0=8x8, 1=16x16) + b: bg2 tile size (0=8x8, 1=16x16) + a: bg1 tile size (0=8x8, 1=16x16) + p: bg priority mode + m: screen mode +*/ +void mmio_w2105(byte value) { + ppu.bg_tile_size[BG4] = (value & 0x80)?1:0; + ppu.bg_tile_size[BG3] = (value & 0x40)?1:0; + ppu.bg_tile_size[BG2] = (value & 0x20)?1:0; + ppu.bg_tile_size[BG1] = (value & 0x10)?1:0; + ppu.bg_priority_mode = (value & 0x08)?1:0; + ppu.bg_mode = (value & 0x07); + video_setsnesmode(); +} + +/* + $2106 : mosaic + ssssdcba + + s: size (0=smallest, 15=largest) + d: affect bg4 + c: affect bg3 + b: affect bg2 + a: affect bg1 +*/ +void mmio_w2106(byte value) { + ppu.mosaic_size = (value >> 4) & 15; + ppu.mosaic_enabled[BG4] = (value & 0x08)?true:false; + ppu.mosaic_enabled[BG3] = (value & 0x04)?true:false; + ppu.mosaic_enabled[BG2] = (value & 0x02)?true:false; + ppu.mosaic_enabled[BG1] = (value & 0x01)?true:false; +} + +/* + $212c : main screen desgination + $212d : sub screen designation + ---sdcba + + s: oam enable + d: bg4 enable + c: bg3 enable + b: bg2 enable + a: bg1 enable +*/ +void mmio_w212c(byte value) { + ppu.bg_enabled[OAM] = (value & 0x10)?true:false; + ppu.bg_enabled[BG4] = (value & 0x08)?true:false; + ppu.bg_enabled[BG3] = (value & 0x04)?true:false; + ppu.bg_enabled[BG2] = (value & 0x02)?true:false; + ppu.bg_enabled[BG1] = (value & 0x01)?true:false; +} + +void mmio_w212d(byte value) { + ppu.ss_bg_enabled[OAM] = (value & 0x10)?true:false; + ppu.ss_bg_enabled[BG4] = (value & 0x08)?true:false; + ppu.ss_bg_enabled[BG3] = (value & 0x04)?true:false; + ppu.ss_bg_enabled[BG2] = (value & 0x02)?true:false; + ppu.ss_bg_enabled[BG1] = (value & 0x01)?true:false; +} + +/* + $2133 : screen mode settings + ?????h?i + + h: snes height (0 = 224, 1 = 240) + i: interlace (0 = off, 1 = on) +*/ +void mmio_w2133(byte value) { + ppu.toggle_visible_scanlines = (value & 0x04)?240:224; + ppu.interlace = (value & 0x01)?true:false; + video_setsnesmode(); +} diff --git a/bsnes/ppu/ppu_scroll.cpp b/bsnes/ppu/ppu_scroll.cpp new file mode 100644 index 00000000..c5345950 --- /dev/null +++ b/bsnes/ppu/ppu_scroll.cpp @@ -0,0 +1,46 @@ +/* + $210d-$2114 : Scroll registers + + 210d/210e: bg1 hscroll/bg1 vscroll + 210f/2110: bg2 hscroll/bg2 vscroll + 2111/2112: bg3 hscroll/bg3 vscroll + 2113/2114: bg4 hscroll/bg4 vscroll + + you must write to this register twice to write the full address. + starting positions are 0, 0. only 11 bits of the address are used. +*/ +void mmio_w210d(byte value) { + ppu.bg_hscroll_pos[BG1] = (value << 8) | (ppu.bg_hscroll_pos[BG1] >> 8); + ppu.m7hofs = (value << 8) | m7_latch; + m7_latch = value; +} + +void mmio_w210e(byte value) { + ppu.bg_vscroll_pos[BG1] = (value << 8) | (ppu.bg_vscroll_pos[BG1] >> 8); + ppu.m7vofs = (value << 8) | m7_latch; + m7_latch = value; +} + +void mmio_w210f(byte value) { + ppu.bg_hscroll_pos[BG2] = (value << 8) | (ppu.bg_hscroll_pos[BG2] >> 8); +} + +void mmio_w2110(byte value) { + ppu.bg_vscroll_pos[BG2] = (value << 8) | (ppu.bg_vscroll_pos[BG2] >> 8); +} + +void mmio_w2111(byte value) { + ppu.bg_hscroll_pos[BG3] = (value << 8) | (ppu.bg_hscroll_pos[BG3] >> 8); +} + +void mmio_w2112(byte value) { + ppu.bg_vscroll_pos[BG3] = (value << 8) | (ppu.bg_vscroll_pos[BG3] >> 8); +} + +void mmio_w2113(byte value) { + ppu.bg_hscroll_pos[BG4] = (value << 8) | (ppu.bg_hscroll_pos[BG4] >> 8); +} + +void mmio_w2114(byte value) { + ppu.bg_vscroll_pos[BG4] = (value << 8) | (ppu.bg_vscroll_pos[BG4] >> 8); +} diff --git a/bsnes/ppu/ppu_timing.cpp b/bsnes/ppu/ppu_timing.cpp new file mode 100644 index 00000000..31169975 --- /dev/null +++ b/bsnes/ppu/ppu_timing.cpp @@ -0,0 +1,160 @@ +/* + $213d : vertical latch position + + returns the current scanline. must read from + $2137 before reading from this register. +*/ +byte mmio_r2137(void) { + ppu.latch_toggle = 0; + ppu.latch_vpos = snes_time->vscan_pos; + ppu.latch_hpos = snes_time->hscan_pos; + return 0x00; +} + +byte mmio_r213c(void) { +word r; + r = ppu.latch_hpos; + if(ppu.latch_toggle)r >>= 8; + ppu.latch_toggle ^= 1; + return r; +} + +byte mmio_r213d(void) { +word r; + r = ppu.latch_vpos; + if(ppu.latch_toggle)r >>= 8; + ppu.latch_toggle ^= 1; + return r; +} + +/* + $213e : ppu1 status register + + trm0vvvv + t: time over (?) + r: range over (?) + m: master/slave mode select (?) + v: version # (returns 1) +*/ +byte mmio_r213e(void) { + return 0x01; +} + +/* + $213f : ppu2 status register + fl0mvvvv + f: field # (?) + l: external signal applied (should be 0) + m: ntsc/pal mode (0=ntsc, 1=pal) + v: version # (returns 0) +*/ +byte mmio_r213f(void) { + return 0x00; +} + +/* + $4200 : counter enable + n-vh---j + + n: nmi enable + v: vertical counter enable + h: horizontal counter enable + j: automatic joypad enable + + the v/h counters must be enabled to invoke IRQs. the vertical + counter will override the horizontal counter. in other words, + if both v+h are set, only vertical IRQs will be performed. +*/ +void mmio_w4200(byte value) { + gx816->nmi_enabled = (value & 0x80)?true:false; + ppu.vcounter_enabled = (value & 0x20)?true:false; + ppu.hcounter_enabled = (value & 0x10)?true:false; + ppu.auto_joypad_read = (value & 0x01)?true:false; +} + +/* + $4207/$4208 : horizontal counter position + + 9-bit value, used to invoke horizontal IRQs + horizontal range: 0-339 +*/ +void mmio_w4207(byte value) { + ppu.hirq_pos = (ppu.hirq_pos & 0x0100) | value; +} +void mmio_w4208(byte value) { + ppu.hirq_pos = (ppu.hirq_pos & 0x00ff) | (value & 1) << 8; +} + +/* + $4209/$420a : vertical counter position + + 9-bit value, used to invoke vertical IRQs + vertical range: 0-261 +*/ +void mmio_w4209(byte value) { + ppu.virq_pos = (ppu.virq_pos & 0x0100) | value; +} +void mmio_w420a(byte value) { + ppu.virq_pos = (ppu.virq_pos & 0x00ff) | (value & 1) << 8; +} + +/* + $420d : memory speed + 0000000x + + x: 0 = SlowROM + 1 = FastROM +*/ +void mmio_w420d(byte value) { + gx816->toggle_memory_speed = (value) & 0x01; +} + +/* + $4210 : nmi status + n------- + + n: outside nmi (0=no, 1=yes) +*/ +byte mmio_r4210(void) { +byte r; + r = (gx816->nmi_pin ^ 1)?0x80:0x00; + gx816->nmi_pin = 1; + return r; +} + +/* + $4211 : irq toggle + i?------ + + i: irq state (1=in irq, 0=not in irq)? + ?: unknown, always return 1? +*/ +byte mmio_r4211(void) { +byte r; + r = 0x40; + if(ppu.irq_triggered == true)r |= 0x80; + ppu.irq_triggered = false; + return r; +} + +/* + $4212 : video status + vh-----j + + v: vblank (0=no, 1=yes) + h: hblank (0=no, 1=yes) + j: joypad ready (for auto joypad mode) +*/ +byte mmio_r4212(void) { +byte r; + r = 0x00; + +//set when the SNES is updating the joypad data automatically + if(snes_time->vscan_pos >= (ppu.visible_scanlines + 1) && snes_time->vscan_pos <= (ppu.visible_scanlines + 3))r |= 0x01; + +//set when the SNES is in hblank/vblank + if(snes_time->hscan_pos >= 256)r |= 0x40; + if(snes_time->vscan_pos >= ppu.visible_scanlines)r |= 0x80; + + return r; +} diff --git a/bsnes/ppu/ppu_vram.cpp b/bsnes/ppu/ppu_vram.cpp new file mode 100644 index 00000000..5ce65a35 --- /dev/null +++ b/bsnes/ppu/ppu_vram.cpp @@ -0,0 +1,131 @@ +/* + $2107-$210a : bg1-4 tilemap location + bbbbbbss + + b: location of bg tilemap - highest bit is ignored + s: tilemap size (00 = 32x32, 01 = 64x32, 10 = 32x64, 11 = 64x64) +*/ +void mmio_w2107(byte value) { + ppu.bg_tilemap_loc[BG1] = (value & 0x7c) << 9; + ppu.bg_tilemap_size[BG1] = value & 3; +} +void mmio_w2108(byte value) { + ppu.bg_tilemap_loc[BG2] = (value & 0x7c) << 9; + ppu.bg_tilemap_size[BG2] = value & 3; +} +void mmio_w2109(byte value) { + ppu.bg_tilemap_loc[BG3] = (value & 0x7c) << 9; + ppu.bg_tilemap_size[BG3] = value & 3; +} +void mmio_w210a(byte value) { + ppu.bg_tilemap_loc[BG4] = (value & 0x7c) << 9; + ppu.bg_tilemap_size[BG4] = value & 3; +} + +/* + $210b/$210c: bg1-4 tiledata location + bbbbaaaa + + a: bg1/3 tiledata location (210b/210c) + b: bg2/4 tiledata location (210b/210c) +*/ +void mmio_w210b(byte value) { + ppu.bg_tiledata_loc[BG1] = (value & 0x07) << 13; + ppu.bg_tiledata_loc[BG2] = (value & 0x70) << 9; +} +void mmio_w210c(byte value) { + ppu.bg_tiledata_loc[BG3] = (value & 0x07) << 13; + ppu.bg_tiledata_loc[BG4] = (value & 0x70) << 9; +} + +/* + $2115 : vram write counter + i---ggrr + + i: 0 = increment on $2118/$2139 + 1 = increment on $2119/$213a + g: graphic increment + r: increment rate + 00 = increment by 2 + 01 = increment by 64 + 10 = increment by 128 + 11 = increment by 256 +*/ +void mmio_w2115(byte value) { +if(value & 0x0c)dprintf("$2115 = %0.2x", value); + ppu.vram_inc_reg = (value & 0x80)?1:0; + switch(value & 3) { + case 0x00:ppu.vram_inc_size = 1;break; + case 0x01:ppu.vram_inc_size = 32;break; + case 0x02:ppu.vram_inc_size = 64;break; + case 0x03:ppu.vram_inc_size = 128;break; + } +} + +/* + $2116/$2117 : vram write position + + 15-bit value ($2116/$2117) determining position in vram to write to using $2118 + this value is doubled to get true write position (0000-ffff) +*/ +void mmio_w2116(byte value) { + ppu.vram_write_pos = ((ppu.vram_write_pos & 0xff00) | value) & 0x7fff; +} +void mmio_w2117(byte value) { + ppu.vram_write_pos = ((value << 8) | (ppu.vram_write_pos & 0xff)) & 0x7fff; +} + +/* + $2118/$2119 : vram write + + $2118/$2119 write to vram using vram_write_pos, this is then incremented based on + the settings of $2115 (vram_inc_size / vram_inc_reg) +*/ +void mmio_w2118(byte value) { +word w = ppu.vram_write_pos * 2; + ppu.vram[w] = value; + if(ppu.vram_inc_reg == 0) { + ppu.vram_write_pos += ppu.vram_inc_size; + ppu.vram_write_pos &= 0x7fff; + } + ppu_bg_tiledata_state[TILE_2BIT][(w >> 4)] = 1; + ppu_bg_tiledata_state[TILE_4BIT][(w >> 5)] = 1; + ppu_bg_tiledata_state[TILE_8BIT][(w >> 6)] = 1; +} + +void mmio_w2119(byte value) { +word w = ppu.vram_write_pos * 2 + 1; + ppu.vram[w] = value; + if(ppu.vram_inc_reg == 1) { + ppu.vram_write_pos += ppu.vram_inc_size; + ppu.vram_write_pos &= 0x7fff; + } + ppu_bg_tiledata_state[TILE_2BIT][(w >> 4)] = 1; + ppu_bg_tiledata_state[TILE_4BIT][(w >> 5)] = 1; + ppu_bg_tiledata_state[TILE_8BIT][(w >> 6)] = 1; +} + +/* + $2139/$213a : vram read +*/ +byte mmio_r2139(void) { +word w = ppu.vram_write_pos * 2; +byte r; + r = ppu.vram[w]; + if(ppu.vram_inc_reg == 0) { + ppu.vram_write_pos += ppu.vram_inc_size; + ppu.vram_write_pos &= 0x7fff; + } + return r; +} + +byte mmio_r213a(void) { +word w = ppu.vram_write_pos * 2 + 1; +byte r; + r = ppu.vram[w]; + if(ppu.vram_inc_reg == 1) { + ppu.vram_write_pos += ppu.vram_inc_size; + ppu.vram_write_pos &= 0x7fff; + } + return r; +} diff --git a/bsnes/ppu/ppu_window.cpp b/bsnes/ppu/ppu_window.cpp new file mode 100644 index 00000000..a7a012cf --- /dev/null +++ b/bsnes/ppu/ppu_window.cpp @@ -0,0 +1,121 @@ +/* + $2123/$2124/$2125 : window mask settings + + $2123: + hgfedcba + (bg2) + h: enable window 2 + g: clip window 2 (0=in, 1=out) + f: enable window 1 + e: clip window 1 (0=in, 1=out) + (bg1) + h: enable window 2 + g: clip window 2 (0=in, 1=out) + f: enable window 1 + e: clip window 1 (0=in, 1=out) + $2124: same as $2123, but with bg4/3 + $2125: + hgfedcba + h: enable color window 2 + g: clip window 2 (0=in, 1=out) + f: enable color window 1 + e: clip window 1 (0=in, 1=out) + d: enable OAM window 2 + c: clip window 2 (0=in, 1=out) + b: enable OAM window 1 + a: clip window 1 (0=in, 1=out) +*/ +void mmio_w2123(byte value) { + ppu.bg_window2_enabled [BG2] = (value & 0x80)?true:false; + ppu.bg_window2_clipmode[BG2] = (value & 0x40)?CLIPMODE_OUT:CLIPMODE_IN; + ppu.bg_window1_enabled [BG2] = (value & 0x20)?true:false; + ppu.bg_window1_clipmode[BG2] = (value & 0x10)?CLIPMODE_OUT:CLIPMODE_IN; + ppu.bg_window2_enabled [BG1] = (value & 0x08)?true:false; + ppu.bg_window2_clipmode[BG1] = (value & 0x04)?CLIPMODE_OUT:CLIPMODE_IN; + ppu.bg_window1_enabled [BG1] = (value & 0x02)?true:false; + ppu.bg_window1_clipmode[BG1] = (value & 0x01)?CLIPMODE_OUT:CLIPMODE_IN; +} + +void mmio_w2124(byte value) { + ppu.bg_window2_enabled [BG4] = (value & 0x80)?true:false; + ppu.bg_window2_clipmode[BG4] = (value & 0x40)?CLIPMODE_OUT:CLIPMODE_IN; + ppu.bg_window1_enabled [BG4] = (value & 0x20)?true:false; + ppu.bg_window1_clipmode[BG4] = (value & 0x10)?CLIPMODE_OUT:CLIPMODE_IN; + ppu.bg_window2_enabled [BG3] = (value & 0x08)?true:false; + ppu.bg_window2_clipmode[BG3] = (value & 0x04)?CLIPMODE_OUT:CLIPMODE_IN; + ppu.bg_window1_enabled [BG3] = (value & 0x02)?true:false; + ppu.bg_window1_clipmode[BG3] = (value & 0x01)?CLIPMODE_OUT:CLIPMODE_IN; +} + +void mmio_w2125(byte value) { + ppu.color_window2_enabled = (value & 0x80)?true:false; + ppu.color_window2_clipmode = (value & 0x40)?CLIPMODE_OUT:CLIPMODE_IN; + ppu.color_window1_enabled = (value & 0x20)?true:false; + ppu.color_window1_clipmode = (value & 0x10)?CLIPMODE_OUT:CLIPMODE_IN; + ppu.bg_window2_enabled [OAM] = (value & 0x08)?true:false; + ppu.bg_window2_clipmode[OAM] = (value & 0x04)?CLIPMODE_OUT:CLIPMODE_IN; + ppu.bg_window1_enabled [OAM] = (value & 0x02)?true:false; + ppu.bg_window1_clipmode[OAM] = (value & 0x01)?CLIPMODE_OUT:CLIPMODE_IN; +} + +/* + $2126-$2129 : window position settings + + $2126: window 1 left + $2127: window 1 right + $2128: window 2 left + $2129: window 2 right +*/ +void mmio_w2126(byte value) { ppu.window1_left = value; } +void mmio_w2127(byte value) { ppu.window1_right = value; } +void mmio_w2128(byte value) { ppu.window2_left = value; } +void mmio_w2129(byte value) { ppu.window2_right = value; } + +/* + $212a/$212b : window mask settings + $212a: ddccbbaa (d=bg4, c=bg3, b=bg2, a=bg1) + $212b: ----ccss (c=color add/sub, s=oam) + + 00=or + 01=and + 10=xor + 11=xnor +*/ +void mmio_w212a(byte value) { + ppu.bg_window_mask[BG4] = (value >> 6) & 3; + ppu.bg_window_mask[BG3] = (value >> 4) & 3; + ppu.bg_window_mask[BG2] = (value >> 2) & 3; + ppu.bg_window_mask[BG1] = (value ) & 3; +} + +void mmio_w212b(byte value) { + ppu.color_window_mask = (value >> 2) & 3; + ppu.bg_window_mask[OAM] = (value ) & 3; +} + +/* + $212e/$212f : main window designation + + ---odcba + + o: OAM enable + d: BG4 enable + c: BG3 enable + b: BG2 enable + a: BG1 enable +*/ +void mmio_w212e(byte value) { + ppu.bg_windowing_enabled[OAM] = (value & 0x10)?true:false; + ppu.bg_windowing_enabled[BG4] = (value & 0x08)?true:false; + ppu.bg_windowing_enabled[BG3] = (value & 0x04)?true:false; + ppu.bg_windowing_enabled[BG2] = (value & 0x02)?true:false; + ppu.bg_windowing_enabled[BG1] = (value & 0x01)?true:false; +} + +void mmio_w212f(byte value) { + ppu.ss_bg_windowing_enabled[OAM] = (value & 0x10)?true:false; + ppu.ss_bg_windowing_enabled[BG4] = (value & 0x08)?true:false; + ppu.ss_bg_windowing_enabled[BG3] = (value & 0x04)?true:false; + ppu.ss_bg_windowing_enabled[BG2] = (value & 0x02)?true:false; + ppu.ss_bg_windowing_enabled[BG1] = (value & 0x01)?true:false; +} diff --git a/bsnes/ppu/ppu_wram.cpp b/bsnes/ppu/ppu_wram.cpp new file mode 100644 index 00000000..87f59f23 --- /dev/null +++ b/bsnes/ppu/ppu_wram.cpp @@ -0,0 +1,24 @@ +/* + $2180 : wram write + + write byte to wram write pointer ($2181-$2183), then increment pointer. + always stays within 7e0000-7fffff, high 7 bits of 24-bit offset ignored. +*/ +void mmio_w2180(byte value) { + gx816->mem_write(MEMMODE_LONG, MEMSIZE_BYTE, 0x7e0000 | ppu.wram_write_pos, value); + ppu.wram_write_pos++; + ppu.wram_write_pos &= 0x01ffff; +} + +/* + $2181-$2183: wram write pointer set +*/ +void mmio_w2181(byte value) { + ppu.wram_write_pos = ((ppu.wram_write_pos & 0xffff00) | value) & 0x01ffff; +} +void mmio_w2182(byte value) { + ppu.wram_write_pos = ((ppu.wram_write_pos & 0xff00ff) | (value << 8)) & 0x01ffff; +} +void mmio_w2183(byte value) { + ppu.wram_write_pos = ((ppu.wram_write_pos & 0x00ffff) | (value << 16)) & 0x01ffff; +} diff --git a/bsnes/qc.bat b/bsnes/qc.bat new file mode 100644 index 00000000..76e3786d --- /dev/null +++ b/bsnes/qc.bat @@ -0,0 +1,3 @@ +del c:\root\bsnes_testrom\bsnes.exe +copy bsnes.exe c:\root\bsnes_testrom\bsnes.exe +@pause \ No newline at end of file diff --git a/bsnes/timing.obj b/bsnes/timing.obj new file mode 100644 index 00000000..450d6b3d Binary files /dev/null and b/bsnes/timing.obj differ diff --git a/bsnes/timing/timing.cpp b/bsnes/timing/timing.cpp new file mode 100644 index 00000000..60449829 --- /dev/null +++ b/bsnes/timing/timing.cpp @@ -0,0 +1,103 @@ +#include "../base.h" +#include "../cpu/g65816.h" +extern g65816 *gx816; +#include "timing.h" + +snes_timer::snes_timer() { + master_cycles = 0; + vscan_pos = 0; + hscan_pos = 0; +} + +#define MEMSPEED_FAST 6 +#define MEMSPEED_SLOW 8 +#define MEMSPEED_XSLOW 12 +ulong snes_timer::get_master_cycle_count(ulong offset) { +byte db; +word addr; + db = (offset >> 16) & 0xff; + addr = (offset) & 0xffff; + if(db >= 0x00 && db <= 0x3f) { + if (addr >= 0x0000 && addr <= 0x1fff)return MEMSPEED_SLOW; + else if(addr >= 0x2000 && addr <= 0x3fff)return MEMSPEED_FAST; + else if(addr >= 0x4000 && addr <= 0x41ff)return MEMSPEED_XSLOW; + else if(addr >= 0x4200 && addr <= 0x5fff)return MEMSPEED_FAST; + else if(addr >= 0x6000 && addr <= 0xffff)return MEMSPEED_SLOW; + } else if(db >= 0x40 && db <= 0x7f) { + return MEMSPEED_SLOW; + } else if(db >= 0x80 && db <= 0xbf) { + if (addr >= 0x0000 && addr <= 0x1fff)return MEMSPEED_SLOW; + else if(addr >= 0x2000 && addr <= 0x3fff)return MEMSPEED_FAST; + else if(addr >= 0x4000 && addr <= 0x41ff)return MEMSPEED_XSLOW; + else if(addr >= 0x4200 && addr <= 0x5fff)return MEMSPEED_FAST; + else if(addr >= 0x6000 && addr <= 0x7fff)return MEMSPEED_SLOW; + else if(addr >= 0x8000 && addr <= 0xffff) { + if(gx816->memory_speed == MEMSPEED_SLOWROM) { + return MEMSPEED_SLOW; + } else { //gx816->memory_speed == MEMSPEED_FASTROM + return MEMSPEED_FAST; + } + } + } else if(db >= 0xc0 && db <= 0xff) { + if(gx816->memory_speed == MEMSPEED_SLOWROM) { + return MEMSPEED_SLOW; + } else { //gx816->memory_speed == MEMSPEED_FASTROM + return MEMSPEED_FAST; + } + } + return MEMSPEED_FAST; //this should never be hit +} + +/* + vpa = 1, vda = 1 -> add_cpu_pcycles (opcode fetch) + vpa = 1, vda = 0 -> add_cpu_pcycles (operand fetch) + vpa = 0, vda = 1 -> add_cpu_dcycles (memory fetch) + vpa = 0, vda = 0 -> add_cpu_icycles (internal operation) +*/ +void snes_timer::add_cpu_pcycles(ulong n) { +ulong speed; + speed = get_master_cycle_count(gx816->regs.pc); + master_cycles += n * speed; +} + +void snes_timer::add_cpu_scycles(ulong n) { +ulong speed; + speed = get_master_cycle_count(gx816->regs.s); + master_cycles += n * speed; +} + +void snes_timer::add_cpu_mcycles(ulong n, ulong addr) { +ulong speed; + speed = get_master_cycle_count(addr); + master_cycles += n * speed; +} + +void snes_timer::add_cpu_icycles(ulong n) { + master_cycles += n * MEMSPEED_FAST; +} + +void snes_timer::add_cpu_icycles(ulong n, ulong flags) { + if(flags & TIMING_BANKCROSS) { + if(gx816->index_bank_crossed == true)n++; + } +//regs.dl != 0x00 + if(flags & TIMING_CONDITION2) { + if((gx816->regs.d & 0xff) != 0x00)n++; + } +//add 1 cycle for indexing across page boundaries, or write, or x=0 + if(flags & TIMING_CONDITION4) { + if(gx816->index_bank_crossed == true || !(gx816->regs.p & PF_X))n++; + } + master_cycles += n * MEMSPEED_FAST; +} + +void snes_timer::add_cpu_cycles(ulong n) { + master_cycles += n; +} + +void snes_timer::update_timer(void) { + vscan_pos = (master_cycles / CYCLES_PER_SCANLINE) % 262; + hscan_pos = (master_cycles % CYCLES_PER_SCANLINE) / 4; +} + +snes_timer *snes_time; diff --git a/bsnes/timing/timing.h b/bsnes/timing/timing.h new file mode 100644 index 00000000..b3dfb6d7 --- /dev/null +++ b/bsnes/timing/timing.h @@ -0,0 +1,23 @@ +#define CYCLES_PER_SCANLINE 1360 +#define WRAM_REFRESH_DOT_POS 132 + +#define TIMING_NONE 0x00 +#define TIMING_BANKCROSS 0x01 +#define TIMING_REGD 0x02 +#define TIMING_CONDITION2 0x02 +#define TIMING_CONDITION4 0x04 + +class snes_timer { +public: +ulong master_cycles; +word vscan_pos, hscan_pos; + ulong get_master_cycle_count(ulong offset); + void add_cpu_pcycles(ulong n); + void add_cpu_scycles(ulong n); + void add_cpu_mcycles(ulong n, ulong addr); + void add_cpu_icycles(ulong n); + void add_cpu_icycles(ulong n, ulong flags); + void add_cpu_cycles(ulong n); + void update_timer(void); + snes_timer(); +}; diff --git a/bsnes/win/gui.cpp b/bsnes/win/gui.cpp new file mode 100644 index 00000000..7d0f8f7e --- /dev/null +++ b/bsnes/win/gui.cpp @@ -0,0 +1,434 @@ +#include "../base.h" +#include "../timing/timing.h" +extern snes_timer *snes_time; +#include "../cpu/g65816.h" +extern g65816 *gx816; +extern emustate emu_state; +extern debugstate debugger; +extern videostate render; +extern ppustate ppu; +#include + +#define BSNES_TITLE "bsnes v0.0.002 ir9" + +enum { + MENU_FILE_LOAD = 100, + MENU_FILE_RESET, + MENU_FILE_EXIT, + MENU_SETTINGS_VIDEOMODE_512x448w, + MENU_SETTINGS_VIDEOMODE_640x480f, + MENU_SETTINGS_FRAMESKIP_OFF, + MENU_SETTINGS_FRAMESKIP_1, + MENU_SETTINGS_FRAMESKIP_2, + MENU_SETTINGS_FRAMESKIP_3, + MENU_SETTINGS_FRAMESKIP_4, + MENU_SETTINGS_FRAMESKIP_5, + MENU_SETTINGS_FRAMESKIP_6, + MENU_SETTINGS_FRAMESKIP_7, + MENU_SETTINGS_FRAMESKIP_8, + MENU_SETTINGS_FRAMESKIP_9, + MENU_SETTINGS_DEBUGGER, + MENU_HELP_ABOUT +}; + +HWND hwndMain = 0; +HMENU hmenuMain; +HFONT hFontFixed, hFont; + +extern joypad_state joypad1; + +#define KEY_UP VK_UP +#define KEY_DOWN VK_DOWN +#define KEY_LEFT VK_LEFT +#define KEY_RIGHT VK_RIGHT +#define KEY_SHIFT VK_RSHIFT +#define KEY_ENTER VK_RETURN +#define KEY_A 'A' +#define KEY_S 'S' +#define KEY_D 'D' +#define KEY_Z 'Z' +#define KEY_X 'X' +#define KEY_C 'C' + +#define KeyState(key) ((GetAsyncKeyState(key) & 0x8000)?1:0) + +void UpdateJoypad(void) { + joypad1.up = KeyState(KEY_UP ); + joypad1.down = KeyState(KEY_DOWN ); + joypad1.left = KeyState(KEY_LEFT ); + joypad1.right = KeyState(KEY_RIGHT); + joypad1.select = KeyState(KEY_SHIFT); + joypad1.start = KeyState(KEY_ENTER); + joypad1.y = KeyState(KEY_A ); + joypad1.b = KeyState(KEY_Z ); + joypad1.x = KeyState(KEY_S ); + joypad1.a = KeyState(KEY_X ); + joypad1.l = KeyState(KEY_D ); + joypad1.r = KeyState(KEY_C ); +} + +void alert(char *s, ...) { +char str[4096]; +va_list args; + va_start(args, s); + vsprintf(str, s, args); + va_end(args); + MessageBox(0, str, "bsnes", MB_OK); +} + +void FixWindowSize(HWND hwnd, ulong width, ulong height, ulong px = null, ulong py = null) { +RECT rc; +ulong x, y, wx, wy; + ShowWindow(hwnd, SW_HIDE); + SetWindowPos(hwnd, 0, 0, 0, width, height, SWP_NOZORDER); + GetClientRect(hwnd, &rc); + x = width + width - (rc.right - rc.left); + y = height + height - (rc.bottom - rc.top); + wx = (GetSystemMetrics(SM_CXSCREEN) - x) / 2; + wy = (GetSystemMetrics(SM_CYSCREEN) - y) / 2; + if(px == null || py == null) { + SetWindowPos(hwnd, 0, wx, wy, x, y, SWP_NOZORDER); + } else { + SetWindowPos(hwnd, 0, px, py, x, y, SWP_NOZORDER); + } +} + +HBRUSH black_brush; + +long __stdcall wndprocMain(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); + +void RegisterMainWindow() { +WNDCLASS wc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = black_brush; + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(0, IDI_APPLICATION); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = wndprocMain; + wc.lpszClassName = "bsnes"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); +} + +void CreateMainMenu(void) { +HMENU hsubmenu, hbranchmenu; + hmenuMain = CreateMenu(); + + hsubmenu = CreatePopupMenu(); + AppendMenu(hsubmenu, MF_STRING, MENU_FILE_LOAD, "&Load ROM"); + AppendMenu(hsubmenu, MF_STRING, MENU_FILE_RESET, "&Reset"); + AppendMenu(hsubmenu, MF_SEPARATOR, 0, ""); + AppendMenu(hsubmenu, MF_STRING, MENU_FILE_EXIT, "E&xit"); + AppendMenu(hmenuMain, MF_STRING | MF_POPUP, (unsigned int)hsubmenu, "&File"); + + hsubmenu = CreatePopupMenu(); + + hbranchmenu = CreatePopupMenu(); + AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_VIDEOMODE_512x448w, "512x448 Windowed"); + AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_VIDEOMODE_640x480f, "640x480 Fullscreen"); + AppendMenu(hsubmenu, MF_STRING | MF_POPUP, (unsigned int)hbranchmenu, "&Video Mode"); + + hbranchmenu = CreatePopupMenu(); + AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_FRAMESKIP_OFF, "Off"); + AppendMenu(hbranchmenu, MF_SEPARATOR, 0, ""); + AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_FRAMESKIP_1, "1"); + AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_FRAMESKIP_2, "2"); + AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_FRAMESKIP_3, "3"); + AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_FRAMESKIP_4, "4"); + AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_FRAMESKIP_5, "5"); + AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_FRAMESKIP_6, "6"); + AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_FRAMESKIP_7, "7"); + AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_FRAMESKIP_8, "8"); + AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_FRAMESKIP_9, "9"); + AppendMenu(hsubmenu, MF_STRING | MF_POPUP, (unsigned int)hbranchmenu, "&Frameskip"); + + AppendMenu(hsubmenu, MF_SEPARATOR, 0, ""); + AppendMenu(hsubmenu, MF_STRING | (debug_get_state() == DEBUGMODE_WAIT)?MF_CHECKED:MF_UNCHECKED, MENU_SETTINGS_DEBUGGER, "&Debug Mode"); + AppendMenu(hmenuMain, MF_STRING | MF_POPUP, (unsigned int)hsubmenu, "&Settings"); + + hsubmenu = CreatePopupMenu(); + AppendMenu(hsubmenu, MF_STRING, MENU_HELP_ABOUT, "&About"); + AppendMenu(hmenuMain, MF_STRING | MF_POPUP, (unsigned int)hsubmenu, "&Help"); + + CheckMenuItem(hmenuMain, MENU_SETTINGS_VIDEOMODE_512x448w, MF_CHECKED); + CheckMenuItem(hmenuMain, MENU_SETTINGS_FRAMESKIP_OFF + render.frame_skip, MF_CHECKED); +} + +void CreateMainWindow(void) { + hwndMain = CreateWindow("bsnes", BSNES_TITLE, WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, + 0, 0, 640, 480, 0, 0, GetModuleHandle(0), 0); + CreateMainMenu(); +} + +void SetMainWindowPos(bool update_style) { + if(render.fullscreen == true) { + if(update_style == true) { + SetWindowLong(hwndMain, GWL_STYLE, WS_POPUP); + SetWindowLong(hwndMain, GWL_EXSTYLE, WS_EX_TOPMOST); + SetWindowPos(hwndMain, HWND_TOPMOST, 0, 0, 640, 480, 0); + } + if(render.show_menu == true) { + ShowCursor(TRUE); + } else { + ShowCursor(FALSE); + } + } else { + if(update_style == true) { + SetWindowLong(hwndMain, GWL_STYLE, WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX); + SetWindowLong(hwndMain, GWL_EXSTYLE, 0); + } + FixWindowSize(hwndMain, render.width, render.height); + } +} + +void UpdateMainWindowStyle(bool update_style) { + if(render.fullscreen == false) { + ShowWindow(hwndMain, SW_HIDE); + } + + if(render.show_menu == true) { + SetMenu(hwndMain, hmenuMain); + SetMainWindowPos(update_style); + } else { + SetMenu(hwndMain, 0); + SetMainWindowPos(update_style); + } + + if(render.fullscreen == false) { + ShowWindow(hwndMain, SW_NORMAL); + } +} + +HWND NewWindow(WNDPROC wndproc, char *classname, char *title, ulong color, ulong width, ulong height) { +WNDCLASS wc; +HWND hwnd; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = (color == null)?(HBRUSH)(COLOR_WINDOW):black_brush; + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(0, IDI_APPLICATION); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = wndproc; + wc.lpszClassName = classname; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); + + hwnd = CreateWindow(classname, title, WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, + 0, 0, width, height, 0, 0, wc.hInstance, 0); + return hwnd; +} + +#include "render.cpp" + +bool GUIOpenFile(char *fn) { +OPENFILENAME ofn; + memset(&ofn, 0, sizeof(ofn)); + + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwndMain; + ofn.lpstrFilter = "SNES ROM Images (*.smc;*.swc;*.fig;*.ufo;*.gd3;*.078)\0*.smc;*.swc;*.fig;*.ufo;*.gd3;*.078\0All Files (*.*)\0*.*\0"; + ofn.lpstrFile = fn; + ofn.nMaxFile = MAX_PATH; + ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST; + ofn.lpstrDefExt = "smc"; + + if(GetOpenFileName(&ofn)) { + return true; + } else { + return false; + } +} + +void EnableDebugger(byte first_time); +void DisableDebugger(void); + +long __stdcall wndprocMain(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { +char fn[MAX_PATH]; +bool result; + switch(msg) { + case WM_DESTROY: + PostQuitMessage(0); + break; + case WM_PAINT: + UpdateDisplay_NoRender(); + break; + case WM_KEYDOWN: + switch(wparam) { + case VK_ESCAPE: + if(render.show_menu == true) { + render.show_menu = false; + } else { + render.show_menu = true; + } + UpdateMainWindowStyle(false); + break; + } + break; + case WM_COMMAND: + switch(LOWORD(wparam)) { + case MENU_FILE_LOAD: + strcpy(fn, ""); + result = GUIOpenFile(fn); + if(result == true) { + strcpy(emu_state.rom_name, fn); + fn[strlen(fn) - 4] = 0; + strcat(fn, ".srm"); + strcpy(emu_state.sram_name, fn); + gx816->PowerOn(0); + gx816->LoadROM(); + if(debug_get_state() == DEBUGMODE_NOROM) { + debug_set_state(DEBUGMODE_DISABLED); + } + } + break; + case MENU_FILE_RESET: + gx816->Reset(); + break; + case MENU_FILE_EXIT: + PostQuitMessage(0); + break; + case MENU_SETTINGS_VIDEOMODE_512x448w: + video_setmode(false, 512, 448); + CheckMenuItem(hmenuMain, MENU_SETTINGS_VIDEOMODE_512x448w, MF_CHECKED); + CheckMenuItem(hmenuMain, MENU_SETTINGS_VIDEOMODE_640x480f, MF_UNCHECKED); + break; + case MENU_SETTINGS_VIDEOMODE_640x480f: + video_setmode(true, 512, 448); + CheckMenuItem(hmenuMain, MENU_SETTINGS_VIDEOMODE_512x448w, MF_UNCHECKED); + CheckMenuItem(hmenuMain, MENU_SETTINGS_VIDEOMODE_640x480f, MF_CHECKED); + break; + case MENU_SETTINGS_FRAMESKIP_OFF: + case MENU_SETTINGS_FRAMESKIP_1: + case MENU_SETTINGS_FRAMESKIP_2: + case MENU_SETTINGS_FRAMESKIP_3: + case MENU_SETTINGS_FRAMESKIP_4: + case MENU_SETTINGS_FRAMESKIP_5: + case MENU_SETTINGS_FRAMESKIP_6: + case MENU_SETTINGS_FRAMESKIP_7: + case MENU_SETTINGS_FRAMESKIP_8: + case MENU_SETTINGS_FRAMESKIP_9: + CheckMenuItem(hmenuMain, MENU_SETTINGS_FRAMESKIP_OFF + render.frame_skip, MF_UNCHECKED); + render.frame_skip = LOWORD(wparam) - MENU_SETTINGS_FRAMESKIP_OFF; + render.frame_count = 0; + CheckMenuItem(hmenuMain, MENU_SETTINGS_FRAMESKIP_OFF + render.frame_skip, MF_CHECKED); + break; + case MENU_SETTINGS_DEBUGGER: + if(debug_get_state() == DEBUGMODE_NOROM)break; + + if(debug_get_state() == DEBUGMODE_DISABLED) { + CheckMenuItem(hmenuMain, MENU_SETTINGS_DEBUGGER, MF_CHECKED); + EnableDebugger(0); + } else { + CheckMenuItem(hmenuMain, MENU_SETTINGS_DEBUGGER, MF_UNCHECKED); + DisableDebugger(); + } + break; + case MENU_HELP_ABOUT: + MessageBox(hwndMain, "bsnes -- written by byuu", "About", MB_OK); + break; + } + break; + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +void CreateFonts(void) { +HDC hdc; +long height; + hdc = GetDC(0); + height = -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72); + ReleaseDC(0, hdc); + hFontFixed = CreateFont(height, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Courier New"); + + hdc = GetDC(0); + height = -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72); + ReleaseDC(0, hdc); + hFont = CreateFont(height, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Tahoma"); +} + +#include "gui_cpu.cpp" +#include "gui_mem.cpp" +#include "gui_bp.cpp" +#include "gui_bgtoggle.cpp" + +void EnableDebugger(byte first_time) { + debug_set_state(DEBUGMODE_WAIT); + + hwndDCPU = NewWindow(wndprocDCPU, "bsnes_cpu", "g65816 cpu debugger", null, DCPU_WIDTH, DCPU_HEIGHT); + CreateDCPU(); + FixWindowSize(hwndDCPU, DCPU_WIDTH, DCPU_HEIGHT, 0, 1024 - 320); + + hwndDMEM = NewWindow(wndprocDMEM, "bsnes_mem", "g65816 memory editor -- snes memory mode", null, 495, 238); + CreateDMEM(); + FixWindowSize(hwndDMEM, 495, 238, 316, 441); + + hwndDBP = NewWindow(wndprocDBP, "bsnes_bp", "g65816 breakpoint editor", null, 310, 238); + CreateDBP(); + FixWindowSize(hwndDBP, 310, 238, 0, 441); + + hwndDBGToggle = NewWindow(wndprocDBGToggle, "bsnes_bgtoggle", "ppu bg toggle", null, 275, 90); + CreateDBGToggle(); + FixWindowSize(hwndDBGToggle, 275, 90, 0, 326); + + FixWindowSize(hwndMain, 256, 224, 681, 1024 - 320); + + ShowWindow(hwndDCPU, SW_NORMAL); + ShowWindow(hwndDMEM, SW_NORMAL); + ShowWindow(hwndDBP, SW_NORMAL); + ShowWindow(hwndDBGToggle, SW_NORMAL); + ShowWindow(hwndMain, SW_NORMAL); + + if(first_time == 0) { + debug_refresh_mem(); + debug_refresh_bp(); + debug_update_cycles(); + dprintf("* Debugger Enabled"); + UpdateDisplay(); + } +} + +void DisableDebugger(void) { + debug_set_state(DEBUGMODE_DISABLED); + + DestroyWindow(hwndDCPU); + DestroyWindow(hwndDBP); + DestroyWindow(hwndDMEM); + DestroyWindow(hwndDBGToggle); +} + +void __winmain(void) { +MSG msg; + CreateFonts(); + black_brush = CreateSolidBrush(RGB(0, 0, 0)); + RegisterMainWindow(); + CreateMainWindow(); + UpdateMainWindowStyle(false); + + if(debug_get_state() == DEBUGMODE_WAIT) { + EnableDebugger(1); + } + video_setmode(render.fullscreen, render.width, render.height); + + InitDisplay(); + CreateColorTable(); + SelectRenderer(); + + InitSNES(); + + UpdateDisplay(); + UpdateDisplay(); + + while(1) { + if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { + if(msg.message == WM_QUIT)break; + TranslateMessage(&msg); + DispatchMessage(&msg); + } else { + RunSNES(); + } + } +} diff --git a/bsnes/win/gui_bgtoggle.cpp b/bsnes/win/gui_bgtoggle.cpp new file mode 100644 index 00000000..40a05344 --- /dev/null +++ b/bsnes/win/gui_bgtoggle.cpp @@ -0,0 +1,149 @@ +#define DBGTOGGLE_BG1ENABLE 100 +#define DBGTOGGLE_BG1ENABLE0 101 +#define DBGTOGGLE_BG1ENABLE1 102 +#define DBGTOGGLE_BG2ENABLE 103 +#define DBGTOGGLE_BG2ENABLE0 104 +#define DBGTOGGLE_BG2ENABLE1 105 +#define DBGTOGGLE_BG3ENABLE 106 +#define DBGTOGGLE_BG3ENABLE0 107 +#define DBGTOGGLE_BG3ENABLE1 108 +#define DBGTOGGLE_BG4ENABLE 109 +#define DBGTOGGLE_BG4ENABLE0 110 +#define DBGTOGGLE_BG4ENABLE1 111 +#define DBGTOGGLE_OAMENABLE 112 +#define DBGTOGGLE_OAMENABLE0 113 +#define DBGTOGGLE_OAMENABLE1 114 +#define DBGTOGGLE_OAMENABLE2 115 +#define DBGTOGGLE_OAMENABLE3 116 + +#define BGTOGGLE_CLICK(src, val) \ + case src: \ + state = SendDlgItemMessage(hwndDBGToggle, src, BM_GETCHECK, 0, 0); \ + if(state == 0) { \ + val = true; \ + SendDlgItemMessage(hwndDBGToggle, src, BM_SETCHECK, 1, 0); \ + } else { \ + val = false; \ + SendDlgItemMessage(hwndDBGToggle, src, BM_SETCHECK, 0, 0); \ + } \ + break + +HWND hwndDBGToggle; + +long __stdcall wndprocDBGToggle(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { +int state; + if(msg == WM_DESTROY || msg == WM_CLOSE)return 0; + if(msg == WM_COMMAND) { + if(HIWORD(wparam) == BN_CLICKED) { + switch(LOWORD(wparam)) { + BGTOGGLE_CLICK(DBGTOGGLE_BG1ENABLE, render.bg1_enabled[DEBUG_BGENABLED_ALL ]); + BGTOGGLE_CLICK(DBGTOGGLE_BG1ENABLE0, render.bg1_enabled[DEBUG_BGENABLED_PRI0]); + BGTOGGLE_CLICK(DBGTOGGLE_BG1ENABLE1, render.bg1_enabled[DEBUG_BGENABLED_PRI1]); + BGTOGGLE_CLICK(DBGTOGGLE_BG2ENABLE, render.bg2_enabled[DEBUG_BGENABLED_ALL ]); + BGTOGGLE_CLICK(DBGTOGGLE_BG2ENABLE0, render.bg2_enabled[DEBUG_BGENABLED_PRI0]); + BGTOGGLE_CLICK(DBGTOGGLE_BG2ENABLE1, render.bg2_enabled[DEBUG_BGENABLED_PRI1]); + BGTOGGLE_CLICK(DBGTOGGLE_BG3ENABLE, render.bg3_enabled[DEBUG_BGENABLED_ALL ]); + BGTOGGLE_CLICK(DBGTOGGLE_BG3ENABLE0, render.bg3_enabled[DEBUG_BGENABLED_PRI0]); + BGTOGGLE_CLICK(DBGTOGGLE_BG3ENABLE1, render.bg3_enabled[DEBUG_BGENABLED_PRI1]); + BGTOGGLE_CLICK(DBGTOGGLE_BG4ENABLE, render.bg4_enabled[DEBUG_BGENABLED_ALL ]); + BGTOGGLE_CLICK(DBGTOGGLE_BG4ENABLE0, render.bg4_enabled[DEBUG_BGENABLED_PRI0]); + BGTOGGLE_CLICK(DBGTOGGLE_BG4ENABLE1, render.bg4_enabled[DEBUG_BGENABLED_PRI1]); + BGTOGGLE_CLICK(DBGTOGGLE_OAMENABLE, render.oam_enabled[DEBUG_BGENABLED_ALL ]); + BGTOGGLE_CLICK(DBGTOGGLE_OAMENABLE0, render.oam_enabled[DEBUG_BGENABLED_PRI0]); + BGTOGGLE_CLICK(DBGTOGGLE_OAMENABLE1, render.oam_enabled[DEBUG_BGENABLED_PRI1]); + BGTOGGLE_CLICK(DBGTOGGLE_OAMENABLE2, render.oam_enabled[DEBUG_BGENABLED_PRI2]); + BGTOGGLE_CLICK(DBGTOGGLE_OAMENABLE3, render.oam_enabled[DEBUG_BGENABLED_PRI3]); + } + } + } + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +void CreateDBGToggle(void) { +int x, y, wl, wr, h; + x = 5; + y = 5; + wl = 90; + wr = 45; + h = 16; + CreateWindow("BUTTON", "Enable BG1", WS_CHILD|WS_VISIBLE|BS_CHECKBOX, x, y, wl, h, + hwndDBGToggle, (HMENU)DBGTOGGLE_BG1ENABLE, GetModuleHandle(0), 0); + x += wl; + CreateWindow("BUTTON", "Pri 0", WS_CHILD|WS_VISIBLE|BS_CHECKBOX, x, y, wr, h, + hwndDBGToggle, (HMENU)DBGTOGGLE_BG1ENABLE0, GetModuleHandle(0), 0); + x += wr; + CreateWindow("BUTTON", "Pri 1", WS_CHILD|WS_VISIBLE|BS_CHECKBOX, x, y, wr, h, + hwndDBGToggle, (HMENU)DBGTOGGLE_BG1ENABLE1, GetModuleHandle(0), 0); + + x = 5; + y += h; + CreateWindow("BUTTON", "Enable BG2", WS_CHILD|WS_VISIBLE|BS_CHECKBOX, x, y, wl, h, + hwndDBGToggle, (HMENU)DBGTOGGLE_BG2ENABLE, GetModuleHandle(0), 0); + x += wl; + CreateWindow("BUTTON", "Pri 0", WS_CHILD|WS_VISIBLE|BS_CHECKBOX, x, y, wr, h, + hwndDBGToggle, (HMENU)DBGTOGGLE_BG2ENABLE0, GetModuleHandle(0), 0); + x += wr; + CreateWindow("BUTTON", "Pri 1", WS_CHILD|WS_VISIBLE|BS_CHECKBOX, x, y, wr, h, + hwndDBGToggle, (HMENU)DBGTOGGLE_BG2ENABLE1, GetModuleHandle(0), 0); + + x = 5; + y += h; + CreateWindow("BUTTON", "Enable BG3", WS_CHILD|WS_VISIBLE|BS_CHECKBOX, x, y, wl, h, + hwndDBGToggle, (HMENU)DBGTOGGLE_BG3ENABLE, GetModuleHandle(0), 0); + x += wl; + CreateWindow("BUTTON", "Pri 0", WS_CHILD|WS_VISIBLE|BS_CHECKBOX, x, y, wr, h, + hwndDBGToggle, (HMENU)DBGTOGGLE_BG3ENABLE0, GetModuleHandle(0), 0); + x += wr; + CreateWindow("BUTTON", "Pri 1", WS_CHILD|WS_VISIBLE|BS_CHECKBOX, x, y, wr, h, + hwndDBGToggle, (HMENU)DBGTOGGLE_BG3ENABLE1, GetModuleHandle(0), 0); + + x = 5; + y += h; + CreateWindow("BUTTON", "Enable BG4", WS_CHILD|WS_VISIBLE|BS_CHECKBOX, x, y, wl, h, + hwndDBGToggle, (HMENU)DBGTOGGLE_BG4ENABLE, GetModuleHandle(0), 0); + x += wl; + CreateWindow("BUTTON", "Pri 0", WS_CHILD|WS_VISIBLE|BS_CHECKBOX, x, y, wr, h, + hwndDBGToggle, (HMENU)DBGTOGGLE_BG4ENABLE0, GetModuleHandle(0), 0); + x += wr; + CreateWindow("BUTTON", "Pri 1", WS_CHILD|WS_VISIBLE|BS_CHECKBOX, x, y, wr, h, + hwndDBGToggle, (HMENU)DBGTOGGLE_BG4ENABLE1, GetModuleHandle(0), 0); + + x = 5; + y += h; + CreateWindow("BUTTON", "Enable OAM", WS_CHILD|WS_VISIBLE|BS_CHECKBOX, x, y, wl, h, + hwndDBGToggle, (HMENU)DBGTOGGLE_OAMENABLE, GetModuleHandle(0), 0); + x += wl; + CreateWindow("BUTTON", "Pri 0", WS_CHILD|WS_VISIBLE|BS_CHECKBOX, x, y, wr, h, + hwndDBGToggle, (HMENU)DBGTOGGLE_OAMENABLE0, GetModuleHandle(0), 0); + x += wr; + CreateWindow("BUTTON", "Pri 1", WS_CHILD|WS_VISIBLE|BS_CHECKBOX, x, y, wr, h, + hwndDBGToggle, (HMENU)DBGTOGGLE_OAMENABLE1, GetModuleHandle(0), 0); + x += wr; + CreateWindow("BUTTON", "Pri 2", WS_CHILD|WS_VISIBLE|BS_CHECKBOX, x, y, wr, h, + hwndDBGToggle, (HMENU)DBGTOGGLE_OAMENABLE2, GetModuleHandle(0), 0); + x += wr; + CreateWindow("BUTTON", "Pri 3", WS_CHILD|WS_VISIBLE|BS_CHECKBOX, x, y, wr, h, + hwndDBGToggle, (HMENU)DBGTOGGLE_OAMENABLE3, GetModuleHandle(0), 0); + + SendDlgItemMessage(hwndDBGToggle, DBGTOGGLE_BG1ENABLE, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBGToggle, DBGTOGGLE_BG1ENABLE0, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBGToggle, DBGTOGGLE_BG1ENABLE1, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBGToggle, DBGTOGGLE_BG2ENABLE, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBGToggle, DBGTOGGLE_BG2ENABLE0, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBGToggle, DBGTOGGLE_BG2ENABLE1, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBGToggle, DBGTOGGLE_BG3ENABLE, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBGToggle, DBGTOGGLE_BG3ENABLE0, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBGToggle, DBGTOGGLE_BG3ENABLE1, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBGToggle, DBGTOGGLE_BG4ENABLE, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBGToggle, DBGTOGGLE_BG4ENABLE0, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBGToggle, DBGTOGGLE_BG4ENABLE1, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBGToggle, DBGTOGGLE_OAMENABLE, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBGToggle, DBGTOGGLE_OAMENABLE0, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBGToggle, DBGTOGGLE_OAMENABLE1, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBGToggle, DBGTOGGLE_OAMENABLE2, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBGToggle, DBGTOGGLE_OAMENABLE3, WM_SETFONT, (WPARAM)hFont, TRUE); + + for(int i=DBGTOGGLE_BG1ENABLE;i<=DBGTOGGLE_OAMENABLE3;i++) { + SendDlgItemMessage(hwndDBGToggle, i, BM_SETCHECK, 1, 0); + } +} diff --git a/bsnes/win/gui_bp.cpp b/bsnes/win/gui_bp.cpp new file mode 100644 index 00000000..d488ea9c --- /dev/null +++ b/bsnes/win/gui_bp.cpp @@ -0,0 +1,131 @@ +#define DBP_LIST 100 +#define DBP_ADDBP 101 +#define DBP_REMBP 102 +#define DBP_CLRBP 103 +#define DBP_STATIC1 104 +#define DBP_BPNUM 105 +#define DBP_BPOFFSET 106 +#define DBP_BPR 107 +#define DBP_BPW 108 +#define DBP_BPX 109 +#define DBP_BPV 110 +#define DBP_BPVAL 111 + +HWND hwndDBP; + +void debug_refresh_bp(void) { +char str[64*16], t[64]; + if(debug_get_state() == DEBUGMODE_DISABLED)return; + + strcpy(str, ""); + for(int i=0;i<16;i++) { + sprintf(t, "%0.2d: ", i); + strcat(str, t); + if(gx816->bp_list[i].flags == BP_OFF) { + strcat(str, "------ ---- -- (Disabled)"); + } else { + sprintf(t, "%0.6x %c%c%c%c ", gx816->bp_list[i].offset, + (gx816->bp_list[i].flags & BP_READ )?'R':'r', + (gx816->bp_list[i].flags & BP_WRITE)?'W':'w', + (gx816->bp_list[i].flags & BP_EXEC )?'X':'x', + (gx816->bp_list[i].flags & BP_VAL )?'V':'v'); + strcat(str, t); + if(gx816->bp_list[i].flags & BP_VAL) { + sprintf(t, "%0.2x ", gx816->bp_list[i].value); + strcat(str, t); + } else strcat(str, "-- "); + sprintf(t, "%10d", gx816->bp_list[i].hit_count); + strcat(str, t); + } + if(i != 15)strcat(str, "\n"); + } + + SetDlgItemText(hwndDBP, DBP_LIST, str); +} + +long __stdcall wndprocDBP(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { +char str[256]; +ulong num, offset, val, flags; +int i; + if(msg == WM_DESTROY || msg == WM_CLOSE)return 0; //don't allow debugger to be closed (yet) + + if(msg == WM_COMMAND) { + switch(LOWORD(wparam)) { + case DBP_ADDBP: + GetDlgItemText(hwndDBP, DBP_BPNUM, str, 255); + num = strdec(str); + GetDlgItemText(hwndDBP, DBP_BPOFFSET, str, 255); + offset = strhex(str) & 0xffffff; + GetDlgItemText(hwndDBP, DBP_BPVAL, str, 255); + val = strhex(str); + + flags = 0; + if(SendMessage(GetDlgItem(hwndDBP, DBP_BPR), BM_GETCHECK, 0, 0))flags |= BP_READ; + if(SendMessage(GetDlgItem(hwndDBP, DBP_BPW), BM_GETCHECK, 0, 0))flags |= BP_WRITE; + if(SendMessage(GetDlgItem(hwndDBP, DBP_BPX), BM_GETCHECK, 0, 0))flags |= BP_EXEC; + if(SendMessage(GetDlgItem(hwndDBP, DBP_BPV), BM_GETCHECK, 0, 0))flags |= BP_VAL; + + if(num > 15)dprintf("Invalid breakpoint #: %d -- 0-15 valid", num); + else { + gx816->bp_list[num].offset = offset; + gx816->bp_list[num].flags = flags; + if(gx816->bp_list[num].flags & BP_VAL)gx816->bp_list[num].value = val; + else gx816->bp_list[num].value = 0; + gx816->bp_list[num].hit_count = 0; + } + debugger.refresh_bp = true; + break; + case DBP_REMBP: + GetDlgItemText(hwndDBP, DBP_BPNUM, str, 255); + num = strdec(str); + if(num > 15)dprintf("Invalid breakpoint #: %d -- 0-15 valid", num); + else { + gx816->bp_list[num].offset = 0; + gx816->bp_list[num].flags = BP_OFF; + gx816->bp_list[num].value = 0; + gx816->bp_list[num].hit_count = 0; + } + debugger.refresh_bp = true; + break; + case DBP_CLRBP: + for(i=0;i<16;i++) { + gx816->bp_list[i].offset = 0; + gx816->bp_list[i].flags = BP_OFF; + gx816->bp_list[i].value = 0; + gx816->bp_list[i].hit_count = 0; + } + debugger.refresh_bp = true; + break; + } + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +void CreateDBP(void) { + CreateWindowEx(WS_EX_STATICEDGE, "STATIC", "", WS_CHILD|WS_VISIBLE, 5, 5, 205, 228, hwndDBP, (HMENU)DBP_LIST, GetModuleHandle(0), 0); + CreateWindow("STATIC", "BP #: Offset:", WS_CHILD|WS_VISIBLE, 215, 5, 90, 15, hwndDBP, (HMENU)DBP_STATIC1, GetModuleHandle(0), 0); + CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "00", WS_CHILD|WS_VISIBLE, 215, 20, 30, 23, hwndDBP, (HMENU)DBP_BPNUM, GetModuleHandle(0), 0); + CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "000000", WS_CHILD|WS_VISIBLE, 245, 20, 60, 23, hwndDBP, (HMENU)DBP_BPOFFSET, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "R", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, 215, 44, 30, 18, hwndDBP, (HMENU)DBP_BPR, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "W", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, 245, 44, 30, 18, hwndDBP, (HMENU)DBP_BPW, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "X", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, 275, 44, 30, 18, hwndDBP, (HMENU)DBP_BPX, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "V", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, 215, 65, 30, 18, hwndDBP, (HMENU)DBP_BPV, GetModuleHandle(0), 0); + CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "00", WS_CHILD|WS_VISIBLE, 245, 62, 60, 23, hwndDBP, (HMENU)DBP_BPVAL, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "Set BP", WS_CHILD|WS_VISIBLE, 215, 88, 90, 20, hwndDBP, (HMENU)DBP_ADDBP, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "Clear BP", WS_CHILD|WS_VISIBLE, 215, 108, 90, 20, hwndDBP, (HMENU)DBP_REMBP, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "Clear All BPs", WS_CHILD|WS_VISIBLE, 215, 128, 90, 20, hwndDBP, (HMENU)DBP_CLRBP, GetModuleHandle(0), 0); + + SendDlgItemMessage(hwndDBP, DBP_LIST, WM_SETFONT, (WPARAM)hFontFixed, TRUE); + SendDlgItemMessage(hwndDBP, DBP_STATIC1, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBP, DBP_BPNUM, WM_SETFONT, (WPARAM)hFontFixed, TRUE); + SendDlgItemMessage(hwndDBP, DBP_BPOFFSET, WM_SETFONT, (WPARAM)hFontFixed, TRUE); + SendDlgItemMessage(hwndDBP, DBP_BPR, WM_SETFONT, (WPARAM)hFontFixed, TRUE); + SendDlgItemMessage(hwndDBP, DBP_BPW, WM_SETFONT, (WPARAM)hFontFixed, TRUE); + SendDlgItemMessage(hwndDBP, DBP_BPX, WM_SETFONT, (WPARAM)hFontFixed, TRUE); + SendDlgItemMessage(hwndDBP, DBP_BPV, WM_SETFONT, (WPARAM)hFontFixed, TRUE); + SendDlgItemMessage(hwndDBP, DBP_BPVAL, WM_SETFONT, (WPARAM)hFontFixed, TRUE); + SendDlgItemMessage(hwndDBP, DBP_ADDBP, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBP, DBP_REMBP, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDBP, DBP_CLRBP, WM_SETFONT, (WPARAM)hFont, TRUE); +} diff --git a/bsnes/win/gui_cpu.cpp b/bsnes/win/gui_cpu.cpp new file mode 100644 index 00000000..d1d30917 --- /dev/null +++ b/bsnes/win/gui_cpu.cpp @@ -0,0 +1,208 @@ +#define DCPU_WIDTH 675 +#define DCPU_HEIGHT 295 + +#define DCPU_DISAS 100 +#define DCPU_RUN 101 +#define DCPU_STEP 102 +#define DCPU_PROCEED 103 +#define DCPU_INFO 104 +#define DCPU_TRACE 105 +#define DCPU_CYCLES 106 + +HWND hwndDCPU; + +char dcpu_disas_mem[20][256]; + +void dprintf(char *s, ...) { +char str[256*20]; +va_list args; +int i; + if(debug_get_state() == DEBUGMODE_DISABLED)return; + + va_start(args, s); + vsprintf(str, s, args); + va_end(args); + + if(debugger.trace_enabled == true) { + fprintf(debugger.trace_fp, "%s\r\n", str); + } + +//if(debug_get_state() != DEBUGMODE_RUN) { + for(i=0;i<19;i++)strcpy(dcpu_disas_mem[i], dcpu_disas_mem[i+1]); + strcpy(dcpu_disas_mem[19], str); + + strcpy(str, ""); + for(i=0;i<20;i++) { + strcat(str, dcpu_disas_mem[i]); + if(i != 20)strcat(str, "\n"); + } + + SetDlgItemText(hwndDCPU, DCPU_DISAS, str); +//} +} + +void debug_update_cycles(void) { +char str[256]; + if(debug_get_state() == DEBUGMODE_DISABLED || + debug_get_state() == DEBUGMODE_RUN)return; + + sprintf(str, "Scanline: %d\nCC: %d", ppu.vline_pos, snes_time->master_cycles); + SetDlgItemText(hwndDCPU, DCPU_CYCLES, str); +} + +void debug_set_state(byte state) { + debugger.mode = state; + if(hwndDCPU && state != DEBUGMODE_DISABLED) { + if(state == DEBUGMODE_WAIT || state == DEBUGMODE_STEP) { + SetDlgItemText(hwndDCPU, DCPU_RUN, "Run"); + } else { + SetDlgItemText(hwndDCPU, DCPU_RUN, "Stop"); + } + } + + if(state == DEBUGMODE_DISABLED) { + RunSNES = RunSNES_NoDebug; + } else { + RunSNES = RunSNES_Debug; + } +} + +long __stdcall wndprocDCPU(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { +FILE *fp; + if(msg == WM_DESTROY || msg == WM_CLOSE)return 0; //don't allow debugger to be closed (yet) + + if(msg == WM_COMMAND) { + switch(LOWORD(wparam)) { + case DCPU_RUN: + if(debug_get_state() != DEBUGMODE_RUN) { + debug_set_state(DEBUGMODE_RUN); + SetDlgItemText(hwndDCPU, DCPU_RUN, "Stop"); + } else { + debug_set_state(DEBUGMODE_WAIT); + disas_g65816_op(); + SetDlgItemText(hwndDCPU, DCPU_RUN, "Run"); + } + break; + case DCPU_STEP: + if(debug_get_state() == DEBUGMODE_WAIT) { + debug_set_state(DEBUGMODE_STEP); + } + break; + case DCPU_PROCEED: + fp = fopen("data.bin", "wb"); + fwrite(ppu.vram, 0x10000, 1, fp); + fwrite(gx816->wram, 0x20000, 1, fp); + fwrite(ppu.cgram, 512, 1, fp); + fwrite(ppu.oam, 544, 1, fp); + fclose(fp); + break; + case DCPU_INFO: + fp = fopen("data.txt", "w"); + fprintf(fp, + "Memory speed: %s\n" + "Mode: %d\n" + "BGs On: %d%d%d%d%d\n" + "Sub BGs On: %d%d%d%d%d\n" + "Tilemap Loc: %0.4x,%0.4x,%0.4x,%0.4x\n" + "Tiledata Loc: %0.4x,%0.4x,%0.4x,%0.4x,%0.4x\n" + "Tilemap Size: %d,%d,%d,%d\n" + "Tile Size: %d,%d,%d,%d\n" + "BG Priority Mode: %d\n" + "OAM Base Size: %d\nOAM Name Sel: %d\nBG Enabled: %d\nBG Brightness: %d\n" + "Window 1 Left: %d\nWindow 1 Right: %d\nWindow 2 Left: %d\nWindow 2 Right: %d\n" + "Window 1 Enabled: %d%d%d%d%d\nWindow 2 Enabled: %d%d%d%d%d\n" + "Window 1 Clipmode: %s,%s,%s,%s,%s\nWindow 2 Clipmode: %s,%s,%s,%s,%s\n" + "BG Windowing Enabled: %d%d%d%d%d\nSub BG Windowing Enabled: %d%d%d%d%d\n" + "BG Window Mask: %d,%d,%d,%d,%d\n" + "Color Windows Enabled: %d%d\nColor Window Clipmodes: %d,%d\n" + "Color Window Mask: %d\nColor Mask: %d\nSub Color Mask: %d\nAddsub Mode: %d\nColor Mode: %d\nColor Halve: %d\n" + "BG Color Enabled: %d%d%d%d%d%d\n" + "RGB Color Settings: %d,%d,%d\nVIRQ Counter Enabled: %s\nHIRQ Counter Enabled: %s\n" + "VIRQ Pos: %d\nHIRQ Pos: %d\n" + "Mode 7 Screen Flip: x: %s, y: %s\n" + "m7a: %0.4x (%f) m7b: %0.4x (%f) m7c: %0.4x (%f) m7d: %0.4x (%f)\n" + "m7x: %0.4x m7y: %0.4x\n", + (gx816->memory_speed == 1)?"FastROM":"SlowROM", ppu.bg_mode, + (ppu.bg_enabled[0] == true)?1:0, (ppu.bg_enabled[1] == true)?1:0, + (ppu.bg_enabled[2] == true)?1:0, (ppu.bg_enabled[3] == true)?1:0, (ppu.bg_enabled[4] == true)?1:0, + (ppu.ss_bg_enabled[0] == true)?1:0, (ppu.ss_bg_enabled[1] == true)?1:0, + (ppu.ss_bg_enabled[2] == true)?1:0, (ppu.ss_bg_enabled[3] == true)?1:0, (ppu.ss_bg_enabled[4] == true)?1:0, + ppu.bg_tilemap_loc[0], ppu.bg_tilemap_loc[1], ppu.bg_tilemap_loc[2], ppu.bg_tilemap_loc[3], + ppu.bg_tiledata_loc[0], ppu.bg_tiledata_loc[1], ppu.bg_tiledata_loc[2], ppu.bg_tiledata_loc[3], ppu.oam_tiledata_loc, + ppu.bg_tilemap_size[0], ppu.bg_tilemap_size[1], ppu.bg_tilemap_size[2], ppu.bg_tilemap_size[3], + ppu.bg_tile_size[0], ppu.bg_tile_size[1], ppu.bg_tile_size[2], ppu.bg_tile_size[3], ppu.bg_priority_mode, + ppu.oam_base_size, ppu.oam_name_sel, (ppu.display_disable == true)?0:1, ppu.display_brightness, + ppu.window1_left, ppu.window1_right, ppu.window2_left, ppu.window2_right, + (ppu.bg_window1_enabled[BG1] == true)?1:0, (ppu.bg_window1_enabled[BG2] == true)?1:0, + (ppu.bg_window1_enabled[BG3] == true)?1:0, (ppu.bg_window1_enabled[BG4] == true)?1:0, + (ppu.bg_window1_enabled[OAM] == true)?1:0, + (ppu.bg_window2_enabled[BG1] == true)?1:0, (ppu.bg_window2_enabled[BG2] == true)?1:0, + (ppu.bg_window2_enabled[BG3] == true)?1:0, (ppu.bg_window2_enabled[BG4] == true)?1:0, + (ppu.bg_window2_enabled[OAM] == true)?1:0, + (ppu.bg_window1_clipmode[BG1] == 1)?"in":"out", (ppu.bg_window1_clipmode[BG2] == 1)?"in":"out", + (ppu.bg_window1_clipmode[BG3] == 1)?"in":"out", (ppu.bg_window1_clipmode[BG4] == 1)?"in":"out", + (ppu.bg_window1_clipmode[OAM] == 1)?"in":"out", + (ppu.bg_window2_clipmode[BG1] == 1)?"in":"out", (ppu.bg_window2_clipmode[BG2] == 1)?"in":"out", + (ppu.bg_window2_clipmode[BG3] == 1)?"in":"out", (ppu.bg_window2_clipmode[BG4] == 1)?"in":"out", + (ppu.bg_window2_clipmode[BG4] == 1)?"in":"out", + (ppu.bg_windowing_enabled[BG1] == true)?1:0, (ppu.bg_windowing_enabled[BG2] == true)?1:0, + (ppu.bg_windowing_enabled[BG3] == true)?1:0, (ppu.bg_windowing_enabled[BG4] == true)?1:0, + (ppu.bg_windowing_enabled[OAM] == true)?1:0, + (ppu.ss_bg_windowing_enabled[BG1] == true)?1:0, (ppu.ss_bg_windowing_enabled[BG2] == true)?1:0, + (ppu.ss_bg_windowing_enabled[BG3] == true)?1:0, (ppu.ss_bg_windowing_enabled[BG4] == true)?1:0, + (ppu.ss_bg_windowing_enabled[OAM] == true)?1:0, + ppu.bg_window_mask[BG1], ppu.bg_window_mask[BG2], + ppu.bg_window_mask[BG3], ppu.bg_window_mask[BG4], ppu.bg_window_mask[OAM], + (ppu.color_window1_enabled == true)?1:0, (ppu.color_window2_enabled == true)?1:0, + ppu.color_window1_clipmode, ppu.color_window2_clipmode, ppu.color_window_mask, + ppu.color_mask, ppu.ss_color_mask, ppu.addsub_mode, ppu.color_mode, ppu.color_halve, + (ppu.bg_color_enabled[BG1] == true)?1:0, (ppu.bg_color_enabled[BG2] == true)?1:0, + (ppu.bg_color_enabled[BG3] == true)?1:0, (ppu.bg_color_enabled[BG4] == true)?1:0, + (ppu.bg_color_enabled[OAM] == true)?1:0, (ppu.bg_color_enabled[BACK] == true)?1:0, + ppu.color_r, ppu.color_g, ppu.color_b, + (ppu.vcounter_enabled == true)?"Yes":"No", (ppu.hcounter_enabled == true)?"Yes":"No", + ppu.virq_pos, ppu.hirq_pos, + (ppu.mode7_vflip == true)?"Yes":"No", (ppu.mode7_hflip == true)?"Yes":"No", + ppu.m7a, (float)ppu.m7a / 256, ppu.m7b, (float)ppu.m7b / 256, + ppu.m7c, (float)ppu.m7c / 256, ppu.m7d, (float)ppu.m7d / 256, + ppu.m7x, ppu.m7y + ); + fclose(fp); + break; + case DCPU_TRACE: + if(debugger.trace_enabled == true) { + fclose(debugger.trace_fp); + debugger.trace_enabled = false; + } else { + debugger.trace_fp = fopen("trace.log", "wb"); + debugger.trace_enabled = true; + } + break; + } + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +void CreateDCPU(void) { +int i; + for(i=0;i<20;i++)strcpy(dcpu_disas_mem[i], ""); + CreateWindowEx(WS_EX_STATICEDGE, "STATIC", "", WS_CHILD|WS_VISIBLE, 5, 5, 580, 285, hwndDCPU, (HMENU)DCPU_DISAS, GetModuleHandle(0), 0); + + CreateWindow("BUTTON", "Run", WS_CHILD|WS_VISIBLE, 590, 5, 80, 20, hwndDCPU, (HMENU)DCPU_RUN, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "Step", WS_CHILD|WS_VISIBLE, 590, 25, 80, 20, hwndDCPU, (HMENU)DCPU_STEP, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "Export Mem", WS_CHILD|WS_VISIBLE, 590, 45, 80, 20, hwndDCPU, (HMENU)DCPU_PROCEED, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "Info", WS_CHILD|WS_VISIBLE, 590, 65, 80, 20, hwndDCPU, (HMENU)DCPU_INFO, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "Trace", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, 590, 85, 80, 20, hwndDCPU, (HMENU)DCPU_TRACE, GetModuleHandle(0), 0); + + CreateWindow("STATIC", "Scanline: 0\nCycles: 0", WS_CHILD|WS_VISIBLE, 590, 260, 80, 30, hwndDCPU, (HMENU)DCPU_CYCLES, GetModuleHandle(0), 0); + + SendDlgItemMessage(hwndDCPU, DCPU_DISAS, WM_SETFONT, (WPARAM)hFontFixed, TRUE); + SendDlgItemMessage(hwndDCPU, DCPU_RUN, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDCPU, DCPU_STEP, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDCPU, DCPU_PROCEED, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDCPU, DCPU_INFO, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDCPU, DCPU_TRACE, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDCPU, DCPU_CYCLES, WM_SETFONT, (WPARAM)hFont, TRUE); +} + diff --git a/bsnes/win/gui_mem.cpp b/bsnes/win/gui_mem.cpp new file mode 100644 index 00000000..ba68a08a --- /dev/null +++ b/bsnes/win/gui_mem.cpp @@ -0,0 +1,252 @@ +#define DMEM_VIEW 100 +#define DMEM_EDITWRAM 101 +#define DMEM_UP40 102 +#define DMEM_DOWN40 103 +#define DMEM_UP400 104 +#define DMEM_DOWN400 105 +#define DMEM_UP4000 106 +#define DMEM_DOWN4000 107 +#define DMEM_UP40000 108 +#define DMEM_DOWN40000 109 +#define DMEM_TOWRAM 110 +#define DMEM_TOROM 111 +#define DMEM_TOVRAM 112 +#define DMEM_TOCGRAM 113 +#define DMEM_TOOAM 114 +#define DMEM_TOOFFSET 115 +#define DMEM_EDITLOC 116 +#define DMEM_EDITVAL 117 +#define DMEM_STATIC1 118 +#define DMEM_STATIC2 119 + +#define DMEMMODE_WRAM 0 +#define DMEMMODE_VRAM 1 +#define DMEMMODE_CGRAM 2 +#define DMEMMODE_OAM 3 +ulong dmem_mode = DMEMMODE_WRAM; + +HWND hwndDMEM; + +void debug_refresh_mem(void) { +char str[64*16], t[16]; +ulong ptr; +int x, y; + if(debug_get_state() == DEBUGMODE_DISABLED)return; + + ptr = debugger.mem_ptr; + strcpy(str, ""); + + if(dmem_mode == DMEMMODE_WRAM) { + ptr &= 0xffffff; + for(y=0;y<16;y++) { + sprintf(t, "%0.6x: ", ptr); + strcat(str, t); + for(x=0;x<16;x++) { + sprintf(t, "%0.2x", gx816->mem_read(MEMMODE_LONG, MEMSIZE_BYTE, ptr++, MEMACCESS_DEBUGGER)); + ptr &= 0xffffff; + strcat(str, t); + if(x != 15)strcat(str, " "); + } + if(y != 15)strcat(str, "\n"); + } + } else if(dmem_mode == DMEMMODE_VRAM) { + ptr &= 0xffff; + for(y=0;y<16;y++) { + sprintf(t, "--%0.4x: ", ptr); + strcat(str, t); + for(x=0;x<16;x++) { + sprintf(t, "%0.2x", ppu.vram[ptr++]); + ptr &= 0xffff; + strcat(str, t); + if(x != 15)strcat(str, " "); + } + if(y != 15)strcat(str, "\n"); + } + } else if(dmem_mode == DMEMMODE_CGRAM) { + ptr &= 0x01ff; + for(y=0;y<16;y++) { + sprintf(t, "---%0.3x: ", ptr); + strcat(str, t); + for(x=0;x<16;x++) { + sprintf(t, "%0.2x", ppu.cgram[ptr++]); + ptr &= 0x01ff; + strcat(str, t); + if(x != 15)strcat(str, " "); + } + if(y != 15)strcat(str, "\n"); + } + } else if(dmem_mode == DMEMMODE_OAM) { + ptr &= 0x03ff; + for(y=0;y<16;y++) { + sprintf(t, "---%0.3x: ", ptr); + strcat(str, t); + for(x=0;x<16;x++) { + sprintf(t, "%0.2x", oam_read(ptr++)); + ptr &= 0x03ff; + strcat(str, t); + if(x != 15)strcat(str, " "); + } + if(y != 15)strcat(str, "\n"); + } + } + + SetDlgItemText(hwndDMEM, DMEM_VIEW, str); +} + +void __mask_mem_ptr(void) { + if(dmem_mode == DMEMMODE_WRAM )debugger.mem_ptr &= 0xffffff; + if(dmem_mode == DMEMMODE_VRAM )debugger.mem_ptr &= 0x00ffff; + if(dmem_mode == DMEMMODE_CGRAM)debugger.mem_ptr &= 0x0001ff; + if(dmem_mode == DMEMMODE_OAM )debugger.mem_ptr &= 0x0003ff; +} + +long __stdcall wndprocDMEM(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { +char str[256]; +ulong pos, val; + if(msg == WM_DESTROY || msg == WM_CLOSE)return 0; //don't allow debugger to be closed (yet) + + if(msg == WM_COMMAND) { + switch(LOWORD(wparam)) { + case DMEM_EDITWRAM: + GetDlgItemText(hwndDMEM, DMEM_EDITLOC, str, 255); + pos = strhex(str); + GetDlgItemText(hwndDMEM, DMEM_EDITVAL, str, 255); + val = strhex(str); + if(dmem_mode == DMEMMODE_WRAM) { + gx816->mem_write(MEMMODE_LONG, MEMSIZE_BYTE, pos & 0xffffff, val, MEMACCESS_DEBUGGER); + } else if(dmem_mode == DMEMMODE_VRAM) { + ppu.vram[pos & 0xffff] = val; + } else if(dmem_mode == DMEMMODE_CGRAM) { + ppu.cgram[pos & 0x01ff] = val; + } else if(dmem_mode == DMEMMODE_OAM) { + oam_write(pos, val); + } + debug_refresh_mem(); + break; + case DMEM_UP40: + debugger.mem_ptr -= 0x40; + debug_refresh_mem(); + __mask_mem_ptr(); + break; + case DMEM_DOWN40: + debugger.mem_ptr += 0x40; + debug_refresh_mem(); + __mask_mem_ptr(); + break; + case DMEM_UP400: + debugger.mem_ptr -= 0x400; + debug_refresh_mem(); + __mask_mem_ptr(); + break; + case DMEM_DOWN400: + debugger.mem_ptr += 0x400; + debug_refresh_mem(); + __mask_mem_ptr(); + break; + case DMEM_UP4000: + debugger.mem_ptr -= 0x4000; + debug_refresh_mem(); + __mask_mem_ptr(); + break; + case DMEM_DOWN4000: + debugger.mem_ptr += 0x4000; + debug_refresh_mem(); + __mask_mem_ptr(); + break; + case DMEM_UP40000: + debugger.mem_ptr -= 0x40000; + debug_refresh_mem(); + __mask_mem_ptr(); + break; + case DMEM_DOWN40000: + debugger.mem_ptr += 0x40000; + debug_refresh_mem(); + __mask_mem_ptr(); + break; + case DMEM_TOWRAM: + dmem_mode = DMEMMODE_WRAM; + debugger.mem_ptr = 0x7e0000; + SetWindowText(hwndDMEM, "g65816 memory editor -- snes memory mode"); + debug_refresh_mem(); + break; + case DMEM_TOROM: + dmem_mode = DMEMMODE_WRAM; + if(gx816->map == MEMMAP_LOROM)debugger.mem_ptr = 0x008000; + else if(gx816->map == MEMMAP_HIROM)debugger.mem_ptr = 0xc00000; + SetWindowText(hwndDMEM, "g65816 memory editor -- snes memory mode"); + debug_refresh_mem(); + break; + case DMEM_TOVRAM: + dmem_mode = DMEMMODE_VRAM; + debugger.mem_ptr = 0x0000; + SetWindowText(hwndDMEM, "g65816 memory editor -- ppu vram mode"); + debug_refresh_mem(); + break; + case DMEM_TOCGRAM: + dmem_mode = DMEMMODE_CGRAM; + debugger.mem_ptr = 0x0000; + SetWindowText(hwndDMEM, "g65816 memory editor -- ppu cgram mode"); + debug_refresh_mem(); + break; + case DMEM_TOOAM: + dmem_mode = DMEMMODE_OAM; + debugger.mem_ptr = 0x0000; + SetWindowText(hwndDMEM, "g65816 memory editor -- ppu oam mode"); + debug_refresh_mem(); + break; + case DMEM_TOOFFSET: + GetDlgItemText(hwndDMEM, DMEM_EDITLOC, str, 255); + debugger.mem_ptr = strhex(str); + __mask_mem_ptr(); + debug_refresh_mem(); + break; + } + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +void CreateDMEM(void) { + CreateWindowEx(WS_EX_STATICEDGE, "STATIC", "", WS_CHILD|WS_VISIBLE, 5, 5, 390, 228, hwndDMEM, (HMENU)DMEM_VIEW, GetModuleHandle(0), 0); + CreateWindow("STATIC", "Offset: Val:", WS_CHILD|WS_VISIBLE, 400, 5, 100, 15, hwndDMEM, (HMENU)DMEM_STATIC1, GetModuleHandle(0), 0); + CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "000000", WS_CHILD|WS_VISIBLE, 400, 20, 60, 23, hwndDMEM, (HMENU)DMEM_EDITLOC, GetModuleHandle(0), 0); + CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "00", WS_CHILD|WS_VISIBLE, 460, 20, 30, 23, hwndDMEM, (HMENU)DMEM_EDITVAL, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "Edit Memory", WS_CHILD|WS_VISIBLE, 400, 45, 90, 20, hwndDMEM, (HMENU)DMEM_EDITWRAM, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "-40", WS_CHILD|WS_VISIBLE, 400, 70, 45, 20, hwndDMEM, (HMENU)DMEM_UP40, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "+40", WS_CHILD|WS_VISIBLE, 445, 70, 45, 20, hwndDMEM, (HMENU)DMEM_DOWN40, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "-400", WS_CHILD|WS_VISIBLE, 400, 90, 45, 20, hwndDMEM, (HMENU)DMEM_UP400, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "+400", WS_CHILD|WS_VISIBLE, 445, 90, 45, 20, hwndDMEM, (HMENU)DMEM_DOWN400, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "-4000", WS_CHILD|WS_VISIBLE, 400, 110, 45, 20, hwndDMEM, (HMENU)DMEM_UP4000, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "+4000", WS_CHILD|WS_VISIBLE, 445, 110, 45, 20, hwndDMEM, (HMENU)DMEM_DOWN4000, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "-40000", WS_CHILD|WS_VISIBLE, 400, 130, 45, 20, hwndDMEM, (HMENU)DMEM_UP40000, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "+40000", WS_CHILD|WS_VISIBLE, 445, 130, 45, 20, hwndDMEM, (HMENU)DMEM_DOWN40000, GetModuleHandle(0), 0); + CreateWindow("STATIC", "Seek To:", WS_CHILD|WS_VISIBLE, 400, 155, 100, 15, hwndDMEM, (HMENU)DMEM_STATIC2, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "WRAM", WS_CHILD|WS_VISIBLE, 400, 173, 45, 20, hwndDMEM, (HMENU)DMEM_TOWRAM, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "ROM", WS_CHILD|WS_VISIBLE, 445, 173, 45, 20, hwndDMEM, (HMENU)DMEM_TOROM, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "VRAM", WS_CHILD|WS_VISIBLE, 400, 193, 45, 20, hwndDMEM, (HMENU)DMEM_TOVRAM, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "CGRAM", WS_CHILD|WS_VISIBLE, 445, 193, 45, 20, hwndDMEM, (HMENU)DMEM_TOCGRAM, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "OAM", WS_CHILD|WS_VISIBLE, 400, 213, 45, 20, hwndDMEM, (HMENU)DMEM_TOOAM, GetModuleHandle(0), 0); + CreateWindow("BUTTON", "Offset", WS_CHILD|WS_VISIBLE, 445, 213, 45, 20, hwndDMEM, (HMENU)DMEM_TOOFFSET, GetModuleHandle(0), 0); + + SendDlgItemMessage(hwndDMEM, DMEM_VIEW, WM_SETFONT, (WPARAM)hFontFixed, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_EDITLOC, WM_SETFONT, (WPARAM)hFontFixed, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_EDITVAL, WM_SETFONT, (WPARAM)hFontFixed, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_STATIC1, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_EDITWRAM, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_UP40, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_DOWN40, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_UP400, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_DOWN400, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_UP4000, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_DOWN4000, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_UP40000, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_DOWN40000, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_STATIC2, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_TOWRAM, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_TOROM, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_TOVRAM, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_TOCGRAM, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_TOOAM, WM_SETFONT, (WPARAM)hFont, TRUE); + SendDlgItemMessage(hwndDMEM, DMEM_TOOFFSET, WM_SETFONT, (WPARAM)hFont, TRUE); +} + diff --git a/bsnes/win/render.cpp b/bsnes/win/render.cpp new file mode 100644 index 00000000..d3bff380 --- /dev/null +++ b/bsnes/win/render.cpp @@ -0,0 +1,269 @@ +#include + +LPDIRECTDRAW lpdd = 0; +LPDIRECTDRAWSURFACE lpdds = 0, lpddsb = 0; +LPDIRECTDRAWCLIPPER lpddc = 0; +DDSURFACEDESC ddsd; +DDSCAPS ddscaps; + +void DestroyDDraw(void) { + if(lpddc) { + lpddc->Release(); + lpddc = 0; + } + if(lpddsb) { + lpddsb->Release(); + lpddsb = 0; + } + if(lpdds) { + lpdds->Release(); + lpdds = 0; + } + if(lpdd) { + lpdd->Release(); + lpdd = 0; + } +} + +void CreateDDraw_Win(void) { + DestroyDDraw(); + + DirectDrawCreate(0, &lpdd, 0); + lpdd->SetCooperativeLevel(hwndMain, DDSCL_NORMAL); + + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + lpdd->CreateSurface(&ddsd, &lpdds, 0); + + lpdd->CreateClipper(0, &lpddc, 0); + lpddc->SetHWnd(0, hwndMain); + lpdds->SetClipper(lpddc); + + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + ddsd.dwWidth = 512; + ddsd.dwHeight = 480; + lpdd->CreateSurface(&ddsd, &lpddsb, 0); +} + +void CreateDDraw_Full(void) { + DestroyDDraw(); + + DirectDrawCreate(0, &lpdd, 0); + lpdd->SetCooperativeLevel(hwndMain, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE); + lpdd->SetDisplayMode(640, 480, 16); + + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + lpdd->CreateSurface(&ddsd, &lpdds, 0); + + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + ddsd.dwWidth = 512; + ddsd.dwHeight = 480; + lpdd->CreateSurface(&ddsd, &lpddsb, 0); +} + +void InitDisplay(void) { + CreateDDraw_Win(); +} + +//size is doubled (mirrored) to prevent having to mask the top unused bit of snes color data +ulong render_color_lookup[65536]; + +void InitColorTable16(void) { +int i, r, g, b; + for(i=0;i<65536;i++) { + r = (i ) & 31; + g = (i >> 5) & 31; + b = (i >> 10) & 31; + render_color_lookup[i] = (r << 11) | (g << 6) | (b); + } +} + +void InitColorTable24(void) { +int i, r, g, b; + for(i=0;i<65536;i++) { + r = (i ) & 31; + g = (i >> 5) & 31; + b = (i >> 10) & 31; + render_color_lookup[i] = (r << 19) | (g << 11) | (b << 3); + } +} + +vfunc RenderScene; + +//sets up color table and sets render proc +void CreateColorTable(void) { + lpdds->GetSurfaceDesc(&ddsd); + switch(ddsd.ddpfPixelFormat.dwRGBBitCount) { + case 16: + InitColorTable16(); + break; + case 32: + InitColorTable24(); + break; + default: + alert("Error: Bit depth [%d] unsupported (supported depths: 16, 32)", ddsd.ddpfPixelFormat.dwRGBBitCount); + exit(0); + break; + } +} + +#include "render_modes.cpp" + +void SelectRenderer(void) { + lpdds->GetSurfaceDesc(&ddsd); + switch(ddsd.ddpfPixelFormat.dwRGBBitCount) { + case 16: + if (render.snes_width == 512 && render.snes_height == 480) { + RenderScene = RenderScene16_512x480; + } else if(render.snes_width == 512 && render.snes_height == 448) { + RenderScene = RenderScene16_512x448; + } else if(render.snes_width == 512 && render.snes_height == 240) { + RenderScene = RenderScene16_512x240; + } else if(render.snes_width == 512 && render.snes_height == 224) { + RenderScene = RenderScene16_512x224; + } else if(render.snes_width == 256 && render.snes_height == 480) { + RenderScene = RenderScene16_256x480; + } else if(render.snes_width == 256 && render.snes_height == 448) { + RenderScene = RenderScene16_256x448; + } else if(render.snes_width == 256 && render.snes_height == 240) { + RenderScene = RenderScene16_256x240; + } else if(render.snes_width == 256 && render.snes_height == 224) { + RenderScene = RenderScene16_256x224; + } else { + alert("Error: Unsupported SNES Resolution: %dx%d", render.snes_width, render.snes_height); + } + break; + case 32: + if (render.snes_width == 512 && render.snes_height == 480) { + RenderScene = RenderScene32_512x480; + } else if(render.snes_width == 512 && render.snes_height == 448) { + RenderScene = RenderScene32_512x448; + } else if(render.snes_width == 512 && render.snes_height == 240) { + RenderScene = RenderScene32_512x240; + } else if(render.snes_width == 512 && render.snes_height == 224) { + RenderScene = RenderScene32_512x224; + } else if(render.snes_width == 256 && render.snes_height == 480) { + RenderScene = RenderScene32_256x480; + } else if(render.snes_width == 256 && render.snes_height == 448) { + RenderScene = RenderScene32_256x448; + } else if(render.snes_width == 256 && render.snes_height == 240) { + RenderScene = RenderScene32_256x240; + } else if(render.snes_width == 256 && render.snes_height == 224) { + RenderScene = RenderScene32_256x224; + } else { + alert("Error: Unsupported SNES Resolution: %dx%d", render.snes_width, render.snes_height); + } + break; + default: + alert("Error: Bit depth [%d] unsupported (supported depths: 16, 32)", ddsd.ddpfPixelFormat.dwRGBBitCount); + exit(0); + break; + } +} + +void UpdateDisplay(void) { +RECT rsrc, rdest; +POINT p; +HRESULT hr; + RenderScene(); + + p.x = p.y = 0; + if(render.fullscreen == true) { + SetRect(&rdest, 0, 0, 512, 448); + OffsetRect(&rdest, (640 - 512) / 2, (480 - 448) / 2); + } else { + ClientToScreen(hwndMain, &p); + GetClientRect(hwndMain, &rdest); + OffsetRect(&rdest, p.x, p.y); + } + + SetRect(&rsrc, 0, 0, render.snes_width, render.snes_height); + + hr = lpdds->Blt(&rdest, lpddsb, &rsrc, DDBLT_WAIT, 0); + if(hr == DDERR_SURFACELOST) { + lpdds->Restore(); + lpddsb->Restore(); + } +} + +void UpdateDisplay_NoRender(void) { +RECT rsrc, rdest; +POINT p; +HRESULT hr; + p.x = p.y = 0; + if(render.fullscreen == true) { + SetRect(&rdest, 0, 0, 512, 448); + OffsetRect(&rdest, (640 - 512) / 2, (480 - 448) / 2); + } else { + ClientToScreen(hwndMain, &p); + GetClientRect(hwndMain, &rdest); + OffsetRect(&rdest, p.x, p.y); + } + + SetRect(&rsrc, 0, 0, render.snes_width, render.snes_height); + + hr = lpdds->Blt(&rdest, lpddsb, &rsrc, DDBLT_WAIT, 0); + if(hr == DDERR_SURFACELOST) { + lpdds->Restore(); + lpddsb->Restore(); + } +} + +void video_setmode(bool fullscreen, word width, word height) { +bool prev_mode = render.fullscreen; + render.fullscreen = fullscreen; + render.width = width; + render.height = height; + + FixWindowSize(hwndMain, width, height); + ShowWindow(hwndMain, SW_NORMAL); + + if(prev_mode != fullscreen) { + if(fullscreen == true) { + render.show_menu = false; + UpdateMainWindowStyle(true); + CreateDDraw_Full(); + ShowWindow(hwndMain, SW_NORMAL); + } else { + render.show_menu = true; + UpdateMainWindowStyle(true); + CreateDDraw_Win(); + FixWindowSize(hwndMain, width, height); + ShowWindow(hwndMain, SW_NORMAL); + } + } +} + +void video_setsnesmode(void) { + if(ppu.bg_mode == 5 || ppu.bg_mode == 6) { + render.snes_width = 512; + } else { + render.snes_width = 256; + } + if(ppu.interlace == true) { + if(ppu.visible_scanlines == 240) { + render.snes_height = 480; + } else { + render.snes_height = 448; + } + } else { + if(ppu.visible_scanlines == 240) { + render.snes_height = 240; + } else { + render.snes_height = 224; + } + } + + SelectRenderer(); +} diff --git a/bsnes/win/render_modes.cpp b/bsnes/win/render_modes.cpp new file mode 100644 index 00000000..40980dcb --- /dev/null +++ b/bsnes/win/render_modes.cpp @@ -0,0 +1,303 @@ +void RenderScene16_256x224(void) { +word *screen; +word *src; +word pitch; +HRESULT hr; +int x, y; + hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); + if(hr != DD_OK)return; + pitch = ddsd.lPitch >> 1; + for(y=0;y<224;y++) { + screen = (word*)ddsd.lpSurface + (pitch * y); + src = (word*)ppu.screen + y * 512; + for(x=0;x<256;x++) { + *screen++ = render_color_lookup[*src++]; + } + } + lpddsb->Unlock(0); +} + +void RenderScene32_256x224(void) { +ulong *screen; +word *src; +word pitch; +HRESULT hr; +int x, y; + hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); + if(hr != DD_OK)return; + pitch = ddsd.lPitch >> 2; + for(y=0;y<224;y++) { + screen = (ulong*)ddsd.lpSurface + (pitch * y); + src = (word*)ppu.screen + y * 512; + for(x=0;x<256;x++) { + *screen++ = render_color_lookup[*src++]; + } + } + lpddsb->Unlock(0); +} + +void RenderScene16_256x240(void) { +word *screen; +word *src; +word pitch; +HRESULT hr; +int x, y; + hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); + if(hr != DD_OK)return; + pitch = ddsd.lPitch >> 1; + for(y=0;y<240;y++) { + screen = (word*)ddsd.lpSurface + (pitch * y); + src = (word*)ppu.screen + y * 512; + for(x=0;x<256;x++) { + *screen++ = render_color_lookup[*src++]; + } + } + lpddsb->Unlock(0); +} + +void RenderScene32_256x240(void) { +ulong *screen; +word *src; +word pitch; +HRESULT hr; +int x, y; + hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); + if(hr != DD_OK)return; + pitch = ddsd.lPitch >> 2; + for(y=0;y<240;y++) { + screen = (ulong*)ddsd.lpSurface + (pitch * y); + src = (word*)ppu.screen + y * 512; + for(x=0;x<256;x++) { + *screen++ = render_color_lookup[*src++]; + } + } + lpddsb->Unlock(0); +} + +void RenderScene16_256x448(void) { +word *screen; +word *src; +word pitch; +HRESULT hr; +int x, y; + hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); + if(hr != DD_OK)return; + pitch = ddsd.lPitch >> 1; + for(y=0;y<448;y++) { + screen = (word*)ddsd.lpSurface + (pitch * y); + src = (word*)ppu.screen + y * 512; + for(x=0;x<256;x++) { + *screen++ = render_color_lookup[*src++]; + } + } + lpddsb->Unlock(0); +} + +void RenderScene32_256x448(void) { +ulong *screen; +word *src; +word pitch; +HRESULT hr; +int x, y; + hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); + if(hr != DD_OK)return; + pitch = ddsd.lPitch >> 2; + for(y=0;y<448;y++) { + screen = (ulong*)ddsd.lpSurface + (pitch * y); + src = (word*)ppu.screen + y * 512; + for(x=0;x<256;x++) { + *screen++ = render_color_lookup[*src++]; + } + } + lpddsb->Unlock(0); +} + +void RenderScene16_256x480(void) { +word *screen; +word *src; +word pitch; +HRESULT hr; +int x, y; + hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); + if(hr != DD_OK)return; + pitch = ddsd.lPitch >> 1; + for(y=0;y<480;y++) { + screen = (word*)ddsd.lpSurface + (pitch * y); + src = (word*)ppu.screen + y * 512; + for(x=0;x<256;x++) { + *screen++ = render_color_lookup[*src++]; + } + } + lpddsb->Unlock(0); +} + +void RenderScene32_256x480(void) { +ulong *screen; +word *src; +word pitch; +HRESULT hr; +int x, y; + hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); + if(hr != DD_OK)return; + pitch = ddsd.lPitch >> 2; + for(y=0;y<480;y++) { + screen = (ulong*)ddsd.lpSurface + (pitch * y); + src = (word*)ppu.screen + y * 512; + for(x=0;x<256;x++) { + *screen++ = render_color_lookup[*src++]; + } + } + lpddsb->Unlock(0); +} + +void RenderScene16_512x224(void) { +word *screen; +word *src; +word pitch; +HRESULT hr; +int x, y; + hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); + if(hr != DD_OK)return; + pitch = ddsd.lPitch >> 1; + for(y=0;y<224;y++) { + screen = (word*)ddsd.lpSurface + (pitch * y); + src = (word*)ppu.screen + y * 512; + for(x=0;x<512;x++) { + *screen++ = render_color_lookup[*src++]; + } + } + lpddsb->Unlock(0); +} + +void RenderScene32_512x224(void) { +ulong *screen; +word *src; +word pitch; +HRESULT hr; +int x, y; + hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); + if(hr != DD_OK)return; + pitch = ddsd.lPitch >> 2; + for(y=0;y<224;y++) { + screen = (ulong*)ddsd.lpSurface + (pitch * y); + src = (word*)ppu.screen + y * 512; + for(x=0;x<512;x++) { + *screen++ = render_color_lookup[*src++]; + } + } + lpddsb->Unlock(0); +} + +void RenderScene16_512x240(void) { +word *screen; +word *src; +word pitch; +HRESULT hr; +int x, y; + hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); + if(hr != DD_OK)return; + pitch = ddsd.lPitch >> 1; + for(y=0;y<240;y++) { + screen = (word*)ddsd.lpSurface + (pitch * y); + src = (word*)ppu.screen + y * 512; + for(x=0;x<512;x++) { + *screen++ = render_color_lookup[*src++]; + } + } + lpddsb->Unlock(0); +} + +void RenderScene32_512x240(void) { +ulong *screen; +word *src; +word pitch; +HRESULT hr; +int x, y; + hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); + if(hr != DD_OK)return; + pitch = ddsd.lPitch >> 2; + for(y=0;y<240;y++) { + screen = (ulong*)ddsd.lpSurface + (pitch * y); + src = (word*)ppu.screen + y * 512; + for(x=0;x<512;x++) { + *screen++ = render_color_lookup[*src++]; + } + } + lpddsb->Unlock(0); +} + +void RenderScene16_512x448(void) { +word *screen; +word *src; +word pitch; +HRESULT hr; +int x, y; + hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); + if(hr != DD_OK)return; + pitch = ddsd.lPitch >> 1; + for(y=0;y<448;y++) { + screen = (word*)ddsd.lpSurface + (pitch * y); + src = (word*)ppu.screen + y * 512; + for(x=0;x<512;x++) { + *screen++ = render_color_lookup[*src++]; + } + } + lpddsb->Unlock(0); +} + +void RenderScene32_512x448(void) { +ulong *screen; +word *src; +word pitch; +HRESULT hr; +int x, y; + hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); + if(hr != DD_OK)return; + pitch = ddsd.lPitch >> 2; + for(y=0;y<448;y++) { + screen = (ulong*)ddsd.lpSurface + (pitch * y); + src = (word*)ppu.screen + y * 512; + for(x=0;x<512;x++) { + *screen++ = render_color_lookup[*src++]; + } + } + lpddsb->Unlock(0); +} + +void RenderScene16_512x480(void) { +word *screen; +word *src; +word pitch; +HRESULT hr; +int x, y; + hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); + if(hr != DD_OK)return; + pitch = ddsd.lPitch >> 1; + for(y=0;y<480;y++) { + screen = (word*)ddsd.lpSurface + (pitch * y); + src = (word*)ppu.screen + y * 512; + for(x=0;x<512;x++) { + *screen++ = render_color_lookup[*src++]; + } + } + lpddsb->Unlock(0); +} + +void RenderScene32_512x480(void) { +ulong *screen; +word *src; +word pitch; +HRESULT hr; +int x, y; + hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); + if(hr != DD_OK)return; + pitch = ddsd.lPitch >> 2; + for(y=0;y<480;y++) { + screen = (ulong*)ddsd.lpSurface + (pitch * y); + src = (word*)ppu.screen + y * 512; + for(x=0;x<512;x++) { + *screen++ = render_color_lookup[*src++]; + } + } + lpddsb->Unlock(0); +}