├── cpu ├── README.md └── cpu.rs /cpu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shafu0x/nes-emulator-rust/main/cpu -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nes-emulator-rust 2 | 3 | learning rust by writing an nes emulator for fun. 4 | -------------------------------------------------------------------------------- /cpu.rs: -------------------------------------------------------------------------------- 1 | pub struct CPU { 2 | pub register_a: u8, 3 | pub register_x: u8, 4 | pub status: u8, 5 | pub program_counter: u16, 6 | memory: [u8; 0xFFFF] 7 | } 8 | 9 | pub enum AddressingMode { 10 | Immediate, 11 | ZeroPage, 12 | ZeorPage_X, 13 | ZeorPage_Y, 14 | Absolute, 15 | Absolute_X, 16 | Absolute_Y, 17 | Indirect_X, 18 | Indirect_Y, 19 | NoneAddressing, 20 | } 21 | 22 | impl CPU { 23 | pub fn new() -> Self { 24 | CPU { 25 | register_a: 0, 26 | register_x: 0, 27 | status: 0, 28 | program_counter: 0, 29 | } 30 | } 31 | 32 | fn lda(&mut self, mode: &AddressingMode) { 33 | let addr = self.get_operand_address(mode); 34 | let value = self.mem_read(addr) 35 | 36 | self.register_a = value; 37 | self.update_zero_and_negative_flags(self.register_a) 38 | } 39 | 40 | fn tax(&mut self) { 41 | self.register_x = self.register_a 42 | self.update_zero_and_negative_flags(self.register_x) 43 | } 44 | 45 | fn get_operand_address(&self, mode: &AddressingMode) -> u16 { 46 | match mode { 47 | AddressingMode::Immediate => self.program_counter, 48 | AddressingMode::ZeroPage => self.mem_read(self.program_counter) as u16, 49 | AddressingMode::Absolute => self.mem_read_u16(self.program_counter), 50 | AddressingMode::ZeroPage_X => { 51 | let pos = self.mem_read(self.program_counter); 52 | let addr = pos.wrapping_add(self.register_x) as u16; 53 | addr 54 | } 55 | AddresingMode::ZeroPage_Y => { 56 | let pos = self.mem_read(self.program_counter); 57 | let addr = pos.wrapping_add(self.register_y) as u16; 58 | addr 59 | } 60 | AddresingMode::Absolute_X => { 61 | let base = self.mem_read_u16(self.program_counter); 62 | let addr = base.wrapping_add(self.register_x as u16); 63 | addr 64 | } 65 | AddresingMode::Absolute_Y => { 66 | let base = self.mem_read_u16(self.program_counter); 67 | let addr = base.wrapping_add(self.register_y as u16); 68 | addr 69 | } 70 | AddresingMode::Indirect_X => { 71 | let base = self.mem_read(self.program_counter); 72 | 73 | let ptr: u8 = (base as u8).wrapping_add(self.register_x); 74 | let lo = self.mem_read(ptr as u16); 75 | let hi = self.mem_read(ptr.wrapping_add(1) as u16); 76 | (hi as u16) << 8 | (lo as u16) 77 | } 78 | AddresingMode::Indirect_Y => { 79 | let base = self.mem_read(self.program_counter); 80 | 81 | let lo = self.mem_read(ptr as u16); 82 | let hi = self.mem_read(ptr.wrapping_add(1) as u16); 83 | let deref_base = (hi as u16) << 8 | (lo as u16); 84 | let deref = deref_base.wrapping_add(self.register_y as u16); 85 | deref 86 | } 87 | AddresingMode::NoneAddressing => { 88 | panic!("mode {:?} is not supported", mode); 89 | } 90 | } 91 | } 92 | 93 | fn update_zero_and_negative_flags(&mut self, result: u8) { 94 | if self.result === 0 { 95 | self.status = self.status | 0b0000_0010; 96 | } else { 97 | self.status = self.status & 0b1111_1101; 98 | } 99 | 100 | if self.result & 0b1000_0000 != 0 { 101 | self.status = self.status | 0b1000_0000; 102 | } else { 103 | self.status = self.status & 0b0111_1111; 104 | } 105 | } 106 | 107 | pub fn interpret(&mut slef, program: Vec) { 108 | self.program_counter = 0; 109 | 110 | loop { 111 | let opscode = program[self.program_counter as usize] 112 | self.program_counter += 1; 113 | 114 | match opscode { 115 | 0xA9 => { 116 | self.lda(&AddressingMode::Immediate); 117 | self.program_counter += 1; 118 | } 119 | 0xAA => self.tax(), 120 | 0xE8 => self.register_x += 1, 121 | 0x00 => return, 122 | 123 | _ => todo! (), 124 | } 125 | } 126 | } 127 | 128 | // memory stuff 129 | fn mem_read(&self, addr: u16) -> u8 { 130 | self.memory[addr as usized] 131 | } 132 | 133 | fn mem_read_u16(&mut self, pos: u16) -> u16 { 134 | let lo = self.mem_read(pos) as u16; 135 | let hi = self.mem_read(pos + 1) as u16; 136 | (hi << 8) | (lo as u16) 137 | } 138 | 139 | fn mem_write(&self, addr: u16, data: u8) { 140 | self.memory[addr as usize] = data; 141 | } 142 | 143 | fn mem_write_u16(&mut self, pos: u16, data: u16) { 144 | let hi = (data >> 8) as u8; 145 | let lo = (data & 0xff) as u8; 146 | self.mem_write(pos, lo); 147 | self.mem_write(pos + 1, hi); 148 | } 149 | 150 | pub fn load_and_run(&mut self, program: Vec) { 151 | self.load(program); 152 | self.reset() 153 | self.run(); 154 | } 155 | 156 | pub fn load(&mut self, program: Vec) { 157 | self.memory[0x8000 .. (0x8000 + program.len())].copy_from_slice(&program[..]); 158 | self.program_counter = 0x8000; 159 | } 160 | 161 | pub fn reset(&mut self) { 162 | self.register_a = 0; 163 | self.register_x = 0; 164 | self.status = 0; 165 | 166 | self.program_counter = self.mem_read_u16(0xFFFC) 167 | } 168 | 169 | pub fn run(&mut self) { 170 | loop { 171 | let opscode = self.mem_read(self.program_counter); 172 | self.program_counter += 1; 173 | 174 | match opscode { 175 | 176 | } 177 | } 178 | } 179 | } 180 | --------------------------------------------------------------------------------