melon 0.12.0

A library for creating retro computing platforms
Documentation
#![allow(missing_docs)]

use rand::{
    distributions::{Distribution, Standard}, Rng,
};
use typedef::*;

#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum Instruction {
    Add(IntegerType),
    Sub(IntegerType),
    Mul(IntegerType),
    Div(IntegerType),
    Shr(IntegerType),
    Shl(IntegerType),
    And(IntegerType),
    Or(IntegerType),
    Xor(IntegerType),
    Not(IntegerType),
    Neg(IntegerType),
    Cmp(IntegerType),
    Inc(IntegerType),
    Dec(IntegerType),

    U8Promote,
    U16Demote,
    I8Promote,
    I16Demote,

    PushConstU8(u8),
    PushConstU16(u16),
    PushConstI8(i8),
    PushConstI16(i16),

    LoadReg(Register),

    Load(IntegerType, Address),
    LoadIndirect(IntegerType),
    Store(IntegerType, Address),
    StoreIndirect(IntegerType),

    Dup(IntegerType),
    Drop(IntegerType),

    SysCall(u16),

    Call(Address),
    Ret,

    Alloc(u16),
    Free,

    Jmp(bool, u16),
    Jeq(bool, u16),
    Jneq(bool, u16),
    Jlt(bool, u16),
    JltEq(bool, u16),
    Jgt(bool, u16),
    JgtEq(bool, u16),
}

impl Distribution<Instruction> for Standard {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Instruction {
        let choice: u8 = rng.gen_range(0, 41);

        match choice {
            0 => Instruction::Add(rng.gen()),
            1 => Instruction::Sub(rng.gen()),
            2 => Instruction::Mul(rng.gen()),
            3 => Instruction::Div(rng.gen()),
            4 => Instruction::Shr(rng.gen()),
            5 => Instruction::Shl(rng.gen()),
            6 => Instruction::And(rng.gen()),
            7 => Instruction::Or(rng.gen()),
            8 => Instruction::Xor(rng.gen()),
            9 => Instruction::Not(rng.gen()),
            10 => Instruction::Neg(rng.gen()),
            11 => Instruction::Cmp(rng.gen()),
            12 => Instruction::Inc(rng.gen()),
            13 => Instruction::Dec(rng.gen()),
            14 => Instruction::U8Promote,
            15 => Instruction::U16Demote,
            16 => Instruction::I8Promote,
            17 => Instruction::I16Demote,
            18 => Instruction::PushConstU8(rng.gen()),
            19 => Instruction::PushConstU16(rng.gen()),
            20 => Instruction::PushConstI8(rng.gen()),
            21 => Instruction::PushConstI16(rng.gen()),
            22 => Instruction::LoadReg(rng.gen()),
            23 => Instruction::Load(rng.gen(), rng.gen()),
            24 => Instruction::LoadIndirect(rng.gen()),
            25 => Instruction::Store(rng.gen(), rng.gen()),
            26 => Instruction::StoreIndirect(rng.gen()),
            27 => Instruction::Dup(rng.gen()),
            28 => Instruction::Drop(rng.gen()),
            29 => Instruction::SysCall(rng.gen()),
            30 => Instruction::Call(rng.gen()),
            31 => Instruction::Ret,
            32 => Instruction::Alloc(rng.gen()),
            33 => Instruction::Free,
            34 => Instruction::Jmp(rng.gen(), rng.gen()),
            35 => Instruction::Jneq(rng.gen(), rng.gen()),
            36 => Instruction::Jeq(rng.gen(), rng.gen()),
            37 => Instruction::Jlt(rng.gen(), rng.gen()),
            38 => Instruction::JltEq(rng.gen(), rng.gen()),
            39 => Instruction::Jgt(rng.gen(), rng.gen()),
            40 => Instruction::JgtEq(rng.gen(), rng.gen()),
            _ => unreachable!(),
        }
    }
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum IntegerType {
    U8,
    U16,
    I8,
    I16,
}

impl Distribution<IntegerType> for Standard {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> IntegerType {
        let choice: u8 = rng.gen_range(0, 4);

        match choice {
            0 => IntegerType::U8,
            1 => IntegerType::U16,
            2 => IntegerType::I8,
            3 => IntegerType::I16,
            _ => unreachable!(),
        }
    }
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum Register {
    StackPtr,
    BasePtr,
}

impl Distribution<Register> for Standard {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Register {
        let choice: u8 = rng.gen_range(0, 2);

        match choice {
            0 => Register::StackPtr,
            1 => Register::BasePtr,
            _ => unreachable!(),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn instruction_size() {
        let size = ::std::mem::size_of::<Instruction>();

        assert_eq!(size, 4);
    }

    #[test]
    fn register_size() {
        let size = ::std::mem::size_of::<Register>();

        assert_eq!(size, 1);
    }

    #[test]
    fn type_size() {
        let size = ::std::mem::size_of::<IntegerType>();

        assert_eq!(size, 1);
    }
}