Files
performance_aware_programming/sim_8086/src/logic_instruction.rs
Patrick Stevens c2d09452b3 Count clocks (#19)
2023-05-10 23:09:39 +01:00

131 lines
3.8 KiB
Rust

use crate::effective_address::EffectiveAddress;
use crate::register::Register;
use arbitrary::Arbitrary;
use std::fmt::{Display, Formatter};
#[derive(Eq, PartialEq, Debug, Hash, Clone, Arbitrary)]
pub enum LogicInstructionType {
Not,
Shl,
Shr,
Sar,
Rol,
Ror,
Rcl,
Rcr,
}
impl Display for LogicInstructionType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
LogicInstructionType::Not => "not",
LogicInstructionType::Shl => "shl",
LogicInstructionType::Shr => "shr",
LogicInstructionType::Sar => "sar",
LogicInstructionType::Rol => "rol",
LogicInstructionType::Ror => "ror",
LogicInstructionType::Rcl => "rcl",
LogicInstructionType::Rcr => "rcr",
})
}
}
#[derive(Eq, PartialEq, Debug, Hash, Clone, Arbitrary)]
pub enum LogicTarget {
Address(EffectiveAddress),
Register(Register),
}
impl Display for LogicTarget {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
LogicTarget::Address(addr) => f.write_fmt(format_args!("{}", addr)),
LogicTarget::Register(reg) => f.write_fmt(format_args!("{}", reg)),
}
}
}
#[derive(Eq, PartialEq, Debug, Hash, Clone, Arbitrary)]
pub struct LogicInstruction {
pub op: LogicInstructionType,
pub amount_from_cl: bool,
pub target: LogicTarget,
pub is_wide: bool,
}
impl Display for LogicInstruction {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!(
"{} {}, {}",
self.op,
self.target,
if self.amount_from_cl { "cl" } else { "1" }
))
}
}
impl LogicInstruction {
pub fn length(&self) -> u8 {
match &self.target {
LogicTarget::Register(_) => 2,
LogicTarget::Address(addr) => 1 + addr.length(),
}
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut result = Vec::new();
let byte = match self.op {
LogicInstructionType::Not => 0b11110110,
_ => 0b11010000 + if self.amount_from_cl { 2 } else { 0 },
} + if self.is_wide { 1 } else { 0 };
result.push(byte);
let code = match &self.op {
LogicInstructionType::Rol => 0,
LogicInstructionType::Ror => 1,
LogicInstructionType::Rcl => 2,
LogicInstructionType::Rcr => 3,
LogicInstructionType::Shl => 4,
LogicInstructionType::Shr => 5,
LogicInstructionType::Sar => 7,
LogicInstructionType::Not => 2,
};
match &self.target {
LogicTarget::Address(addr) => addr.push(code, &mut result),
LogicTarget::Register(reg) => {
let (id, _is_wide) = reg.to_id();
result.push(3 * 64 + code * 8 + id)
}
};
result
}
pub fn clock_count(&self) -> (u32, String) {
match (&self.op, &self.target) {
(LogicInstructionType::Not, LogicTarget::Register(_)) => (3, "".to_owned()),
(LogicInstructionType::Not, LogicTarget::Address(addr)) => {
let (count, result) = addr.clock_count();
(count + 16, format!("16 {result}"))
}
(_, LogicTarget::Register(_)) => {
if self.amount_from_cl {
todo!()
} else {
(2, "".to_owned())
}
}
(_, LogicTarget::Address(addr)) => {
if self.amount_from_cl {
todo!()
} else {
let (count, result) = addr.clock_count();
(count + 15, format!("15 {result}"))
}
}
}
}
}