<commit_before>
use std::fmt;

use opcode::{Opcode, OpcodeError, SetRegMode};

const PROGRAM_START: u16 = 0x200;

const MEMORY_SIZE: usize = 4096;
const REGISTER_COUNT: usize = 16;

pub enum RuntimeError {
    EmptyCallStack,
    InvalidRegister(u8),
    AddressOutOfBounds(u16),
    OpcodeErr(OpcodeError),
}

pub struct Chip8 {
    memory: [u8; MEMORY_SIZE],
    regs: [u8; REGISTER_COUNT], // registers V0 - V15
    addressReg: u16, // register I

    pc: u16,
    // Stores the program counters of sub routine calls, used to return after a sub routine ends
    stack: Vec<u16>,

    screen: [[bool; 64]; 32],
}

impl Chip8 {
    pub fn new() -> Chip8 {
        Chip8 {
            memory: [0; 4096],
            regs: [0; 16],
            addressReg: 0,
            
            pc: PROGRAM_START,
            stack: Vec::new(),

            screen: [[false; 64]; 32],
        }
    }

    pub fn cycle(&mut self) -> Result<(), RuntimeError> {
        use self::RuntimeError::*;
        use opcode::Opcode::*;

        let pc_index = self.pc as usize;
        let opcode_bytes = (self.memory[pc_index] as u16) << 8 | (self.memory[pc_index + 1] as u16);

        let opcode = match Opcode::from_u16(opcode_bytes) {
            Ok(opcode) => opcode,
            Err(err) => return Err(OpcodeErr(err)),
        };

        match opcode { 
            ClearScreen => self.clear_screen(),
            Return => {
                self.pc = match self.stack.pop() {
                    Some(addr) => addr,
                    None => return Err(EmptyCallStack),
                };
            },

            JumpTo { addr, plus_v0 } => {
                self.pc = addr;

                if plus_v0 { 
                    self.pc += self.regs[0] as u16; 
                }
            },
            Call(addr) => {
                self.stack.push(self.pc);
                self.pc = addr;
            },

            SkipIfRegEqualConst { not_equal, reg, value } => {
                let mut should_jump = self.regs[reg as usize] == value;

                if not_equal {
                    should_jump = !should_jump; // Effectively computes self.regs[reg] != value
                }

                if should_jump {
                    self.pc += 4;
                    return Ok(());
                }
            },
            SkipIfRegsEqual { not_equal, regs: (v_x, v_y) } => {
                let mut should_jump = self.regs[v_x as usize] == self.regs[v_y as usize];

                if not_equal {
                    should_jump = !should_jump;
                }

                if should_jump {
                    self.pc += 4;
                    return Ok(());
                }
            },

            SetRegToConst { add, reg, value } => {
                if add {
                    self.regs[reg as usize] += value;
                } else {
                    self.regs[reg as usize] = value;
                }
            },
            SetRegToReg { regs: (v_x, v_y), mode } => {
                let v_x = v_x as usize;
                let v_y = v_y as usize;

                match mode {
                    SetRegMode::Copy => {
                        self.regs[v_x] = self.regs[v_y];
                    },
                    SetRegMode::Or => {
                        self.regs[v_x] |= self.regs[v_y];
                    },
                    SetRegMode::And => {
                        self.regs[v_x] &= self.regs[v_y];
                    },
                    SetRegMode::Xor => {
                        self.regs[v_x] ^= self.regs[v_y];
                    },

                    SetRegMode::Add => {
                        let reg_value = self.regs[v_x] as usize + self.regs[v_y] as usize;
                        if reg_value > 255 {
                            reg_value -= 255;
                            self.regs[0xF] = 1;
                        }

                        self.regs[v_x] = reg_value as u8;
                    },
                    SetRegMode::Subtract | SetRegMode::InverseSubtract => {
                        let reg_value = if let SetRegMode::Subtract = mode {
                            self.regs[v_x] as isize - self.regs[v_y] as isize;
                        else { // Must be InverseSubtract
                            self.regs[v_y] as isize - self.regs[v_x] as isize;
                        };

                        if reg_value < 0 {
                            reg_value += 255;
                            self.regs[0xF] = 1;
                        }

                        self.regs[v_x] = reg_value as u8;
                    },
                    SetRegMode::InverseSubtract => {

                    },

                    SetRegMode::ShiftLeft => {

                    },
                    SetRegMode::ShiftRight => {

                    }
                }
            },
            _ => unreachable!(),
        }

        self.pc += 2;

        Ok(())
    }

    pub fn clear_screen(&mut self) {
        for row in self.screen.iter_mut() {
            for col in row.iter_mut() {
                *col = false;
            }
        }
    }
}

impl fmt::<commit_msg>Formatting fixes<commit_after>
use std::fmt;

use opcode::{Opcode, OpcodeError, SetRegMode};

const PROGRAM_START: u16 = 0x200;

const MEMORY_SIZE: usize = 4096;
const REGISTER_COUNT: usize = 16;

pub enum RuntimeError {
    EmptyCallStack,
    InvalidRegister(u8),
    AddressOutOfBounds(u16),
    OpcodeErr(OpcodeError),
}

pub struct Chip8 {
    memory: [u8; MEMORY_SIZE],
    regs: [u8; REGISTER_COUNT], // registers V0 - V15
    addressReg: u16, // register I

