use crate::CPU::Endian;
use crate::CPU::Mips32::{Mips32Instruction, Mips32RTypeInstruction, Mips32ITypeInstruction, Mips32Register, Mips32InstructionOpcode, Mips32InstructionFunctionCode};
#[derive (Debug, Clone)]
pub struct Mips32Shell
{
endian: Endian,
instructions: Vec<Mips32Instruction>,
}
impl Mips32Shell
{
pub fn New (endian: Endian) -> Self
{
Self
{
endian,
instructions: Vec::new (),
}
}
pub fn Lui (&mut self, rt: Mips32Register, number: u16)
{
self.instructions.push (Mips32Instruction::IType(Mips32ITypeInstruction::New (Mips32InstructionOpcode::LUI, Mips32Register::ZERO, rt, number)));
}
pub fn Ori (&mut self, rt: Mips32Register, rs: Mips32Register, number: u16)
{
self.instructions.push (Mips32Instruction::IType(Mips32ITypeInstruction::New (Mips32InstructionOpcode::ORI, rs, rt, number)));
}
pub fn Or (&mut self, rd: Mips32Register, rt: Mips32Register, rs: Mips32Register)
{
self.instructions.push (Mips32Instruction::RType(Mips32RTypeInstruction::New (Mips32InstructionOpcode::REG, rs, rt, rd, 0, Mips32InstructionFunctionCode::OR)));
}
pub fn Li (&mut self, register: Mips32Register, number: u32)
{
let upperHalf = ((number&0xffff_0000)>>16) as u16;
let lowerHalf = (number&0x0000_ffff) as u16;
self.Lui (register, upperHalf);
self.Ori (register, register, lowerHalf);
}
pub fn Add (&mut self, rd: Mips32Register, rs: Mips32Register, rt: Mips32Register)
{
self.instructions.push (Mips32Instruction::RType(Mips32RTypeInstruction::New (Mips32InstructionOpcode::REG, rs, rt, rd, 0, Mips32InstructionFunctionCode::ADD)));
}
pub fn Addi (&mut self, rt: Mips32Register, rs: Mips32Register, imm: i16)
{
self.instructions.push (Mips32Instruction::IType(Mips32ITypeInstruction::New (Mips32InstructionOpcode::ADDI, rs, rt, imm as u16)))
}
pub fn Addiu (&mut self, rt: Mips32Register, rs: Mips32Register, imm: u16)
{
self.instructions.push (Mips32Instruction::IType(Mips32ITypeInstruction::New (Mips32InstructionOpcode::ADDIU, rs, rt, imm)))
}
pub fn Sub (&mut self, rd: Mips32Register, rs: Mips32Register, rt: Mips32Register)
{
self.instructions.push (Mips32Instruction::RType(Mips32RTypeInstruction::New (Mips32InstructionOpcode::REG, rs, rt, rd, 0, Mips32InstructionFunctionCode::SUB)));
}
pub fn Subu (&mut self, rd: Mips32Register, rs: Mips32Register, rt: Mips32Register)
{
self.instructions.push (Mips32Instruction::RType(Mips32RTypeInstruction::New (Mips32InstructionOpcode::REG, rs, rt, rd, 0, Mips32InstructionFunctionCode::SUBU)));
}
pub fn Subi (&mut self, rt: Mips32Register, rs: Mips32Register, imm: i16)
{
self.instructions.push (Mips32Instruction::IType(Mips32ITypeInstruction::New (Mips32InstructionOpcode::ADDI, rs, rt, -imm as u16)))
}
pub fn Xori (&mut self, rt: Mips32Register, rs: Mips32Register, imm: u16)
{
self.instructions.push (Mips32Instruction::IType(Mips32ITypeInstruction::New (Mips32InstructionOpcode::XORI, rs, rt, imm as u16)))
}
pub fn Mult (&mut self, rs: Mips32Register, rt: Mips32Register)
{
self.instructions.push (Mips32Instruction::RType(Mips32RTypeInstruction::New (Mips32InstructionOpcode::REG, rs, rt, Mips32Register::ZERO, 0, Mips32InstructionFunctionCode::MULT)));
}
pub fn Multu (&mut self, rs: Mips32Register, rt: Mips32Register)
{
self.instructions.push (Mips32Instruction::RType(Mips32RTypeInstruction::New (Mips32InstructionOpcode::REG, rs, rt, Mips32Register::ZERO, 0, Mips32InstructionFunctionCode::MULTU)));
}
pub fn Mfhi (&mut self, rd: Mips32Register)
{
self.instructions.push (Mips32Instruction::RType(Mips32RTypeInstruction::New (Mips32InstructionOpcode::REG, Mips32Register::ZERO, Mips32Register::ZERO, rd, 0, Mips32InstructionFunctionCode::MFHI)));
}
pub fn Mflo (&mut self, rd: Mips32Register)
{
self.instructions.push (Mips32Instruction::RType(Mips32RTypeInstruction::New (Mips32InstructionOpcode::REG, Mips32Register::ZERO, Mips32Register::ZERO, rd, 0, Mips32InstructionFunctionCode::MFLO)));
}
pub fn Lb (&mut self, rt: Mips32Register, rs: Mips32Register, offset: i16)
{
self.instructions.push (Mips32Instruction::IType(Mips32ITypeInstruction::New (Mips32InstructionOpcode::LB, rs, rt, offset as u16)));
}
pub fn Lhu (&mut self, rt: Mips32Register, rs: Mips32Register, offset: i16)
{
self.instructions.push (Mips32Instruction::IType(Mips32ITypeInstruction::New (Mips32InstructionOpcode::LHU, rs, rt, offset as u16)));
}
pub fn Lw (&mut self, rt: Mips32Register, rs: Mips32Register, offset: i16)
{
self.instructions.push (Mips32Instruction::IType(Mips32ITypeInstruction::New (Mips32InstructionOpcode::LW, rs, rt, offset as u16)));
}
pub fn Sh (&mut self, rt: Mips32Register, rs: Mips32Register, offset: i16)
{
self.instructions.push (Mips32Instruction::IType(Mips32ITypeInstruction::New (Mips32InstructionOpcode::SH, rs, rt, offset as u16)));
}
pub fn Sw (&mut self, rt: Mips32Register, rs: Mips32Register, offset: i16)
{
self.instructions.push (Mips32Instruction::IType(Mips32ITypeInstruction::New (Mips32InstructionOpcode::SW, rs, rt, offset as u16)));
}
pub fn Slt (&mut self, rd: Mips32Register, rs: Mips32Register, rt: Mips32Register)
{
self.instructions.push (Mips32Instruction::RType(Mips32RTypeInstruction::New (Mips32InstructionOpcode::REG, rs, rt, rd, 0, Mips32InstructionFunctionCode::SLT)));
}
pub fn Sltu (&mut self, rd: Mips32Register, rs: Mips32Register, rt: Mips32Register)
{
self.instructions.push (Mips32Instruction::RType(Mips32RTypeInstruction::New (Mips32InstructionOpcode::REG, rs, rt, rd, 0, Mips32InstructionFunctionCode::SLTU)));
}
pub fn Slti (&mut self, rt: Mips32Register, rs: Mips32Register, imm: i16)
{
self.instructions.push (Mips32Instruction::IType(Mips32ITypeInstruction::New (Mips32InstructionOpcode::SLTI, rs, rt, imm as u16)));
}
pub fn Sltiu (&mut self, rt: Mips32Register, rs: Mips32Register, imm: u16)
{
self.instructions.push (Mips32Instruction::IType(Mips32ITypeInstruction::New (Mips32InstructionOpcode::SLTIU, rs, rt, imm)));
}
pub fn Bne (&mut self, rs: Mips32Register, rt: Mips32Register, offset: i16)
{
self.instructions.push (Mips32Instruction::IType(Mips32ITypeInstruction::New (Mips32InstructionOpcode::BNE, rs, rt, offset as u16)));
}
pub fn Beq (&mut self, rs: Mips32Register, rt: Mips32Register, offset: i16)
{
self.instructions.push (Mips32Instruction::IType(Mips32ITypeInstruction::New (Mips32InstructionOpcode::BEQ, rs, rt, offset as u16)));
}
pub fn Sync (&mut self)
{
self.instructions.push (Mips32Instruction::RType(Mips32RTypeInstruction::New (Mips32InstructionOpcode::REG, Mips32Register::T9, Mips32Register::T9, Mips32Register::T9, 0, Mips32InstructionFunctionCode::SYNC)));
}
pub fn Syscall (&mut self, imm: usize)
{
let imm = imm&0xfffff;
let rs = ((imm&0b11111_00000_00000_00000)>>15).try_into ().unwrap ();
let rt = ((imm&0b00000_11111_00000_00000)>>10).try_into ().unwrap ();
let rd = ((imm&0b00000_00000_11111_00000)>>5).try_into ().unwrap ();
let shamt = (imm&0b00000_00000_00000_11111).try_into ().unwrap ();
self.instructions.push (Mips32Instruction::RType(Mips32RTypeInstruction::New (Mips32InstructionOpcode::REG, rs, rt, rd, shamt, Mips32InstructionFunctionCode::SYSCALL)));
}
pub fn PushU32 (&mut self, value: u32)
{
self.Subi (Mips32Register::SP, Mips32Register::SP, 8);
self.Sw (Mips32Register::T0, Mips32Register::SP, 0);
self.Li (Mips32Register::T0, value);
self.Sw (Mips32Register::T0, Mips32Register::SP, 4);
self.Addi (Mips32Register::SP, Mips32Register::SP, 4);
}
pub fn PushU64 (&mut self, value: u64)
{
match self.endian
{
Endian::BIG => self.PushByteArray (&value.to_be_bytes ()),
Endian::LITTLE => self.PushByteArray (&value.to_le_bytes ()),
};
}
pub fn PushU128 (&mut self, value: u128)
{
match self.endian
{
Endian::BIG => self.PushByteArray (&value.to_be_bytes ()),
Endian::LITTLE => self.PushByteArray (&value.to_le_bytes ()),
};
}
pub fn PushByteArray (&mut self, data: &[u8]) -> usize
{
let mut data = data.to_vec ();
let paddingLen = ((data.len () + 8 - 1)/8)*8 - data.len ();
data.append (&mut vec! [0u8; paddingLen]);
self.Subi (Mips32Register::SP, Mips32Register::SP, (8 + data.len ()).try_into ().unwrap ());
self.Sw (Mips32Register::T0, Mips32Register::SP, 0);
for i in (0..data.len ()).step_by (4).rev ()
{
let num = match self.endian
{
Endian::BIG => u32::from_be_bytes (data[i..i + 4].try_into ().unwrap ()),
Endian::LITTLE => u32::from_le_bytes (data[i..i + 4].try_into ().unwrap ()),
};
self.Li (Mips32Register::T0, num);
self.Sw (Mips32Register::T0, Mips32Register::SP, (8 + i).try_into ().unwrap ());
}
self.Lw (Mips32Register::T0, Mips32Register::SP, 0);
self.Addi (Mips32Register::SP, Mips32Register::SP, 8);
data.len ()
}
pub fn PushString (&mut self, string: &str) -> usize
{
let mut tmp = string.as_bytes ().to_vec ();
tmp.push (0); self.PushByteArray (&tmp)
}
pub fn GetLabel (&self) -> usize
{
self.instructions.len ()
}
pub fn BeqLabel (&mut self, rs: Mips32Register, rt: Mips32Register, label: usize)
{
let offset = label as isize - (self.instructions.len () as isize + 1);
self.Beq (rs, rt, offset as i16);
}
pub fn BneLabel (&mut self, rs: Mips32Register, rt: Mips32Register, label: usize)
{
let offset = label as isize - (self.instructions.len () as isize + 1);
self.Bne (rs, rt, offset as i16);
}
pub fn ToByteArray (&self) -> Vec<u8>
{
let mut result = Vec::new ();
for instruction in &self.instructions
{
result.append (&mut instruction.ToByteArray (self.endian));
}
result
}
pub fn ToAssemblySource (&self) -> String
{
let mut result = String::new ();
for instruction in &self.instructions
{
result.push_str (&instruction.ToAssemblySource ());
}
result
}
}