Skip to content
Snippets Groups Projects
cpu.rs 4.99 KiB
Newer Older
  • Learn to ignore specific revisions
  • pub const RAM_SIZE: usize = 8192;
    
    
    pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 11] = [
    
        // 0x0 opcodes
        (nop, 4, "NOP"),
        (ld_bc_u16, 12, "LD BC, NN"),
    
        (ld_mbc_a, 8, "LD [BC], A"),
        (inc_bc, 8, "INC BC"),
        (inc_b, 4, "INC B"),
        (dec_b, 4, "DEC B"),
        (ld_b_u8, 8, "LD B, N"),
        (rlca, 4, "RLCA"),
        (ld_mu16_sp, 20, "LD [u16], SP"),
        (add_hl_bc, 8, "ADD HL, BC"),
    
        // 0x2 opcodes
        (ld_sp_u16, 12, "LD SP, NN"),
    ];
    
    pub struct Cpu {
    
    João Magalhães's avatar
    João Magalhães committed
        pc: u16,
        sp: u16,
    
        a: u8,
        b: u8,
        c: u8,
        d: u8,
        e: u8,
        h: u8,
        l: u8,
        zero: bool,
        sub: bool,
        half_carry: bool,
        carry: bool,
    
        ram: [u8; RAM_SIZE],
    
    João Magalhães's avatar
    João Magalhães committed
    }
    
    impl Cpu {
    
        pub fn new() -> Cpu {
            Cpu {
                pc: 0x0,
                sp: 0x0,
    
                a: 0x0,
                b: 0x0,
                c: 0x0,
                d: 0x0,
                e: 0x0,
                h: 0x0,
                l: 0x0,
                zero: false,
                sub: false,
                half_carry: false,
                carry: false,
    
                ram: [0u8; RAM_SIZE],
            }
        }
    
        pub fn clock(&mut self) {
            // fetches the current instruction and increments
            // the PC (program counter) accordingly
    
            let _instruction = self.ram[self.pc as usize];
    
    João Magalhães's avatar
    João Magalhães committed
        #[inline(always)]
    
        fn af(&self) -> u16 {
            (self.a as u16) << 8 | self.f() as u16
    
    João Magalhães's avatar
    João Magalhães committed
        }
    
        #[inline(always)]
    
        fn bc(&self) -> u16 {
            (self.b as u16) << 8 | self.c as u16
    
    João Magalhães's avatar
    João Magalhães committed
        }
    
        #[inline(always)]
    
        fn f(&self) -> u8 {
            let mut f = 0x0u8;
            if self.zero {
                f |= 0x80;
            }
            if self.sub {
                f |= 0x40;
            }
            if self.half_carry {
                f |= 0x20;
            }
            if self.carry {
                f |= 0x10;
            }
            f
        }
    
        #[inline(always)]
        fn set_bc(&mut self, value: u16) {
            self.b = (value >> 8) as u8;
            self.c = value as u8;
        }
    
        #[inline(always)]
        fn de(&self) -> u16 {
            (self.d as u16) << 8 | self.e as u16
        }
    
        #[inline(always)]
        fn set_de(&mut self, value: u16) {
            self.d = (value >> 8) as u8;
            self.e = value as u8;
    
    João Magalhães's avatar
    João Magalhães committed
        }
    
        #[inline(always)]
    
        fn hl(&self) -> u16 {
            (self.h as u16) << 8 | self.l as u16
        }
    
        #[inline(always)]
        fn set_hl(&mut self, value: u16) {
            self.h = (value >> 8) as u8;
            self.l = value as u8;
    
    João Magalhães's avatar
    João Magalhães committed
        }
    
        #[inline(always)]
    
        fn read_u8(&mut self) -> u8 {
            let byte = self.ram[self.pc as usize];
    
            self.pc = self.pc.wrapping_add(1);
    
            byte
        }
    
        #[inline(always)]
        fn read_u16(&mut self) -> u16 {
    
            let byte1 = self.read_u8();
            let byte2 = self.read_u8();
            let word = byte1 as u16 | ((byte2 as u16) << 8);
    
            word
        }
    
        #[inline(always)]
        fn get_zero(&self) -> bool {
    
            self.zero
        }
    
        #[inline(always)]
        fn set_zero(&mut self, value: bool) {
            self.zero = value
    
    João Magalhães's avatar
    João Magalhães committed
        }
    
        #[inline(always)]
    
        fn get_sub(&self) -> bool {
    
            self.sub
        }
    
        #[inline(always)]
        fn set_sub(&mut self, value: bool) {
            self.sub = value;
    
    João Magalhães's avatar
    João Magalhães committed
        }
    
        #[inline(always)]
    
        fn get_half_carry(&self) -> bool {
    
            self.half_carry
        }
    
        #[inline(always)]
        fn set_half_carry(&mut self, value: bool) {
            self.half_carry = value
    
    João Magalhães's avatar
    João Magalhães committed
        }
    
        #[inline(always)]
    
        fn get_carry(&self) -> bool {
    
            self.carry
        }
    
        #[inline(always)]
        fn set_carry(&mut self, value: bool) {
            self.carry = value;
    
    João Magalhães's avatar
    João Magalhães committed
        }
    
    
    fn nop(_cpu: &mut Cpu) {}
    
    fn ld_bc_u16(cpu: &mut Cpu) {
    
        let word = cpu.read_u16();
        cpu.set_bc(word);
    }
    
    fn ld_mbc_a(cpu: &mut Cpu) {
        cpu.ram[cpu.bc() as usize] = cpu.a;
    }
    
    fn inc_bc(cpu: &mut Cpu) {
        cpu.set_bc(cpu.bc().wrapping_add(1));
    
    fn inc_b(cpu: &mut Cpu) {
        let value = cpu.b.wrapping_add(1);
    
        cpu.set_sub(false);
        cpu.set_zero(value == 0);
        cpu.set_half_carry((value & 0xf) == 0xf);
    
        cpu.b = value;
    }
    
    fn dec_b(cpu: &mut Cpu) {
        let value = cpu.b.wrapping_sub(1);
    
        cpu.set_sub(true);
        cpu.set_zero(value == 0);
        cpu.set_half_carry((value & 0xf) == 0xf);
    
        cpu.b = value;
    }
    
    fn ld_b_u8(cpu: &mut Cpu) {
        let byte = cpu.read_u8();
        cpu.b = byte;
    }
    
    fn rlca(cpu: &mut Cpu) {
        let carry = cpu.a >> 7;
    
        cpu.a = cpu.a << 1 | carry;
    
        cpu.set_sub(false);
        cpu.set_zero(false);
        cpu.set_half_carry(false);
        cpu.set_carry(carry == 1);
    }
    
    fn ld_mu16_sp(cpu: &mut Cpu) {
        let word = cpu.read_u16();
        cpu.ram[word as usize] = cpu.sp as u8;
        cpu.ram[word as usize + 1] = (cpu.sp >> 8) as u8;
    }
    
    fn add_hl_bc(cpu: &mut Cpu) {
    
        let value = add_u16_u16(cpu, cpu.hl(), cpu.bc());
        cpu.set_hl(value);
    
    }
    
    fn ld_sp_u16(cpu: &mut Cpu) {
        cpu.sp = cpu.read_u16();
    }
    
    
    fn add_u16_u16(cpu: &mut Cpu, first: u16, second: u16) -> u16 {
        let first = first as u32;
        let second = second as u32;
        let value = first.wrapping_add(second);
    
        cpu.set_sub(false);
        cpu.set_carry(value & 0x1000 == 0x1000);
        cpu.set_half_carry((first ^ second ^ value) & 0x1000 == 0x1000);
    
        value as u16
    }