示例#1
0
 public void process_delays()
 {
     // triggering an interrupt with a write to the control register takes 4 cycles to trigger interrupt
     controller_delay_cd--;
     if (controller_delay_cd == 0)
     {
         if (REG_FFFF.Bit(4))
         {
             cpu.FlagI = true;
         }
         REG_FF0F         |= 0x10;
         delays_to_process = false;
     }
 }
示例#2
0
        public void do_controller_check()
        {
            // check if new input changed the input register and triggered IRQ
            byte contr_prev = input_register;

            input_register &= 0xF0;
            if ((input_register & 0x30) == 0x20)
            {
                input_register |= (byte)(controller_state & 0xF);
            }
            else if ((input_register & 0x30) == 0x10)
            {
                input_register |= (byte)((controller_state & 0xF0) >> 4);
            }
            else if ((input_register & 0x30) == 0x00)
            {
                // if both polls are set, then a bit is zero if either or both pins are zero
                byte temp = (byte)((controller_state & 0xF) & ((controller_state & 0xF0) >> 4));
                input_register |= temp;
            }
            else
            {
                input_register |= 0xF;
            }

            // check for interrupts
            if (((contr_prev & 8) > 0) && ((input_register & 8) == 0) ||
                ((contr_prev & 4) > 0) && ((input_register & 4) == 0) ||
                ((contr_prev & 2) > 0) && ((input_register & 2) == 0) ||
                ((contr_prev & 1) > 0) && ((input_register & 1) == 0))
            {
                if (REG_FFFF.Bit(4))
                {
                    cpu.FlagI = true;
                }
                REG_FF0F |= 0x10;
            }
        }
