Update SDL + rust fmt

This commit is contained in:
Kevin Hamacher 2020-02-14 11:21:48 +01:00
parent cc9cef785e
commit 50471f1ec6
12 changed files with 432 additions and 346 deletions

View File

@ -4,5 +4,5 @@ version = "0.1.0"
authors = ["Kevin Hamacher <kevin.hamacher@rub.de>"]
[dependencies]
sdl2 = "0.19.0"
sdl2 = "*"
libc = "*"

View File

@ -41,7 +41,7 @@ impl Cartridge {
0x52 => 72,
0x53 => 80,
0x54 => 96,
_ => panic!("Unknown rom size: {:?}", rom[0x148])
_ => panic!("Unknown rom size: {:?}", rom[0x148]),
};
let ram_size: RamSize = match rom[0x0149] {
@ -49,7 +49,7 @@ impl Cartridge {
0x01 => RamSize::Ram2KB,
0x02 => RamSize::Ram8KB,
0x03 => RamSize::Ram32KB,
_ => panic!("Unknown ram size: {:?}", rom[0x149])
_ => panic!("Unknown ram size: {:?}", rom[0x149]),
};
println!("Rom size: {} banks", rom_banks);

View File

@ -1,7 +1,7 @@
use super::interconnect;
use std::time::{Duration, Instant};
use std::thread::sleep;
use std::time::{Duration, Instant};
const REG_A: usize = 6;
@ -21,7 +21,6 @@ const FLAG_N: u8 = 1 << 6;
const FLAG_H: u8 = 1 << 5;
const FLAG_C: u8 = 1 << 4;
pub struct CPU {
// Registers: B, C, D, E, H, L, A
regs: [u8; 7],
@ -154,7 +153,10 @@ impl CPU {
self.set_flag(FLAG_N);
self.set_clear_flag(FLAG_Z, new == 0);
self.set_clear_flag(FLAG_C, new > old || (new == old && c == 1));
self.set_clear_flag(FLAG_H, ((old & 0x0F).wrapping_sub((val & 0x0F)).wrapping_sub(c)) > 0x0F);
self.set_clear_flag(
FLAG_H,
((old & 0x0F).wrapping_sub((val & 0x0F)).wrapping_sub(c)) > 0x0F,
);
}
#[inline]
@ -209,7 +211,7 @@ impl CPU {
self.set_clear_flag(FLAG_Z, nval == 0);
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
},
}
0x08...0x0F => {
let reg_id = (instruction - 0x08) as usize;
let val = self.get_8bit_reg(reg_id);
@ -227,7 +229,7 @@ impl CPU {
self.set_clear_flag(FLAG_Z, val == 0);
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
},
}
0x10...0x17 => {
let reg_id = (instruction - 0x10) as usize;
let val = self.get_8bit_reg(reg_id);
@ -247,8 +249,9 @@ impl CPU {
self.set_clear_flag(FLAG_Z, nval == 0);
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
},
0x18 ... 0x1F => { // RR
}
0x18...0x1F => {
// RR
let reg_id = (instruction - 0x18) as usize;
let val = self.get_8bit_reg(reg_id);
if self.debug {
@ -267,7 +270,7 @@ impl CPU {
self.set_clear_flag(FLAG_Z, v == 0);
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
},
}
0x20...0x27 => {
let reg_id = (instruction - 0x20) as usize;
if self.debug {
@ -278,7 +281,7 @@ impl CPU {
self.set_clear_flag(FLAG_C, v & 0x80 == 0x80);
self.set_clear_flag(FLAG_Z, v & 0x7F == 0);
self.set_8bit_reg(reg_id, v << 1);
},
}
0x28...0x2F => {
let reg_id = (instruction - 0x28) as usize;
if self.debug {
@ -290,7 +293,7 @@ impl CPU {
self.flags = 0;
self.set_clear_flag(FLAG_Z, nv == 0);
self.set_clear_flag(FLAG_C, v & 1 == 1);
},
}
0x30...0x37 => {
let reg_id = (instruction - 0x30) as usize;
if self.debug {
@ -300,7 +303,7 @@ impl CPU {
self.set_8bit_reg(reg_id, (v << 4) | (v >> 4));
self.flags = 0;
self.set_clear_flag(FLAG_Z, v == 0);
},
}
0x38...0x3F => {
let reg_id = (instruction - 0x38) as usize;
if self.debug {
@ -312,7 +315,7 @@ impl CPU {
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
self.set_clear_flag(FLAG_Z, (v & 0xFE) == 0);
},
}
// Bits
0x40...0x47 => {
@ -766,7 +769,10 @@ impl CPU {
#[inline]
fn add_rr_rr(&mut self, r1: usize, r2: usize, r3: usize, r4: usize) -> u8 {
if self.debug {
println!("ADD {}{}, {}{}", REG_NAMES[r1], REG_NAMES[r2], REG_NAMES[r3], REG_NAMES[r4]);
println!(
"ADD {}{}, {}{}",
REG_NAMES[r1], REG_NAMES[r2], REG_NAMES[r3], REG_NAMES[r4]
);
}
let val1 = self.get_pair_value(r1, r2);
@ -875,7 +881,8 @@ impl CPU {
let gb_dur = cycles * 238;
let our_dur = start.elapsed().subsec_nanos() as i32;
let delta = gb_dur - our_dur;
if delta > (20 * 238) { // We're at least 20 cycles faster.
if delta > (20 * 238) {
// We're at least 20 cycles faster.
sleep(Duration::new(0, delta as u32));
} else if delta < 0 {
print!("-");
@ -937,7 +944,10 @@ impl CPU {
// We need to double-check the flags
instruction = self.read_byte(self.ip);
if self.debug {
print!("{:#06x}: [SP: {:#04X}] i={:02X}. ", &self.ip, &self.sp, &instruction);
print!(
"{:#06x}: [SP: {:#04X}] i={:02X}. ",
&self.ip, &self.sp, &instruction
);
for i in 0..6 {
print!("{}: {:02X} ", REG_NAMES[i], self.get_8bit_reg(i));
}
@ -959,7 +969,7 @@ impl CPU {
println!("NOP");
}
4
},
}
0x01 => self.ld_rr_vv(REG_N_B, REG_N_C),
0x02 => self.ld_dref_rr_a(REG_N_B, REG_N_C),
0x03 => self.inc_rr(REG_N_B, REG_N_C),
@ -996,9 +1006,11 @@ impl CPU {
if self.debug {
println!("LD A, (BC)");
}
self.regs[REG_A] = self.interconnect.read_byte(self.get_pair_value(REG_N_B, REG_N_C));
self.regs[REG_A] = self
.interconnect
.read_byte(self.get_pair_value(REG_N_B, REG_N_C));
8
},
}
0x0B => self.dec_rr(REG_N_B, REG_N_C),
0x0C => self.reg_inc(REG_N_C),
0x0D => self.reg_dec(REG_N_C),
@ -1023,7 +1035,7 @@ impl CPU {
0x10 => {
println!("STOP 0 {:02X} not implemented.", self.load_args(1)[0]);
4
},
}
0x11 => self.ld_rr_vv(REG_N_D, REG_N_E),
0x12 => self.ld_dref_rr_a(REG_N_D, REG_N_E),
0x13 => self.inc_rr(REG_N_D, REG_N_E),
@ -1046,20 +1058,22 @@ impl CPU {
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
4
},
}
0x18 => {
let dst = self.load_args(1)[0];
self.jmp_r(dst);
12
},
}
0x19 => self.add_rr_rr(REG_N_H, REG_N_L, REG_N_D, REG_N_E),
0x1A => {
if self.debug {
println!("LD A, (DE)");
}
self.regs[REG_A] = self.interconnect.read_byte(self.get_pair_value(REG_N_D, REG_N_E));
self.regs[REG_A] = self
.interconnect
.read_byte(self.get_pair_value(REG_N_D, REG_N_E));
8
},
}
0x1B => self.dec_rr(REG_N_D, REG_N_E),
0x1C => self.reg_inc(REG_N_E),
0x1D => self.reg_dec(REG_N_E),
@ -1080,8 +1094,7 @@ impl CPU {
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
4
},
}
0x20 => {
let c = self.flags & FLAG_Z == 0;
@ -1096,7 +1109,7 @@ impl CPU {
self.interconnect.write_byte(addr, self.regs[REG_A]);
self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_add(1));
8
},
}
0x23 => self.inc_rr(REG_N_H, REG_N_L),
0x24 => self.reg_inc(REG_N_H),
0x25 => self.reg_dec(REG_N_H),
@ -1138,11 +1151,11 @@ impl CPU {
self.set_clear_flag(FLAG_Z, a == 0);
4
},
}
0x28 => {
let c = self.flags & FLAG_Z == FLAG_Z;
self.jmp_r_condition("Z".to_owned(), c)
},
}
0x29 => self.add_rr_rr(REG_N_H, REG_N_L, REG_N_H, REG_N_L),
0x2A => {
if self.debug {
@ -1152,7 +1165,7 @@ impl CPU {
self.regs[REG_A] = self.interconnect.read_byte(addr);
self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_add(1));
8
},
}
0x2B => self.dec_rr(REG_N_H, REG_N_L),
0x2C => self.reg_inc(REG_N_L),
0x2D => self.reg_dec(REG_N_L),
@ -1165,13 +1178,12 @@ impl CPU {
self.set_flag(FLAG_N);
self.set_flag(FLAG_H);
4
},
}
0x30 => {
let c = self.flags & FLAG_C == 0;
self.jmp_r_condition("NC".to_owned(), c)
},
}
0x31 => {
let args = self.load_args(2);
self.sp = to_u16(args);
@ -1179,7 +1191,7 @@ impl CPU {
println!("LD SP, {:04x}", self.sp);
}
12
},
}
0x32 => {
if self.debug {
println!("LD (HL-), A");
@ -1188,7 +1200,7 @@ impl CPU {
self.interconnect.write_byte(addr, self.regs[REG_A]);
self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_sub(1));
8
},
}
0x33 => {
if self.debug {
println!("INC SP");
@ -1208,11 +1220,11 @@ impl CPU {
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
4
},
}
0x38 => {
let c = self.flags & FLAG_C == FLAG_C;
self.jmp_r_condition("C".to_owned(), c)
},
}
0x39 => {
if self.debug {
println!("ADD HL, SP");
@ -1226,7 +1238,7 @@ impl CPU {
self.set_clear_flag(FLAG_C, old > v && sp > 0);
self.set_clear_flag(FLAG_H, ((old & 0xFFF) + (sp & 0xFFF)) > 0xFFF);
8
},
}
0x3A => {
if self.debug {
println!("LD A, (HL-)");
@ -1274,7 +1286,7 @@ impl CPU {
}
self.halted = true;
4
},
}
// ADD
0x80...0x87 => {
@ -1351,7 +1363,7 @@ impl CPU {
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
4
},
}
// OR
0xB0...0xB7 => {
@ -1379,17 +1391,17 @@ impl CPU {
let v = self.get_8bit_reg(reg_id);
self.cp_r(v);
4
},
}
0xC0 => {
let c = self.flags & FLAG_Z == 0;
self.ret_condition("NZ".to_owned(), c)
},
}
0xC1 => self.pop_rr(REG_N_B, REG_N_C),
0xC2 => {
let c = self.flags & FLAG_Z == 0;
self.jmp_p_condition("NZ".to_owned(), c)
},
}
0xC3 => {
let dst = to_u16(self.load_args(2));
if self.debug {
@ -1397,7 +1409,7 @@ impl CPU {
}
self.jmp_p(dst);
16
},
}
0xC4 => {
let c = self.flags & FLAG_Z == 0;
self.call_condition("NZ".to_owned(), c)
@ -1412,19 +1424,19 @@ impl CPU {
self.add_r(val);
8
},
}
0xC7 => self.rst(0x00),
0xC8 => {
let c = self.flags & FLAG_Z == FLAG_Z;
self.ret_condition("Z".to_owned(), c)
},
}
0xC9 => {
if self.debug {
println!("RET");
}
self.ret();
16
},
}
0xCA => {
let c = self.flags & FLAG_Z == FLAG_Z;
self.jmp_p_condition("Z".to_owned(), c)
@ -1432,11 +1444,11 @@ impl CPU {
0xCB => {
self.run_prefix_instruction();
12 // TODO: Verify that this is the case for all prefix instructions.
},
}
0xCC => {
let c = self.flags & FLAG_Z == FLAG_Z;
self.call_condition("Z".to_owned(), c)
},
}
0xCD => self.call_condition("".to_owned(), true),
0xCE => {
let arg = self.load_args(1)[0];
@ -1445,14 +1457,13 @@ impl CPU {
}
self.adc_r(arg);
8
},
}
0xCF => self.rst(0x08),
0xD0 => {
let c = self.flags & FLAG_C == 0;
self.ret_condition("NC".to_owned(), c)
},
}
0xD1 => self.pop_rr(REG_N_D, REG_N_E),
0xD2 => {
let c = self.flags & FLAG_C == 0;
@ -1472,12 +1483,12 @@ impl CPU {
self.sub_r(val);
8
},
}
0xD7 => self.rst(0x10),
0xD8 => {
let c = self.flags & FLAG_C == FLAG_C;
self.ret_condition("C".to_owned(), c)
},
}
0xD9 => {
if self.debug {
println!("RETI");
@ -1487,7 +1498,7 @@ impl CPU {
0xDA => {
let c = self.flags & FLAG_C == FLAG_C;
self.jmp_p_condition("C".to_owned(), c)
},
}
0xDB => panic!("NON-EXISTING OPCODE"),
0xDC => {
let c = self.flags & FLAG_C == FLAG_C;
@ -1501,7 +1512,7 @@ impl CPU {
}
self.sbc_r(arg);
8
},
}
0xDF => self.rst(0x18),
0xE0 => {
@ -1509,9 +1520,10 @@ impl CPU {
if self.debug {
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]);
12
},
}
0xE1 => self.pop_rr(REG_N_H, REG_N_L),
0xE2 => {
if self.debug {
@ -1520,7 +1532,7 @@ impl CPU {
let addr: u16 = 0xFF00 + self.get_8bit_reg(REG_N_C) as u16;
self.interconnect.write_byte(addr, self.regs[REG_A]);
8
},
}
0xE3 | 0xE4 => panic!("NON-EXISTING OPCODE"),
0xE5 => self.push_rr(REG_N_H, REG_N_L),
0xE6 => {
@ -1536,7 +1548,7 @@ impl CPU {
self.clear_flag(FLAG_C);
8
},
}
0xE7 => self.rst(0x20),
0xE8 => {
let arg = self.load_args(1)[0] as i8;
@ -1563,7 +1575,7 @@ impl CPU {
}
self.ip = self.get_pair_value(REG_N_H, REG_N_L);
4
},
}
0xEA => {
let addr = to_u16(self.load_args(2));
if self.debug {
@ -1571,7 +1583,7 @@ impl CPU {
}
self.interconnect.write_byte(addr, self.regs[REG_A]);
16
},
}
0xEB...0xED => panic!("NON-EXISTING OPCODE"),
0xEE => {
let arg = self.load_args(1)[0];
@ -1585,7 +1597,7 @@ impl CPU {
self.clear_flag(FLAG_C);
self.clear_flag(FLAG_N);
8
},
}
0xEF => self.rst(0x28),
0xF0 => {
@ -1595,7 +1607,7 @@ impl CPU {
}
self.regs[REG_A] = self.interconnect.read_byte(0xFF00 + args[0] as u16);
12
},
}
0xF1 => self.pop_rr(REG_N_A, REG_N_F),
0xF2 => {
if self.debug {
@ -1604,14 +1616,14 @@ impl CPU {
let addr = 0xFF00 + self.get_8bit_reg(REG_N_C) as u16;
self.regs[REG_A] = self.interconnect.read_byte(addr);
8
},
}
0xF3 => {
if self.debug {
println!("DI");
}
self.ime = false;
4
},
}
0xF4 => panic!("NON-EXISTING OPCODE"),
0xF5 => self.push_rr(REG_N_A, REG_N_F),
0xF6 => {
@ -1626,7 +1638,7 @@ impl CPU {
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
8
},
}
0xF7 => self.rst(0x30),
0xF8 => {
let arg = self.load_args(1)[0] as i8;
@ -1650,14 +1662,14 @@ impl CPU {
self.set_clear_flag(FLAG_H, (sp ^ arg as u16 ^ v) & 0x10 == 0x10);
}
12
},
}
0xF9 => {
if self.debug {
println!("LD SP, HL");
}
self.sp = self.get_pair_value(REG_N_H, REG_N_L);
8
},
}
0xFA => {
let addr = to_u16(self.load_args(2));
if self.debug {
@ -1665,7 +1677,7 @@ impl CPU {
}
self.regs[REG_A] = self.interconnect.read_byte(addr);
16
},
}
0xFB => {
// Enable interrupts - TODO
if self.debug {
@ -1673,7 +1685,7 @@ impl CPU {
}
self.ime = true; // interrupt master enable
4
},
}
0xFC | 0xFD => panic!("NON-EXISTING OPCODE"),
0xFE => {
@ -1684,9 +1696,9 @@ impl CPU {
self.cp_r(args[0]);
8
},
}
0xFF => self.rst(0x38),
_ => panic!("Unknown instruction: {:02x}", instruction)
_ => panic!("Unknown instruction: {:02x}", instruction),
};
}
self.interconnect.tick(cycles);

