Add memory and registers implementations
authorGreg Burri <greg.burri@gmail.com>
Sat, 10 Sep 2022 17:42:18 +0000 (19:42 +0200)
committerGreg Burri <greg.burri@gmail.com>
Sat, 10 Sep 2022 17:42:18 +0000 (19:42 +0200)
ch5-data-in-depth/src/chip8.rs

index 2b6d1a4..77c7363 100644 (file)
@@ -6,52 +6,84 @@
 /// 4) Opcode subgroup (d) / Number of bytes (n). / Integer (kk) / Memory address (nnn).
 
 struct CPU {
-    registers: [u8; 16],
-    position_in_memory: usize,
+    registers: [u8; 16], // 4 bits can address a 16 positions register. The last position (0xF) is used to indicate an overflow.
+    position_in_memory: usize, // Programm counter.
     memory: [u8; 0x1000], // 4 KB of memory.
 }
 
 impl CPU {
+    fn new() -> CPU {
+        CPU {
+            registers: [0; 16],
+            position_in_memory: 0,
+            memory: [0; 0x1000],
+        }
+    }
+
     fn read_opcode(&self) -> u16 {
-        self.current_operation
+        let p = self.position_in_memory;
+        let op_byte1 = self.memory[p] as u16;
+        let op_byte2 = self.memory[p + 1] as u16;
+        op_byte1 << 8 | op_byte2
     }
 
     fn run(&mut self) {
-        // loop {
+        loop {
             let opcode = self.read_opcode();
+            self.position_in_memory += 2;
+
             let c = ((opcode & 0xF000) >> 12) as u8;
             let x = ((opcode & 0x0F00) >>  8) as u8;
             let y = ((opcode & 0x00F0) >>  4) as u8;
             let d = ((opcode & 0x000F) >>  0) as u8;
 
             match (c, x, y, d) {
+                (0, 0, 0, 0) => { return; }
                 (0x8, _, _, 0x4) => self.add_xy(x, y),
                 _ => todo!("opcode: {:04x}", opcode),
             }
-        //}
+        }
     }
 
     fn add_xy(&mut self, x: u8, y: u8) {
-        self.registers[x as usize] += self.registers[y as usize];
+        let arg1 = self.registers[x as usize];
+        let arg2 = self.registers[y as usize];
+
+        let (val, overflow) = arg1.overflowing_add(arg2);
+        self.registers[x as usize] = val;
+
+        if overflow {
+            self.registers[0xF] = 1;
+        } else {
+            self.registers[0xF] = 0;
+        }
     }
 }
 
 mod tests {
     use super::*;
 
+    /// 5 + 10 + 10 + 10 = 35. (three operations).
     #[test]
     fn addition() {
-        let mut cpu = CPU {
-            current_operation: 0,
-            registers: [0; 2]
-        };
+        let mut cpu = CPU::new();
+
+        cpu.memory[0] = 0x80;
+        cpu.memory[1] = 0x14;
+
+        cpu.memory[2] = 0x80;
+        cpu.memory[3] = 0x24;
+
+        cpu.memory[4] = 0x80;
+        cpu.memory[5] = 0x34;
 
-        cpu.current_operation = 0x8014;
         cpu.registers[0] = 5;
         cpu.registers[1] = 10;
+        cpu.registers[2] = 10;
+        cpu.registers[3] = 10;
 
         cpu.run();
 
-        assert_eq!(cpu.registers[0], 15);
+        assert_eq!(cpu.registers[0], 35);
     }
 }
\ No newline at end of file