示例#3
0
        public void Write_Registers(int addr, byte value)
        {
            switch (addr)
            {
            // select input
            case 0xFF00:
                input_register &= 0xCF;
                input_register |= (byte)(value & 0x30);                         // top 2 bits always 1

                // check for high to low transitions that trigger IRQs
                byte contr_prev = input_register;

                input_register &= 0xF0;
                if ((input_register & 0x30) == 0x20)
                {
                    input_register |= (byte)(controller_state & 0xF);
                }
                else if ((input_register & 0x30) == 0x10)
                {
                    input_register |= (byte)((controller_state & 0xF0) >> 4);
                }
                else if ((input_register & 0x30) == 0x00)
                {
                    // if both polls are set, then a bit is zero if either or both pins are zero
                    byte temp = (byte)((controller_state & 0xF) & ((controller_state & 0xF0) >> 4));
                    input_register |= temp;
                }
                else
                {
                    input_register |= 0xF;
                }

                // check for interrupts
                // if an interrupt is triggered, it is delayed by 4 cycles
                if (((contr_prev & 8) > 0) && ((input_register & 8) == 0) ||
                    ((contr_prev & 4) > 0) && ((input_register & 4) == 0) ||
                    ((contr_prev & 2) > 0) && ((input_register & 2) == 0) ||
                    ((contr_prev & 1) > 0) && ((input_register & 1) == 0))
                {
                    controller_delay_cd = 4; delays_to_process = true;
                }

                break;

            // Serial data port
            case 0xFF01:
                serialport.WriteReg(addr, value);
                break;

            // Serial port control
            case 0xFF02:
                serialport.WriteReg(addr, value);
                break;

            // Timer Registers
            case 0xFF04:
            case 0xFF05:
            case 0xFF06:
            case 0xFF07:
                timer.WriteReg(addr, value);
                break;

            // Interrupt flags
            case 0xFF0F:
                REG_FF0F = (byte)(0xE0 | value);

                // check if enabling any of the bits triggered an IRQ
                for (int i = 0; i < 5; i++)
                {
                    if (REG_FFFF.Bit(i) && REG_FF0F.Bit(i))
                    {
                        cpu.FlagI = true;
                    }
                }

                // if no bits are in common between flags and enables, de-assert the IRQ
                if (((REG_FF0F & 0x1F) & REG_FFFF) == 0)
                {
                    cpu.FlagI = false;
                }
                break;

            // audio regs
            case 0xFF10:
            case 0xFF11:
            case 0xFF12:
            case 0xFF13:
            case 0xFF14:
            case 0xFF16:
            case 0xFF17:
            case 0xFF18:
            case 0xFF19:
            case 0xFF1A:
            case 0xFF1B:
            case 0xFF1C:
            case 0xFF1D:
            case 0xFF1E:
            case 0xFF20:
            case 0xFF21:
            case 0xFF22:
            case 0xFF23:
            case 0xFF24:
            case 0xFF25:
            case 0xFF26:
            case 0xFF30:
            case 0xFF31:
            case 0xFF32:
            case 0xFF33:
            case 0xFF34:
            case 0xFF35:
            case 0xFF36:
            case 0xFF37:
            case 0xFF38:
            case 0xFF39:
            case 0xFF3A:
            case 0xFF3B:
            case 0xFF3C:
            case 0xFF3D:
            case 0xFF3E:
            case 0xFF3F:
                audio.WriteReg(addr, value);
                break;

            // PPU Regs
            case 0xFF40:
            case 0xFF41:
            case 0xFF42:
            case 0xFF43:
            case 0xFF44:
            case 0xFF45:
            case 0xFF46:
            case 0xFF47:
            case 0xFF48:
            case 0xFF49:
            case 0xFF4A:
            case 0xFF4B:
                ppu.WriteReg(addr, value);
                break;

            // GBC compatibility register (I think)
            case 0xFF4C:
                if ((value != 0xC0) && (value != 0x80) && (GB_bios_register == 0))                        // && (value != 0xFF) && (value != 0x04))
                {
                    GBC_compat = false;

                    // cpu operation is a function of hardware only
                    //cpu.is_GBC = GBC_compat;
                }
                Console.Write("GBC Compatibility? ");
                Console.WriteLine(value);
                break;

            // Speed Control for GBC
            case 0xFF4D:
                if (GBC_compat)
                {
                    speed_switch = (value & 1) > 0;
                }
                break;

            // VBK
            case 0xFF4F:
                if (is_GBC /* && !ppu.HDMA_active*/)
                {
                    VRAM_Bank = (byte)(value & 1);
                }
                break;

            // Bios control register. Writing 1 permanently disables BIOS until a power cycle occurs
            case 0xFF50:
                // Console.WriteLine(value);
                if (GB_bios_register == 0)
                {
                    GB_bios_register = value;
                }
                break;

            // PPU Regs for GBC
            case 0xFF51:
            case 0xFF52:
            case 0xFF53:
            case 0xFF54:
            case 0xFF55:
                if (GBC_compat)
                {
                    ppu.WriteReg(addr, value);
                }
                break;

            case 0xFF56:
                if (is_GBC)
                {
                    IR_reg = (byte)((value & 0xC1) | (IR_reg & 0x3E));

                    // send IR signal out
                    if ((IR_reg & 0x1) == 0x1)
                    {
                        IR_signal = (byte)(0 | IR_mask);
                    }
                    else
                    {
                        IR_signal = 2;
                    }

                    // receive own signal if IR on and receive on
                    if ((IR_reg & 0xC1) == 0xC1)
                    {
                        IR_self = (byte)(0 | IR_mask);
                    }
                    else
                    {
                        IR_self = 2;
                    }

                    IR_write = 8;
                }
                break;

            case 0xFF68:
            case 0xFF69:
            case 0xFF6A:
            case 0xFF6B:
                if (is_GBC)
                {
                    ppu.WriteReg(addr, value);
                }
                break;

            // RAM Bank in GBC mode
            case 0xFF70:
                if (GBC_compat)
                {
                    RAM_Bank = value & 7;
                    if (RAM_Bank == 0)
                    {
                        RAM_Bank = 1;
                    }
                }
                break;

            case 0xFF6C:
                if (GBC_compat)
                {
                    undoc_6C |= (byte)(value & 1);
                }
                break;

            case 0xFF72:
                if (is_GBC)
                {
                    undoc_72 = value;
                }
                break;

            case 0xFF73:
                if (is_GBC)
                {
                    undoc_73 = value;
                }
                break;

            case 0xFF74:
                if (GBC_compat)
                {
                    undoc_74 = value;
                }
                break;

            case 0xFF75:
                if (is_GBC)
                {
                    undoc_75 |= (byte)(value & 0x70);
                }
                break;

            case 0xFF76:
                // read only
                break;

            case 0xFF77:
                // read only
                break;

            // interrupt control register
            case 0xFFFF:
                REG_FFFF = value;

                // check if enabling any of the bits triggered an IRQ
                for (int i = 0; i < 5; i++)
                {
                    if (REG_FFFF.Bit(i) && REG_FF0F.Bit(i))
                    {
                        cpu.FlagI = true;
                    }
                }

                // if no bits are in common between flags and enables, de-assert the IRQ
                if (((REG_FF0F & 0x1F) & REG_FFFF) == 0)
                {
                    cpu.FlagI = false;
                }
                break;

            default:
                Console.WriteLine(addr + " " + value);
                break;
            }
        }
