Beispiel #1
0
        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;
                }
            }
        }
Beispiel #2
0
 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;
 }
Beispiel #3
0
        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;
        }
Beispiel #4
0
        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;
            }
        }
Beispiel #5
0
        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.");
        }