public BgControlRegister(GameboyAdvance gba, LcdController lcd, int bgNumber, UInt32 address) { this.lcd = lcd; this.bgNumber = bgNumber; MemoryRegister8WithSetHook r0 = new MemoryRegister8WithSetHook(gba.Memory, address, true, true); MemoryRegister8WithSetHook r1 = new MemoryRegister8WithSetHook(gba.Memory, address + 1, true, true); register = new MemoryRegister16(gba.Memory, address, true, true, r0, r1); r0.OnSet = (oldValue, newValue) => { lcd.Bg[bgNumber].CacheRenderData(); }; r1.OnSet = (oldValue, newValue) => { // This *should* be 0x1F but it breaks bg on mario kart track 1. Hopefully we can just get rid of tilemap reset and be done with this //if ((oldValue & 0x1F) != (newValue & 0x1F)) { // THIS HAS GOT TO GO! Mario Kart canes it! lcd.Bg[bgNumber].TileMap.Reset(); } lcd.Bg[bgNumber].CacheRenderData(); }; }
public BgAffineMatrix(GameboyAdvance gba, UInt32 address) { pa = new MemoryRegister16(gba.Memory, address, false, true); pb = new MemoryRegister16(gba.Memory, address + 2, false, true); pc = new MemoryRegister16(gba.Memory, address + 4, false, true); pd = new MemoryRegister16(gba.Memory, address + 6, false, true); }
public DisplayStatusRegister(GameboyAdvance gba, LcdController lcd) { this.lcd = lcd; DispStatRegister r0 = new DispStatRegister(lcd, this, gba.Memory, 0x4000004); MemoryRegister8 r1 = new MemoryRegister8(gba.Memory, 0x4000005, true, true); register = new MemoryRegister16(gba.Memory, 0x4000004, true, true, r0, r1); }
public Joypad(GameboyAdvance gba) { this.gba = gba; JoypadRegister r0 = new JoypadRegister(this, gba.Memory, 0x4000130); JoypadRegister r1 = new JoypadRegister(this, gba.Memory, 0x4000131); register = new MemoryRegister16(gba.Memory, 0x4000130, true, false, r0, r1); }
public DmaChannel(GameboyAdvance gba, int channelNumber) { this.gba = gba; this.channelNumber = channelNumber; DmaCnt = new DmaControlRegister(gba, this, (UInt32)(0x40000BA + (channelNumber * 0xC))); // TODO: These are all write only! // Should: reads open bus if the whole 32-bit word is unused and zero otherwise. SourceAddress = new MemoryRegister32(gba.Memory, (UInt32)(0x40000B0 + (channelNumber * 0xC)), true, true); DestAddress = new MemoryRegister32(gba.Memory, (UInt32)(0x40000B4 + (channelNumber * 0xC)), true, true); WordCount = new MemoryRegister16(gba.Memory, (UInt32)(0x40000B8 + (channelNumber * 0xC)), true, true); }
public Interrupts(GameboyAdvance gba) { this.gba = gba; InterruptMasterEnable = new MemoryRegister16(gba.Memory, 0x4000208, true, true); InterruptEnableRegister = new MemoryRegister16(gba.Memory, 0x4000200, true, true); IntFlagsRegister r0 = new IntFlagsRegister(this, gba.Memory, 0x4000202); IntFlagsRegister r1 = new IntFlagsRegister(this, gba.Memory, 0x4000203); InterruptRequestFlagsRegister = new MemoryRegister16(gba.Memory, 0x4000202, true, true, r0, r1); }
public LcdController(GameboyAdvance gba) { this.gba = gba; frameBuffer0 = new DirectBitmap(Screen_X_Resolution, Screen_Y_Resolution); frameBuffer1 = new DirectBitmap(Screen_X_Resolution, Screen_Y_Resolution); FrameBuffer = frameBuffer0; drawBuffer = frameBuffer1; this.Palettes = new Palettes(); DisplayControlRegister = new DisplayControlRegister(gba, this); DispStatRegister = new DisplayStatusRegister(gba, this); Bg = new Background[4]; UInt32 scrollBaseAddress = 0x4000010; for (int i = 0; i < 4; i++) { BgControlRegister cntReg = new BgControlRegister(gba, this, i, (UInt32) (0x4000008 + (i * 2))); MemoryRegister16 scrollXReg = new MemoryRegister16(gba.Memory, scrollBaseAddress, false, true, 0x01); MemoryRegister16 scrollYReg = new MemoryRegister16(gba.Memory, scrollBaseAddress + 2, false, true, 0x01); Bg[i] = new Background(gba, i, cntReg, scrollXReg, scrollYReg); scrollBaseAddress += 4; } VCount = new MemoryRegister8(gba.Memory, 0x04000006, true, false); this.ObjController = new ObjController(gba); Windows = new Window[4]; Windows[0] = new Window(gba, 0x4000040, 0x4000048); Windows[1] = new Window(gba, 0x4000042, 0x4000049); Windows[2] = new Window(gba, 0, 0x400004A); Windows[3] = new Window(gba, 0, 0x400004B); this.BlendControlRegister = new BlendControlRegister(this, gba); BlendingCoefficientRegister = new PixelCoefficientRegister(this, gba, 0x4000052); BrightnessCoefficientRegister = new PixelCoefficientRegister(this, gba, 0x4000054); #if THREADED_SCANLINE //Interlocked.Exchange(ref drawScanline, 0); drawScanline = 0; exitThread = false; scanlineThread = new Thread(new ThreadStart(ScanlineThread)); scanlineThread.Priority = ThreadPriority.Highest; scanlineThread.Start(); #endif }
public MemoryRegister32(Memory memory, UInt32 address, bool readable, bool writeable) { LoWord = new MemoryRegister16(memory, address, readable, writeable); HiWord = new MemoryRegister16(memory, address + 2, readable, writeable); if (readable) { memory.IoRegisters32Read.Add(address, this); } if (writeable) { memory.IoRegisters32Write.Add(address, this); } }
public Cpu(GameboyAdvance gba) { this.Gba = gba; Memory = gba.Memory; InstructionPipeline = new UInt32[Pipeline_Size]; CalculateArmDecodeLookUpTable(); CalculateThumbDecodeLookUpTable(); RegisterConditionalHandlers(); MemoryRegister8WithSetHook r0 = new MemoryRegister8WithSetHook(gba.Memory, 0x4000204, true, true); MemoryRegister8WithSetHook r1 = new MemoryRegister8WithSetHook(gba.Memory, 0x4000205, true, true); waitStateControlRegister = new MemoryRegister16(gba.Memory, 0x4000204, true, true, r0, r1); Action <byte, byte> waitStateSet = (oldValue, newValue) => { //Always make sure Bit 15 is 0 and Read-Only in GBA mode //memory_map[WAITCNT + 1] &= ~0x80; ushort waitControl = (ushort)(waitStateControlRegister.Value & ~0x80); //Determine first access cycles (Non-Sequential) switch ((waitControl >> 2) & 0x3) { case 0x0: nonSequentialAccessTime = 4; break; case 0x1: nonSequentialAccessTime = 3; break; case 0x2: nonSequentialAccessTime = 2; break; case 0x3: nonSequentialAccessTime = 8; break; } //Determine second access cycles (Sequential) switch ((waitControl >> 4) & 0x1) { case 0x0: sequentialAccessTime = 2; break; case 0x1: sequentialAccessTime = 1; break; } }; r0.OnSet = waitStateSet; r1.OnSet = waitStateSet; }
public DisplayControlRegister(GameboyAdvance gba, LcdController lcd) { this.lcd = lcd; MemoryRegister8WithSetHook r0 = new MemoryRegister8WithSetHook(gba.Memory, 0x4000000, true, true); MemoryRegister8 r1 = new MemoryRegister8(gba.Memory, 0x4000001, true, true); register = new MemoryRegister16(gba.Memory, 0x4000000, true, true, r0, r1); r0.OnSet = (oldValue, newValue) => { // BgMode changed? if ((oldValue & 0x07) != (newValue & 0x07)) { lcd.Bg[0].CacheRenderData(); lcd.Bg[1].CacheRenderData(); lcd.Bg[2].CacheRenderData(); lcd.Bg[3].CacheRenderData(); } }; }
public GbaTimer(Timers timers, GameboyAdvance gba, int timerNumber) { this.timers = timers; this.gba = gba; this.timerNumber = timerNumber; FiresOnCycle = 0xFFFFFFFF; UInt32 baseAddr = (UInt32)(0x4000100 + (timerNumber * 4)); TimerValueRegister r0 = new TimerValueRegister(gba, this, gba.Memory, baseAddr); TimerValueRegister r1 = new TimerValueRegister(gba, this, gba.Memory, baseAddr + 1); TimerValueRegister = new MemoryRegister16(gba.Memory, baseAddr, true, false, r0, r1); ReloadValue = new MemoryRegister16(gba.Memory, baseAddr, false, true); baseAddr = (UInt32)(0x4000102 + (timerNumber * 4)); MemoryRegister8WithSetHook reg = new MemoryRegister8WithSetHook(gba.Memory, baseAddr, true, true); MemoryRegister8 unused = new MemoryRegister8(gba.Memory, baseAddr + 1, true, true); TimerControlRegister = new MemoryRegister16(gba.Memory, baseAddr, true, true, reg, unused); reg.OnSet = (oldValue, newValue) => { CalculateWhichCycleTheTimerWillFire(); timers.CalculateWhenToNextUpdate(); // When a timer is enabled, it reloads it's starting value. When it is disabled it just maintains its current values bool wasEnabled = ((oldValue & 0x80) != 0); bool enabled = ((newValue & 0x80) != 0); if (wasEnabled == false && enabled) { startCycle = gba.Cpu.Cycles; timers.ScheduledUpdate(); TimerValue = ReloadValue.Value; } }; }
public AffineScrollRegister(Memory memory, UInt32 address, bool readable, bool writeable) : base() { MemoryRegister8WithSetHook r0 = new MemoryRegister8WithSetHook(memory, address, false, true); MemoryRegister8WithSetHook r1 = new MemoryRegister8WithSetHook(memory, address + 1, false, true); MemoryRegister8WithSetHook r2 = new MemoryRegister8WithSetHook(memory, address + 2, false, true); AffineNegRegister r3 = new AffineNegRegister(memory, address + 3, false, true); MemoryRegister16 loWord = new MemoryRegister16(memory, address, false, true, r0, r1); MemoryRegister16 hiWord = new MemoryRegister16(memory, address + 2, false, true, r2, r3); // Whenever a byte of this register is changed, we update the cached value // TODO: I don't understand the performance cost of 'capturing' the Value call here.... Action <byte, byte> updateAction = (oldValue, newValue) => { CachedValue = (int)Value; }; r0.OnSet = updateAction; r1.OnSet = updateAction; r2.OnSet = updateAction; r3.OnSet = updateAction; LoWord = loWord; HiWord = hiWord; }
public DmaControlRegister(GameboyAdvance gba, DmaChannel channel, UInt32 address) { this.channel = channel; MemoryRegister8 r0 = new MemoryRegister8(gba.Memory, address, true, true); MemoryRegister8WithSetHook r1 = new MemoryRegister8WithSetHook(gba.Memory, address + 1, true, true); register = new MemoryRegister16(gba.Memory, address, true, true, r0, r1); r1.OnSet = (oldValue, newValue) => { bool oldEnable = ((oldValue & 0x80) != 0); bool newEnable = ((newValue & 0x80) != 0); if (oldEnable == false && newEnable == true) { // Dma transfers take 2 cycles to start channel.DelayTransfer = 2; channel.ScheduledUpdateOnCycle = gba.Cpu.Cycles + 2; gba.Scheduler.RefreshSchedule(); } }; }
public Background(GameboyAdvance gba, int bgNumber, BgControlRegister cntRegister, MemoryRegister16 scrollXReg, MemoryRegister16 scrollYReg) { this.gba = gba; this.BgNumber = bgNumber; CntRegister = cntRegister; AffineMode = false; TileMap = new TileMap(gba.Memory.VRam, cntRegister, bgNumber); BGXHOFS = scrollXReg; BGXVOFS = scrollYReg; // Only bg 2 & 3 can rotate and scale if (bgNumber == 2) { AffineMatrix = new BgAffineMatrix(gba, 0x4000020); AffineScrollXReg = new AffineScrollRegister(gba.Memory, 0x4000028, false, true); AffineScrollYReg = new AffineScrollRegister(gba.Memory, 0x400002C, false, true); } else if (bgNumber == 3) { AffineMatrix = new BgAffineMatrix(gba, 0x4000030); AffineScrollXReg = new AffineScrollRegister(gba.Memory, 0x4000038, false, true); AffineScrollYReg = new AffineScrollRegister(gba.Memory, 0x400003C, false, true); } ScanlineData = new int[LcdController.Screen_X_Resolution]; #if THREADED_SCANLINE Interlocked.Exchange(ref cacheScanline, 0); exitThread = false; scanlineThread = new Thread(new ThreadStart(ScanlineThread)); scanlineThread.Start(); #endif }
public PixelCoefficientRegister(LcdController lcd, GameboyAdvance gba, UInt32 address) { this.lcd = lcd; register = new MemoryRegister16(gba.Memory, address, true, true); }
public BlendControlRegister(LcdController lcd, GameboyAdvance gba) { this.lcd = lcd; register = new MemoryRegister16(gba.Memory, 0x4000050, true, true); }