Add basic hardware IO.

Emulator passes bios! hooray
This commit is contained in:
Kevin Hamacher 2016-05-26 14:18:02 +02:00
parent 8df38e9c11
commit 94e73b2eda
6 changed files with 536 additions and 43 deletions

View File

@ -6,7 +6,7 @@ E000 FCFF Copy of the work RAM
FE00 FE9F OAM (Sprite Attribute Table) FE00 FE9F OAM (Sprite Attribute Table)
FEA0 FEFF Unused FEA0 FEFF Unused
FF00 FF7F Hardware IO FF00 FF7F Hardware IO
FE80 FFFE High RAM FF80 FFFE High RAM
FFFF FFFF Interrupt switch FFFF FFFF Interrupt switch
Hardware IO: Hardware IO:

View File

@ -32,6 +32,8 @@ fn to_u16(bytes: Box<[u8]>) -> u16 {
impl CPU { impl CPU {
pub fn new(interconnect: interconnect::Interconnect) -> CPU { pub fn new(interconnect: interconnect::Interconnect) -> CPU {
// Ugly patch ^.^
// interconnect.write_byte(0xFF44 as u16, 0x90);
CPU { CPU {
flags: 0, flags: 0,
regs: [0, 0, 0, 0, 0, 0, 0], regs: [0, 0, 0, 0, 0, 0, 0],
@ -59,7 +61,8 @@ impl CPU {
if reg_id == 7 { if reg_id == 7 {
self.regs[REG_A] = value; self.regs[REG_A] = value;
} else if reg_id == 6 { } else if reg_id == 6 {
panic!("(HL) not supported yet."); let addr: u16 = self.get_pair_value(REG_H, REG_L);
self.interconnect.write_byte(addr, value);
} else { } else {
self.regs[reg_id] = value; self.regs[reg_id] = value;
} }
@ -70,7 +73,8 @@ impl CPU {
if reg_id == 7 { if reg_id == 7 {
self.regs[REG_A] self.regs[REG_A]
} else if reg_id == 6 { } else if reg_id == 6 {
panic!("(HL) not supported yet."); let addr: u16 = self.get_pair_value(REG_H, REG_L);
self.interconnect.read_byte(addr)
} else { } else {
self.regs[reg_id] self.regs[reg_id]
} }
@ -83,10 +87,75 @@ impl CPU {
match instruction { match instruction {
0x10 ... 0x17 => { 0x10 ... 0x17 => {
let reg_id = (instruction - 0x10) as usize; let reg_id = (instruction - 0x10) as usize;
let args = self.load_args(1); let val = self.get_8bit_reg(reg_id);
let mut val = self.get_8bit_reg(reg_id); println!("RL {}", REG_NAMES[reg_id]);
println!("RL {}, {}", REG_NAMES[reg_id], args[0]); self.regs[REG_A].rotate_left(val as u32);
self.set_8bit_reg(reg_id, val.rotate_left(args[0] as u32)); }
0x40 ... 0x47 => {
// Test 0th bit
let reg_id = (instruction - 0x40) as usize;
let reg_content = self.get_8bit_reg(reg_id);
println!("BIT 0, {}", REG_NAMES[reg_id]);
if reg_content & (1 << 0) == 0 {
self.flags |= FLAG_Z;
} else {
self.flags &= !FLAG_Z;
}
}
0x48 ... 0x4F => {
// Test 1th bit
let reg_id = (instruction - 0x48) as usize;
let reg_content = self.get_8bit_reg(reg_id);
println!("BIT 1, {}", REG_NAMES[reg_id]);
if reg_content & (1 << 1) == 0 {
self.flags |= FLAG_Z;
} else {
self.flags &= !FLAG_Z;
}
}
0x50 ... 0x57 => {
// Test 2th bit
let reg_id = (instruction - 0x50) as usize;
let reg_content = self.get_8bit_reg(reg_id);
println!("BIT 2, {}", REG_NAMES[reg_id]);
if reg_content & (1 << 2) == 0 {
self.flags |= FLAG_Z;
} else {
self.flags &= !FLAG_Z;
}
}
0x58 ... 0x5F => {
// Test 3th bit
let reg_id = (instruction - 0x58) as usize;
let reg_content = self.get_8bit_reg(reg_id);
println!("BIT 3, {}", REG_NAMES[reg_id]);
if reg_content & (1 << 3) == 0 {
self.flags |= FLAG_Z;
} else {
self.flags &= !FLAG_Z;
}
}
0x60 ... 0x67 => {
// Test 4th bit
let reg_id = (instruction - 0x60) as usize;
let reg_content = self.get_8bit_reg(reg_id);
println!("BIT 4, {}", REG_NAMES[reg_id]);
if reg_content & (1 << 4) == 0 {
self.flags |= FLAG_Z;
} else {
self.flags &= !FLAG_Z;
}
}
0x68 ... 0x6F => {
// Test 5th bit
let reg_id = (instruction - 0x68) as usize;
let reg_content = self.get_8bit_reg(reg_id);
println!("BIT 5, {}", REG_NAMES[reg_id]);
if reg_content & (1 << 5) == 0 {
self.flags |= FLAG_Z;
} else {
self.flags &= !FLAG_Z;
}
} }
0x70 ... 0x77 => { 0x70 ... 0x77 => {
// Test 6th bit // Test 6th bit
@ -117,51 +186,151 @@ impl CPU {
} }
fn get_pair_value(&self, a: usize, b: usize) -> u16 { fn get_pair_value(&self, a: usize, b: usize) -> u16 {
(self.regs[a] as u16) | (self.regs[b] as u16) << 8 (self.regs[a] as u16) << 8 | (self.regs[b] as u16)
} }
fn set_pair_value(&mut self, a: usize, b: usize, value: u16) { fn set_pair_value(&mut self, a: usize, b: usize, value: u16) {
self.regs[a] = value as u8; self.regs[a] = (value >> 8) as u8;
self.regs[b] = (value >> 8) as u8; self.regs[b] = value as u8;
}
fn dump_stack(&self) {
for i in self.sp .. 0xFFFE {
println!("[{:#04X}]: {:#02X}", i, self.interconnect.read_byte(i));
}
}
fn reg_inc(&mut self, reg_id: usize) {
self.regs[reg_id] = self.regs[reg_id].wrapping_add(1);
if self.regs[reg_id] == 0 {
self.flags |= FLAG_Z;
}
self.flags &= !FLAG_N;
}
fn reg_dec(&mut self, reg_id: usize) {
self.regs[reg_id] = self.regs[reg_id].wrapping_sub(1);
if self.regs[reg_id] == 0 {
self.flags |= FLAG_Z;
} else {
self.flags &= !FLAG_Z;
}
self.flags |= FLAG_N;
} }
pub fn run_instruction(&mut self) { pub fn run_instruction(&mut self) {
let instruction = self.read_byte(self.ip); let instruction = self.read_byte(self.ip);
print!("{:#04x}: {:#04x}: ", &self.ip, &instruction); print!("{:#04x}: [SP: {:#04X}] i={:02X}. ", &self.ip, &self.sp, &instruction);
for i in 0 .. 6 {
print!("{}: {:02X} ", REG_NAMES[i], self.get_8bit_reg(i));
}
print!("A: {:02X} ", self.regs[REG_A]);
print!("I: {:02X} ", self.interconnect.read_byte(0xFFFF));
// Flags
print!("Z={} ", self.flags & FLAG_Z != 0);
print!("N={} ", self.flags & FLAG_N != 0);
print!("H={} ", self.flags & FLAG_H != 0);
print!("C={} ", self.flags & FLAG_C != 0);
self.ip += 1; self.ip += 1;
match instruction { match instruction {
0x04 => {
println!("INC B");
self.reg_inc(REG_B);
},
0x05 => { 0x05 => {
println!("DEC B"); println!("DEC B");
self.regs[REG_B].wrapping_sub(1); self.reg_dec(REG_B);
} },
0x06 => { 0x06 => {
let args = self.load_args(1); let args = self.load_args(1);
println!("LD B, {:02x}", args[0]); println!("LD B, {:02x}", args[0]);
self.regs[REG_B] = args[0]; self.regs[REG_B] = args[0];
} },
0x0C => { 0x0C => {
println!("INC C"); println!("INC C");
self.regs[REG_C] += 1; self.reg_inc(REG_C);
} },
0x0D => {
println!("DEC C");
self.reg_dec(REG_C);
},
0x0E => { 0x0E => {
let args = self.load_args(1); let args = self.load_args(1);
println!("LD C, {:02x}", args[0]); println!("LD C, {:02x}", args[0]);
self.regs[REG_C] = args[0]; self.regs[REG_C] = args[0];
} },
0x11 => { 0x11 => {
let args = self.load_args(2); let args = self.load_args(2);
println!("LD DE, {:02x}{:02x}", args[1], args[0]); let val = to_u16(args);
println!("LD DE, {:04x}", val);
self.set_pair_value(REG_D, REG_E, val);
},
0x13 => {
println!("INC DE");
let old_value = self.get_pair_value(REG_D, REG_E);
self.set_pair_value(REG_D, REG_E, old_value + 1);
},
0x14 => {
println!("INC D");
self.reg_inc(REG_D);
},
0x15 => {
println!("DEC D");
self.reg_dec(REG_D);
},
0x16 => {
let args = self.load_args(1);
println!("LD D, {:02x}", args[0]);
self.regs[REG_D] = args[0]; self.regs[REG_D] = args[0];
self.regs[REG_E] = args[1]; },
0x17 => {
println!("RLA");
let carry = self.flags & FLAG_C == FLAG_C;
if !carry {
// No carry before, now we got a carry => set it
if self.regs[REG_A] & 0x80 == 0x80 {
self.flags |= FLAG_C
}
self.regs[REG_A] = self.regs[REG_A] << 1;
} else {
if self.regs[REG_A] & 0x80 == 0 {
self.flags &= !FLAG_C;
}
self.regs[REG_A] = self.regs[REG_A] << 1 | 1;
}
},
0x18 => {
let args = self.load_args(1);
println!("JR {:02X}", args[0] as i8);
let off: i8 = args[0] as i8;
if off < 0 {
self.ip -= (-off) as u16;
} else {
self.ip += off as u16;
}
}, },
0x1A => { 0x1A => {
println!("LD A, (DE)"); println!("LD A, (DE)");
self.regs[REG_A] = self.interconnect.read_byte(self.get_pair_value(REG_D, REG_E)); self.regs[REG_A] = self.interconnect.read_byte(self.get_pair_value(REG_D, REG_E));
} },
0x1C => {
println!("INC E");
self.reg_inc(REG_E);
},
0x1D => {
println!("DEC E");
self.reg_dec(REG_E);
},
0x1E => {
let args = self.load_args(1);
println!("LD E, {:02x}", args[0]);
self.regs[REG_E] = args[0];
},
0x20 => { 0x20 => {
let args = self.load_args(1); let args = self.load_args(1);
println!("JR NZ {:02x}", args[0]); println!("JR NZ {:02x}", args[0] as i8);
if self.flags & FLAG_Z == 0 { if self.flags & FLAG_Z == 0 {
let offset = args[0] as i8; let offset = args[0] as i8;
if offset < 0 { if offset < 0 {
@ -172,16 +341,58 @@ impl CPU {
} }
} }
0x21 => { 0x21 => {
let args = self.load_args(2); let value = to_u16(self.load_args(2));
println!("LD HL, {:02x}{:02x}", args[1], args[0]); println!("LD HL, {:04x}", value);
self.regs[REG_H] = args[0]; self.set_pair_value(REG_H, REG_L, value);
self.regs[REG_L] = args[1]; },
0x22 => {
println!("LD (HL+), A");
let addr: u16 = self.get_pair_value(REG_H, REG_L);
self.interconnect.write_byte(addr, self.regs[REG_A]);
self.set_pair_value(REG_H, REG_L, addr + 1);
},
0x23 => {
println!("INC HL");
let old_value = self.get_pair_value(REG_H, REG_L);
self.set_pair_value(REG_H, REG_L, old_value + 1);
},
0x24 => {
println!("INC H");
self.reg_inc(REG_H);
},
0x25 => {
println!("DEC H");
self.reg_dec(REG_H);
}, },
0x26 => { 0x26 => {
let args = self.load_args(1); let args = self.load_args(1);
println!("LD H, {:02x}", args[0]); println!("LD H, {:02x}", args[0]);
self.regs[REG_H] = args[0]; self.regs[REG_H] = args[0];
}, },
0x28 => {
let args = self.load_args(1);
let mut target;
if args[0] < 0 {
target = self.ip - (-(args[0] as i8)) as u16;
} else {
target = self.ip + args[0] as u16;
}
println!("LR Z, {:04X}", target);
self.ip = target;
},
0x2C => {
println!("INC L");
self.reg_inc(REG_L);
},
0x2D => {
println!("DEC L");
self.reg_dec(REG_L);
},
0x2E => {
let args = self.load_args(1);
println!("LD L, {:02x}", args[0]);
self.regs[REG_L] = args[0];
},
0x31 => { 0x31 => {
let args = self.load_args(2); let args = self.load_args(2);
self.sp = to_u16(args); self.sp = to_u16(args);
@ -189,18 +400,33 @@ impl CPU {
}, },
0x32 => { 0x32 => {
println!("LD (HL-), A"); println!("LD (HL-), A");
let mut addr: u16 = (self.regs[REG_H] as u16) | ((self.regs[REG_L] as u16) << 8); let mut addr = self.get_pair_value(REG_H, REG_L);
self.interconnect.write_byte(addr, self.regs[REG_A]); self.interconnect.write_byte(addr, self.regs[REG_A]);
addr -= 1; addr -= 1;
self.regs[REG_H] = addr as u8; self.set_pair_value(REG_H, REG_L, addr);
self.regs[REG_L] = (addr >> 8) as u8;
}, },
0x36 => {
let args = self.load_args(1);
println!("LD (HL), {:02x}", args[0]);
let addr = self.get_pair_value(REG_H, REG_L);
self.interconnect.write_byte(addr, args[0]);
},
0x3C => {
println!("INC A");
self.reg_inc(REG_A);
}
0x3D => {
println!("DEC A");
self.reg_dec(REG_A);
}
0x3E => { 0x3E => {
let args = self.load_args(1); let args = self.load_args(1);
println!("LD A, {:02x}", args[0]); println!("LD A, {:02x}", args[0]);
self.regs[REG_A] = args[0]; self.regs[REG_A] = args[0];
}, },
// LDs
0x40 ... 0x47 => { 0x40 ... 0x47 => {
let reg_id = (instruction - 0x40) as usize; let reg_id = (instruction - 0x40) as usize;
println!("LD B, {}", REG_NAMES[reg_id]); println!("LD B, {}", REG_NAMES[reg_id]);
@ -235,7 +461,7 @@ impl CPU {
let reg_id = (instruction - 0x70) as usize; let reg_id = (instruction - 0x70) as usize;
println!("LD (HL), {}", REG_NAMES[reg_id]); println!("LD (HL), {}", REG_NAMES[reg_id]);
let reg_value: u8 = self.get_8bit_reg(reg_id); let reg_value: u8 = self.get_8bit_reg(reg_id);
let addr: u16 = (self.regs[REG_L] as u16) << 8 | (self.regs[REG_H] as u16); let addr: u16 = self.get_pair_value(REG_H, REG_L);
self.interconnect.write_byte(addr, reg_value); self.interconnect.write_byte(addr, reg_value);
}, },
@ -244,10 +470,81 @@ impl CPU {
println!("LD A, {}", REG_NAMES[reg_id]); println!("LD A, {}", REG_NAMES[reg_id]);
self.regs[REG_A] = self.get_8bit_reg(reg_id); self.regs[REG_A] = self.get_8bit_reg(reg_id);
}, },
// ADD
0x80 ... 0x87 => {
let reg_id = (instruction - 0x80) as usize;
println!("ADD {}", REG_NAMES[reg_id]);
self.regs[REG_A] = self.regs[REG_A].wrapping_add(self.get_8bit_reg(reg_id));
self.flags &= !FLAG_N;
}
// ADC
0x88 ... 0x8F => {
let reg_id = (instruction - 0x88) as usize;
println!("ADC {}", REG_NAMES[reg_id]);
self.regs[REG_A] = self.regs[REG_A].wrapping_add(self.get_8bit_reg(reg_id));
if self.flags & FLAG_C == FLAG_C {
self.regs[REG_A] = self.regs[REG_A].wrapping_add(1);
}
self.flags &= !FLAG_N;
}
// SUBs
0x90 ... 0x97 => {
let reg_id = (instruction - 0x90) as usize;
println!("SUB {}", REG_NAMES[reg_id]);
self.regs[REG_A] = self.regs[REG_A].wrapping_sub(self.get_8bit_reg(reg_id));
self.flags |= FLAG_N;
if self.regs[REG_A] == 0 {
self.flags |= FLAG_Z;
} else {
self.flags &= !FLAG_Z;
}
// TODO: H, C
}
// SBC
0x98 ... 0x9F => {
let reg_id = (instruction - 0x98) as usize;
println!("SBC {}", REG_NAMES[reg_id]);
self.regs[REG_A] = self.regs[REG_A].wrapping_sub(self.get_8bit_reg(reg_id));
if self.flags & FLAG_C == FLAG_C {
self.regs[REG_A] = self.regs[REG_A].wrapping_sub(1);
}
self.flags |= FLAG_N;
}
// XOR
0xA8 ... 0xAF => { 0xA8 ... 0xAF => {
let reg_id = (instruction - 0xA8) as usize; let reg_id = (instruction - 0xA8) as usize;
println!("XOR {}", REG_NAMES[reg_id]); println!("XOR {}", REG_NAMES[reg_id]);
self.regs[REG_A] ^= self.get_8bit_reg(reg_id); self.regs[REG_A] ^= self.get_8bit_reg(reg_id);
if self.regs[REG_A] == 0 {
self.flags |= FLAG_Z;
} else {
self.flags &= !FLAG_Z;
}
self.flags &= !FLAG_C;
self.flags &= !FLAG_N;
self.flags &= !FLAG_H;
},
// CP
0xB8 ... 0xBF => {
let reg_id = (instruction - 0xB8) as usize;
println!("CP {}", REG_NAMES[reg_id]);
let val = self.get_8bit_reg(reg_id);
if self.regs[REG_A] < self.get_8bit_reg(reg_id) {
self.flags |= FLAG_C;
self.flags &= !FLAG_Z;
} else if self.regs[REG_A] == self.get_8bit_reg(reg_id) {
self.flags |= FLAG_Z;
self.flags &= !FLAG_C;
} else {
self.flags &= !FLAG_Z;
self.flags &= !FLAG_C;
}
}, },
0xC1 => { 0xC1 => {
println!("POP BC"); println!("POP BC");
@ -258,9 +555,15 @@ impl CPU {
0xC5 => { 0xC5 => {
println!("PUSH BC"); println!("PUSH BC");
let val: u16 = self.get_pair_value(REG_B, REG_C); let val: u16 = self.get_pair_value(REG_B, REG_C);
self.interconnect.write_word(self.sp, val); self.interconnect.write_word(self.sp - 2, val);
self.sp -= 2; self.sp -= 2;
}, },
0xC9 => {
println!("RET");
self.dump_stack();
self.ip = self.interconnect.read_word(self.sp+1);
self.sp += 2;
},
0xCB => { 0xCB => {
// Prefix CB. This is annoying. // Prefix CB. This is annoying.
self.run_prefix_instruction(); self.run_prefix_instruction();
@ -273,23 +576,56 @@ impl CPU {
// self.interconnect.write_byte(self.sp - 1, (self.ip >> 8) as u8); // self.interconnect.write_byte(self.sp - 1, (self.ip >> 8) as u8);
self.interconnect.write_word(self.sp - 1, self.ip); self.interconnect.write_word(self.sp - 1, self.ip);
self.sp -= 2; self.sp -= 2;
self.dump_stack();
self.ip = target; self.ip = target;
} },
0xE0 => { 0xE0 => {
let args = self.load_args(1); let args = self.load_args(1);
println!("LDH {:02X}, A", args[0]); println!("LDH {:02X}, A", args[0]);
self.interconnect.write_byte(0xFF00 + args[0] as u16, self.regs[REG_A]); self.interconnect.write_byte(0xFF00 + args[0] as u16, self.regs[REG_A]);
} },
0xE2 => { 0xE2 => {
println!("LD (C), A"); println!("LD (C), A");
println!("[{:04X}] = {:02X}", 0xFF00 + self.regs[REG_C] as u16, self.regs[REG_A]);
self.interconnect.write_byte(0xFF00 + self.regs[REG_C] as u16, self.regs[REG_A]) self.interconnect.write_byte(0xFF00 + self.regs[REG_C] as u16, self.regs[REG_A])
},
0xEA => {
let addr = to_u16(self.load_args(2));
println!("LD ({:04X}), A", addr);
self.interconnect.write_byte(addr, self.regs[REG_A]);
} }
0xF0 => {
let args = self.load_args(1);
println!("LDH A, {:02X}", args[0]);
self.regs[REG_A] = self.interconnect.read_byte(0xFF00 + args[0] as u16);
},
0xFB => { 0xFB => {
// Enable interrupts - TODO // Enable interrupts - TODO
println!("EI"); println!("EI");
self.interconnect.write_byte(0xFFFF, 0x01);
panic!("Uh uh");
},
0xFE => {
let args = self.load_args(1);
println!("CP {:02X}", args[0]);
self.flags |= FLAG_N;
if args[0] > self.regs[REG_A] {
self.flags |= FLAG_C;
} else {
self.flags &= !FLAG_C;
}
if args[0] == self.regs[REG_A] {
self.flags |= FLAG_Z;
} else {
self.flags &= !FLAG_Z;
}
// TODO H
} }
_ => panic!("Unknown instruction: {:02x}", instruction) _ => panic!("Unknown instruction: {:02x}", instruction)
} }
// self.dump_stack();
self.interconnect.tick();
} }
} }

51
src/display.rs Normal file
View File

@ -0,0 +1,51 @@
#[derive(Debug, Default)]
pub struct Display {
control: u8,
status: u8,
background_palette: u8,
scrollx: u8,
scrolly: u8,
curline: u8,
// TODO
}
impl Display {
pub fn new() -> Display {
Display::default()
}
pub fn write_byte(&mut self, addr: u16, val: u8) {
match addr {
0xFF40 => self.control = val,
0xFF41 => self.status = val,
0xFF42 => self.scrolly = val,
0xFF43 => self.scrollx = val,
0xFF44 => self.curline = 0,
0xFF47 => self.background_palette = val,
_ => panic!("Display: Write {:02X} to {:04X} unsupported", val, addr),
}
}
pub fn read_byte(&self, addr: u16) -> u8 {
match addr {
0xFF40 => self.control,
0xFF41 => self.status,
0xFF42 => self.scrolly,
0xFF43 => self.scrollx,
0xFF44 => self.curline,
0xFF47 => self.background_palette,
_ => panic!("Display: Read from {:04X} unsupported", addr),
}
}
pub fn vblank_interrupt(&mut self) {
self.curline += 1;
if self.curline > 153 {
self.curline = 0;
}
}
pub fn controller_interrupt(&self) {
}
}

View File

@ -1,13 +1,24 @@
const RAM_SIZE: usize = 0x2000; const RAM_SIZE: usize = 0x2000;
const VRAM_SIZE: usize = 0x2000; const VRAM_SIZE: usize = 0x2000;
const HIRAM_SIZE: usize = (0xFFFE - 0xFE80) + 1; const HIRAM_SIZE: usize = (0xFFFE - 0xFF80) + 1;
const INTERRUPT_DISPLAY: u8 = 1 << 1;
const INTERRUPT_DISPLAY_VBLANK: u8 = 1 << 0;
use super::display;
use super::sound;
pub struct Interconnect { pub struct Interconnect {
bios: Box<[u8]>, bios: Box<[u8]>,
rom: Box<[u8]>, rom: Box<[u8]>,
ram: Box<[u8]>, ram: Box<[u8]>,
vram: Box<[u8]>, vram: Box<[u8]>,
hiram: Box<[u8]> hiram: Box<[u8]>,
sound: sound::Sound,
display: display::Display,
interrupt: u8,
timer: u8,
disable_bootrom: u8,
} }
impl Interconnect { impl Interconnect {
@ -18,6 +29,32 @@ impl Interconnect {
ram: vec![0; RAM_SIZE].into_boxed_slice(), ram: vec![0; RAM_SIZE].into_boxed_slice(),
vram: vec![0; VRAM_SIZE].into_boxed_slice(), vram: vec![0; VRAM_SIZE].into_boxed_slice(),
hiram: vec![0; HIRAM_SIZE].into_boxed_slice(), hiram: vec![0; HIRAM_SIZE].into_boxed_slice(),
sound: sound::Sound::new(),
display: display::Display::new(),
interrupt: 0,
timer: 0,
disable_bootrom: 0,
}
}
// Somehow we need different timers for this.
pub fn tick(&mut self) {
self.timer += 1;
if self.timer == 5 {
self.display_blank_interrupt();
self.timer = 0;
}
}
pub fn display_blank_interrupt(&mut self) {
if self.interrupt & INTERRUPT_DISPLAY_VBLANK >= 0 {
self.display.vblank_interrupt();
}
}
pub fn display_interrupt(&mut self) {
if self.interrupt & INTERRUPT_DISPLAY > 0 {
self.display.controller_interrupt();
} }
} }
@ -28,7 +65,7 @@ impl Interconnect {
match addr { match addr {
0x0000 ... 0x7FFF => { 0x0000 ... 0x7FFF => {
// TODO: Check if bios or cartridge (additional condition: isEnabled) // TODO: Check if bios or cartridge (additional condition: isEnabled)
if addr < 0x100 { if addr < 0x100 && self.disable_bootrom == 0 {
self.bios[addr as usize] self.bios[addr as usize]
} else { } else {
self.rom[addr as usize] self.rom[addr as usize]
@ -40,8 +77,20 @@ impl Interconnect {
0xC000 ... 0xDFFF => { 0xC000 ... 0xDFFF => {
self.ram[(addr - 0xC000) as usize] self.ram[(addr - 0xC000) as usize]
}, },
0xFE80 ... 0xFFFE => { 0xFF10 ... 0xFF26 => {
self.hiram[(addr - 0xFE80) as usize] self.sound.read_byte(addr)
},
0xFF40 ... 0xFF4B => {
self.display.read_byte(addr)
},
0xFF50 => {
self.disable_bootrom
},
0xFF80 ... 0xFFFE => {
self.hiram[(addr - 0xFF80) as usize]
},
0xFFFF => {
self.interrupt
} }
_ => { _ => {
panic!("Read from {:04X} not supported.", addr); panic!("Read from {:04X} not supported.", addr);
@ -61,7 +110,7 @@ impl Interconnect {
FE00 FE9F OAM (Sprite Attribute Table) FE00 FE9F OAM (Sprite Attribute Table)
FEA0 FEFF Unused FEA0 FEFF Unused
FF00 FF7F Hardware IO FF00 FF7F Hardware IO
FE80 FFFE High RAM FF80 FFFE High RAM
FFFF FFFF Interrupt switch FFFF FFFF Interrupt switch
*/ */
@ -72,9 +121,21 @@ impl Interconnect {
0xC000 ... 0xDFFF => { 0xC000 ... 0xDFFF => {
self.ram[(addr - 0xC000) as usize] = val; self.ram[(addr - 0xC000) as usize] = val;
}, },
0xFE80 ... 0xFFFE => { 0xFF10 ... 0xFF26 => {
self.hiram[(addr - 0xFE80) as usize] = val; self.sound.write_byte(addr, val);
},
0xFF40 ... 0xFF4B => {
self.display.write_byte(addr, val);
},
0xFF50 => {
self.disable_bootrom = val;
} }
0xFF80 ... 0xFFFE => {
self.hiram[(addr - 0xFF80) as usize] = val;
},
0xFFFF => {
self.interrupt = val;
},
_ => { _ => {
panic!("Write {:02X} to {:04X} not supported.", val, addr); panic!("Write {:02X} to {:04X} not supported.", val, addr);
} }

View File

@ -7,7 +7,10 @@ use std::fs;
use std::env; use std::env;
mod cpu; mod cpu;
mod display;
mod interconnect; mod interconnect;
mod sound;
fn main() { fn main() {
let bios_path = env::args().nth(1).unwrap(); let bios_path = env::args().nth(1).unwrap();
@ -16,11 +19,11 @@ fn main() {
let rom = read_rom(&rom_path); let rom = read_rom(&rom_path);
// Now we need to execute commands // Now we need to execute commands
let mut interconnect = interconnect::Interconnect::new(bios, rom); let interconnect = interconnect::Interconnect::new(bios, rom);
let mut CPU = cpu::CPU::new(interconnect); let mut cpu = cpu::CPU::new(interconnect);
loop { loop {
CPU.run_instruction(); cpu.run_instruction();
} }
} }

42
src/sound.rs Normal file
View File

@ -0,0 +1,42 @@
#[derive(Debug, Default)]
pub struct Sound {
enabled: u8,
sound_length_1: u8,
sound_control_1: u8,
sound_channel_volume_control: u8,
sound_output_terminal_selector: u8,
sound_freq_low: u8,
sound_freq_high: u8,
}
impl Sound {
pub fn new() -> Sound {
Sound::default()
}
pub fn write_byte(&mut self, addr: u16, val: u8) {
match addr {
0xFF11 => self.sound_length_1 = val,
0xFF12 => self.sound_control_1 = val,
0xFF13 => self.sound_freq_low = val,
0xFF14 => self.sound_freq_high = val,
0xFF24 => self.sound_channel_volume_control = val,
0xFF25 => self.sound_output_terminal_selector = val,
0xFF26 => self.enabled = val,
_ => panic!("Sound: Write {:02X} to {:04X} unsupported", val, addr),
}
}
pub fn read_byte(&self, addr: u16) -> u8 {
match addr {
0xFF11 => self.sound_length_1,
0xFF12 => self.sound_control_1,
0xFF13 => self.sound_freq_low,
0xFF14 => self.sound_freq_high,
0xFF24 => self.sound_channel_volume_control,
0xFF25 => self.sound_output_terminal_selector,
0xFF26 => self.enabled,
_ => panic!("Sound: Read from {:04X} unsupported", addr),
}
}
}