2024-08-31 23:57:44 +02:00

249 lines
5.7 KiB
Dart

import 'package:dartboy/emulator/joypad.dart';
import 'package:dartboy/emulator/mbc.dart';
import 'package:dartboy/emulator/ppu.dart';
import 'package:dartboy/emulator/timer.dart';
import 'package:dartboy/emulator/utils.dart';
class Ie extends BitFieldU8 {
Ie() : super({});
Ie.fromU8(int u8) : super.fromU8(u8);
Bit get vBlank => value(0);
Bit get lcdStat => value(1);
Bit get timer => value(2);
Bit get serial => value(3);
Bit get joypad => value(4);
}
class Bus {
Bus(this.ppu, this.mbc);
Ppu ppu = Ppu();
Joypad joypad = Joypad();
Timer timer = Timer();
List<int> ram = List.filled(0x8000, 0);
List<int> hram = List.filled(0x0080, 0);
Mbc mbc;
Ie ie = Ie();
bool _prevSerial = false;
bool _intSerial = false;
void tick() {
ppu.tick();
timer.tick();
}
bool get irqVBlank => ppu.intVBlank;
set irqVBlank(bool val) {
ppu.intVBlank = val;
}
bool get irqLcdStat => ppu.intLcdStat;
set irqLcdStat(bool val) {
ppu.intLcdStat = val;
}
bool get irqTimer => timer.interrupt;
set irqTimer(bool val) {
timer.interrupt = val;
}
bool get irqSerial => _intSerial;
set irqSerial(bool val) {
_intSerial = val;
}
bool get irqJoypad => joypad.interrupt;
set irqJoypad(bool val) {
joypad.interrupt = val;
}
int read(int addr) {
if (0x0000 <= addr && addr <= 0x7FFF) return mbc.read(addr);
if (0x8000 <= addr && addr <= 0x9FFF) return ppu.read(addr);
if (0xA000 <= addr && addr <= 0xBFFF) return mbc.read(addr);
if (0xC000 <= addr && addr <= 0xDFFF) return ram[addr - 0xC000];
if (0xE000 <= addr && addr <= 0xFDFF) return ram[addr - 0xE000];
if (0xFE00 <= addr && addr <= 0xFE9F) return ppu.readOam(addr);
if (0xFEA0 <= addr && addr <= 0xFEFF) return 0;
if (0xFF00 == addr) return joypad.read();
if (0xFF01 == addr) return readSerial();
if (0xFF02 == addr) return readSerialCtrl();
if (0xFF04 == addr) return timer.readDiv();
if (0xFF05 == addr) return timer.readTima();
if (0xFF06 == addr) return timer.readTma();
if (0xFF07 == addr) return timer.readTac();
if (0xFF0F == addr) return readIrq();
if (0xFF40 == addr) return ppu.readLcdControl();
if (0xFF41 == addr) return ppu.readLcdStatus();
if (0xFF42 == addr) return ppu.readScrollY();
if (0xFF43 == addr) return ppu.readScrollX();
if (0xFF44 == addr) return ppu.readLines();
if (0xFF45 == addr) return ppu.readLineCompare();
if (0xFF47 == addr) return ppu.readBgPalette();
if (0xFF48 == addr) return ppu.readObjectPalette0();
if (0xFF49 == addr) return ppu.readObjectPalette1();
if (0xFF4A == addr) return ppu.readWindowY();
if (0xFF4B == addr) return ppu.readWindowX();
if (0xFF80 <= addr && addr <= 0xFFFE) return hram[addr - 0xFF80];
if (0xFFFF == addr) return ie.toU8();
return 0;
}
int readWord(int addr) {
final low = read(addr);
final high = read(addr + 1);
return ((high) << 8) | low;
}
int readIrq() {
return bitpack([
false,
false,
false,
joypad.interrupt,
_intSerial,
timer.interrupt,
ppu.intLcdStat,
ppu.intVBlank
]);
}
int readSerial() {
return 0;
}
int readSerialCtrl() {
return 0;
}
void write(int addr, int val) {
if (0x0000 <= addr && addr <= 0x7FFF) {
mbc.write(addr, val);
}
if (0x8000 <= addr && addr <= 0x9FFF) {
ppu.write(addr, val);
}
if (0xA000 <= addr && addr <= 0xBFFF) {
mbc.write(addr, val);
}
if (0xC000 <= addr && addr <= 0xDFFF) {
ram[addr - 0xC000] = val;
}
if (0xE000 <= addr && addr <= 0xFDFF) {
ram[addr - 0xE000] = val;
}
if (0xFE00 <= addr && addr <= 0xFE9F) {
ppu.writeOam(addr, val);
}
if (0xFEA0 <= addr && addr <= 0xFEFF) {
return;
}
if (0xFF00 == addr) {
joypad.write(val);
}
if (0xFF01 == addr) {
writeSerial(val);
}
if (0xFF02 == addr) {
writeSerialCtrl(val);
}
if (0xFF04 == addr) {
timer.writeDiv(val);
}
if (0xFF05 == addr) {
timer.writeTima(val);
}
if (0xFF06 == addr) {
timer.writeTma(val);
}
if (0xFF07 == addr) {
timer.writeTac(val);
}
if (0xFF0F == addr) {
writeIrq(val);
}
if (0xFF40 == addr) {
ppu.writeLcdControl(val);
}
if (0xFF41 == addr) {
ppu.writeLcdStatus(val);
}
if (0xFF42 == addr) {
ppu.writeScrollY(val);
}
if (0xFF43 == addr) {
ppu.writeScrollX(val);
}
if (0xFF45 == addr) {
ppu.writeLineCompare(val);
}
if (0xFF46 == addr) {
writeDma(val);
}
if (0xFF47 == addr) {
ppu.writeBgPalette(val);
}
if (0xFF48 == addr) {
ppu.writeObjectPalette0(val);
}
if (0xFF49 == addr) {
ppu.writeObjectPalette1(val);
}
if (0xFF4A == addr) {
ppu.writeWindowY(val);
}
if (0xFF4B == addr) {
ppu.writeWindowX(val);
}
if (0xFF80 <= addr && addr <= 0xFFFE) {
hram[addr - 0xFF80] = val;
}
if (0xFFFF == addr) {
ie = Ie.fromU8(val);
}
}
void writeWord(int addr, int val) {
final low = val.toU8();
final high = (val >> 8).toU8();
write(addr, low);
write(addr + 1, high);
}
void writeIrq(int val) {
ppu.intVBlank = isSet(val, 0);
ppu.intLcdStat = isSet(val, 1);
timer.interrupt = isSet(val, 2);
_intSerial = isSet(val, 3);
joypad.interrupt = isSet(val, 4);
}
void writeSerial(int val) {}
void writeSerialCtrl(int val) {
final cur = isSet(val, 7);
if (_prevSerial && !cur) {
_intSerial = true;
}
_prevSerial = cur;
}
void writeDma(int val) {
final baseAddr = (val << 8).toU16();
for (var i = 0; i < 0x100; i++) {
write(0xFE00 + i, read(baseAddr + i));
}
}
}