示例#4
0
        public void do_frame()
        {
            // gameboy frames can be variable lengths
            // we want to end a frame when VBlank turns from false to true
            int ticker = 0;

            // check if new input changed the input register and triggered IRQ
            byte contr_prev = input_register;

            input_register &= 0xF0;
            if ((input_register & 0x30) == 0x20)
            {
                input_register |= (byte)(controller_state & 0xF);
            }
            else if ((input_register & 0x30) == 0x10)
            {
                input_register |= (byte)((controller_state & 0xF0) >> 4);
            }
            else if ((input_register & 0x30) == 0x00)
            {
                // if both polls are set, then a bit is zero if either or both pins are zero
                byte temp = (byte)((controller_state & 0xF) & ((controller_state & 0xF0) >> 4));
                input_register |= temp;
            }
            else
            {
                input_register |= 0xF;
            }

            // check for interrupts


            if (((contr_prev & 8) > 0) && ((input_register & 8) == 0) ||
                ((contr_prev & 4) > 0) && ((input_register & 4) == 0) ||
                ((contr_prev & 2) > 0) && ((input_register & 2) == 0) ||
                ((contr_prev & 1) > 0) && ((input_register & 1) == 0))
            {
                if (REG_FFFF.Bit(4))
                {
                    cpu.FlagI = true;
                }
                REG_FF0F |= 0x10;
            }


            while (!vblank_rise && (ticker < 100000))
            {
                audio.tick();
                timer.tick_1();
                ppu.tick();
                serialport.serial_transfer_tick();

                if (Use_RTC)
                {
                    mapper.RTC_Tick();
                }

                cpu.ExecuteOne(ref REG_FF0F, REG_FFFF);

                timer.tick_2();

                if (in_vblank && !in_vblank_old)
                {
                    vblank_rise = true;
                }
                ticker++;
                in_vblank_old = in_vblank;
            }

            vblank_rise = false;
        }