    pc: u16,
    // Stores the program counters of sub routine calls, used to return after a sub routine ends
    stack: Vec<u16>,

    screen: [[bool; 64]; 32],
}

impl Chip8 {
    pub fn new() -> Chip8 {
        Chip8 {
            memory: [0; 4096],
            regs: [0; 16],
            addressReg: 0,
            
            pc: PROGRAM_START,
            stack: Vec::new(),

            screen: [[false; 64]; 32],
        }
    }

    pub fn cycle(&mut self) -> Result<(), RuntimeError> {
        use self::RuntimeError::*;
        use opcode::Opcode::*;

        let pc_index = self.pc as usize;
        let opcode_bytes = (self.memory[pc_index] as u16) << 8 | (self.memory[pc_index + 1] as u16);

        let opcode = match Opcode::from_u16(opcode_bytes) {
            Ok(opcode) => opcode,
            Err(err) => return Err(OpcodeErr(err)),
        };

        match opcode { 
            ClearScreen => self.clear_screen(),
            Return => {
                self.pc = match self.stack.pop() {
                    Some(addr) => addr,
                    None => return Err(EmptyCallStack),
                };
            },

            JumpTo { addr, plus_v0 } => {
                self.pc = addr;

                if plus_v0 { 
                    self.pc += self.regs[0] as u16; 
                }
            },
            Call(addr) => {
                self.stack.push(self.pc);
                self.pc = addr;
            },

            SkipIfRegEqualConst { not_equal, reg, value } => {
                let mut should_jump = self.regs[reg as usize] == value;

                if not_equal {
                    should_jump = !should_jump; // Effectively computes self.regs[reg] != value
                }

                if should_jump {
                    self.pc += 4;
                    return Ok(());
                }
            },
            SkipIfRegsEqual { not_equal, regs: (v_x, v_y) } => {
                let mut should_jump = self.regs[v_x as usize] == self.regs[v_y as usize];

                if not_equal {
                    should_jump = !should_jump;
                }

                if should_jump {
                    self.pc += 4;
                    return Ok(());
                }
            },

            SetRegToConst { add, reg, value } => {
                if add {
                    self.regs[reg as usize] += value;
                } else {
                    self.regs[reg as usize] = value;
                }
            },
            SetRegToReg { regs: (v_x, v_y), mode } => {
                let v_x = v_x as usize;
                let v_y = v_y as usize;

                match mode {
                    SetRegMode::Copy => self.regs[v_x] = self.regs[v_y],
                    
                    SetRegMode::Or => self.regs[v_x] |= self.regs[v_y],
                    SetRegMode::And => self.regs[v_x] &= self.regs[v_y],
                    SetRegMode::Xor => self.regs[v_x] ^= self.regs[v_y],

                    SetRegMode::Add => {
                        let reg_value = self.regs[v_x] as usize + self.regs[v_y] as usize;
                        if reg_value > 255 {
                            reg_value -= 255;
                            self.regs[0xF] = 1;
                        }

                        self.regs[v_x] = reg_value as u8;
                    },
                    SetRegMode::Subtract | SetRegMode::InverseSubtract => {
                        let reg_value = if let SetRegMode::Subtract = mode {
                            self.regs[v_x] as isize - self.regs[v_y] as isize;
                        else { // Must be InverseSubtract
                            self.regs[v_y] as isize - self.regs[v_x] as isize;
                        };

                        if reg_value < 0 {
                            reg_value += 255;
                            self.regs[0xF] = 1;
                        }

                        self.regs[v_x] = reg_value as u8;
                    },

                    // v_y is ignored for the shift opcodes, not sure why
                    SetRegMode::ShiftLeft => {
                        self.regs[0xF] = self.regs[v_x] & 0xF0 >> 8;
                        self.regs[v_x] <<= 1; 
                    },
                    SetRegMode::ShiftRight => {
                        self.regs[0xF] = self.regs[v_x] & 0x0F;
                        self.regs[v_x] >>= 1; 
                    }
                }
            },
            _ => unreachable!(),
        }

        self.pc += 2;

        Ok(())
    }

    pub fn clear_screen(&mut self) {
        for row in self.screen.iter_mut() {
            for col in row.iter_mut() {
                *col = false;
            }
        }
    }
}

impl fmt::Debug for Chip8 {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "Register Contents: {:?}", self.regs);
    }
}
{'fraction_non_alphanumeric': 0.11116380536849094, 'fraction_numerical': 0.015934743431660816, 'mean_word_length': 1.054960046774508, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7099345', 'n_tokens_mistral': 3252, 'n_tokens_neox': 2948, 'n_words': 676}