View File

@ -1,5 +1,5 @@
extern crate sdl2;
extern crate libc;
extern crate sdl2;
// Internal ram size
const VRAM_SIZE: usize = 0x2000;
@ -65,7 +65,7 @@ enum PixelOrigin {
Empty,
Background,
Window,
Sprite
Sprite,
}
#[derive(Copy, Clone)]
@ -149,8 +149,7 @@ pub struct Display {
current_ticks: u16,
current_mode: DisplayMode,
// TODO
renderer: sdl2::render::Renderer<'static>,
renderer: sdl2::render::Canvas<sdl2::video::Window>,
pub event_pump: sdl2::EventPump,
@ -167,8 +166,12 @@ impl Display {
pub fn new() -> Display {
let sdl_ctx = sdl2::init().unwrap();
let video_ctx = sdl_ctx.video().unwrap();
let wnd = video_ctx.window("RustBoy", WND_RES_X as u32, WND_RES_Y as u32).position_centered().build().expect("Failed to create window :<");
let renderer = wnd.renderer().build().expect("Could not build renderer");
let wnd = video_ctx
.window("RustBoy", WND_RES_X as u32, WND_RES_Y as u32)
.position_centered()
.build()
.expect("Failed to create window :<");
let renderer = wnd.into_canvas().build().expect("Could not build renderer");
let event_pump = sdl_ctx.event_pump().expect("Getting event pump failed");
let pixels = [Pixel::default(); (GB_PIXELS_X as usize) * (GB_PIXELS_Y as usize)];
@ -218,29 +221,30 @@ impl Display {
for x in 0..GB_PIXELS_X {
let f = &mut self.pixels[(x as usize) + (y as usize) * GB_PIXELS_X];
self.renderer.set_draw_color(f.color);
self.renderer.fill_rect(
sdl2::rect::Rect::new(
self.renderer
.fill_rect(sdl2::rect::Rect::new(
x as i32 * SCALE as i32,
y as i32 * SCALE as i32,
SCALE as u32,
SCALE as u32,
)
).expect("Rendering failed");
))
.expect("Rendering failed");
// Clear origin after rendering
f.origin = PixelOrigin::Empty;
}
}
self.renderer.set_draw_color(sdl2::pixels::Color::RGB(255, 0, 255));
self.renderer.draw_rect(
sdl2::rect::Rect::new(
self.renderer
.set_draw_color(sdl2::pixels::Color::RGB(255, 0, 255));
self.renderer
.draw_rect(sdl2::rect::Rect::new(
0,
0,
(GB_PIXELS_X * SCALE) as u32,
(GB_PIXELS_Y * SCALE) as u32,
)
).expect("Rendering failed");
))
.expect("Rendering failed");
}
#[inline]
@ -329,14 +333,16 @@ impl Display {
self.current_ticks += ticks;
match self.current_mode {
DisplayMode::ReadOAMMemory => { // Mode 2, Reading OAM memory, RAM may be accessed.
DisplayMode::ReadOAMMemory => {
// Mode 2, Reading OAM memory, RAM may be accessed.
if self.current_ticks > TICKS_END_SCANLINE {
self.current_ticks = 0;
self.current_mode = DisplayMode::ReadFullMemory;
}
self.status |= 2;
},
DisplayMode::ReadFullMemory => { // Mode 3, reading OAM, VMEM and palette data.
}
DisplayMode::ReadFullMemory => {
// Mode 3, reading OAM, VMEM and palette data.
// Nothing may be accessed.
if self.current_ticks > TICKS_END_READMODE {
self.current_ticks = 0;
@ -349,8 +355,9 @@ impl Display {
}
}
self.status |= 3;
},
DisplayMode::HBlank => { // Mode 0, H-Blank, Memory (RAM, OAM) may be accessed.
}
DisplayMode::HBlank => {
// Mode 0, H-Blank, Memory (RAM, OAM) may be accessed.
if self.current_ticks > TICKS_END_HBLANK {
self.current_ticks = 0;
self.curline += 1;
@ -369,8 +376,9 @@ impl Display {
}
self.status &= 0xFC;
self.status |= 0;
},
DisplayMode::VBlank => { // Mode 1, V-Blank (or display disabled), Memory (RAM, OAM)
}
DisplayMode::VBlank => {
// Mode 1, V-Blank (or display disabled), Memory (RAM, OAM)
// may be accessed
if self.current_ticks > TICKS_END_VBLANK {
self.current_ticks = 0;
@ -383,7 +391,8 @@ impl Display {
if self.frameskip < self.frame_no {
self.render_screen();
self.renderer.present();
self.renderer.set_draw_color(sdl2::pixels::Color::RGB(255, 255, 255));
self.renderer
.set_draw_color(sdl2::pixels::Color::RGB(255, 255, 255));
self.renderer.clear();
self.frame_no = 0;
} else {
@ -425,7 +434,6 @@ impl Display {
continue;
}
// Calculate correct coords
let x: u8 = sprite.x.wrapping_sub(8);
let y: u8 = sprite.y.wrapping_sub(16);
@ -438,7 +446,7 @@ impl Display {
// Flip sprite, TODO: Validate
let y_o: u8 = match sprite.is_y_flipped() {
true => y ^ 7,
false => y
false => y,
};
let tile_offset_y: usize = render_y as usize - y_o as usize;
let tile_base_addr: usize = sprite.tile as usize * 16; // Should this be twice as wide in wide mode?
@ -456,7 +464,7 @@ impl Display {
}
let limit = match wide_mode {
true => 16,
false => 8
false => 8,
};
for x_o in 0..limit {
let b1: bool;
@ -513,7 +521,12 @@ impl Display {
let entry = MONOCHROME_PALETTE[lookup[c as usize] as usize];
// Draw stuff. We're currently only in monochrome mode
self.set_pixel(x.wrapping_add(x_o), render_y, sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]), PixelOrigin::Sprite);
self.set_pixel(
x.wrapping_add(x_o),
render_y,
sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]),
PixelOrigin::Sprite,
);
}
}
}
@ -580,7 +593,6 @@ impl Display {
});
queue.reverse();
// Render background
if (self.control & CTRL_BG_DISPLAY) == CTRL_BG_DISPLAY {
// Render pixels (20 tiles)
@ -595,7 +607,8 @@ impl Display {
let tile_index_y: u8 = render_abs_y >> 3;
let tile_offset_y: u8 = render_abs_y & 7;
let vram_offset: usize = background_map + ((tile_index_y as usize) * 32) + tile_index_x as usize;
let vram_offset: usize =
background_map + ((tile_index_y as usize) * 32) + tile_index_x as usize;
// Obtain tile ID in this area
let tile_id = self.vram[vram_offset];
@ -624,7 +637,12 @@ impl Display {
0 => PixelOrigin::Empty, // Hack so that objects will be in front of it.
_ => PixelOrigin::Background,
};
self.set_pixel(render_x, render_y, sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]), origin);
self.set_pixel(
render_x,
render_y,
sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]),
origin,
);
}
}
@ -643,7 +661,8 @@ impl Display {
let tile_index_y: u8 = ry >> 3;
let tile_offset_y: u8 = ry & 7;
let vram_offset: usize = window_map + (tile_index_y as usize) * 32 + tile_index_x as usize;
let vram_offset: usize =
window_map + (tile_index_y as usize) * 32 + tile_index_x as usize;
// Obtain tile ID in this area
let tile_id = self.vram[vram_offset];
@ -672,7 +691,12 @@ impl Display {
0 => PixelOrigin::Empty, // Hack so that objects will be in front of it.
_ => PixelOrigin::Window,
};
self.set_pixel(render_x, render_y, sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]), origin);
self.set_pixel(
render_x,
render_y,
sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]),
origin,
);
}
}
}