示例#5
0
        public void Write_Registers(int addr, byte value)
        {
            switch (addr)
            {
            // select input
            case 0xFF00:
                input_register &= 0xCF;
                input_register |= (byte)(value & 0x30);                         // top 2 bits always 1

                // check for high to low transitions that trigger IRQs
                byte contr_prev = input_register;

                input_register &= 0xF0;
                if ((input_register & 0x30) == 0x20)
                {
                    input_register |= (byte)(controller_state & 0xF);
                }
                else if ((input_register & 0x30) == 0x10)
                {
                    input_register |= (byte)((controller_state & 0xF0) >> 4);
                }
                else if ((input_register & 0x30) == 0x00)
                {
                    // if both polls are set, then a bit is zero if either or both pins are zero
                    byte temp = (byte)((controller_state & 0xF) & ((controller_state & 0xF0) >> 4));
                    input_register |= temp;
                }
                else
                {
                    input_register |= 0xF;
                }

                // check for interrupts
                if (((contr_prev & 8) > 0) && ((input_register & 8) == 0) ||
                    ((contr_prev & 4) > 0) && ((input_register & 4) == 0) ||
                    ((contr_prev & 2) > 0) && ((input_register & 2) == 0) ||
                    ((contr_prev & 1) > 0) && ((input_register & 1) == 0))
                {
                    if (REG_FFFF.Bit(4))
                    {
                        cpu.FlagI = true;
                    }
                    REG_FF0F |= 0x10;
                }

                break;

            // Serial data port
            case 0xFF01:
                serialport.WriteReg(addr, value);
                break;

            // Serial port control
            case 0xFF02:
                serialport.WriteReg(addr, value);
                break;

            // Timer Registers
            case 0xFF04:
            case 0xFF05:
            case 0xFF06:
            case 0xFF07:
                timer.WriteReg(addr, value);
                break;

            // Interrupt flags
            case 0xFF0F:
                REG_FF0F = (byte)(0xE0 | value);

                // check if enabling any of the bits triggered an IRQ
                for (int i = 0; i < 5; i++)
                {
                    if (REG_FFFF.Bit(i) && REG_FF0F.Bit(i))
                    {
                        cpu.FlagI = true;
                    }
                }

                // if no bits are in common between flags and enables, de-assert the IRQ
                if (((REG_FF0F & 0x1F) & REG_FFFF) == 0)
                {
                    cpu.FlagI = false;
                }

                break;

            // audio regs
            case 0xFF10:
            case 0xFF11:
            case 0xFF12:
            case 0xFF13:
            case 0xFF14:
            case 0xFF16:
            case 0xFF17:
            case 0xFF18:
            case 0xFF19:
            case 0xFF1A:
            case 0xFF1B:
            case 0xFF1C:
            case 0xFF1D:
            case 0xFF1E:
            case 0xFF20:
            case 0xFF21:
            case 0xFF22:
            case 0xFF23:
            case 0xFF24:
            case 0xFF25:
            case 0xFF26:
            case 0xFF30:
            case 0xFF31:
            case 0xFF32:
            case 0xFF33:
            case 0xFF34:
            case 0xFF35:
            case 0xFF36:
            case 0xFF37:
            case 0xFF38:
            case 0xFF39:
            case 0xFF3A:
            case 0xFF3B:
            case 0xFF3C:
            case 0xFF3D:
            case 0xFF3E:
            case 0xFF3F:
                audio.WriteReg(addr, value);
                break;

            // PPU Regs
            case 0xFF40:
            case 0xFF41:
            case 0xFF42:
            case 0xFF43:
            case 0xFF44:
            case 0xFF45:
            case 0xFF46:
            case 0xFF47:
            case 0xFF48:
            case 0xFF49:
            case 0xFF4A:
            case 0xFF4B:
                ppu.WriteReg(addr, value);
                break;

            // GBC compatibility register (I think)
            case 0xFF4C:
                if ((value != 0xC0) && (value != 0x80))
                {
                    Console.Write("GBC Compatibility? ");
                    Console.WriteLine(value);
                    GBC_compat = false;
                }
                break;

            // Speed Control for GBC
            case 0xFF4D:
                if (is_GBC)
                {
                    speed_switch = (value & 1) > 0;
                }
                break;

            // VBK
            case 0xFF4F:
                if (is_GBC && !ppu.HDMA_active)
                {
                    VRAM_Bank = (byte)(value & 1);
                }
                break;

            // Bios control register. Writing 1 permanently disables BIOS until a power cycle occurs
            case 0xFF50:
                //Console.WriteLine(value);
                if (GB_bios_register != 1)
                {
                    GB_bios_register = value;
                }
                break;

            // PPU Regs for GBC
            case 0xFF51:
            case 0xFF52:
            case 0xFF53:
            case 0xFF54:
            case 0xFF55:
            case 0xFF68:
            case 0xFF69:
            case 0xFF6A:
            case 0xFF6B:
                if (is_GBC)
                {
                    ppu.WriteReg(addr, value);
                }
                break;

            // RAM Bank in GBC mode
            case 0xFF70:
                //Console.WriteLine(value);
                if (is_GBC)
                {
                    RAM_Bank = value & 7;
                    if (RAM_Bank == 0)
                    {
                        RAM_Bank = 1;
                    }
                }
                break;

            // interrupt control register
            case 0xFFFF:
                REG_FFFF    = value;
                enable_VBL  = REG_FFFF.Bit(0);
                enable_STAT = REG_FFFF.Bit(1);
                enable_TIMO = REG_FFFF.Bit(2);
                enable_SER  = REG_FFFF.Bit(3);
                enable_PRS  = REG_FFFF.Bit(4);

                // check if enabling any of the bits triggered an IRQ
                for (int i = 0; i < 5; i++)
                {
                    if (REG_FFFF.Bit(i) && REG_FF0F.Bit(i))
                    {
                        cpu.FlagI = true;
                    }
                }

                // if no bits are in common between flags and enables, de-assert the IRQ
                if (((REG_FF0F & 0x1F) & REG_FFFF) == 0)
                {
                    cpu.FlagI = false;
                }

                break;

            default:
                Console.Write(addr);
                Console.Write(" ");
                Console.WriteLine(value);
                break;
            }
        }
