maikor-vm-core 0.1.15

VM for playing Maikor games
Documentation
use crate::VM;

impl VM {
    pub fn cpy_reg_num_byte(&mut self) -> usize {
        let dst = self.read_arg_register();
        let src = self.read_arg_byte();
        let (offset, offset_cost) = self.pre_process(&dst, 1);
        let write_cost = self.write_byte_reg(&dst, offset, src);
        offset_cost + write_cost + self.post_process(&dst, 1)
    }

    pub fn cpy_reg_reg_byte(&mut self) -> usize {
        let dst = self.read_arg_register();
        let src = self.read_arg_register();
        let (dst_offset, dst_offset_cost) = self.pre_process(&dst, 1);
        let (src_offset, src_offset_cost) = self.pre_process(&src, 1);
        let (src_value, read_cost) = self.read_byte_reg(&src, src_offset);
        let write_cost = self.write_byte_reg(&dst, dst_offset, src_value);
        dst_offset_cost + write_cost + src_offset_cost + read_cost + self.post_process(&dst, 1)
    }

    pub fn cpy_reg_addr_byte(&mut self) -> usize {
        let dst = self.read_arg_register();
        let src = self.read_arg_word();
        let (offset, offset_cost) = self.pre_process(&dst, 1);
        let (src_value, read_cost) = self.read_byte_mem(src);
        let write_cost = self.write_byte_reg(&dst, offset, src_value);
        offset_cost + write_cost + read_cost + self.post_process(&dst, 1)
    }

    pub fn cpy_reg_num_word(&mut self) -> usize {
        let dst = self.read_arg_register();
        let src = self.read_arg_word();
        let (offset, offset_cost) = self.pre_process(&dst, 2);
        let write_cost = self.write_word_reg(&dst, offset, src);
        offset_cost + write_cost + self.post_process(&dst, 2)
    }

    pub fn cpy_reg_reg_word(&mut self) -> usize {
        let dst = self.read_arg_register();
        let src = self.read_arg_register();
        let (dst_offset, dst_offset_cost) = self.pre_process(&dst, 2);
        let (src_offset, src_offset_cost) = self.pre_process(&src, 2);
        let (src_value, read_cost) = self.read_word_reg(&src, src_offset);
        let write_cost = self.write_word_reg(&dst, dst_offset, src_value);
        dst_offset_cost + write_cost + src_offset_cost + read_cost + self.post_process(&dst, 2)
    }

    pub fn cpy_reg_addr_word(&mut self) -> usize {
        let dst = self.read_arg_register();
        let src = self.read_arg_word();
        let (offset, offset_cost) = self.pre_process(&dst, 2);
        let (src_value, read_cost) = self.read_word_mem(src);
        let write_cost = self.write_word_reg(&dst, offset, src_value);
        offset_cost + write_cost + read_cost + self.post_process(&dst, 2)
    }

    pub fn cpy_addr_num_byte(&mut self) -> usize {
        let dst = self.read_arg_word();
        let src = self.read_arg_byte();
        self.write_byte_mem(dst, src)
    }

    pub fn cpy_addr_addr_byte(&mut self) -> usize {
        let dst = self.read_arg_word();
        let src = self.read_arg_word();
        let (src_value, read_cost) = self.read_byte_mem(src);
        let write_cost = self.write_byte_mem(dst, src_value);
        write_cost + read_cost
    }

    pub fn cpy_addr_reg_byte(&mut self) -> usize {
        let dst = self.read_arg_word();
        let src = self.read_arg_register();
        let (offset, offset_cost) = self.pre_process(&src, 1);
        let (src_value, read_cost) = self.read_byte_reg(&src, offset);
        let write_cost = self.write_byte_mem(dst, src_value);
        write_cost + read_cost + offset_cost + self.post_process(&src, 1)
    }

    pub fn cpy_addr_num_word(&mut self) -> usize {
        let dst = self.read_arg_word();
        let src = self.read_arg_word();
        self.write_word_mem(dst, src)
    }

    pub fn cpy_addr_addr_word(&mut self) -> usize {
        let dst = self.read_arg_word();
        let src = self.read_arg_word();
        let (src_value, read_cost) = self.read_word_mem(src);
        let write_cost = self.write_word_mem(dst, src_value);
        write_cost + read_cost
    }

    pub fn cpy_addr_reg_word(&mut self) -> usize {
        let dst = self.read_arg_word();
        let src = self.read_arg_register();
        let (offset, offset_cost) = self.pre_process(&src, 2);
        let (src_value, read_cost) = self.read_word_reg(&src, offset);
        let write_cost = self.write_word_mem(dst, src_value);
        write_cost + offset_cost + read_cost + self.post_process(&src, 2)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::ops::test::check_cycles;
    use maikor_platform::op_params::*;
    use maikor_platform::registers::id;

    #[test]
    fn test_costs() {
        check_cycles(&[id::AL as u8, 10], 1, VM::cpy_reg_num_byte);
        check_cycles(&[id::AL as u8, id::AH as u8], 2, VM::cpy_reg_reg_byte);
        check_cycles(&[id::AL as u8, 0, 0], 2, VM::cpy_reg_addr_byte);
        check_cycles(&[0, 0, 10], 1, VM::cpy_addr_num_byte);
        check_cycles(&[3, 4, id::CH as u8], 2, VM::cpy_addr_reg_byte);
        check_cycles(&[1, 2, 3, 4], 2, VM::cpy_addr_addr_byte);
        check_cycles(&[id::AX as u8, 10], 2, VM::cpy_reg_num_word);
        check_cycles(&[id::AL as u8, id::BX as u8], 4, VM::cpy_reg_reg_word);
        check_cycles(&[id::AX as u8, 10, 1], 4, VM::cpy_reg_addr_word);
        check_cycles(&[9, 9, 10], 2, VM::cpy_addr_num_word);
        check_cycles(&[1, 2, id::CX as u8], 4, VM::cpy_addr_reg_word);
        check_cycles(&[6, 7, 8, 9], 4, VM::cpy_addr_addr_word);

        check_cycles(
            &[id::CX as u8 | INDIRECT, id::AH as u8],
            4,
            VM::cpy_reg_reg_byte,
        );
        check_cycles(
            &[id::AL as u8 | IND_OFFSET_REG, 0, 0, 0],
            5,
            VM::cpy_reg_addr_byte,
        );
        check_cycles(
            &[id::AX as u8 | IND_PRE_DEC, 10, 1],
            8,
            VM::cpy_reg_addr_word,
        );
    }
}