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::rom::ROM;
|
||||||
|
use rust_boy::console::Console;
|
||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
fn main() -> std::io::Result<()> {
|
||||||
let myrom = ROM::load_file("roms/cpu_instrs.gb".to_string())?;
|
/* let myrom = ROM::load_file("roms/cpu_instrs.gb".to_string())?;
|
||||||
myrom.print_content();
|
myrom.print_content(); */
|
||||||
|
let mut console = Console::new();
|
||||||
|
console.cpu_run();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
60
src/bus.rs
60
src/bus.rs
@ -1,3 +1,5 @@
|
|||||||
|
use crate::rom::ROM;
|
||||||
|
|
||||||
pub enum MemoryMap {
|
pub enum MemoryMap {
|
||||||
BankZero,
|
BankZero,
|
||||||
BankSwitchable,
|
BankSwitchable,
|
||||||
@ -15,18 +17,50 @@ pub enum MemoryMap {
|
|||||||
|
|
||||||
impl MemoryMap {
|
impl MemoryMap {
|
||||||
pub fn get_map(address: u16) -> Self {
|
pub fn get_map(address: u16) -> Self {
|
||||||
if address <= 0x3FFF {return Self::BankZero;}
|
match address {
|
||||||
if address >= 0x4000 && address <= 0x7FFF {return Self::BankSwitchable;}
|
0x0000..=0x3FFF => Self::BankZero,
|
||||||
if address >= 0x8000 && address <= 0x9FFF {return Self::VideoRAM;}
|
0x4000..=0x7FFF => Self::BankSwitchable,
|
||||||
if address >= 0xA000 && address <= 0xBFFF {return Self::ExternalRAM;}
|
0x8000..=0x9FFF => Self::VideoRAM,
|
||||||
if address >= 0xC000 && address <= 0xCFFF {return Self::WorkRAM1;}
|
0xA000..=0xBFFF => Self::ExternalRAM,
|
||||||
if address >= 0xD000 && address <= 0xDFFF {return Self::WorkRAM2;}
|
0xC000..=0xCFFF => Self::WorkRAM1,
|
||||||
if address >= 0xE000 && address <= 0xFDFF {return Self::EchoRAM;} // Mirror of C000~DDFF
|
0xD000..=0xDFFF => Self::WorkRAM2,
|
||||||
if address >= 0xFE00 && address <= 0xFE9F {return Self::SpriteAttributeTable;}
|
0xE000..=0xFDFF => Self::EchoRAM, // Mirror of C000~DDFF
|
||||||
if address >= 0xFEA0 && address <= 0xFEFF {return Self::NotUsable;}
|
0xFE00..=0xFE9F => Self::SpriteAttributeTable,
|
||||||
if address >= 0xFF00 && address <= 0xFF7F {return Self::IORegisters;}
|
0xFEA0..=0xFEFF => Self::NotUsable,
|
||||||
if address >= 0xFF80 && address <= 0xFFFE {return Self::HighRAM;}
|
0xFF00..=0xFF7F => Self::IORegisters,
|
||||||
if address == 0xFFFF {return Self::InterruptEnableRegister;}
|
0xFF80..=0xFFFE => Self::HighRAM,
|
||||||
Self::BankZero
|
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::utils::{BitIndex, get_bit, set_bit};
|
||||||
|
use crate::bus::Bus;
|
||||||
|
|
||||||
pub enum Register {
|
pub enum Register {
|
||||||
A(u8), // Accumulator
|
A(u8), // Accumulator
|
||||||
@ -43,7 +44,7 @@ impl Registers {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
a: 0,
|
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,
|
b: 0,
|
||||||
c: 0,
|
c: 0,
|
||||||
d: 0,
|
d: 0,
|
||||||
@ -111,6 +112,10 @@ impl Registers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn increment_pc(&mut self) {
|
||||||
|
self.pc += 1;
|
||||||
|
}
|
||||||
|
|
||||||
fn get_af(&self) -> u16 {
|
fn get_af(&self) -> u16 {
|
||||||
((self.a as u16) << 8) | (self.f as u16)
|
((self.a as u16) << 8) | (self.f as u16)
|
||||||
}
|
}
|
||||||
@ -249,6 +254,28 @@ pub struct CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
pub fn parse_opcode(opcode: u8) -> CpuOpcode {
|
||||||
match opcode {
|
match opcode {
|
||||||
0x06 => CpuOpcode::LD(OpcodeParameter::Register_U8(Register::B(0))),
|
0x06 => CpuOpcode::LD(OpcodeParameter::Register_U8(Register::B(0))),
|
||||||
@ -572,5 +599,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cpu_instructions() {
|
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 utils;
|
||||||
pub mod cpu;
|
pub mod cpu;
|
||||||
|
pub mod ppu;
|
||||||
pub mod rom;
|
pub mod rom;
|
||||||
pub mod bus;
|
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) {
|
pub fn read(&self, address: u16) -> u8 {
|
||||||
println!("{:02X?}", self.bytes);
|
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