public static void inc() { var oldclk = TIMER._clock.main; TIMER._clock.sub += Z80._r.m; if (TIMER._clock.sub > 3) { TIMER._clock.main++; TIMER._clock.sub -= 4; TIMER._clock.div++; if (TIMER._clock.div == 16) { TIMER._clock.div = 0; TIMER._div++; TIMER._div &= 255; } } if ((TIMER._tac & 4) != 0) { switch (TIMER._tac & 3) { case 0: if (TIMER._clock.main >= 64) { TIMER.step(); } break; case 1: if (TIMER._clock.main >= 1) { TIMER.step(); } break; case 2: if (TIMER._clock.main >= 4) { TIMER.step(); } break; case 3: if (TIMER._clock.main >= 16) { TIMER.step(); } break; } } }
public static void Reset() { LOG.reset(); GPU.reset(); MMU.reset(); Z80.reset(); KEY.reset(); TIMER.reset(); Z80._r.pc = 0x100; MMU._inbios = true; Z80._r.sp = 0xFFFE; Z80._r.h = 0x01; Z80._r.l = 0x4D; Z80._r.c = 0x13; Z80._r.e = 0xD8; Z80._r.a = 1; }
public static void frame() { // a frame takes 17556 clock cycles to render. we're stuck here until it's complete. var fclock = Z80._clock.m + 17556; //var brk = document.getElementById('breakpoint').value; //var t0 = new Date(); do { // if halted, do nothing and increment m if (Z80._halt) { Z80._r.m = 1; } else { // Z80._r.r = (Z80._r.r+1) & 127; // increment and execute PC Z80._map[MMU.rb(Z80._r.pc++)](); // wrap PC to 16 bits - now handled in PC setter //Z80._r.pc &= 65535; } // if interrupt master enabled and any interrupts enabled and any interrupts triggered if (Z80._r.ime && MMU._ie != 0 && MMU._if != 0) { // disable interrupts Z80._halt = false; Z80._r.ime = false; // get fired interrupts that are enabled var ifired = MMU._ie & MMU._if; // interrupts get triggered according to priority (see page 40) if ((ifired & (1 << 0)) != 0) { MMU._if &= 0xFE; Z80._ops.RST40(); } // V-Blank else if ((ifired & (1 << 1)) != 0) { MMU._if &= 0xFD; Z80._ops.RST48(); } // LCDC (see STAT) else if ((ifired & (1 << 2)) != 0) { MMU._if &= 0xFB; Z80._ops.RST50(); } // Timer Overflow else if ((ifired & (1 << 3)) != 0) { MMU._if &= 0xF7; Z80._ops.RST58(); } // Serial I/O Complete else if ((ifired & (1 << 4)) != 0) { MMU._if &= 0xEF; Z80._ops.RST60(); } // P10-P13 transition H => L else { Z80._r.ime = true; } // otherwise, re-enable IME } //jsGB.dbgtrace(); Z80._clock.m += Z80._r.m; GPU.checkline(); TIMER.inc(); //if ((brk && parseInt(brk, 16) == Z80._r.pc) || Z80._stop) //{ // jsGB.pause(); // break; //} } while (Z80._clock.m < fclock); //var t1 = new Date(); //document.getElementById('fps').innerHTML = Math.round(10000 / (t1 - t0)) / 10; }
public static void wb(int addr, int val) { byte bval = (byte)val; switch (addr & 0xF000) { // ROM bank 0 // MBC1: Turn external RAM on case 0x0000: case 0x1000: switch (MMU._carttype) { case 1: MMU._mbc[1].ramon = ((bval & 0xF) == 0xA) ? 1 : 0; break; } break; // MBC1: ROM bank switch case 0x2000: case 0x3000: switch (MMU._carttype) { case 1: MMU._mbc[1].rombank &= 0x60; bval &= 0x1F; if (bval == 0) { bval = 1; } MMU._mbc[1].rombank |= bval; MMU._romoffs = MMU._mbc[1].rombank * 0x4000; break; } break; // ROM bank 1 // MBC1: RAM bank switch case 0x4000: case 0x5000: switch (MMU._carttype) { case 1: if (MMU._mbc[1].mode != 0) { MMU._mbc[1].rambank = (bval & 3); MMU._ramoffs = MMU._mbc[1].rambank * 0x2000; } else { MMU._mbc[1].rombank &= 0x1F; MMU._mbc[1].rombank |= ((bval & 3) << 5); MMU._romoffs = MMU._mbc[1].rombank * 0x4000; } break; } break; case 0x6000: case 0x7000: switch (MMU._carttype) { case 1: MMU._mbc[1].mode = bval & 1; break; } break; // VRAM case 0x8000: case 0x9000: GPU._vram[addr & 0x1FFF] = bval; GPU.updatetile(addr & 0x1FFF, bval); break; // External RAM case 0xA000: case 0xB000: MMU._eram[MMU._ramoffs + (addr & 0x1FFF)] = bval; break; // Work RAM and echo case 0xC000: case 0xD000: case 0xE000: MMU._wram[addr & 0x1FFF] = bval; break; // Everything else case 0xF000: switch (addr & 0x0F00) { // Echo RAM case 0x000: case 0x100: case 0x200: case 0x300: case 0x400: case 0x500: case 0x600: case 0x700: case 0x800: case 0x900: case 0xA00: case 0xB00: case 0xC00: case 0xD00: MMU._wram[addr & 0x1FFF] = bval; break; // OAM case 0xE00: if ((addr & 0xFF) < 0xA0) { GPU._oam[addr & 0xFF] = bval; } GPU.updateoam(addr, bval); break; // Zeropage RAM, I/O, interrupts case 0xF00: if (addr == 0xFFFF) { MMU._ie = bval; } else if (addr > 0xFF7F) { MMU._zram[addr & 0x7F] = bval; } else { switch (addr & 0xF0) { case 0x00: switch (addr & 0xF) { case 0: KEY.wb(bval); break; case 4: case 5: case 6: case 7: TIMER.wb(addr, bval); break; case 15: MMU._if = bval; break; } break; case 0x10: case 0x20: case 0x30: break; case 0x40: case 0x50: case 0x60: case 0x70: GPU.wb(addr, bval); break; } } break; } break; } }
public static int rb(int addr) { switch (addr & 0xF000) { // ROM bank 0 case 0x0000: if (MMU._inbios) { if (addr < 0x0100) { return(MMU._bios[addr]); } else if (Z80._r.pc == 0x0100) { MMU._inbios = false; LOG.@out("MMU", "Leaving BIOS."); return(rb(addr)); } } else { return(MMU._rom[addr]); } break; case 0x1000: case 0x2000: case 0x3000: return(MMU._rom[addr]); // ROM bank 1 case 0x4000: case 0x5000: case 0x6000: case 0x7000: return(MMU._rom[MMU._romoffs + (addr & 0x3FFF)]); // VRAM case 0x8000: case 0x9000: return(GPU._vram[addr & 0x1FFF]); // External RAM case 0xA000: case 0xB000: return(MMU._eram[MMU._ramoffs + (addr & 0x1FFF)]); // Work RAM and echo case 0xC000: case 0xD000: case 0xE000: return(MMU._wram[addr & 0x1FFF]); // Everything else case 0xF000: switch (addr & 0x0F00) { // Echo RAM case 0x000: case 0x100: case 0x200: case 0x300: case 0x400: case 0x500: case 0x600: case 0x700: case 0x800: case 0x900: case 0xA00: case 0xB00: case 0xC00: case 0xD00: return(MMU._wram[addr & 0x1FFF]); // OAM case 0xE00: return(((addr & 0xFF) < 0xA0) ? GPU._oam[addr & 0xFF] : 0); // Zeropage RAM, I/O, interrupts case 0xF00: if (addr == 0xFFFF) { return(MMU._ie); } else if (addr > 0xFF7F) { return(MMU._zram[addr & 0x7F]); } else { switch (addr & 0xF0) { case 0x00: switch (addr & 0xF) { case 0: return(KEY.rb()); // JOYP case 4: case 5: case 6: case 7: return(TIMER.rb(addr)); case 15: return(MMU._if); // Interrupt flags default: return(0); } case 0x10: case 0x20: case 0x30: return(0); case 0x40: case 0x50: case 0x60: case 0x70: return(GPU.rb(addr)); } } break; } break; } throw new InvalidOperationException($"Unable to read address {addr}: Out of range."); }