mirror of
https://github.com/FranLMSP/rmg-001.git
synced 2024-11-23 10:12:11 +00:00
Modeling the Bus and writing first test for NOP instruction
This commit is contained in:
parent
2afa2a1ff8
commit
5d04b7c346
@ -1,7 +1,10 @@
|
||||
use rust_boy::rom::ROM;
|
||||
use rust_boy::console::Console;
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
let myrom = ROM::load_file("roms/cpu_instrs.gb".to_string())?;
|
||||
myrom.print_content();
|
||||
/* let myrom = ROM::load_file("roms/cpu_instrs.gb".to_string())?;
|
||||
myrom.print_content(); */
|
||||
let mut console = Console::new();
|
||||
console.cpu_run();
|
||||
Ok(())
|
||||
}
|
||||
|
60
src/bus.rs
60
src/bus.rs
@ -1,3 +1,5 @@
|
||||
use crate::rom::ROM;
|
||||
|
||||
pub enum MemoryMap {
|
||||
BankZero,
|
||||
BankSwitchable,
|
||||
@ -15,18 +17,50 @@ pub enum MemoryMap {
|
||||
|
||||
impl MemoryMap {
|
||||
pub fn get_map(address: u16) -> Self {
|
||||
if address <= 0x3FFF {return Self::BankZero;}
|
||||
if address >= 0x4000 && address <= 0x7FFF {return Self::BankSwitchable;}
|
||||
if address >= 0x8000 && address <= 0x9FFF {return Self::VideoRAM;}
|
||||
if address >= 0xA000 && address <= 0xBFFF {return Self::ExternalRAM;}
|
||||
if address >= 0xC000 && address <= 0xCFFF {return Self::WorkRAM1;}
|
||||
if address >= 0xD000 && address <= 0xDFFF {return Self::WorkRAM2;}
|
||||
if address >= 0xE000 && address <= 0xFDFF {return Self::EchoRAM;} // Mirror of C000~DDFF
|
||||
if address >= 0xFE00 && address <= 0xFE9F {return Self::SpriteAttributeTable;}
|
||||
if address >= 0xFEA0 && address <= 0xFEFF {return Self::NotUsable;}
|
||||
if address >= 0xFF00 && address <= 0xFF7F {return Self::IORegisters;}
|
||||
if address >= 0xFF80 && address <= 0xFFFE {return Self::HighRAM;}
|
||||
if address == 0xFFFF {return Self::InterruptEnableRegister;}
|
||||
Self::BankZero
|
||||
match address {
|
||||
0x0000..=0x3FFF => Self::BankZero,
|
||||
0x4000..=0x7FFF => Self::BankSwitchable,
|
||||
0x8000..=0x9FFF => Self::VideoRAM,
|
||||
0xA000..=0xBFFF => Self::ExternalRAM,
|
||||
0xC000..=0xCFFF => Self::WorkRAM1,
|
||||
0xD000..=0xDFFF => Self::WorkRAM2,
|
||||
0xE000..=0xFDFF => Self::EchoRAM, // Mirror of C000~DDFF
|
||||
0xFE00..=0xFE9F => Self::SpriteAttributeTable,
|
||||
0xFEA0..=0xFEFF => Self::NotUsable,
|
||||
0xFF00..=0xFF7F => Self::IORegisters,
|
||||
0xFF80..=0xFFFE => Self::HighRAM,
|
||||
0xFFFF => Self::InterruptEnableRegister,
|
||||
_ => Self::BankZero,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bus {
|
||||
game_rom: ROM,
|
||||
data: [u8; 0xFFFF],
|
||||
}
|
||||
|
||||
impl Bus {
|
||||
pub fn new() -> Self {
|
||||
let game_rom = match ROM::load_file("roms/cpu_instrs.gb".to_string()) {
|
||||
Ok(rom) => rom,
|
||||
_ => ROM::from_bytes(&[0; 0xFFFF])
|
||||
};
|
||||
game_rom.print_content(Some(0x102));
|
||||
Self {
|
||||
data: [0; 0xFFFF],
|
||||
game_rom,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&self, address: u16) -> u8 {
|
||||
match MemoryMap::get_map(address) {
|
||||
MemoryMap::BankZero => self.game_rom.read(address),
|
||||
_ => self.data[address as usize],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&mut self, address: u16, data: u8) {
|
||||
self.data[address as usize] = data;
|
||||
}
|
||||
}
|
||||
|
23
src/console.rs
Normal file
23
src/console.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use crate::cpu::CPU;
|
||||
use crate::ppu::PPU;
|
||||
use crate::bus::Bus;
|
||||
|
||||
pub struct Console {
|
||||
cpu: CPU,
|
||||
ppu: PPU,
|
||||
bus: Bus,
|
||||
}
|
||||
|
||||
impl Console {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
cpu: CPU::new(),
|
||||
ppu: PPU::new(),
|
||||
bus: Bus::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cpu_run(&mut self) {
|
||||
self.cpu.run(&mut self.bus);
|
||||
}
|
||||
}
|
32
src/cpu.rs
32
src/cpu.rs
@ -1,4 +1,5 @@
|
||||
use crate::utils::{BitIndex, get_bit, set_bit};
|
||||
use crate::bus::Bus;
|
||||
|
||||
pub enum Register {
|
||||
A(u8), // Accumulator
|
||||
@ -43,7 +44,7 @@ impl Registers {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
a: 0,
|
||||
f: 0b11110000, // The first 4 lower bits are always set to 0
|
||||
f: 0b00000000, // The first 4 lower bits are always set to 0
|
||||
b: 0,
|
||||
c: 0,
|
||||
d: 0,
|
||||
@ -111,6 +112,10 @@ impl Registers {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn increment_pc(&mut self) {
|
||||
self.pc += 1;
|
||||
}
|
||||
|
||||
fn get_af(&self) -> u16 {
|
||||
((self.a as u16) << 8) | (self.f as u16)
|
||||
}
|
||||
@ -249,6 +254,28 @@ pub struct CPU {
|
||||
}
|
||||
|
||||
impl CPU {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
registers: Registers::new(),
|
||||
}
|
||||
}
|
||||
|
||||
// Get the program counter
|
||||
pub fn get_register(&self, register: Register) -> u16 {
|
||||
self.registers.get(register)
|
||||
}
|
||||
|
||||
pub fn run(&mut self, bus: &mut Bus) {
|
||||
println!("Opcode: {:02X}", bus.read(self.registers.get(Register::PC(0))));
|
||||
}
|
||||
|
||||
pub fn exec(&mut self, opcode: CpuOpcode) {
|
||||
match opcode {
|
||||
CpuOpcode::NOP => self.registers.increment_pc(),
|
||||
_ => println!("Illegal instruction"),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn parse_opcode(opcode: u8) -> CpuOpcode {
|
||||
match opcode {
|
||||
0x06 => CpuOpcode::LD(OpcodeParameter::Register_U8(Register::B(0))),
|
||||
@ -572,5 +599,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_cpu_instructions() {
|
||||
let mut cpu = CPU::new();
|
||||
cpu.exec(CpuOpcode::NOP);
|
||||
assert_eq!(cpu.registers.get(Register::PC(0)), 0x101);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
pub mod utils;
|
||||
pub mod cpu;
|
||||
pub mod ppu;
|
||||
pub mod rom;
|
||||
pub mod bus;
|
||||
pub mod console;
|
||||
|
7
src/ppu.rs
Normal file
7
src/ppu.rs
Normal file
@ -0,0 +1,7 @@
|
||||
pub struct PPU;
|
||||
|
||||
impl PPU {
|
||||
pub fn new() -> Self {
|
||||
Self{}
|
||||
}
|
||||
}
|
20
src/rom.rs
20
src/rom.rs
@ -15,7 +15,23 @@ impl ROM {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn print_content(&self) {
|
||||
println!("{:02X?}", self.bytes);
|
||||
pub fn read(&self, address: u16) -> u8 {
|
||||
match self.bytes.get(address as usize) {
|
||||
Some(val) => *val,
|
||||
None => 0xFF,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Self {
|
||||
Self {
|
||||
bytes: bytes.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_content(&self, address: Option<u16>) {
|
||||
match address {
|
||||
Some(address) => println!("{:02X?}", self.read(address)),
|
||||
None => println!("{:02X?}", self.bytes),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user