Compare commits

...

7 Commits

14 changed files with 267 additions and 273 deletions

1
.envrc Normal file
View File

@ -0,0 +1 @@
use_nix

39
shell.nix Normal file
View File

@ -0,0 +1,39 @@
let
moz_overlay = import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz);
nixpkgs = import <nixpkgs> { overlays = [ moz_overlay ]; };
rustNightlyChannelClippy = (nixpkgs.rustChannelOf { date = "2020-01-29"; channel = "nightly"; }).rust.override {
extensions = [
"rust-src"
"rls-preview"
"rustfmt-preview"
];
};
rustNightlyChannel = nixpkgs.latest.rustChannels.nightly.rust.override {
extensions = [
"rust-src"
"rls-preview"
"rustfmt-preview"
];
};
rustStableChannel = nixpkgs.latest.rustChannels.stable.rust.override {
extensions = [
"rust-src"
"rls-preview"
"clippy-preview"
"rustfmt-preview"
];
};
in
with nixpkgs;
stdenv.mkDerivation {
name = "moz_overlay_shell";
buildInputs = [
rustNightlyChannelClippy
rls
rustup
pkg-config
SDL2
pulseaudio
];
TELOXIDE_TOKEN = "916718418:AAFFtn9WmqipuKCvwiXZ2cEIA_IuNqlO94I";
}

View File