示例#6
0
        public void do_frame()
        {
            // gameboy frames can be variable lengths
            // we want to end a frame when VBlank turns from false to true
            int ticker = 0;

            // check if new input changed the input register and triggered IRQ
            byte contr_prev = input_register;

            input_register &= 0xF0;
            if ((input_register & 0x30) == 0x20)
            {
                input_register |= (byte)(controller_state & 0xF);
            }
            else if ((input_register & 0x30) == 0x10)
            {
                input_register |= (byte)((controller_state & 0xF0) >> 4);
            }
            else if ((input_register & 0x30) == 0x00)
            {
                // if both polls are set, then a bit is zero if either or both pins are zero
                byte temp = (byte)((controller_state & 0xF) & ((controller_state & 0xF0) >> 4));
                input_register |= temp;
            }
            else
            {
                input_register |= 0xF;
            }

            // check for interrupts
            if (((contr_prev & 8) > 0) && ((input_register & 8) == 0) ||
                ((contr_prev & 4) > 0) && ((input_register & 4) == 0) ||
                ((contr_prev & 2) > 0) && ((input_register & 2) == 0) ||
                ((contr_prev & 1) > 0) && ((input_register & 1) == 0))
            {
                if (REG_FFFF.Bit(4))
                {
                    cpu.FlagI = true;
                }
                REG_FF0F |= 0x10;
            }

            while (!vblank_rise)
            {
                // These things do not change speed in GBC double spped mode
                audio.tick();
                ppu.tick();
                if (Use_MT)
                {
                    mapper.Mapper_Tick();
                }

                if (!HDMA_transfer)
                {
                    // These things all tick twice as fast in GBC double speed mode
                    ppu.DMA_tick();
                    timer.tick_1();
                    serialport.serial_transfer_tick();
                    cpu.ExecuteOne(ref REG_FF0F, REG_FFFF);
                    timer.tick_2();

                    if (double_speed)
                    {
                        ppu.DMA_tick();
                        timer.tick_1();
                        serialport.serial_transfer_tick();
                        cpu.ExecuteOne(ref REG_FF0F, REG_FFFF);
                        timer.tick_2();
                    }
                }
                else
                {
                    timer.tick_1();
                    timer.tick_2();
                    cpu.TotalExecutedCycles++;
                    if (double_speed)
                    {
                        timer.tick_1();
                        timer.tick_2();
                        cpu.TotalExecutedCycles++;
                    }
                }

                if (in_vblank && !in_vblank_old)
                {
                    vblank_rise = true;
                }

                ticker++;
                // if (ticker > 10000000) { vblank_rise = true; }//throw new Exception("ERROR: Unable to Resolve Frame"); }

                in_vblank_old = in_vblank;
                REG_FF0F_OLD  = REG_FF0F;
            }

            vblank_rise = false;
        }