View File

@ -21,11 +21,11 @@ const KEY_SELECT: u8 = 1 << 2;
const KEY_B: u8 = 1 << 1;
const KEY_A: u8 = 1 << 0;
use super::cartridge;
use super::display;
use super::serial;
use super::sound;
use super::timer;
use super::serial;
use super::cartridge;
extern crate sdl2;
@ -34,7 +34,14 @@ use self::sdl2::keyboard::Keycode;
#[derive(Debug)]
enum Key {
UP, LEFT, DOWN, RIGHT, START, SELECT, A, B
UP,
LEFT,
DOWN,
RIGHT,
START,
SELECT,
A,
B,
}
pub struct Interconnect {
@ -155,27 +162,79 @@ impl Interconnect {
loop {
if let Some(event) = self.display.event_pump.poll_event() {
match event {
Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
Event::Quit { .. }
| Event::KeyDown {
keycode: Some(Keycode::Escape),
..
} => {
self.cartridge.save();
panic!("TODO: Proper shutdown");
},
Event::KeyDown { keycode: Some(Keycode::Left), .. } => self.press_key(Key::LEFT),
Event::KeyDown { keycode: Some(Keycode::Down), .. } => self.press_key(Key::DOWN),
Event::KeyDown { keycode: Some(Keycode::Up), .. } => self.press_key(Key::UP),
Event::KeyDown { keycode: Some(Keycode::Right), .. } => self.press_key(Key::RIGHT),
Event::KeyDown { keycode: Some(Keycode::A), .. } => self.press_key(Key::START),
Event::KeyDown { keycode: Some(Keycode::S), .. } => self.press_key(Key::SELECT),
Event::KeyDown { keycode: Some(Keycode::Z), .. } => self.press_key(Key::A),
Event::KeyDown { keycode: Some(Keycode::X), .. } => self.press_key(Key::B),
}
Event::KeyDown {
keycode: Some(Keycode::Left),
..
} => self.press_key(Key::LEFT),
Event::KeyDown {
keycode: Some(Keycode::Down),
..
} => self.press_key(Key::DOWN),
Event::KeyDown {
keycode: Some(Keycode::Up),
..
} => self.press_key(Key::UP),
Event::KeyDown {
keycode: Some(Keycode::Right),
..
} => self.press_key(Key::RIGHT),
Event::KeyDown {
keycode: Some(Keycode::A),
..
} => self.press_key(Key::START),
Event::KeyDown {
keycode: Some(Keycode::S),
..
} => self.press_key(Key::SELECT),
Event::KeyDown {
keycode: Some(Keycode::Z),
..
} => self.press_key(Key::A),
Event::KeyDown {
keycode: Some(Keycode::X),
..
} => self.press_key(Key::B),
Event::KeyUp { keycode: Some(Keycode::Left), .. } => self.release_key(Key::LEFT),
Event::KeyUp { keycode: Some(Keycode::Down), .. } => self.release_key(Key::DOWN),
Event::KeyUp { keycode: Some(Keycode::Up), .. } => self.release_key(Key::UP),
Event::KeyUp { keycode: Some(Keycode::Right), .. } => self.release_key(Key::RIGHT),
Event::KeyUp { keycode: Some(Keycode::A), .. } => self.release_key(Key::START),
Event::KeyUp { keycode: Some(Keycode::S), .. } => self.release_key(Key::SELECT),
Event::KeyUp { keycode: Some(Keycode::Z), .. } => self.release_key(Key::A),
Event::KeyUp { keycode: Some(Keycode::X), .. } => self.release_key(Key::B),
Event::KeyUp {
keycode: Some(Keycode::Left),
..
} => self.release_key(Key::LEFT),
Event::KeyUp {
keycode: Some(Keycode::Down),
..
} => self.release_key(Key::DOWN),
Event::KeyUp {
keycode: Some(Keycode::Up),
..
} => self.release_key(Key::UP),
Event::KeyUp {
keycode: Some(Keycode::Right),
..
} => self.release_key(Key::RIGHT),
Event::KeyUp {
keycode: Some(Keycode::A),
..
} => self.release_key(Key::START),
Event::KeyUp {
keycode: Some(Keycode::S),
..
} => self.release_key(Key::SELECT),
Event::KeyUp {
keycode: Some(Keycode::Z),
..
} => self.release_key(Key::A),
Event::KeyUp {
keycode: Some(Keycode::X),
..
} => self.release_key(Key::B),
_ => {}
}
} else {
@ -205,19 +264,15 @@ impl Interconnect {
} else {
self.cartridge.read_byte(addr)
}
},
}
0x100...0x7FFF => self.cartridge.read_byte(addr),
0x8000...0x9FFF => self.display.read_byte(addr),
0xA000...0xBFFF => self.cartridge.read_byte(addr),
0xC000 ... 0xCFFF => {
self.ram[(addr - 0xC000) as usize]
},
0xC000...0xCFFF => self.ram[(addr - 0xC000) as usize],
0xD000...0xDFFF => {
self.ram[(addr - 0xD000) as usize + self.wram_bank as usize * 0x1000]
},
0xE000 ... 0xEFFF => {
self.ram[(addr - 0xE000) as usize]
}
0xE000...0xEFFF => self.ram[(addr - 0xE000) as usize],
0xFF00 => {
if self.joy_switch & KEY_REGULAR == 0 {
self.joy_regular_keys
@ -233,34 +288,20 @@ impl Interconnect {
0xFF0F => {
// println!("Reading IF: {:02X}", self.interrupt_request_flags);
self.interrupt_request_flags
},
0xFF10 ... 0xFF26 => {
self.sound.read_byte(addr)
},
}
0xFF10...0xFF26 => self.sound.read_byte(addr),
0xFF30...0xFF3F => self.sound.read_byte(addr),
0xFF40 ... 0xFF4B => {
self.display.read_byte(addr)
},
0xFF50 => {
self.disable_bootrom
},
0xFF40...0xFF4B => self.display.read_byte(addr),
0xFF50 => self.disable_bootrom,
0xFF51 => self.vram_dma_source_high,
0xFF52 => self.vram_dma_source_low,
0xFF53 => self.vram_dma_destination_high,
0xFF54 => self.vram_dma_destination_low,
0xFF55 => {
self.vram_dma_length
}
0xFF56 => {
self.infrared_com_port
},
0xFF55 => self.vram_dma_length,
0xFF56 => self.infrared_com_port,
0xFF70 => self.wram_bank,
0xFF80 ... 0xFFFE => {
self.hiram[(addr - 0xFF80) as usize]
},
0xFFFF => {
self.interrupt
}
0xFF80...0xFFFE => self.hiram[(addr - 0xFF80) as usize],
0xFFFF => self.interrupt,
_ => {
println!("Read from {:04X} not supported.", addr);
0
@ -290,7 +331,7 @@ impl Interconnect {
0xA000...0xBFFF => self.cartridge.write_byte(addr, val),
0xC000...0xCFFF => {
self.ram[(addr - 0xC000) as usize] = val;
},
}
0xD000...0xDFFF => {
self.ram[(addr - 0xD000) as usize + self.wram_bank as usize * 0x1000] = val;
}
@ -306,12 +347,12 @@ impl Interconnect {
}
0xFF10...0xFF26 => {
self.sound.write_byte(addr, val);
},
}
0xFF30...0xFF3F => self.sound.write_byte(addr, val),
// Exclude DMA transfer, we will do this below
0xFF40...0xFF45 | 0xFF47...0xFF4B => {
self.display.write_byte(addr, val);
},
}
0xFF46 => {
// println!("OAM DMA transfer");
for x in 0x00..0x9F {
@ -322,17 +363,22 @@ impl Interconnect {
0xFF50 => {
println!("Disabling boot rom.");
self.disable_bootrom = val;
},
}
0xFF51 => self.vram_dma_source_high = val,
0xFF52 => self.vram_dma_source_low = val & 0xF0,
0xFF53 => self.vram_dma_destination_high = val & 0x1F,
0xFF54 => self.vram_dma_destination_low = val & 0xF0,
0xFF55 => {
let src: u16 = ((self.vram_dma_source_high as u16) << 8) | self.vram_dma_source_low as u16;
let mut dst: u16 = ((self.vram_dma_destination_high as u16) << 8) | self.vram_dma_destination_low as u16;
let src: u16 =
((self.vram_dma_source_high as u16) << 8) | self.vram_dma_source_low as u16;
let mut dst: u16 = ((self.vram_dma_destination_high as u16) << 8)
| self.vram_dma_destination_low as u16;
dst += 0x8000;
println!("VRAM DMA transfer from {:04X} to {:04X}; {:02X}", src, dst, val);
println!(
"VRAM DMA transfer from {:04X} to {:04X}; {:02X}",
src, dst, val
);
let len: u16 = ((val & 0x7F) + 1) as u16 * 0x10 - 1;
for i in 0..len {
let v = self.read_byte(src.wrapping_add(i));
@ -344,7 +390,7 @@ impl Interconnect {
}
0xFF56 => {
self.infrared_com_port = val;
},
}
0xFF70 => {
if self.wram_bank != val {
println!("Switching wram bank to {:02X}", val);
@ -360,11 +406,11 @@ impl Interconnect {
}
0xFF80...0xFFFE => {
self.hiram[(addr - 0xFF80) as usize] = val;
},
}
0xFFFF => {
println!("Setting interrupt mask value {:02X}", val);
self.interrupt = val;
},
}
_ => {
println!("Write {:02X} to {:04X} not supported.", val, addr);
}

View File

@ -1,22 +1,21 @@
// let's try to write our own, awesome emulator.
// gameboy (color?)
use std::path::Path;
use std::env;
use std::fs;
use std::io;
use std::io::Read;
use std::io::Write;
use std::fs;
use std::env;
use std::path::Path;
mod cartridge;
mod cpu;
mod display;
mod interconnect;
mod mbc;
mod serial;
mod sound;
mod timer;
mod serial;
mod mbc;
fn main() {
let args: Vec<String> = env::args().collect();

View File

@ -12,10 +12,7 @@ pub struct NoMBC {
impl NoMBC {
pub fn new(rom: Box<[u8]>, ram: Box<[u8]>) -> NoMBC {
NoMBC {
rom: rom,
ram: ram,
}
NoMBC { rom: rom, ram: ram }
}
}
@ -25,7 +22,10 @@ impl MBC for NoMBC {
}
fn write_byte(&mut self, addr: u16, val: u8) {
println!("Writing not supported for cartridges without MBC. (Tried to set {:04X} to {:02X})", addr, val);
println!(
"Writing not supported for cartridges without MBC. (Tried to set {:04X} to {:02X})",
addr, val
);
}
fn read_byte(&self, addr: u16) -> u8 {
@ -36,7 +36,10 @@ impl MBC for NoMBC {
let addr = (addr as usize) - 0xA000;
if addr >= self.ram.len() {
println!("Tried to access {:04X}, however the memory is not present.", addr + 0xA000);
println!(
"Tried to access {:04X}, however the memory is not present.",
addr + 0xA000
);
0
} else {
self.ram[addr]

View File

@ -30,14 +30,14 @@ impl MBC1 {
fn active_rom_bank(&self) -> u8 {
match self.bank_mode {
BankMode::RomBankMode => self.rom_bank_no | (self.bank_no_high << 5),
BankMode::RamBankMode => self.rom_bank_no
BankMode::RamBankMode => self.rom_bank_no,
}
}
fn active_ram_bank(&self) -> u8 {
match self.bank_mode {
BankMode::RomBankMode => 0,
BankMode::RamBankMode => self.bank_no_high
BankMode::RamBankMode => self.bank_no_high,
}
}
}
@ -55,7 +55,7 @@ impl MBC for MBC1 {
let abs_addr: usize = addr as usize + self.active_rom_bank() as usize * 0x4000;
let val: u8 = self.rom[abs_addr];
val
},
}
0xA000...0xBFFF => {
let addr = addr - 0xA000;
println!("Access [{:02X}] {:04X}", self.active_ram_bank(), addr);
@ -69,12 +69,10 @@ impl MBC for MBC1 {
fn write_byte(&mut self, addr: u16, val: u8) {
match addr {
0x0000 ... 0x1FFF => {
match val {
0x0000...0x1FFF => match val {
0x0A => self.ram_enable = true,
0x00 => self.ram_enable = false,
_ => println!("Unknown MBC1 value {:02X} for {:04X}", val, addr)
}
_ => println!("Unknown MBC1 value {:02X} for {:04X}", val, addr),
},
0x2000...0x3FFF => {
if val != 0 {
@ -87,7 +85,7 @@ impl MBC for MBC1 {
0x4000...0x5FFF => {
// Upper ROM bank / RAM bank select
self.bank_no_high = val & 3;
},
}
0x6000...0x7FFF => {
// Select upper ROM bytes or RAM bytes
match val {
@ -95,7 +93,7 @@ impl MBC for MBC1 {
1 => self.bank_mode = BankMode::RamBankMode,
_ => panic!("Invalid bank mode {:02X}", val),
}
},
}
_ => panic!("MBC1: Writing {:02X} to {:04X} not supported", val, addr),
}
}

View File

@ -35,7 +35,7 @@ impl MBC for MBC2 {
let abs_addr: usize = addr as usize + self.active_rom_bank() as usize * 0x4000;
let val: u8 = self.rom[abs_addr];
val
},
}
0xA000...0xA1FF => {
let addr = addr - 0xA000;
self.ram[addr as usize] & 0x0F
@ -54,12 +54,12 @@ impl MBC for MBC2 {
match val {
0x0A => self.ram_enable = true,
0x00 => self.ram_enable = false,
_ => println!("Unknown MBC2 value {:02X} for {:04X}", val, addr)
_ => println!("Unknown MBC2 value {:02X} for {:04X}", val, addr),
}
} else {
println!("MBC2: Write {:02X} to {:04X} has no effect", val, addr);
}
},
}
0x2000...0x3FFF => {
if addr & 0x0100 == 1 {
self.rom_bank_no = val & 0x0F;

View File

@ -25,7 +25,6 @@ impl MBC3 {
fn active_ram_bank(&self) -> u8 {
self.ram_bank_no
}
}
impl MBC for MBC3 {
@ -41,7 +40,7 @@ impl MBC for MBC3 {
let abs_addr: usize = addr as usize + self.active_rom_bank() as usize * 0x4000;
let val: u8 = self.rom[abs_addr];
val
},
}
0xA000...0xBFFF => {
let addr = addr - 0xA000;
match self.active_ram_bank() {
@ -53,7 +52,10 @@ impl MBC for MBC3 {
println!("MBC3: Ignoring RTC read");
0
}
_ => panic!("MBC3: Accessing unknown RAM bank {:02X}", self.active_ram_bank())
_ => panic!(
"MBC3: Accessing unknown RAM bank {:02X}",
self.active_ram_bank()
),
}
}
_ => {
@ -64,12 +66,10 @@ impl MBC for MBC3 {
fn write_byte(&mut self, addr: u16, val: u8) {
match addr {
0x0000 ... 0x1FFF => {
match val {
0x0000...0x1FFF => match val {
0x0A => self.ram_rtc_enabled = true,
0x00 => self.ram_rtc_enabled = false,
_ => println!("MBC3: Unknown MBC value {:02X} for {:04X}", val, addr)
}
_ => println!("MBC3: Unknown MBC value {:02X} for {:04X}", val, addr),
},
0x2000...0x3FFF => self.rom_bank_no = val & 0x7F,
0x4000...0x5FFF => {
@ -77,17 +77,17 @@ impl MBC for MBC3 {
match val {
0x00...0x03 => self.ram_bank_no = val,
0x08...0x0C => self.ram_bank_no = val,
_ => panic!("MBC3: Unknown RAM bank {:02X}", val)
_ => panic!("MBC3: Unknown RAM bank {:02X}", val),
}
}
},
0x6000...0x7FFF => {
// Latch clock data
match val {
0x00 => println!("latch = 0"),
0x01 => println!("latch = 1"), // TODO: This should copy the current clock to the register
_ => panic!("MBC3: Unknown latch value {:02X}", val)
_ => panic!("MBC3: Unknown latch value {:02X}", val),
}
}
},
0xA000...0xBFFF => {
let addr = addr - 0xA000;
match self.active_ram_bank() {
@ -99,7 +99,10 @@ impl MBC for MBC3 {
// TODO
println!("MBC3: Ignoring RTC write ({:02X})", val);
}
_ => panic!("MBC3: Writing unknown RAM bank {:02X}", self.active_ram_bank())
_ => panic!(
"MBC3: Writing unknown RAM bank {:02X}",
self.active_ram_bank()
),
}
}
_ => panic!("MBC3: Writing {:02X} to {:04X} not supported", val, addr),

View File

@ -36,7 +36,7 @@ impl Sound {
0xFF26 => self.enabled = val,
_ => {
// println!("Sound: Write {:02X} to {:04X} unsupported", val, addr);
},
}
}
}

View File

@ -27,7 +27,8 @@ impl Timer {
self.div_tick_counter -= TIMER_SPEED[3];
}
if (self.tac & TIMER_ENABLE) == TIMER_ENABLE { // Is timer enabled?
if (self.tac & TIMER_ENABLE) == TIMER_ENABLE {
// Is timer enabled?
self.tick_counter += 1;
let req_ticks = TIMER_SPEED[(self.tac & 3) as usize];
@ -72,7 +73,7 @@ impl Timer {
_ => {
println!("Timer: Read from {:04X} unsupported", addr);
0
},
}
}
}