cpu: fix renaming mistake "screen" -> "mem"
This commit is contained in:
parent
ea357be477
commit
57c2ac681c
51
src/cpu.rs
51
src/cpu.rs
@ -43,7 +43,7 @@ pub struct CPU {
|
|||||||
/// chip-8. Includes [Quirks], target IPF, etc.
|
/// chip-8. Includes [Quirks], target IPF, etc.
|
||||||
pub flags: Flags,
|
pub flags: Flags,
|
||||||
// memory map info
|
// memory map info
|
||||||
screen: Bus,
|
mem: Bus,
|
||||||
font: Adr,
|
font: Adr,
|
||||||
// memory
|
// memory
|
||||||
stack: Vec<Adr>,
|
stack: Vec<Adr>,
|
||||||
@ -108,11 +108,26 @@ impl CPU {
|
|||||||
|
|
||||||
/// Loads bytes into the CPU's program space
|
/// Loads bytes into the CPU's program space
|
||||||
pub fn load_program_bytes(&mut self, rom: &[u8]) -> Result<&mut Self> {
|
pub fn load_program_bytes(&mut self, rom: &[u8]) -> Result<&mut Self> {
|
||||||
self.screen.clear_region(Program);
|
self.mem.clear_region(Program);
|
||||||
self.screen.load_region(Program, rom)?;
|
self.mem.load_region(Program, rom)?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pokes a value into memory
|
||||||
|
pub fn poke(&mut self, addr: Adr, data: u8) {
|
||||||
|
self.mem.write(addr, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Peeks a value from memory
|
||||||
|
pub fn peek(&mut self, addr: Adr) -> u8 {
|
||||||
|
self.mem.read(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Grabs a reference to the [CPU]'s memory
|
||||||
|
pub fn introspect(&mut self) -> &Bus {
|
||||||
|
&self.mem
|
||||||
|
}
|
||||||
|
|
||||||
/// Presses a key, and reports whether the key's state changed.
|
/// Presses a key, and reports whether the key's state changed.
|
||||||
/// If key does not exist, returns [Error::InvalidKey].
|
/// If key does not exist, returns [Error::InvalidKey].
|
||||||
///
|
///
|
||||||
@ -453,12 +468,12 @@ impl CPU {
|
|||||||
/// # cpu.flags.debug = true; // enable live disassembly
|
/// # cpu.flags.debug = true; // enable live disassembly
|
||||||
/// # cpu.flags.monotonic = true; // enable monotonic/test timing
|
/// # cpu.flags.monotonic = true; // enable monotonic/test timing
|
||||||
/// let mut bus = bus!{
|
/// let mut bus = bus!{
|
||||||
/// Program [0x0200..0x0f00] = &[
|
|
||||||
/// 0xff, 0xff, // invalid!
|
|
||||||
/// 0x22, 0x02, // jump 0x202 (pc)
|
|
||||||
/// ],
|
|
||||||
/// Screen [0x0f00..0x1000],
|
/// Screen [0x0f00..0x1000],
|
||||||
/// };
|
/// };
|
||||||
|
/// cpu.load_program_bytes(&[
|
||||||
|
/// 0xff, 0xff, // invalid!
|
||||||
|
/// 0x22, 0x02, // jump 0x202
|
||||||
|
/// ]);
|
||||||
/// dbg!(cpu.tick(&mut bus))
|
/// dbg!(cpu.tick(&mut bus))
|
||||||
/// .expect_err("Should return Error::InvalidInstruction { 0xffff }");
|
/// .expect_err("Should return Error::InvalidInstruction { 0xffff }");
|
||||||
/// ```
|
/// ```
|
||||||
@ -472,23 +487,13 @@ impl CPU {
|
|||||||
return Ok(self);
|
return Ok(self);
|
||||||
}
|
}
|
||||||
self.cycle += 1;
|
self.cycle += 1;
|
||||||
|
// Fetch slice of memory starting at pc, for var-width opcode 0xf000_iiii
|
||||||
let opchunk = self
|
let opchunk = self
|
||||||
.screen
|
.mem
|
||||||
.get(self.pc as usize..)
|
.get(self.pc as usize..)
|
||||||
.ok_or(Error::InvalidAddressRange {
|
.ok_or(Error::InvalidAddressRange {
|
||||||
range: (self.pc as usize..).into(),
|
range: (self.pc as usize..).into(),
|
||||||
})?;
|
})?;
|
||||||
// fetch opcode
|
|
||||||
let opcode: &[u8; 2] =
|
|
||||||
if let Some(slice) = self.screen.get(self.pc as usize..self.pc as usize + 2) {
|
|
||||||
slice
|
|
||||||
.try_into()
|
|
||||||
.expect("`slice` should be exactly 4 bytes.")
|
|
||||||
} else {
|
|
||||||
return Err(Error::InvalidAddressRange {
|
|
||||||
range: (self.pc as usize..self.pc as usize + 4).into(),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Print opcode disassembly:
|
// Print opcode disassembly:
|
||||||
if self.flags.debug {
|
if self.flags.debug {
|
||||||
@ -496,7 +501,7 @@ impl CPU {
|
|||||||
"{:3} {:03x}: {:<36}",
|
"{:3} {:03x}: {:<36}",
|
||||||
self.cycle.bright_black(),
|
self.cycle.bright_black(),
|
||||||
self.pc,
|
self.pc,
|
||||||
self.disassembler.once(u16::from_be_bytes(*opcode))
|
self.disassembler.once(self.mem.read(self.pc))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,7 +511,7 @@ impl CPU {
|
|||||||
self.execute(screen, insn);
|
self.execute(screen, insn);
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::UnimplementedInstruction {
|
return Err(Error::UnimplementedInstruction {
|
||||||
word: u16::from_be_bytes(*opcode),
|
word: self.mem.read(self.pc),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -515,7 +520,7 @@ impl CPU {
|
|||||||
self.flags.pause = true;
|
self.flags.pause = true;
|
||||||
return Err(Error::BreakpointHit {
|
return Err(Error::BreakpointHit {
|
||||||
addr: self.pc,
|
addr: self.pc,
|
||||||
next: self.screen.read(self.pc),
|
next: self.mem.read(self.pc),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
@ -600,7 +605,7 @@ impl Default for CPU {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
CPU {
|
CPU {
|
||||||
stack: vec![],
|
stack: vec![],
|
||||||
screen: bus! {
|
mem: bus! {
|
||||||
Charset [0x0050..0x00a0] = include_bytes!("mem/charset.bin"),
|
Charset [0x0050..0x00a0] = include_bytes!("mem/charset.bin"),
|
||||||
Program [0x0200..0x1000],
|
Program [0x0200..0x1000],
|
||||||
},
|
},
|
||||||
|
@ -407,10 +407,7 @@ impl CPU {
|
|||||||
pub(super) fn draw_sprite(&mut self, x: u16, y: u16, n: Nib, w: u16, h: u16, screen: &mut Bus) {
|
pub(super) fn draw_sprite(&mut self, x: u16, y: u16, n: Nib, w: u16, h: u16, screen: &mut Bus) {
|
||||||
let w_bytes = w / 8;
|
let w_bytes = w / 8;
|
||||||
self.v[0xf] = 0;
|
self.v[0xf] = 0;
|
||||||
if let Some(sprite) = self
|
if let Some(sprite) = self.mem.get(self.i as usize..(self.i + n as u16) as usize) {
|
||||||
.screen
|
|
||||||
.get(self.i as usize..(self.i + n as u16) as usize)
|
|
||||||
{
|
|
||||||
for (line, &sprite) in sprite.iter().enumerate() {
|
for (line, &sprite) in sprite.iter().enumerate() {
|
||||||
let line = line as u16;
|
let line = line as u16;
|
||||||
let sprite = ((sprite as u16) << (8 - (x % 8))).to_be_bytes();
|
let sprite = ((sprite as u16) << (8 - (x % 8))).to_be_bytes();
|
||||||
@ -460,7 +457,7 @@ impl CPU {
|
|||||||
pub(super) fn draw_schip_sprite(&mut self, x: u16, y: u16, w: u16, screen: &mut Bus) {
|
pub(super) fn draw_schip_sprite(&mut self, x: u16, y: u16, w: u16, screen: &mut Bus) {
|
||||||
self.v[0xf] = 0;
|
self.v[0xf] = 0;
|
||||||
let w_bytes = w / 8;
|
let w_bytes = w / 8;
|
||||||
if let Some(sprite) = self.screen.get(self.i as usize..(self.i + 32) as usize) {
|
if let Some(sprite) = self.mem.get(self.i as usize..(self.i + 32) as usize) {
|
||||||
let sprite = sprite.to_owned();
|
let sprite = sprite.to_owned();
|
||||||
for (line, sprite) in sprite.chunks_exact(2).enumerate() {
|
for (line, sprite) in sprite.chunks_exact(2).enumerate() {
|
||||||
let sprite = u16::from_be_bytes(
|
let sprite = u16::from_be_bytes(
|
||||||
@ -572,9 +569,9 @@ impl CPU {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(super) fn bcd_convert(&mut self, x: Reg) {
|
pub(super) fn bcd_convert(&mut self, x: Reg) {
|
||||||
let x = self.v[x];
|
let x = self.v[x];
|
||||||
self.screen.write(self.i.wrapping_add(2), x % 10);
|
self.mem.write(self.i.wrapping_add(2), x % 10);
|
||||||
self.screen.write(self.i.wrapping_add(1), x / 10 % 10);
|
self.mem.write(self.i.wrapping_add(1), x / 10 % 10);
|
||||||
self.screen.write(self.i, x / 100 % 10);
|
self.mem.write(self.i, x / 100 % 10);
|
||||||
}
|
}
|
||||||
/// |`Fx55`| DMA Stor from I to registers 0..=X
|
/// |`Fx55`| DMA Stor from I to registers 0..=X
|
||||||
///
|
///
|
||||||
@ -585,7 +582,7 @@ impl CPU {
|
|||||||
pub(super) fn store_dma(&mut self, x: Reg) {
|
pub(super) fn store_dma(&mut self, x: Reg) {
|
||||||
let i = self.i as usize;
|
let i = self.i as usize;
|
||||||
for (reg, value) in self
|
for (reg, value) in self
|
||||||
.screen
|
.mem
|
||||||
.get_mut(i..=i + x)
|
.get_mut(i..=i + x)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
@ -606,7 +603,7 @@ impl CPU {
|
|||||||
pub(super) fn load_dma(&mut self, x: Reg) {
|
pub(super) fn load_dma(&mut self, x: Reg) {
|
||||||
let i = self.i as usize;
|
let i = self.i as usize;
|
||||||
for (reg, value) in self
|
for (reg, value) in self
|
||||||
.screen
|
.mem
|
||||||
.get(i..=i + x)
|
.get(i..=i + x)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.iter()
|
.iter()
|
||||||
@ -642,7 +639,7 @@ impl CPU {
|
|||||||
pub(super) fn store_flags(&mut self, x: Reg) {
|
pub(super) fn store_flags(&mut self, x: Reg) {
|
||||||
// TODO: Save these, maybe
|
// TODO: Save these, maybe
|
||||||
for (reg, value) in self
|
for (reg, value) in self
|
||||||
.screen
|
.mem
|
||||||
.get_mut(0..=x)
|
.get_mut(0..=x)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
@ -656,13 +653,7 @@ impl CPU {
|
|||||||
/// I just chuck it in 0x0..0xf. Screw it.
|
/// I just chuck it in 0x0..0xf. Screw it.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(super) fn load_flags(&mut self, x: Reg) {
|
pub(super) fn load_flags(&mut self, x: Reg) {
|
||||||
for (reg, value) in self
|
for (reg, value) in self.mem.get(0..=x).unwrap_or_default().iter().enumerate() {
|
||||||
.screen
|
|
||||||
.get(0..=x)
|
|
||||||
.unwrap_or_default()
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
{
|
|
||||||
self.v[reg] = *value;
|
self.v[reg] = *value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ fn setup_environment() -> (CPU, Bus) {
|
|||||||
},
|
},
|
||||||
bus! {
|
bus! {
|
||||||
// Create a screen
|
// Create a screen
|
||||||
Screen [0x0F00..0x1000] = include_bytes!("../../chip8Archive/roms/1dcell.ch8"),
|
Screen [0x000..0x100] = include_bytes!("../../chip8Archive/roms/1dcell.ch8"),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
ch8.0
|
ch8.0
|
||||||
@ -755,7 +755,7 @@ mod io {
|
|||||||
// Debug mode is 5x slower
|
// Debug mode is 5x slower
|
||||||
cpu.flags.debug = false;
|
cpu.flags.debug = false;
|
||||||
// Load the test program
|
// Load the test program
|
||||||
cpu.screen.load_region(Program, test.program).unwrap();
|
cpu.mem.load_region(Program, test.program).unwrap();
|
||||||
// Run the test program for the specified number of steps
|
// Run the test program for the specified number of steps
|
||||||
while cpu.cycle() < test.steps {
|
while cpu.cycle() < test.steps {
|
||||||
cpu.multistep(&mut bus, 10.min(test.steps - cpu.cycle()))
|
cpu.multistep(&mut bus, 10.min(test.steps - cpu.cycle()))
|
||||||
@ -958,7 +958,7 @@ mod io {
|
|||||||
|
|
||||||
let addr = cpu.i as usize;
|
let addr = cpu.i as usize;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cpu.screen
|
cpu.mem
|
||||||
.get(addr..addr.wrapping_add(5))
|
.get(addr..addr.wrapping_add(5))
|
||||||
.expect("Region at addr should exist!"),
|
.expect("Region at addr should exist!"),
|
||||||
test.output,
|
test.output,
|
||||||
@ -1004,10 +1004,7 @@ mod io {
|
|||||||
|
|
||||||
cpu.bcd_convert(5);
|
cpu.bcd_convert(5);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(cpu.mem.get(addr..addr.saturating_add(3)), Some(test.output))
|
||||||
cpu.screen.get(addr..addr.saturating_add(3)),
|
|
||||||
Some(test.output)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1030,7 +1027,7 @@ mod io {
|
|||||||
cpu.store_dma(len);
|
cpu.store_dma(len);
|
||||||
// Check that bus grabbed the correct data
|
// Check that bus grabbed the correct data
|
||||||
let bus = cpu
|
let bus = cpu
|
||||||
.screen
|
.mem
|
||||||
.get_mut(addr..addr + DATA.len())
|
.get_mut(addr..addr + DATA.len())
|
||||||
.expect("Getting a mutable slice at addr 0x0456 should not fail");
|
.expect("Getting a mutable slice at addr 0x0456 should not fail");
|
||||||
assert_eq!(bus[0..=len], DATA[0..=len]);
|
assert_eq!(bus[0..=len], DATA[0..=len]);
|
||||||
@ -1048,7 +1045,7 @@ mod io {
|
|||||||
const DATA: &[u8] = b"ABCDEFGHIJKLMNOP";
|
const DATA: &[u8] = b"ABCDEFGHIJKLMNOP";
|
||||||
// Load some test data into memory
|
// Load some test data into memory
|
||||||
let addr = 0x456;
|
let addr = 0x456;
|
||||||
cpu.screen
|
cpu.mem
|
||||||
.get_mut(addr..addr + DATA.len())
|
.get_mut(addr..addr + DATA.len())
|
||||||
.expect("Getting a mutable slice at addr 0x0456..0x0466 should not fail")
|
.expect("Getting a mutable slice at addr 0x0456..0x0466 should not fail")
|
||||||
.write_all(DATA)
|
.write_all(DATA)
|
||||||
@ -1088,8 +1085,8 @@ mod behavior {
|
|||||||
#[test]
|
#[test]
|
||||||
fn sound() {
|
fn sound() {
|
||||||
let (mut cpu, mut bus) = setup_environment();
|
let (mut cpu, mut bus) = setup_environment();
|
||||||
cpu.flags.monotonic = None; // disable monotonic timing
|
|
||||||
cpu.sound = 10.0;
|
cpu.sound = 10.0;
|
||||||
|
cpu.flags.monotonic = false; // disable monotonic timing
|
||||||
for _ in 0..2 {
|
for _ in 0..2 {
|
||||||
cpu.multistep(&mut bus, 8)
|
cpu.multistep(&mut bus, 8)
|
||||||
.expect("Running valid instructions should always succeed");
|
.expect("Running valid instructions should always succeed");
|
||||||
|
@ -15,7 +15,7 @@ fn run_single_op(op: &[u8]) -> CPU {
|
|||||||
Screen[0x0..0x1000],
|
Screen[0x0..0x1000],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
cpu.screen
|
cpu.mem
|
||||||
.load_region(Program, op).unwrap();
|
.load_region(Program, op).unwrap();
|
||||||
cpu.v = *INDX;
|
cpu.v = *INDX;
|
||||||
cpu.flags.quirks = Quirks::from(false);
|
cpu.flags.quirks = Quirks::from(false);
|
||||||
|
Loading…
Reference in New Issue
Block a user