Migrated display to custom crate
Things still need to be ironed out, mainly in the display crate, but the system is working
This commit is contained in:
parent
7a13325eb0
commit
27585d6440
1698
Cargo.lock
generated
1698
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -9,8 +9,11 @@ edition = "2021"
|
|||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
chrono = "0.4.19"
|
chrono = "0.4.19"
|
||||||
fern = "0.6.0"
|
fern = "0.6.0"
|
||||||
winit = "0.24.0"
|
|
||||||
mini_gl_fb = "0.9.0"
|
|
||||||
bitflags = "1.3.2"
|
bitflags = "1.3.2"
|
||||||
rusttype = "0.9.2"
|
rusttype = "0.9.2"
|
||||||
|
canvas = "0.1.0"
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
canvas = { git = "https://git.steins7.ovh/Steins7/canvas.git", branch = "dev" }
|
||||||
|
cgmath = { path = "cgmath" }
|
||||||
|
|
||||||
|
|||||||
16
src/bus.rs
16
src/bus.rs
@ -28,7 +28,7 @@ impl<M: Mapper> fmt::Debug for Bus<M> {
|
|||||||
impl<M: Mapper> Peripheral for Bus<M> {
|
impl<M: Mapper> Peripheral for Bus<M> {
|
||||||
|
|
||||||
fn read_addr(&self, addr: u16) -> u8 {
|
fn read_addr(&self, addr: u16) -> u8 {
|
||||||
|
|
||||||
match addr {
|
match addr {
|
||||||
0x0000..=0x1FFF => self.ram.read_addr(addr % 0x0800), //RAM is mirrored 3 times
|
0x0000..=0x1FFF => self.ram.read_addr(addr % 0x0800), //RAM is mirrored 3 times
|
||||||
0x2000..=0x3FFF => self.ppu.read_addr(addr % 0x8), //PPU is mirrored every 8 bytes
|
0x2000..=0x3FFF => self.ppu.read_addr(addr % 0x8), //PPU is mirrored every 8 bytes
|
||||||
@ -38,11 +38,11 @@ impl<M: Mapper> Peripheral for Bus<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write_addr(&mut self, addr: u16, data: u8) {
|
fn write_addr(&mut self, addr: u16, data: u8) {
|
||||||
|
|
||||||
match addr {
|
match addr {
|
||||||
0x0000..=0x1FFF => self.ram.write_addr(addr % 0x0800, data),
|
0x0000..=0x1FFF => self.ram.write_addr(addr % 0x0800, data),
|
||||||
0x2000..=0x3FFF => self.ppu.write_addr(addr % 0x8, data),
|
0x2000..=0x3FFF => self.ppu.write_addr(addr % 0x8, data),
|
||||||
0x4000..=0x401F => self.apu.write_addr(addr, data),
|
0x4000..=0x401F => self.apu.write_addr(addr, data),
|
||||||
0x4020..=0xFFFF => self.cartridge.borrow_mut().write_addr(addr, data),
|
0x4020..=0xFFFF => self.cartridge.borrow_mut().write_addr(addr, data),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -51,7 +51,7 @@ impl<M: Mapper> Peripheral for Bus<M> {
|
|||||||
impl<M: Mapper> Bus<M> {
|
impl<M: Mapper> Bus<M> {
|
||||||
|
|
||||||
pub fn new(mapper: Rc<RefCell<M>>,
|
pub fn new(mapper: Rc<RefCell<M>>,
|
||||||
screen: Rc<RefCell<DisplayBuffer>>,
|
screen: Rc<RefCell<DisplayBuffer>>,
|
||||||
pattern_table: Rc<RefCell<DisplayBuffer>>)
|
pattern_table: Rc<RefCell<DisplayBuffer>>)
|
||||||
-> Self {
|
-> Self {
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ impl<M: Mapper> Bus<M> {
|
|||||||
//TODO temporary for instruction tests
|
//TODO temporary for instruction tests
|
||||||
ram.buffer[0x01] = 0xE9; //sbc
|
ram.buffer[0x01] = 0xE9; //sbc
|
||||||
ram.buffer[0x02] = (-3 as i8) as u8;
|
ram.buffer[0x02] = (-3 as i8) as u8;
|
||||||
ram.buffer[0x03] = 0x09;
|
ram.buffer[0x03] = 0x09;
|
||||||
ram.buffer[0x04] = 0x00;
|
ram.buffer[0x04] = 0x00;
|
||||||
ram.buffer[0x05] = 0xA9; //lda
|
ram.buffer[0x05] = 0xA9; //lda
|
||||||
ram.buffer[0x06] = 0x01;
|
ram.buffer[0x06] = 0x01;
|
||||||
@ -106,7 +106,7 @@ impl<M: Mapper> Bus<M> {
|
|||||||
ram.buffer[0x01FF] = 0x01;
|
ram.buffer[0x01FF] = 0x01;
|
||||||
ram.buffer[0x02FF] = 0xFF; //boundary
|
ram.buffer[0x02FF] = 0xFF; //boundary
|
||||||
ram.buffer[0x0300] = 0x03;
|
ram.buffer[0x0300] = 0x03;
|
||||||
|
|
||||||
// ptr to test
|
// ptr to test
|
||||||
ram.buffer[0x030F] = 0xFF;
|
ram.buffer[0x030F] = 0xFF;
|
||||||
ram.buffer[0x0310] = 0x03;
|
ram.buffer[0x0310] = 0x03;
|
||||||
@ -123,7 +123,7 @@ impl<M: Mapper> Bus<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self) {
|
pub fn tick(&mut self) {
|
||||||
self.ppu.tick();
|
self.ppu.tick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
84
src/cpu.rs
84
src/cpu.rs
@ -89,7 +89,7 @@ struct MemoryValExtra {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Input for MemoryValExtra {
|
impl Input for MemoryValExtra {
|
||||||
fn get_cycles(&self) -> u32 {
|
fn get_cycles(&self) -> u32 {
|
||||||
match self.extra_cycle {
|
match self.extra_cycle {
|
||||||
false => self.cycles,
|
false => self.cycles,
|
||||||
true => self.cycles + 1,
|
true => self.cycles + 1,
|
||||||
@ -154,7 +154,7 @@ pub struct Cpu<M: Mapper> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Mapper> fmt::Debug for Cpu<M> {
|
impl<M: Mapper> fmt::Debug for Cpu<M> {
|
||||||
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
fmt.debug_struct("Cpu")
|
fmt.debug_struct("Cpu")
|
||||||
.field("acc", &format_args!("0x{:0>2X}", self.a))
|
.field("acc", &format_args!("0x{:0>2X}", self.a))
|
||||||
@ -171,20 +171,20 @@ impl<M: Mapper> fmt::Debug for Cpu<M> {
|
|||||||
|
|
||||||
impl<M: Mapper> Cpu<M> {
|
impl<M: Mapper> Cpu<M> {
|
||||||
|
|
||||||
pub fn new(mapper: Rc<RefCell<M>>,
|
pub fn new(mapper: Rc<RefCell<M>>,
|
||||||
screen: Rc<RefCell<DisplayBuffer>>,
|
screen: Rc<RefCell<DisplayBuffer>>,
|
||||||
pattern_table: Rc<RefCell<DisplayBuffer>>)
|
pattern_table: Rc<RefCell<DisplayBuffer>>)
|
||||||
-> Self {
|
-> Self {
|
||||||
|
|
||||||
// read initial PC value from reset vector
|
// read initial PC value from reset vector
|
||||||
let bus = Bus::new(mapper, screen, pattern_table);
|
let bus = Bus::new(mapper, screen, pattern_table);
|
||||||
let pc_lo = bus.read_addr(0xFFFC) as u16;
|
let pc_lo = bus.read_addr(0xFFFC) as u16;
|
||||||
let pc_hi = bus.read_addr(0xFFFD) as u16;
|
let pc_hi = bus.read_addr(0xFFFD) as u16;
|
||||||
|
|
||||||
Cpu {
|
Cpu {
|
||||||
a: 0,
|
a: 0,
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
pc: (pc_lo | (pc_hi << 8)) + 3,
|
pc: (pc_lo | (pc_hi << 8)) + 3,
|
||||||
s: 0xFD,
|
s: 0xFD,
|
||||||
p: StatusReg::from_bits(0x34).unwrap(),
|
p: StatusReg::from_bits(0x34).unwrap(),
|
||||||
@ -194,7 +194,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
|
|
||||||
pub fn tick(&mut self) {
|
pub fn tick(&mut self) {
|
||||||
|
|
||||||
self.execute();
|
self.execute();
|
||||||
self.bus.tick();
|
self.bus.tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +207,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
// if (self.pc-1) != 0x36D8 {
|
// if (self.pc-1) != 0x36D8 {
|
||||||
// println!("0x{:0>4X}: {:0>2X}", self.pc-1, opcode);
|
// println!("0x{:0>4X}: {:0>2X}", self.pc-1, opcode);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let cycles = parse_opcode!(self, opcode,
|
let cycles = parse_opcode!(self, opcode,
|
||||||
0x69 => adc(mode_immediate),
|
0x69 => adc(mode_immediate),
|
||||||
0x65 => adc(mode_zero_page),
|
0x65 => adc(mode_zero_page),
|
||||||
@ -266,7 +266,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
0xE0 => cpx(mode_immediate),
|
0xE0 => cpx(mode_immediate),
|
||||||
0xE4 => cpx(mode_zero_page),
|
0xE4 => cpx(mode_zero_page),
|
||||||
0xEC => cpx(mode_absolute),
|
0xEC => cpx(mode_absolute),
|
||||||
|
|
||||||
0xC0 => cpy(mode_immediate),
|
0xC0 => cpy(mode_immediate),
|
||||||
0xC4 => cpy(mode_zero_page),
|
0xC4 => cpy(mode_zero_page),
|
||||||
0xCC => cpy(mode_absolute),
|
0xCC => cpy(mode_absolute),
|
||||||
@ -343,13 +343,13 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
0x08 => php(mode_implicit),
|
0x08 => php(mode_implicit),
|
||||||
0x68 => pla(mode_implicit),
|
0x68 => pla(mode_implicit),
|
||||||
0x28 => plp(mode_implicit),
|
0x28 => plp(mode_implicit),
|
||||||
|
|
||||||
0x2A => rol(mode_accumulator),
|
0x2A => rol(mode_accumulator),
|
||||||
0x26 => rol(mode_zero_page),
|
0x26 => rol(mode_zero_page),
|
||||||
0x36 => rol(mode_zero_page_x),
|
0x36 => rol(mode_zero_page_x),
|
||||||
0x2E => rol(mode_absolute),
|
0x2E => rol(mode_absolute),
|
||||||
0x3E => rol(mode_absolute_x),
|
0x3E => rol(mode_absolute_x),
|
||||||
|
|
||||||
0x6A => ror(mode_accumulator),
|
0x6A => ror(mode_accumulator),
|
||||||
0x66 => ror(mode_zero_page),
|
0x66 => ror(mode_zero_page),
|
||||||
0x76 => ror(mode_zero_page_x),
|
0x76 => ror(mode_zero_page_x),
|
||||||
@ -397,7 +397,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implicit mode
|
/// Implicit mode
|
||||||
/// instructions that use implied mode don't need inputs
|
/// instructions that use implied mode don't need inputs
|
||||||
fn mode_implicit(&self) -> () {}
|
fn mode_implicit(&self) -> () {}
|
||||||
|
|
||||||
@ -408,7 +408,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
data: self.read_pc_addr(),
|
data: self.read_pc_addr(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Immediate mode "#v":
|
/// Immediate mode "#v":
|
||||||
/// use 8bit operand as signed offset for PC
|
/// use 8bit operand as signed offset for PC
|
||||||
fn mode_relative(&mut self) -> Data {
|
fn mode_relative(&mut self) -> Data {
|
||||||
@ -470,7 +470,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
let addr_lo = self.read_pc_addr() as u16;
|
let addr_lo = self.read_pc_addr() as u16;
|
||||||
let addr_hi = self.read_pc_addr() as u16;
|
let addr_hi = self.read_pc_addr() as u16;
|
||||||
let mut addr = addr_lo | (addr_hi << 8);
|
let mut addr = addr_lo | (addr_hi << 8);
|
||||||
|
|
||||||
// compute index
|
// compute index
|
||||||
let extra_cycle = (addr_lo + (self.x as u16)) & 0xFF00 != 0;
|
let extra_cycle = (addr_lo + (self.x as u16)) & 0xFF00 != 0;
|
||||||
addr += self.x as u16;
|
addr += self.x as u16;
|
||||||
@ -486,12 +486,12 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
/// Fetch value from anywhere in memory, indexed on Y register
|
/// Fetch value from anywhere in memory, indexed on Y register
|
||||||
/// val = PEEK(arg + Y)
|
/// val = PEEK(arg + Y)
|
||||||
fn mode_absolute_y(&mut self) -> MemoryValExtra {
|
fn mode_absolute_y(&mut self) -> MemoryValExtra {
|
||||||
|
|
||||||
// compute full address
|
// compute full address
|
||||||
let addr_lo = self.read_pc_addr() as u16;
|
let addr_lo = self.read_pc_addr() as u16;
|
||||||
let addr_hi = self.read_pc_addr() as u16;
|
let addr_hi = self.read_pc_addr() as u16;
|
||||||
let mut addr = addr_lo | (addr_hi << 8);
|
let mut addr = addr_lo | (addr_hi << 8);
|
||||||
|
|
||||||
// compute index
|
// compute index
|
||||||
let extra_cycle = (addr_lo + (self.y as u16)) & 0xFF00 != 0;
|
let extra_cycle = (addr_lo + (self.y as u16)) & 0xFF00 != 0;
|
||||||
addr += self.y as u16;
|
addr += self.y as u16;
|
||||||
@ -513,7 +513,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
let addr_ind_lo = self.read_pc_addr() as u16;
|
let addr_ind_lo = self.read_pc_addr() as u16;
|
||||||
let addr_ind_hi = self.read_pc_addr() as u16;
|
let addr_ind_hi = self.read_pc_addr() as u16;
|
||||||
let addr_ind = addr_ind_lo | (addr_ind_hi << 8);
|
let addr_ind = addr_ind_lo | (addr_ind_hi << 8);
|
||||||
|
|
||||||
// fetch indirect addr to jump to
|
// fetch indirect addr to jump to
|
||||||
let addr_lo = self.bus.read_addr(addr_ind) as u16;
|
let addr_lo = self.bus.read_addr(addr_ind) as u16;
|
||||||
//note: bug of the 6502, the carry isn't applied when incrementing the indirect address
|
//note: bug of the 6502, the carry isn't applied when incrementing the indirect address
|
||||||
@ -527,13 +527,13 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Indirect mode "(d.x)"
|
/// Indirect mode "(d.x)"
|
||||||
/// Fetch value from anywhere in memory using an address table built by the user and stored in
|
/// Fetch value from anywhere in memory using an address table built by the user and stored in
|
||||||
/// zero page, indexed on X
|
/// zero page, indexed on X
|
||||||
/// val = PEEK(PEEK((arg + X) & 0xFF) + PEEK((arg + X + 1) & 0xFF) << 8)
|
/// val = PEEK(PEEK((arg + X) & 0xFF) + PEEK((arg + X + 1) & 0xFF) << 8)
|
||||||
fn mode_indirect_x(&mut self) -> MemoryVal {
|
fn mode_indirect_x(&mut self) -> MemoryVal {
|
||||||
|
|
||||||
let addr_ind = self.read_pc_addr() as u16 + self.x as u16;
|
let addr_ind = self.read_pc_addr() as u16 + self.x as u16;
|
||||||
|
|
||||||
// fetch indirect addr to jump to
|
// fetch indirect addr to jump to
|
||||||
let addr_lo = self.bus.read_addr(addr_ind & 0xFF) as u16;
|
let addr_lo = self.bus.read_addr(addr_ind & 0xFF) as u16;
|
||||||
let addr_hi = self.bus.read_addr((addr_ind + 1) & 0xFF) as u16;
|
let addr_hi = self.bus.read_addr((addr_ind + 1) & 0xFF) as u16;
|
||||||
@ -551,7 +551,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
fn mode_indirect_y(&mut self) -> MemoryValExtra {
|
fn mode_indirect_y(&mut self) -> MemoryValExtra {
|
||||||
|
|
||||||
let addr_ind = self.read_pc_addr() as u16;
|
let addr_ind = self.read_pc_addr() as u16;
|
||||||
|
|
||||||
// fetch indirect addr to jump to
|
// fetch indirect addr to jump to
|
||||||
let addr_lo = self.bus.read_addr(addr_ind) as u16;
|
let addr_lo = self.bus.read_addr(addr_ind) as u16;
|
||||||
let addr_hi = self.bus.read_addr((addr_ind + 1) & 0xFF) as u16;
|
let addr_hi = self.bus.read_addr((addr_ind + 1) & 0xFF) as u16;
|
||||||
@ -599,7 +599,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
|
|
||||||
fn adc<I: RInput>(&mut self, input: I) -> u32 {
|
fn adc<I: RInput>(&mut self, input: I) -> u32 {
|
||||||
let val = input.read(&self.a, &self.bus);
|
let val = input.read(&self.a, &self.bus);
|
||||||
|
|
||||||
// add acc and value
|
// add acc and value
|
||||||
let prev_a = self.a as u16;
|
let prev_a = self.a as u16;
|
||||||
let mut a = self.a as u16;
|
let mut a = self.a as u16;
|
||||||
@ -640,7 +640,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
|
|
||||||
fn asl<I: RWInput>(&mut self, mut input: I) -> u32 {
|
fn asl<I: RWInput>(&mut self, mut input: I) -> u32 {
|
||||||
let mut target = input.read(&self.a, &self.bus) as u16;
|
let mut target = input.read(&self.a, &self.bus) as u16;
|
||||||
|
|
||||||
// shift target one bit left
|
// shift target one bit left
|
||||||
target = target << 1;
|
target = target << 1;
|
||||||
|
|
||||||
@ -663,7 +663,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
let old_pc = self.pc;
|
let old_pc = self.pc;
|
||||||
self.pc = self.pc.wrapping_add(offset as u16);
|
self.pc = self.pc.wrapping_add(offset as u16);
|
||||||
match old_pc & 0xFF00 == self.pc & 0xFF00 {
|
match old_pc & 0xFF00 == self.pc & 0xFF00 {
|
||||||
true => input.get_cycles() + 1,
|
true => input.get_cycles() + 1,
|
||||||
false => input.get_cycles() + 2,
|
false => input.get_cycles() + 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -714,7 +714,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
let pc = self.pc.wrapping_add(1);
|
let pc = self.pc.wrapping_add(1);
|
||||||
self.push_stack((pc >> 8) as u8);
|
self.push_stack((pc >> 8) as u8);
|
||||||
self.push_stack(pc as u8);
|
self.push_stack(pc as u8);
|
||||||
|
|
||||||
// store status register
|
// store status register
|
||||||
self.p.set(StatusReg::B | StatusReg::U, true);
|
self.p.set(StatusReg::B | StatusReg::U, true);
|
||||||
self.push_stack(self.p.bits() as u8);
|
self.push_stack(self.p.bits() as u8);
|
||||||
@ -759,7 +759,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn compute_cmp<I: RInput>(&mut self, reg: u8, input: I) -> u32 {
|
fn compute_cmp<I: RInput>(&mut self, reg: u8, input: I) -> u32 {
|
||||||
let val = input.read(&self.a, &self.bus) as u8;
|
let val = input.read(&self.a, &self.bus) as u8;
|
||||||
|
|
||||||
self.p.set(StatusReg::C, reg >= val);
|
self.p.set(StatusReg::C, reg >= val);
|
||||||
self.p.set(StatusReg::Z, reg == val);
|
self.p.set(StatusReg::Z, reg == val);
|
||||||
@ -787,7 +787,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
val = val.wrapping_sub(1);
|
val = val.wrapping_sub(1);
|
||||||
self.p.set(StatusReg::Z, val == 0);
|
self.p.set(StatusReg::Z, val == 0);
|
||||||
self.p.set(StatusReg::N, (val & (0x1 << 7)) != 0);
|
self.p.set(StatusReg::N, (val & (0x1 << 7)) != 0);
|
||||||
|
|
||||||
// store result
|
// store result
|
||||||
input.write(&mut self.a, &mut self.bus, val);
|
input.write(&mut self.a, &mut self.bus, val);
|
||||||
input.get_cycles() + 2
|
input.get_cycles() + 2
|
||||||
@ -799,7 +799,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
self.x = self.x.wrapping_sub(1);
|
self.x = self.x.wrapping_sub(1);
|
||||||
self.p.set(StatusReg::Z, self.x == 0);
|
self.p.set(StatusReg::Z, self.x == 0);
|
||||||
self.p.set(StatusReg::N, (self.x & (0x1 << 7)) != 0);
|
self.p.set(StatusReg::N, (self.x & (0x1 << 7)) != 0);
|
||||||
|
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -809,7 +809,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
self.y = self.y.wrapping_sub(1);
|
self.y = self.y.wrapping_sub(1);
|
||||||
self.p.set(StatusReg::Z, self.y == 0);
|
self.p.set(StatusReg::Z, self.y == 0);
|
||||||
self.p.set(StatusReg::N, (self.y & (0x1 << 7)) != 0);
|
self.p.set(StatusReg::N, (self.y & (0x1 << 7)) != 0);
|
||||||
|
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -836,7 +836,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
input.write(&mut self.a, &mut self.bus, val);
|
input.write(&mut self.a, &mut self.bus, val);
|
||||||
input.get_cycles() + 2
|
input.get_cycles() + 2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inx(&mut self, _: ()) -> u32 {
|
fn inx(&mut self, _: ()) -> u32 {
|
||||||
|
|
||||||
// compute
|
// compute
|
||||||
@ -937,7 +937,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
self.p.set(StatusReg::N, (self.a & (0x1 << 7)) != 0);
|
self.p.set(StatusReg::N, (self.a & (0x1 << 7)) != 0);
|
||||||
|
|
||||||
input.get_cycles()
|
input.get_cycles()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pha(&mut self, _: ()) -> u32 {
|
fn pha(&mut self, _: ()) -> u32 {
|
||||||
self.push_stack(self.a);
|
self.push_stack(self.a);
|
||||||
@ -968,7 +968,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
|
|
||||||
fn rol<I: RWInput>(&mut self, mut input: I) -> u32 {
|
fn rol<I: RWInput>(&mut self, mut input: I) -> u32 {
|
||||||
let mut val = input.read(&self.a, &self.bus);
|
let mut val = input.read(&self.a, &self.bus);
|
||||||
|
|
||||||
// store bit 7 and compute
|
// store bit 7 and compute
|
||||||
let carry = val & (0x1 << 7) != 0;
|
let carry = val & (0x1 << 7) != 0;
|
||||||
val = val << 1;
|
val = val << 1;
|
||||||
@ -987,10 +987,10 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
input.write(&mut self.a, &mut self.bus, val);
|
input.write(&mut self.a, &mut self.bus, val);
|
||||||
input.get_cycles() + 2
|
input.get_cycles() + 2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ror<I: RWInput>(&mut self, mut input: I) -> u32 {
|
fn ror<I: RWInput>(&mut self, mut input: I) -> u32 {
|
||||||
let mut val = input.read(&self.a, &self.bus);
|
let mut val = input.read(&self.a, &self.bus);
|
||||||
|
|
||||||
// store bit 0 and compute
|
// store bit 0 and compute
|
||||||
let carry = val & (0x1 << 0) != 0;
|
let carry = val & (0x1 << 0) != 0;
|
||||||
val = val >> 1;
|
val = val >> 1;
|
||||||
@ -1011,11 +1011,11 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn rti(&mut self, _: ()) -> u32 {
|
fn rti(&mut self, _: ()) -> u32 {
|
||||||
|
|
||||||
// load status register (B is cleared and I overrided)
|
// load status register (B is cleared and I overrided)
|
||||||
self.p = StatusReg::from_bits_truncate(self.pop_stack());
|
self.p = StatusReg::from_bits_truncate(self.pop_stack());
|
||||||
self.p.set(StatusReg::B | StatusReg::U, false);
|
self.p.set(StatusReg::B | StatusReg::U, false);
|
||||||
|
|
||||||
// load pc
|
// load pc
|
||||||
let pc_lo = self.pop_stack() as u16;
|
let pc_lo = self.pop_stack() as u16;
|
||||||
let pc_hi = self.pop_stack() as u16;
|
let pc_hi = self.pop_stack() as u16;
|
||||||
@ -1025,7 +1025,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn rts(&mut self, _: ()) -> u32 {
|
fn rts(&mut self, _: ()) -> u32 {
|
||||||
|
|
||||||
// load pc
|
// load pc
|
||||||
let pc_lo = self.pop_stack() as u16;
|
let pc_lo = self.pop_stack() as u16;
|
||||||
let pc_hi = self.pop_stack() as u16;
|
let pc_hi = self.pop_stack() as u16;
|
||||||
@ -1037,7 +1037,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
|
|
||||||
fn sbc<I: RInput>(&mut self, input: I) -> u32 {
|
fn sbc<I: RInput>(&mut self, input: I) -> u32 {
|
||||||
let val = input.read(&self.a, &self.bus);
|
let val = input.read(&self.a, &self.bus);
|
||||||
|
|
||||||
// sub acc and value
|
// sub acc and value
|
||||||
let prev_a = self.a as u16;
|
let prev_a = self.a as u16;
|
||||||
let mut a = self.a as u16;
|
let mut a = self.a as u16;
|
||||||
@ -1089,7 +1089,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
input.write(&mut self.a, &mut self.bus, x);
|
input.write(&mut self.a, &mut self.bus, x);
|
||||||
input.get_cycles()
|
input.get_cycles()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sty<I: RWInput>(&mut self, mut input: I) -> u32 {
|
fn sty<I: RWInput>(&mut self, mut input: I) -> u32 {
|
||||||
let y = self.y;
|
let y = self.y;
|
||||||
input.write(&mut self.a, &mut self.bus, y);
|
input.write(&mut self.a, &mut self.bus, y);
|
||||||
@ -1113,7 +1113,7 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
|
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tsx(&mut self, _: ()) -> u32 {
|
fn tsx(&mut self, _: ()) -> u32 {
|
||||||
|
|
||||||
self.x = self.s;
|
self.x = self.s;
|
||||||
|
|||||||
325
src/main.rs
325
src/main.rs
@ -1,121 +1,242 @@
|
|||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::{debug, error, info, trace, warn};
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
rc::Rc,
|
||||||
|
cell::RefCell,
|
||||||
|
time::Instant,
|
||||||
|
fmt::Write,
|
||||||
|
};
|
||||||
|
|
||||||
mod cpu;
|
mod cpu;
|
||||||
use cpu::Cpu;
|
use cpu::Cpu;
|
||||||
|
|
||||||
mod bus;
|
mod bus;
|
||||||
mod peripherals;
|
mod peripherals;
|
||||||
|
use peripherals::mapper::Nrom128;
|
||||||
|
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
fn main() -> Result<(), &'static str> {
|
use canvas::{
|
||||||
use utils::{Pixel, PixelBuffer, FontRenderer, DisplayBuffer};
|
Application,
|
||||||
use winit::{
|
Canvas,
|
||||||
event_loop::EventLoop,
|
sprite::{Sprite, TextureSprite, TextSprite, Center},
|
||||||
dpi::LogicalSize,
|
utils::{Size, Color, Position},
|
||||||
};
|
};
|
||||||
use mini_gl_fb::config;
|
use utils::DisplayBuffer;
|
||||||
use std::{
|
|
||||||
fmt::Write,
|
|
||||||
rc::Rc,
|
|
||||||
cell::RefCell,
|
|
||||||
time::Instant,
|
|
||||||
};
|
|
||||||
use peripherals::mapper::Nrom128;
|
|
||||||
|
|
||||||
// setup
|
struct EmulatorState {
|
||||||
setup_logger().map_err(|_| "Failed to setup logger")?;
|
pub screen: Rc<RefCell<DisplayBuffer>>,
|
||||||
|
pub screen_sprite: TextureSprite,
|
||||||
|
|
||||||
let mut event_loop = EventLoop::new();
|
pub pattern_table: Rc<RefCell<DisplayBuffer>>,
|
||||||
let config = config! {
|
pub pattern_sprite: TextureSprite,
|
||||||
window_title: "Test".to_string(),
|
|
||||||
window_size: LogicalSize::new(1280.0, 720.0),
|
|
||||||
invert_y: false,
|
|
||||||
};
|
|
||||||
let mut fb = mini_gl_fb::get_fancy(config, &event_loop);
|
|
||||||
let mut buffer = PixelBuffer::new(1280, 720);
|
|
||||||
let mut renderer = FontRenderer::new(20.0, [0u8, 0, 0]);
|
|
||||||
|
|
||||||
// first image
|
pub fps_text: TextSprite,
|
||||||
let mapper = Rc::new(RefCell::new(Nrom128::new(false)));
|
pub debug_text: TextSprite,
|
||||||
let mut screen = Rc::new(RefCell::new(DisplayBuffer::new(256, 240)));
|
|
||||||
let pattern_table = Rc::new(RefCell::new(DisplayBuffer::new(256, 128)));
|
|
||||||
let mut cpu = Cpu::new(mapper, screen.clone(), pattern_table.clone());
|
|
||||||
let mut debug_str = String::new();
|
|
||||||
//write!(debug_str, "{:#?}", cpu).unwrap();
|
|
||||||
buffer.fill([0, 0], [1280, 720], Pixel::rgba(255, 255, 255, 255));
|
|
||||||
//renderer.draw(&mut buffer, &debug_str, [20, 20], [760, 560]);
|
|
||||||
|
|
||||||
let vec: Vec<[u8; 4]> = (&buffer).into();
|
pub cpu: Cpu<Nrom128>,
|
||||||
fb.update_buffer(&vec);
|
|
||||||
let mut update = false;
|
|
||||||
let mut refresh = true;
|
|
||||||
let mut start = Instant::now();
|
|
||||||
|
|
||||||
// event loop
|
pub start: Instant,
|
||||||
fb.glutin_handle_basic_input(&mut event_loop, |fb, input| {
|
|
||||||
use winit::event::VirtualKeyCode;
|
|
||||||
|
|
||||||
// wait for input before updating
|
|
||||||
|
|
||||||
// close if escape is pressed
|
|
||||||
if input.key_pressed(VirtualKeyCode::Escape) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// execute next cpu instruction (step mode)
|
|
||||||
if input.key_pressed(VirtualKeyCode::S) {
|
|
||||||
cpu.tick();
|
|
||||||
refresh = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if input.key_pressed(VirtualKeyCode::R) {
|
|
||||||
update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if input.key_pressed(VirtualKeyCode::C) {
|
|
||||||
update = false;
|
|
||||||
refresh = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if update {
|
|
||||||
cpu.tick();
|
|
||||||
|
|
||||||
if screen.borrow_mut().is_ready {
|
|
||||||
screen.borrow_mut().is_ready = false;
|
|
||||||
refresh = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.wait = false;
|
|
||||||
} else {
|
|
||||||
input.wait = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if refresh {
|
|
||||||
refresh = false;
|
|
||||||
|
|
||||||
let frame_time = start.elapsed().as_secs_f32();
|
|
||||||
start = Instant::now();
|
|
||||||
|
|
||||||
let mut debug_str = String::new();
|
|
||||||
buffer.fill([0, 0], [1280, 720], Pixel::rgba(255, 255, 255, 255));
|
|
||||||
write!(debug_str, "{} fps", 1.0/frame_time);
|
|
||||||
renderer.draw(&mut buffer, &debug_str, [1, 1], [20, 20]);
|
|
||||||
debug_str = String::new();
|
|
||||||
write!(debug_str, "{:#?}", cpu).unwrap();
|
|
||||||
renderer.draw(&mut buffer, &debug_str, [600, 20], [760, 560]);
|
|
||||||
buffer.embbed([20, 20], &screen.borrow().buffer, 2);
|
|
||||||
|
|
||||||
let vec: Vec<[u8; 4]> = (&buffer).into();
|
|
||||||
fb.update_buffer(&vec);
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct NesEmulator {}
|
||||||
|
|
||||||
|
impl Application<EmulatorState> for NesEmulator {
|
||||||
|
|
||||||
|
fn init(canvas: &mut Canvas) -> Result<EmulatorState, &'static str> {
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
|
||||||
|
let screen_texture = canvas
|
||||||
|
.create_texture(Size {w: 256, h: 240}, Some(Color::RED.into()))
|
||||||
|
.unwrap();
|
||||||
|
let mut screen_sprite = canvas.create_texture_sprite(Size {w: 256 * 2, h: 240 * 2});
|
||||||
|
screen_sprite.set_texture(screen_texture.clone(), None, 0.5);
|
||||||
|
screen_sprite.set_center(Center::BotLeft);
|
||||||
|
screen_sprite.set_position(Position {x: 100, y: 200});
|
||||||
|
let screen = Rc::new(RefCell::new(DisplayBuffer::from_texture(screen_texture)));
|
||||||
|
|
||||||
|
let pattern_texture = canvas
|
||||||
|
.create_texture(Size {w: 256, h: 128}, Some(Color::BLUE.into()))
|
||||||
|
.unwrap();
|
||||||
|
let mut pattern_sprite = canvas.create_texture_sprite(Size {w: 256, h: 128});
|
||||||
|
pattern_sprite.set_texture(pattern_texture.clone(), None, 1.0);
|
||||||
|
pattern_sprite.set_center(Center::BotLeft);
|
||||||
|
pattern_sprite.set_position(Position {x: 100, y: 50});
|
||||||
|
let pattern_table = Rc::new(RefCell::new(DisplayBuffer::from_texture(pattern_texture)));
|
||||||
|
|
||||||
|
let mut fps_text = canvas.create_text_sprite("00", Size {w: 20, h: 20}, 20.0);
|
||||||
|
fps_text.set_center(Center::TopLeft);
|
||||||
|
fps_text.set_position(Position {x:0, y:720});
|
||||||
|
|
||||||
|
let mut debug_text = canvas.create_text_sprite("00", Size {w: 300, h: 600}, 20.0);
|
||||||
|
debug_text.set_center(Center::BotLeft);
|
||||||
|
debug_text.set_position(Position {x:700, y:50});
|
||||||
|
|
||||||
|
let mapper = Rc::new(RefCell::new(Nrom128::new(false)));
|
||||||
|
let cpu = Cpu::new(mapper, screen.clone(), pattern_table.clone());
|
||||||
|
|
||||||
|
canvas.clear();
|
||||||
|
canvas.update();
|
||||||
|
|
||||||
|
Ok(EmulatorState {
|
||||||
|
screen,
|
||||||
|
screen_sprite,
|
||||||
|
pattern_table,
|
||||||
|
pattern_sprite,
|
||||||
|
fps_text,
|
||||||
|
debug_text,
|
||||||
|
cpu,
|
||||||
|
start,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tick(state: &mut EmulatorState, canvas: &mut Canvas) -> Result<(), &'static str> {
|
||||||
|
|
||||||
|
let frame_time = state.start.elapsed().as_secs_f32();
|
||||||
|
state.start = Instant::now();
|
||||||
|
canvas.clear();
|
||||||
|
state.cpu.tick();
|
||||||
|
|
||||||
|
if state.screen.borrow_mut().is_ready {
|
||||||
|
state.screen.borrow_mut().is_ready = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.draw(&mut state.screen_sprite);
|
||||||
|
canvas.draw(&mut state.pattern_sprite);
|
||||||
|
|
||||||
|
let mut fps_str = String::new();
|
||||||
|
write!(fps_str, "{} fps", 1.0/frame_time).unwrap();
|
||||||
|
state.fps_text.set_text(&fps_str);
|
||||||
|
canvas.draw(&mut state.fps_text);
|
||||||
|
|
||||||
|
let mut debug_str = String::new();
|
||||||
|
write!(debug_str, "{:#?}", state.cpu).unwrap();
|
||||||
|
state.debug_text.set_text(&debug_str);
|
||||||
|
canvas.draw(&mut state.debug_text);
|
||||||
|
|
||||||
|
canvas.update();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), &'static str> {
|
||||||
|
|
||||||
|
setup_logger()
|
||||||
|
.map_err(|_| "Failed to setup logger")?;
|
||||||
|
canvas::run_canvas("NES emulator", Size {w: 1280, h: 720}, NesEmulator {});
|
||||||
|
}
|
||||||
|
|
||||||
|
// use utils::{Pixel, PixelBuffer, FontRenderer, DisplayBuffer};
|
||||||
|
// use glutin::{
|
||||||
|
// dpi::LogicalSize,
|
||||||
|
// event_loop::EventLoop,
|
||||||
|
// };
|
||||||
|
// use mini_gl_fb::config;
|
||||||
|
// use std::{
|
||||||
|
// fmt::Write,
|
||||||
|
// rc::Rc,
|
||||||
|
// cell::RefCell,
|
||||||
|
// time::Instant,
|
||||||
|
// };
|
||||||
|
// use peripherals::mapper::Nrom128;
|
||||||
|
// use std::ops::Deref;
|
||||||
|
//
|
||||||
|
// // setup
|
||||||
|
// setup_logger().map_err(|_| "Failed to setup logger")?;
|
||||||
|
//
|
||||||
|
// let mut event_loop = EventLoop::new();
|
||||||
|
// let config = config! {
|
||||||
|
// window_title: "Test".to_string(),
|
||||||
|
// window_size: LogicalSize::new(1280.0, 720.0),
|
||||||
|
// invert_y: false,
|
||||||
|
// };
|
||||||
|
// let mut fb = mini_gl_fb::get_fancy(config, event_loop.deref());
|
||||||
|
// let mut buffer = PixelBuffer::new(1280, 720);
|
||||||
|
// let mut renderer = FontRenderer::new(20.0, [0u8, 0, 0]);
|
||||||
|
//
|
||||||
|
// // first image
|
||||||
|
// let mapper = Rc::new(RefCell::new(Nrom128::new(false)));
|
||||||
|
// let mut screen = Rc::new(RefCell::new(DisplayBuffer::new(256, 240)));
|
||||||
|
// let pattern_table = Rc::new(RefCell::new(DisplayBuffer::new(256, 128)));
|
||||||
|
// let mut cpu = Cpu::new(mapper, screen.clone(), pattern_table.clone());
|
||||||
|
// let mut debug_str = String::new();
|
||||||
|
// //write!(debug_str, "{:#?}", cpu).unwrap();
|
||||||
|
// buffer.fill([0, 0], [1280, 720], Pixel::rgba(255, 255, 255, 255));
|
||||||
|
// //renderer.draw(&mut buffer, &debug_str, [20, 20], [760, 560]);
|
||||||
|
//
|
||||||
|
// let vec: Vec<[u8; 4]> = (&buffer).into();
|
||||||
|
// fb.update_buffer(&vec);
|
||||||
|
// let mut update = false;
|
||||||
|
// let mut refresh = true;
|
||||||
|
// let mut start = Instant::now();
|
||||||
|
//
|
||||||
|
// // event loop
|
||||||
|
// fb.glutin_handle_basic_input(&mut event_loop, |fb, input| {
|
||||||
|
// use glutin::event::VirtualKeyCode;
|
||||||
|
//
|
||||||
|
// // wait for input before updating
|
||||||
|
//
|
||||||
|
// // close if escape is pressed
|
||||||
|
// if input.key_pressed(VirtualKeyCode::Escape) {
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // execute next cpu instruction (step mode)
|
||||||
|
// if input.key_pressed(VirtualKeyCode::S) {
|
||||||
|
// cpu.tick();
|
||||||
|
// refresh = true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if input.key_pressed(VirtualKeyCode::R) {
|
||||||
|
// update = true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if input.key_pressed(VirtualKeyCode::C) {
|
||||||
|
// update = false;
|
||||||
|
// refresh = true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if update {
|
||||||
|
// cpu.tick();
|
||||||
|
//
|
||||||
|
// if screen.borrow_mut().is_ready {
|
||||||
|
// screen.borrow_mut().is_ready = false;
|
||||||
|
// refresh = true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// input.wait = false;
|
||||||
|
// } else {
|
||||||
|
// input.wait = true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if refresh {
|
||||||
|
// refresh = false;
|
||||||
|
//
|
||||||
|
// let frame_time = start.elapsed().as_secs_f32();
|
||||||
|
// start = Instant::now();
|
||||||
|
//
|
||||||
|
// let mut debug_str = String::new();
|
||||||
|
// buffer.fill([0, 0], [1280, 720], Pixel::rgba(255, 255, 255, 255));
|
||||||
|
// write!(debug_str, "{} fps", 1.0/frame_time);
|
||||||
|
// renderer.draw(&mut buffer, &debug_str, [1, 1], [20, 20]);
|
||||||
|
// debug_str = String::new();
|
||||||
|
// write!(debug_str, "{:#?}", cpu).unwrap();
|
||||||
|
// renderer.draw(&mut buffer, &debug_str, [600, 20], [760, 560]);
|
||||||
|
// buffer.embbed([20, 20], &screen.borrow().buffer, 2);
|
||||||
|
//
|
||||||
|
// let vec: Vec<[u8; 4]> = (&buffer).into();
|
||||||
|
// fb.update_buffer(&vec);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// true
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// Ok(())
|
||||||
|
//}
|
||||||
|
|
||||||
fn setup_logger() -> Result<(), fern::InitError> {
|
fn setup_logger() -> Result<(), fern::InitError> {
|
||||||
|
|
||||||
fern::Dispatch::new()
|
fern::Dispatch::new()
|
||||||
@ -129,7 +250,7 @@ fn setup_logger() -> Result<(), fern::InitError> {
|
|||||||
message
|
message
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
.level(log::LevelFilter::Debug)
|
.level(log::LevelFilter::Error)
|
||||||
.chain(std::io::stdout())
|
.chain(std::io::stdout())
|
||||||
.chain(fern::log_file("output.log")?)
|
.chain(fern::log_file("output.log")?)
|
||||||
.apply()?;
|
.apply()?;
|
||||||
|
|||||||
@ -71,23 +71,23 @@ pub struct Ppu<M: Mapper> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Mapper> Peripheral for Ppu<M> {
|
impl<M: Mapper> Peripheral for Ppu<M> {
|
||||||
|
|
||||||
fn read_addr(&self, _addr: u16) -> u8 {
|
fn read_addr(&self, _addr: u16) -> u8 {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_addr(&mut self, addr: u16, data: u8) {
|
fn write_addr(&mut self, addr: u16, data: u8) {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Mapper> Ppu<M> {
|
impl<M: Mapper> Ppu<M> {
|
||||||
|
|
||||||
pub fn new(mapper: Rc<RefCell<M>>,
|
pub fn new(mapper: Rc<RefCell<M>>,
|
||||||
screen: Rc<RefCell<DisplayBuffer>>,
|
screen: Rc<RefCell<DisplayBuffer>>,
|
||||||
pattern_table: Rc<RefCell<DisplayBuffer>>)
|
pattern_table: Rc<RefCell<DisplayBuffer>>)
|
||||||
-> Self {
|
-> Self {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
vbus: mapper,
|
vbus: mapper,
|
||||||
ppu_ctrl: PpuCtrl::from_bits(0).unwrap(),
|
ppu_ctrl: PpuCtrl::from_bits(0).unwrap(),
|
||||||
@ -122,16 +122,16 @@ impl<M: Mapper> Ppu<M> {
|
|||||||
use crate::utils::Pixel;
|
use crate::utils::Pixel;
|
||||||
|
|
||||||
self.screen.borrow_mut()
|
self.screen.borrow_mut()
|
||||||
.buffer.put_pixel(
|
.set_pixel(
|
||||||
self.dot.into(),
|
self.dot.into(),
|
||||||
self.line.into(),
|
self.line.into(),
|
||||||
Pixel::rgba(self.data.into(), 0, 0, 255));
|
Pixel::rgba(self.data.into(), 0, 0, 255));
|
||||||
|
|
||||||
self.execute();
|
self.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute(&mut self) {
|
fn execute(&mut self) {
|
||||||
|
|
||||||
match self.line {
|
match self.line {
|
||||||
0..=239 => self.render_frame(),
|
0..=239 => self.render_frame(),
|
||||||
241 => {
|
241 => {
|
||||||
@ -163,7 +163,7 @@ impl<M: Mapper> Ppu<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render_frame(&mut self) {
|
fn render_frame(&mut self) {
|
||||||
|
|
||||||
match self.dot {
|
match self.dot {
|
||||||
0 => (),
|
0 => (),
|
||||||
33..=40 => (),
|
33..=40 => (),
|
||||||
|
|||||||
@ -1,19 +1,33 @@
|
|||||||
use super::PixelBuffer;
|
use super::Pixel;
|
||||||
|
|
||||||
|
use canvas::texture::TextureHandle;
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
pub struct DisplayBuffer {
|
pub struct DisplayBuffer {
|
||||||
pub buffer: PixelBuffer,
|
|
||||||
pub is_ready: bool,
|
pub is_ready: bool,
|
||||||
|
|
||||||
|
texture: TextureHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DisplayBuffer {
|
impl DisplayBuffer {
|
||||||
|
|
||||||
pub fn new(w: usize, h: usize) -> Self {
|
pub fn from_texture(texture: TextureHandle) -> Self {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
buffer: PixelBuffer::new(w, h),
|
texture,
|
||||||
is_ready: false,
|
is_ready: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_pixel(&mut self, x: usize, y: usize, pixel: Pixel) {
|
||||||
|
self.texture.set_pixel(
|
||||||
|
canvas::utils::Position {x: x.try_into().unwrap(), y: y.try_into().unwrap()},
|
||||||
|
canvas::utils::Pixel {
|
||||||
|
r: pixel.r,
|
||||||
|
g: pixel.g,
|
||||||
|
b: pixel.b,
|
||||||
|
a: pixel.a,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user