@ -1,4 +1,4 @@
use crate::mbc::{mbc, mbc1, mbc2, mbc3, mbc5};
use crate::mbc;
#[derive(Debug, PartialEq)]
enum MemoryBankControllerType {
@ -24,7 +24,7 @@ pub struct Cartridge {
}
impl Cartridge {
pub fn new(rom: Box<[u8]>, save_file: Option<String>) -> Cartridge {
pub fn new(rom: Box<[u8]>, savefile: Option<String>) -> Cartridge {
let mbc_type: MemoryBankControllerType = match rom[0x0147] {
0x00 | 0x08..=0x09 => MemoryBankControllerType::None,
0x01..=0x03 => MemoryBankControllerType::MBC1,
@ -57,23 +57,20 @@ impl Cartridge {
println!("Rom size: {} banks", rom_banks);
println!("Ram size: {:?}", ram_size);
let ram = Cartridge::load_savefile(&save_file, ram_size);
let ram = Cartridge::load_savefile(&savefile, ram_size);
let mbc: Box<dyn mbc::MBC> = match mbc_type {
MemoryBankControllerType::None => Box::new(mbc::NoMBC::new(rom, ram)),
MemoryBankControllerType::MBC1 => Box::new(mbc1::MBC1::new(rom, ram)),
MemoryBankControllerType::MBC2 => Box::new(mbc2::MBC2::new(rom, ram)),
MemoryBankControllerType::MBC3 => Box::new(mbc3::MBC3::new(rom, ram)),
MemoryBankControllerType::MBC5 => Box::new(mbc5::MBC5::new(rom, ram)),
MemoryBankControllerType::MBC1 => Box::new(mbc::MBC1::new(rom, ram)),
MemoryBankControllerType::MBC2 => Box::new(mbc::MBC2::new(rom, ram)),
MemoryBankControllerType::MBC3 => Box::new(mbc::MBC3::new(rom, ram)),
MemoryBankControllerType::MBC5 => Box::new(mbc::MBC5::new(rom, ram)),
};
Cartridge {
mbc: mbc,
savefile: save_file,
}
Cartridge { mbc, savefile }
}
fn load_savefile(save_file: &Option<String>, ram_size: RamSize) -> Box<[u8]> {
fn load_savefile(savefile: &Option<String>, ram_size: RamSize) -> Box<[u8]> {
let size = match ram_size {
RamSize::None => 0,
RamSize::Ram2KB => 2048,
@ -81,7 +78,7 @@ impl Cartridge {
RamSize::Ram32KB => 16 * 2048,
};
if let &Some(ref filename) = save_file {
if let Some(ref filename) = *savefile {
let data = super::read_file(&filename);
if let Ok(data) = data {
if data.len() != size {

View File

@ -1,5 +1,6 @@
use super::interconnect;
use crate::interconnect;
use std::convert::TryFrom;
use std::thread::sleep;
use std::time::{Duration, Instant};
@ -14,7 +15,7 @@ const REG_N_L: usize = 5;
const REG_N_HL: usize = 6;
const REG_N_A: usize = 7;
const REG_N_F: usize = 8;
const REG_NAMES: [&'static str; 9] = ["B", "C", "D", "E", "H", "L", "(HL)", "A", "F"];
const REG_NAMES: [&str; 9] = ["B", "C", "D", "E", "H", "L", "(HL)", "A", "F"];
const FLAG_Z: u8 = 1 << 7;
const FLAG_N: u8 = 1 << 6;
@ -44,23 +45,29 @@ pub struct CPU {
trigger_once: bool,
}
fn to_u16(args: Args) -> u16 {
match args {
Args::Double(a, b) => (a as u16) | ((b as u16) << 8),
_ => panic!("to_u16 only works with Args::Double"),
}
}
enum Args {
Single(u8),
Double(u8, u8),
}
impl Args {
fn single_val(&self) -> u8 {
match self {
&Args::Single(x) => x,
_ => panic!("single_val only works with Args::Single"),
impl TryFrom<Args> for u8 {
type Error = ();
fn try_from(val: Args) -> Result<u8, Self::Error> {
match val {
Args::Single(x) => Ok(x),
_ => Err(()),
}
}
}
impl TryFrom<Args> for u16 {
type Error = ();
fn try_from(val: Args) -> Result<u16, Self::Error> {
match val {
Args::Double(a, b) => Ok((a as u16) | ((b as u16) << 8)),
_ => Err(()),
}
}
}
@ -72,7 +79,7 @@ impl CPU {
regs: [0, 0, 0, 0, 0, 0, 0],
ip: 0,
sp: 0xFFFE,
interconnect: interconnect,
interconnect,
ime: false,
debug: false,
halted: false,
@ -81,12 +88,10 @@ impl CPU {
}
}
#[inline]
fn read_byte(&self, addr: u16) -> u8 {
self.interconnect.read_byte(addr)
}
#[inline]
fn load_args(&mut self, num_args: u8) -> Args {
match num_args {
1 => {
@ -105,7 +110,6 @@ impl CPU {
}
}
#[inline]
fn set_8bit_reg(&mut self, reg_id: usize, value: u8) {
// Make sure that we skip the (HL) part.
if reg_id == REG_N_A {
@ -120,7 +124,6 @@ impl CPU {
}
}
#[inline]
fn get_8bit_reg(&self, reg_id: usize) -> u8 {
// Make sure that we skip the (HL) part.
if reg_id == REG_N_A {
@ -135,7 +138,6 @@ impl CPU {
}
}
#[inline]
fn adc_r(&mut self, val: u8) {
let old: u8 = self.regs[REG_A];
let mut new: u8 = old;
@ -155,7 +157,6 @@ impl CPU {
self.set_clear_flag(FLAG_H, ((old & 0x0F) + (val & 0x0F) + c) > 0x0F);
}
#[inline]
fn add_r(&mut self, val: u8) {
let old: u8 = self.regs[REG_A];
let new: u8 = old.wrapping_add(val);
@ -168,7 +169,6 @@ impl CPU {
self.set_clear_flag(FLAG_H, carry & 0x10 == 0x10);
}
#[inline]
fn sbc_r(&mut self, val: u8) {
let old: u8 = self.regs[REG_A];
let mut new: u8 = old as u8;
@ -192,7 +192,6 @@ impl CPU {
);
}
#[inline]
fn sub_r(&mut self, val: u8) {
let old: u8 = self.regs[REG_A];
let new: u8 = old.wrapping_sub(val);
@ -205,7 +204,6 @@ impl CPU {
self.set_clear_flag(FLAG_H, carry & 0x10 == 0x10);
}
#[inline]
fn cp_r(&mut self, val: u8) {
let old: u8 = self.regs[REG_A];
let new: u8 = old.wrapping_sub(val);
@ -217,7 +215,6 @@ impl CPU {
self.set_clear_flag(FLAG_H, carry & 0x10 == 0x10);
}
#[inline]
fn run_prefix_instruction(&mut self) {
let instruction = self.read_byte(self.ip);
self.ip += 1;
@ -588,18 +585,15 @@ impl CPU {
}
}
#[inline]
fn get_pair_value(&self, a: usize, b: usize) -> u16 {
(self.get_8bit_reg(a) as u16) << 8 | self.get_8bit_reg(b) as u16
}
#[inline]
fn set_pair_value(&mut self, a: usize, b: usize, value: u16) {
self.set_8bit_reg(a, (value >> 8) as u8);
self.set_8bit_reg(b, value as u8);
}
#[inline]
fn call(&mut self, dst: u16) {
let ip = self.ip;
self.push(ip);
@ -607,9 +601,8 @@ impl CPU {
self.ip = dst;
}
#[inline]
fn call_condition(&mut self, cond_str: &'static str, cond: bool) -> u8 {
let dst = to_u16(self.load_args(2));
let dst = u16::try_from(self.load_args(2)).unwrap();
if self.debug {
println!("CALL {} {:04X}", cond_str, dst);
}
@ -621,7 +614,6 @@ impl CPU {
}
}
#[inline]
fn ret_condition(&mut self, cond_str: &'static str, cond: bool) -> u8 {
if self.debug {
println!("RET {}", cond_str);
@ -634,7 +626,6 @@ impl CPU {
}
}
#[inline]
fn jmp_r(&mut self, addr: u8) {
let off: i8 = addr as i8;
if off < 0 {
@ -644,9 +635,8 @@ impl CPU {
}
}
#[inline]
fn jmp_r_condition(&mut self, cond_str: &'static str, cond: bool) -> u8 {
let t = self.load_args(1).single_val();
let t = u8::try_from(self.load_args(1)).unwrap();
if self.debug {
println!("JR {} {:02X}", cond_str, t);
}
@ -658,14 +648,12 @@ impl CPU {
}
}
#[inline]
fn jmp_p(&mut self, addr: u16) {
self.ip = addr;
}
#[inline]
fn jmp_p_condition(&mut self, cond_str: &'static str, cond: bool) -> u8 {
let t = to_u16(self.load_args(2));
let t = u16::try_from(self.load_args(2)).unwrap();
if self.debug {
println!("JP {} {:04X}", cond_str, t);
}
@ -677,7 +665,6 @@ impl CPU {
}
}
#[inline]
fn rst(&mut self, val: u8) -> u8 {
// Make sure this is correct.
if self.debug {
@ -687,7 +674,6 @@ impl CPU {
16
}
#[inline]
fn pop_rr(&mut self, r1: usize, r2: usize) -> u8 {
if self.debug {
println!("POP {}{}", REG_NAMES[r1], REG_NAMES[r2]);
@ -697,7 +683,6 @@ impl CPU {
12
}
#[inline]
fn push_rr(&mut self, r1: usize, r2: usize) -> u8 {
if self.debug {
println!("PUSH {}{}", REG_NAMES[r1], REG_NAMES[r2]);
@ -707,7 +692,6 @@ impl CPU {
16
}
#[inline]
fn dec_rr(&mut self, r1: usize, r2: usize) -> u8 {
if self.debug {
println!("DEC {}{}", REG_NAMES[r1], REG_NAMES[r2]);
@ -718,7 +702,6 @@ impl CPU {
8
}
#[inline]
fn inc_rr(&mut self, r1: usize, r2: usize) -> u8 {
if self.debug {
println!("INC {}{}", REG_NAMES[r1], REG_NAMES[r2]);
@ -729,20 +712,17 @@ impl CPU {
8
}
#[inline]
fn push(&mut self, val: u16) {
self.interconnect.write_word(self.sp - 2, val);
self.sp -= 2;
}
#[inline]
fn pop(&mut self) -> u16 {
let v: u16 = self.interconnect.read_word(self.sp);
self.sp += 2;
v
}
#[inline]
fn ld_r_r(&mut self, reg_dst: usize, reg_src: usize) -> u8 {
if self.debug {
println!("LD {}, {}", REG_NAMES[reg_dst], REG_NAMES[reg_src])
@ -756,9 +736,8 @@ impl CPU {
}
}
#[inline]
fn ld_r_v(&mut self, r: usize) -> u8 {
let val: u8 = self.load_args(1).single_val();
let val = u8::try_from(self.load_args(1)).unwrap();
if self.debug {
println!("LD {}, {:02X}", REG_NAMES[r], val);
}
@ -770,9 +749,8 @@ impl CPU {
}
}
#[inline]
fn ld_rr_vv(&mut self, r1: usize, r2: usize) -> u8 {
let val: u16 = to_u16(self.load_args(2));
let val = u16::try_from(self.load_args(2)).unwrap();
if self.debug {
println!("LD {}{}, {:04X}", REG_NAMES[r1], REG_NAMES[r2], val);
}
@ -780,7 +758,6 @@ impl CPU {
12
}
#[inline]
fn reg_inc(&mut self, reg_id: usize) -> u8 {
if self.debug {
println!("INC {}", REG_NAMES[reg_id]);
@ -794,7 +771,6 @@ impl CPU {
4
}
#[inline]
fn add_rr_rr(&mut self, r1: usize, r2: usize, r3: usize, r4: usize) -> u8 {
if self.debug {
println!(
@ -817,7 +793,6 @@ impl CPU {
8
}
#[inline]
fn reg_dec(&mut self, reg_id: usize) -> u8 {
if self.debug {
println!("DEC {}", REG_NAMES[reg_id]);
@ -833,7 +808,6 @@ impl CPU {
4
}
#[inline]
fn ld_dref_rr_a(&mut self, r1: usize, r2: usize) -> u8 {
if self.debug {
println!("LD ({}{}), A", REG_NAMES[r1], REG_NAMES[r2]);
@ -844,17 +818,14 @@ impl CPU {
8
}
#[inline]
fn set_flag(&mut self, flag: u8) {
self.flags |= flag;
}
#[inline]
fn clear_flag(&mut self, flag: u8) {
self.flags &= !flag;
}
#[inline]
fn set_clear_flag(&mut self, flag: u8, dep: bool) {
if dep {
self.set_flag(flag);
@ -863,7 +834,6 @@ impl CPU {
}
}
#[inline]
fn int_(&mut self, val: u8) {
if self.debug {
println!("INT {:02X}", val);
@ -873,21 +843,18 @@ impl CPU {
self.call(val as u16);
}
#[inline]
fn ret(&mut self) {
let new_ip: u16 = self.pop();
//self.dump_stack();
self.ip = new_ip;
}
#[inline]
fn reti(&mut self) -> u8 {
self.ret();
self.ime = true;
16
}
#[inline]
fn handle_interrupt(&mut self, offset: u8, flag: u8) {
// Remove interrupt requested flag
let new_flag = self.interconnect.read_byte(0xFF0F) & !flag;
@ -1043,7 +1010,7 @@ impl CPU {
4
}
0x08 => {
let a: u16 = to_u16(self.load_args(2));
let a = u16::try_from(self.load_args(2)).unwrap();
if self.debug {
println!("LD ({:04X}), sp", a);
}
@ -1084,7 +1051,7 @@ impl CPU {
0x10 => {
println!(
"STOP 0 {:02X} not implemented.",
self.load_args(1).single_val()
u8::try_from(self.load_args(1)).unwrap()
);
4
}
@ -1112,7 +1079,7 @@ impl CPU {
4
}
0x18 => {
let dst = self.load_args(1).single_val();
let dst = u8::try_from(self.load_args(1)).unwrap();
self.jmp_r(dst);
if self.debug {
println!("JMPR {:02X}", dst);
@ -1241,7 +1208,7 @@ impl CPU {
}
0x31 => {
let args = self.load_args(2);
self.sp = to_u16(args);
self.sp = u16::try_from(args).unwrap();
if self.debug {
println!("LD SP, {:04x}", self.sp);
}
@ -1458,7 +1425,7 @@ impl CPU {
self.jmp_p_condition("NZ", c)
}
0xC3 => {
let dst = to_u16(self.load_args(2));
let dst = u16::try_from(self.load_args(2)).unwrap();
if self.debug {
println!("JMP {:04X}", dst);
}
@ -1471,7 +1438,7 @@ impl CPU {
}
0xC5 => self.push_rr(REG_N_B, REG_N_C),
0xC6 => {
let val = self.load_args(1).single_val();
let val = u8::try_from(self.load_args(1)).unwrap();
if self.debug {
println!("ADD A, {:02X}", val);
}
@ -1506,7 +1473,7 @@ impl CPU {
}
0xCD => self.call_condition("", true),
0xCE => {
let arg = self.load_args(1).single_val();
let arg = u8::try_from(self.load_args(1)).unwrap();
if self.debug {
println!("ADC A, {:02X}", arg);
}
@ -1531,7 +1498,7 @@ impl CPU {
}
0xD5 => self.push_rr(REG_N_D, REG_N_E),
0xD6 => {
let val = self.load_args(1).single_val();
let val = u8::try_from(self.load_args(1)).unwrap();
if self.debug {
println!("SUB {:02X}", val);
}
@ -1561,7 +1528,7 @@ impl CPU {
}
0xDD => panic!("NON-EXISTING OPCODE"),
0xDE => {
let arg = self.load_args(1).single_val();
let arg = u8::try_from(self.load_args(1)).unwrap();
if self.debug {
println!("SBC {:02X}", arg);
}
@ -1571,7 +1538,7 @@ impl CPU {
0xDF => self.rst(0x18),
0xE0 => {
let arg = self.load_args(1).single_val();
let arg = u8::try_from(self.load_args(1)).unwrap();
if self.debug {
println!("LDH {:02X}, A", arg);
}
@ -1591,7 +1558,7 @@ impl CPU {
0xE3 | 0xE4 => panic!("NON-EXISTING OPCODE"),
0xE5 => self.push_rr(REG_N_H, REG_N_L),
0xE6 => {
let val = self.load_args(1).single_val();
let val = u8::try_from(self.load_args(1)).unwrap();
if self.debug {
println!("AND {:02X}", val);
}
@ -1606,7 +1573,7 @@ impl CPU {
}
0xE7 => self.rst(0x20),
0xE8 => {
let arg = self.load_args(1).single_val() as i8;
let arg = u8::try_from(self.load_args(1)).unwrap() as i8;
if self.debug {
println!("ADD SP, {:02X}", arg);
}
@ -1632,7 +1599,7 @@ impl CPU {
4
}
0xEA => {
let addr = to_u16(self.load_args(2));
let addr = u16::try_from(self.load_args(2)).unwrap();
if self.debug {
println!("LD ({:04X}), A", addr);
}
@ -1641,7 +1608,7 @@ impl CPU {
}
0xEB..=0xED => panic!("NON-EXISTING OPCODE"),
0xEE => {
let arg = self.load_args(1).single_val();
let arg = u8::try_from(self.load_args(1)).unwrap();
if self.debug {
println!("XOR {:02X}", arg);
}
@ -1656,7 +1623,7 @@ impl CPU {
0xEF => self.rst(0x28),
0xF0 => {
let arg = self.load_args(1).single_val();
let arg = u8::try_from(self.load_args(1)).unwrap();
if self.debug {
println!("LDH A, {:02X}", arg);
}
@ -1682,7 +1649,7 @@ impl CPU {
0xF4 => panic!("NON-EXISTING OPCODE"),
0xF5 => self.push_rr(REG_N_A, REG_N_F),
0xF6 => {
let val = self.load_args(1).single_val();
let val = u8::try_from(self.load_args(1)).unwrap();
if self.debug {
println!("OR {:02X}", val);
}
@ -1696,7 +1663,7 @@ impl CPU {
}
0xF7 => self.rst(0x30),
0xF8 => {
let arg = self.load_args(1).single_val() as i8;
let arg = u8::try_from(self.load_args(1)).unwrap() as i8;
if self.debug {
println!("LD HL, SP+{:02X}", arg);
}
@ -1726,7 +1693,7 @@ impl CPU {
8
}
0xFA => {
let addr = to_u16(self.load_args(2));
let addr = u16::try_from(self.load_args(2)).unwrap();
if self.debug {
println!("LD A, ({:04X})", addr);
}
@ -1743,7 +1710,7 @@ impl CPU {
0xFC | 0xFD => panic!("NON-EXISTING OPCODE"),
0xFE => {
let arg = self.load_args(1).single_val();
let arg = u8::try_from(self.load_args(1)).unwrap();
if self.debug {
println!("CP {:02X}", arg);
}

View File

@ -193,7 +193,7 @@ pub struct Display {
status: u8,
background_palette: u8,
// Only 0 and 1 for GB
object_palette: [u8; 256], //4 * 2 * 8],
object_palette: [u8; 2],
scrollx: u8,
scrolly: u8,
windowx: u8,
@ -248,7 +248,7 @@ impl Display {
control: 0,
status: 0,
background_palette: 0,
object_palette: [0u8; 256], // 64],
object_palette: [0u8; 2],
scrollx: 0,
scrolly: 0,
windowx: 0,
@ -262,13 +262,13 @@ impl Display {
vram1: vec![0; VRAM_SIZE].into_boxed_slice(),
vram_bank: 0,
oam: vec![0; OAM_SIZE].into_boxed_slice(),
renderer: renderer,
renderer,
event_pump: event_pump,
event_pump,
vblank_interrupt: false,
stat_interrupt: false,
pixels: pixels,
pixels,
frameskip: 0,
frame_no: 0,
@ -281,14 +281,12 @@ impl Display {
}
}
#[inline]
fn set_pixel(&mut self, x: u8, y: u8, color: sdl2::pixels::Color, origin: PixelOrigin) {
let p = &mut self.pixels[(x as usize) + (y as usize) * GB_PIXELS_X];
p.color = color;
p.origin = origin;
}
#[inline]
fn get_pixel_origin(&self, x: u8, y: u8) -> PixelOrigin {
self.pixels[(x as usize) + (y as usize) * GB_PIXELS_X].origin
}
@ -324,7 +322,6 @@ impl Display {
.expect("Rendering failed");
}
#[inline]
pub fn vblank_interrupt(&mut self) -> bool {
// Returns whether or not a vblank interrupt should be done
// Yes, this is polling, and yes, this sucks.
@ -336,7 +333,6 @@ impl Display {
}
}
#[inline]
pub fn stat_interrupt(&mut self) -> bool {
if self.stat_interrupt {
self.stat_interrupt = false;
@ -346,7 +342,6 @@ impl Display {
}
}
#[inline]
pub fn write_byte(&mut self, addr: u16, val: u8) {
match addr {
0x8000..=0x9FFF => {
@ -415,7 +410,6 @@ impl Display {
}
}
#[inline]
pub fn read_byte(&self, addr: u16) -> u8 {
match addr {
0x8000..=0x9FFF => {
@ -467,7 +461,6 @@ impl Display {
BgMapAttributes(self.vram1[vram_offset])
}
#[inline]
pub fn tick(&mut self, ticks: u16) {
self.status &= 0xFC;
if self.control & CTRL_LCD_DISPLAY_ENABLE == 0 {
@ -685,7 +678,6 @@ impl Display {
}
}
#[inline]
fn get_bg_window_tile_addr(&self, tile_id: u8) -> usize {
if (self.control & CTRL_BG_WINDOW_TILE_DATA_SELECT) == CTRL_BG_WINDOW_TILE_DATA_SELECT {
let base_addr = 0x0000;
@ -708,7 +700,6 @@ impl Display {
.unwrap();
}
#[inline]
fn renderscan(&mut self) {
// Points to the background map offset to use.
let background_map: usize;

View File

@ -165,87 +165,83 @@ impl Interconnect {
// Make sure the window is responsive:
if self.cycles > 500 {
loop {
if let Some(event) = self.display.event_pump.poll_event() {
match event {
Event::Quit { .. }
| Event::KeyDown {
keycode: Some(Keycode::Escape),
..
} => {
self.cartridge.save();
self.display.dump_vram();
return TickResult::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::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),
_ => {}
while let Some(event) = self.display.event_pump.poll_event() {
match event {
Event::Quit { .. }
| Event::KeyDown {
keycode: Some(Keycode::Escape),
..
} => {
self.cartridge.save();
self.display.dump_vram();
return TickResult::Shutdown;
}
} else {
break;
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),
_ => {}
}
}
self.cycles = 0;
@ -255,12 +251,10 @@ impl Interconnect {
TickResult::Continue
}
#[inline]
pub fn is_boot_rom(&self) -> bool {
self.disable_bootrom == 0
}
#[inline]
pub fn read_byte(&self, addr: u16) -> u8 {
// TODO: Make this more beautiful.
// TODO: if some flag set, use bios, otherwise only use rom
@ -319,7 +313,6 @@ impl Interconnect {
}
}
#[inline]
pub fn write_byte(&mut self, addr: u16, val: u8) {
// TODO: Make this more beautful
/*
@ -444,13 +437,11 @@ impl Interconnect {
}
}
#[inline]
pub fn write_word(&mut self, addr: u16, val: u16) {
self.write_byte(addr, val as u8);
self.write_byte(addr + 1, (val >> 8) as u8);
}
#[inline]
pub fn read_word(&self, addr: u16) -> u16 {
self.read_byte(addr) as u16 | (self.read_byte(addr + 1) as u16) << 8
// (self.read_byte(addr) as u16) << 8 | (self.read_byte(addr + 1) as u16)

View File

@ -47,8 +47,8 @@ pub fn read_file<P: AsRef<Path>>(rom_path: P) -> Result<Box<[u8]>, io::Error> {
Ok(buf.into_boxed_slice())
}
pub fn write_file<P: AsRef<Path>>(path: P, data: &Box<[u8]>) -> Result<(), io::Error> {
pub fn write_file<P: AsRef<Path>>(path: P, data: &[u8]) -> Result<(), io::Error> {
let mut file = fs::File::create(path)?;
file.write(&data)?;
file.write_all(&data)?;
Ok(())
}

View File

@ -1,53 +0,0 @@
pub trait MBC {
fn read_byte(&self, addr: u16) -> u8;
fn write_byte(&mut self, addr: u16, val: u8);
fn dump_ram(&self, file: &String);
}
pub struct NoMBC {
rom: Box<[u8]>,
ram: Box<[u8]>,
}
impl NoMBC {
pub fn new(rom: Box<[u8]>, ram: Box<[u8]>) -> NoMBC {
NoMBC { rom: rom, ram: ram }
}
}
impl MBC for NoMBC {
fn dump_ram(&self, file: &String) {
super::super::write_file(&file, &self.ram).expect("Saving failed");
}
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
);
}
fn read_byte(&self, addr: u16) -> u8 {
match addr {
0x0000..=0x7FFF => self.rom[addr as usize],
0xA000..=0xBFFF => {
// TODO: Check for ram
let addr = (addr as usize) - 0xA000;
if addr >= self.ram.len() {
println!(
"Tried to access {:04X}, however the memory is not present.",
addr + 0xA000
);
0
} else {
self.ram[addr]
}
}
_ => {
panic!("Cartride: Unable to read from {:04X}", addr);
}
}
}
}

View File

@ -1,4 +1,4 @@
use super::mbc::MBC;
use super::MBC;
enum BankMode {
RomBankMode,
@ -17,8 +17,8 @@ pub struct MBC1 {
impl MBC1 {
pub fn new(rom: Box<[u8]>, ram: Box<[u8]>) -> MBC1 {
MBC1 {
rom: rom,
ram: ram,
rom,
ram,
rom_bank_no: 1,
bank_mode: BankMode::RomBankMode,
bank_no_high: 0,
@ -43,7 +43,7 @@ impl MBC1 {
}
impl MBC for MBC1 {
fn dump_ram(&self, file: &String) {
fn dump_ram(&self, file: &str) {
super::super::write_file(&file, &self.ram).expect("Saving failed");
}

View File

@ -1,4 +1,4 @@
use super::mbc::MBC;
use super::MBC;
pub struct MBC2 {
rom: Box<[u8]>,
@ -10,8 +10,8 @@ pub struct MBC2 {
impl MBC2 {
pub fn new(rom: Box<[u8]>, ram: Box<[u8]>) -> MBC2 {
MBC2 {
rom: rom,
ram: ram,
rom,
ram,
rom_bank_no: 1,
ram_enable: false,
}
@ -23,7 +23,7 @@ impl MBC2 {
}
impl MBC for MBC2 {
fn dump_ram(&self, file: &String) {
fn dump_ram(&self, file: &str) {
super::super::write_file(&file, &self.ram).expect("Saving failed");
}
@ -61,7 +61,7 @@ impl MBC for MBC2 {
}
}
0x2000..=0x3FFF => {
if addr & 0x0100 == 1 {
if addr & 0x0100 == 0 {
self.rom_bank_no = val & 0x0F;
println!("MBC2: Selecting bank {:02X}", self.rom_bank_no);
} else {

View File

@ -1,4 +1,4 @@
use super::mbc::MBC;
use super::MBC;
pub struct MBC3 {
rom: Box<[u8]>,
@ -11,8 +11,8 @@ pub struct MBC3 {
impl MBC3 {
pub fn new(rom: Box<[u8]>, ram: Box<[u8]>) -> MBC3 {
MBC3 {
rom: rom,
ram: ram,
rom,
ram,
rom_bank_no: 1,
ram_bank_no: 0,
ram_rtc_enabled: false,
@ -28,7 +28,7 @@ impl MBC3 {
}
impl MBC for MBC3 {
fn dump_ram(&self, file: &String) {
fn dump_ram(&self, file: &str) {
super::super::write_file(&file, &self.ram).expect("Saving failed");
}

View File

@ -1,4 +1,4 @@
use super::mbc::MBC;
use super::MBC;
pub struct MBC5 {
rom: Box<[u8]>,
@ -11,8 +11,8 @@ pub struct MBC5 {
impl MBC5 {
pub fn new(rom: Box<[u8]>, ram: Box<[u8]>) -> Self {
MBC5 {
rom: rom,
ram: ram,
rom,
ram,
rom_bank_no: 1,
ram_bank_no: 0,
ram_rtc_enabled: false,
@ -28,7 +28,7 @@ impl MBC5 {
}
impl MBC for MBC5 {
fn dump_ram(&self, file: &String) {
fn dump_ram(&self, file: &str) {
use crate::write_file;
write_file(&file, &self.ram).expect("Saving failed");
}

View File

@ -1,5 +1,63 @@
pub mod mbc;
pub mod mbc1;
pub mod mbc2;
pub mod mbc3;
pub mod mbc5;
mod mbc1;
mod mbc2;
mod mbc3;
mod mbc5;
pub use mbc1::MBC1;
pub use mbc2::MBC2;
pub use mbc3::MBC3;
pub use mbc5::MBC5;
pub trait MBC {
fn read_byte(&self, addr: u16) -> u8;
fn write_byte(&mut self, addr: u16, val: u8);
fn dump_ram(&self, file: &str);
}
pub struct NoMBC {
rom: Box<[u8]>,
ram: Box<[u8]>,
}
impl NoMBC {
pub fn new(rom: Box<[u8]>, ram: Box<[u8]>) -> NoMBC {
NoMBC { rom: rom, ram: ram }
}
}
impl MBC for NoMBC {
fn dump_ram(&self, file: &str) {
super::write_file(&file, &self.ram).expect("Saving failed");
}
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
);
}
fn read_byte(&self, addr: u16) -> u8 {
match addr {
0x0000..=0x7FFF => self.rom[addr as usize],
0xA000..=0xBFFF => {
// TODO: Check for ram
let addr = (addr as usize) - 0xA000;
if addr >= self.ram.len() {
println!(
"Tried to access {:04X}, however the memory is not present.",
addr + 0xA000
);
0
} else {
self.ram[addr]
}
}
_ => {
panic!("Cartride: Unable to read from {:04X}", addr);
}
}
}
}

View File

@ -5,7 +5,10 @@ mod square;
mod wave;
use self::pulse_simple::Playback;
use std::sync::{Arc, Mutex};
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex,
};
use std::thread;
const OUTPUT_SAMPLE_RATE: usize = 48100;
@ -332,12 +335,12 @@ pub struct Sound {
pub struct SoundManager {
pub sound_object: Arc<Mutex<Sound>>,
handle: Option<std::thread::JoinHandle<()>>,
do_exit: Arc<Mutex<bool>>,
do_exit: Arc<AtomicBool>,
}
impl Drop for SoundManager {
fn drop(&mut self) {
*self.do_exit.lock().unwrap() = true;
self.do_exit.store(true, Ordering::Relaxed);
self.handle.take().and_then(|h| h.join().ok());
}
}
@ -347,7 +350,7 @@ impl SoundManager {
let mut res = SoundManager {
sound_object: Arc::new(Mutex::new(Sound::new())),
handle: None,
do_exit: Arc::new(Mutex::new(false)),
do_exit: Arc::new(AtomicBool::new(false)),
};
res.launch_thread();
@ -371,7 +374,7 @@ impl SoundManager {
// Counter, used for calling the 512 Hz timer
let mut counter = 0;
while !*do_exit.lock().unwrap() {
while !do_exit.load(Ordering::Relaxed) {
for _ in 0..100 {
let (s1, s2) = {
let mut c_obj = obj.lock().unwrap();