use std::cmp::Ordering;
use std::error::Error;
use std::fmt;
use std::fmt::Write;
use std::hash::Hash;
use std::hash::Hasher;
use std::mem::transmute;
use std::ops::Neg;
#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum Sign {
Plus = 0,
Minus = 1,
}
impl Neg for Sign {
type Output = Sign;
fn neg(self) -> Self::Output {
unsafe { transmute(1 - self as u8) }
}
}
impl fmt::Display for Sign {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_char(if *self == Sign::Plus { '+' } else { '-' })
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct TryFromIntError(());
impl fmt::Display for TryFromIntError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("out of range integral type conversion")
}
}
impl Error for TryFromIntError {}
#[repr(transparent)]
#[derive(
Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default,
)]
pub struct Byte(u8);
impl Byte {
pub const MIN: Byte = Byte(0);
pub const MAX: Byte = Byte(Byte::VALUE_MASK);
pub const fn to_u8(self) -> u8 {
self.0
}
pub const unsafe fn from_u8_unchecked(value: u8) -> Byte {
debug_assert!(value <= Byte::VALUE_MASK);
Byte(value)
}
const VALUE_MASK: u8 = (1 << 6) - 1;
}
impl fmt::Display for Byte {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_fmt(format_args!("{}", self.0))
}
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Default)]
pub struct Short(u16);
impl Short {
pub const MIN: Short = Short(Short::SIGN_MASK | Short::VALUE_MASK);
pub const MAX: Short = Short(Short::VALUE_MASK);
pub const POS_ZERO: Short = Short(0);
pub const NEG_ZERO: Short = Short(Short::SIGN_MASK);
pub const fn to_i16(self) -> i16 {
if self.mask_sign() == 0 {
self.0 as i16
} else {
-(self.mask_value() as i16)
}
}
pub const unsafe fn from_i16_unchecked(value: i16) -> Short {
debug_assert!(value.unsigned_abs() <= Short::VALUE_MASK);
if value >= 0 {
Short(value as u16)
} else {
Short(-value as u16 | Short::SIGN_MASK)
}
}
pub const fn from_sign_and_bytes(sign: Sign, bytes: [Byte; 2]) -> Short {
let signbit = (sign as u16) << 12;
let value = (bytes[0].0 as u16) << 6 | bytes[1].0 as u16;
Short(signbit | value)
}
pub const fn to_sign_and_bytes(self) -> (Sign, [Byte; 2]) {
(self.sign(), self.bytes())
}
pub const fn sign(self) -> Sign {
unsafe { transmute(((self.mask_sign()) >> 12) as u8) }
}
pub const fn bytes(self) -> [Byte; 2] {
let v = self.mask_value();
[Byte((v >> 6) as u8), Byte(v as u8 & Byte::VALUE_MASK)]
}
pub const fn is_zero(self) -> bool {
self.mask_value() == 0
}
pub const fn is_positive(self) -> bool {
self.mask_sign() == 0 && self.mask_value() != 0
}
pub const fn is_negative(self) -> bool {
self.mask_sign() != 0 && self.mask_value() != 0
}
pub const fn abs(self) -> Short {
Short(self.mask_value())
}
const SIGN_MASK: u16 = 1 << 12;
const VALUE_MASK: u16 = (1 << 12) - 1;
const fn mask_sign(self) -> u16 {
self.0 & Short::SIGN_MASK
}
const fn mask_value(self) -> u16 {
self.0 & Short::VALUE_MASK
}
}
impl Neg for Short {
type Output = Short;
fn neg(self) -> Self::Output {
Short(self.0 ^ Short::SIGN_MASK)
}
}
impl PartialEq for Short {
fn eq(&self, other: &Self) -> bool {
self.to_i16() == other.to_i16()
}
}
impl Eq for Short {}
impl PartialOrd for Short {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Short {
fn cmp(&self, other: &Self) -> Ordering {
self.to_i16().cmp(&other.to_i16())
}
}
impl Hash for Short {
fn hash<H: Hasher>(&self, state: &mut H) {
self.to_i16().hash(state);
}
}
impl fmt::Display for Short {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_fmt(format_args!("{}{}", self.sign(), self.mask_value()))
}
}
#[derive(Clone, Copy)]
struct WordFieldInfo {
invalid: bool,
bit_mask: u32,
bit_offset: u8,
}
const WORD_FIELD_INFO: [WordFieldInfo; 64] = {
let mut field_info =
[WordFieldInfo { invalid: false, bit_mask: 0, bit_offset: 0 }; 64];
let mut left = 0;
while left < 8 {
let mut right = 0;
while right < 8 {
let index = left << 3 | right;
if left > right || right > 5 {
field_info[index].invalid = true;
} else {
let byte_left = if left == 0 { 1 } else { left };
let byte_right = if right == 0 { 1 } else { right + 1 };
let bit_width = (byte_right - byte_left) * 6;
let bit_offset = (6 - byte_right) * 6;
let bit_mask = ((1 << bit_width) - 1) << bit_offset;
field_info[index].bit_mask = bit_mask;
field_info[index].bit_offset = bit_offset as u8;
}
right += 1;
}
left += 1;
}
field_info
};
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Default)]
pub struct Word(u32);
impl Word {
pub const MAX: Word = Word(Word::VALUE_MASK);
pub const MIN: Word = Word(Word::VALUE_MASK | Word::SIGN_MASK);
pub const POS_ZERO: Word = Word(0);
pub const NEG_ZERO: Word = Word(Word::SIGN_MASK);
pub const fn to_i32(self) -> i32 {
if self.mask_sign() == 0 {
self.0 as i32
} else {
-(self.mask_value() as i32)
}
}
pub const unsafe fn from_i32_unchecked(value: i32) -> Word {
debug_assert!(value.unsigned_abs() <= Word::VALUE_MASK);
if value >= 0 {
Word(value as u32)
} else {
Word(-value as u32 | Word::SIGN_MASK)
}
}
pub const fn from_sign_and_bytes(sign: Sign, bytes: [Byte; 5]) -> Word {
let signbit = (sign as u32) << 30;
let value = (bytes[0].0 as u32) << 24
| (bytes[1].0 as u32) << 18
| (bytes[2].0 as u32) << 12
| (bytes[3].0 as u32) << 6
| (bytes[4].0 as u32);
Word(signbit | value)
}
pub const fn to_sign_and_bytes(self) -> (Sign, [Byte; 5]) {
(self.sign(), self.bytes())
}
pub const fn sign(self) -> Sign {
unsafe { transmute(((self.mask_sign()) >> 30) as u8) }
}
pub const fn bytes(self) -> [Byte; 5] {
let v = self.mask_value();
[
Byte((v >> 24) as u8),
Byte((v >> 18) as u8 & Byte::VALUE_MASK),
Byte((v >> 12) as u8 & Byte::VALUE_MASK),
Byte((v >> 6) as u8 & Byte::VALUE_MASK),
Byte(v as u8 & Byte::VALUE_MASK),
]
}
pub const fn is_zero(self) -> bool {
self.mask_value() == 0
}
pub const fn is_positive(self) -> bool {
self.mask_sign() == 0 && self.mask_value() != 0
}
pub const fn is_negative(self) -> bool {
self.mask_sign() != 0 && self.mask_value() != 0
}
pub const fn abs(self) -> Word {
Self(self.mask_value())
}
pub const fn load(self, field: Byte) -> Option<Word> {
let field = field.to_u8();
let info = WORD_FIELD_INFO[field as usize];
if info.invalid {
return None;
}
let signbit = if field < 8 { self.mask_sign() } else { 0 };
let uvalue = (self.mask_value() & info.bit_mask) >> info.bit_offset;
Some(Word(signbit | uvalue))
}
pub const fn store(self, dest: Word, field: Byte) -> Option<Word> {
let field = field.to_u8();
let info = WORD_FIELD_INFO[field as usize];
if info.invalid {
return None;
}
let signbit =
if field < 8 { self.mask_sign() } else { dest.mask_sign() };
let overwrite = (self.mask_value() << info.bit_offset) & info.bit_mask;
let uvalue = overwrite | (dest.mask_value() & !info.bit_mask);
Some(Word(signbit | uvalue))
}
pub const fn with_address(self, value: Word) -> Word {
let sign_bit = value.mask_sign();
let high_two_bytes = (value.0 & ((1 << 12) - 1)) << 18;
let low_three_bytes = self.0 & ((1 << 18) - 1);
Word(sign_bit | high_two_bytes | low_three_bytes)
}
pub const fn with_index(self, value: Word) -> Word {
let third_byte = (value.0 & ((1 << 8) - 1)) << 12;
let other_bytes = self.0 & (((1 << 31) - 1) & !(0x3F << 12));
Word(third_byte | other_bytes)
}
pub const fn with_field(self, value: Word) -> Word {
let fourth_byte = (value.0 & ((1 << 8) - 1)) << 6;
let other_bytes = self.0 & (((1 << 31) - 1) & !(0x3F << 6));
Word(fourth_byte | other_bytes)
}
pub const fn with_opcode(self, value: Word) -> Word {
let fifth_byte = value.0 & ((1 << 8) - 1);
let other_bytes = self.0 & (((1 << 31) - 1) & !0x3F);
Word(fifth_byte | other_bytes)
}
pub const fn set_address(&mut self, value: Word) {
*self = self.with_address(value);
}
pub const fn set_index(&mut self, value: Word) {
*self = self.with_index(value);
}
pub const fn set_field(&mut self, value: Word) {
*self = self.with_field(value);
}
pub const fn set_opcode(&mut self, value: Word) {
*self = self.with_opcode(value);
}
pub const fn add(lhs: Word, rhs: Word) -> (Word, bool) {
let value = lhs.to_i32() + rhs.to_i32();
if value == 0 {
(Word(lhs.mask_sign()), false)
} else if value > Word::MAX.to_i32() {
(Word(value as u32 & Word::VALUE_MASK), true)
} else if value < Word::MIN.to_i32() {
(Word(-value as u32 & Word::VALUE_MASK), true)
} else {
(unsafe { Word::from_i32_unchecked(value) }, false)
}
}
pub const fn sub(lhs: Word, rhs: Word) -> (Word, bool) {
Word::add(lhs, Word(rhs.0 ^ Word::SIGN_MASK))
}
pub const fn mul(lhs: Word, rhs: Word) -> (Word, Word) {
let signbit = lhs.mask_sign() ^ rhs.mask_sign();
let res = lhs.mask_value() as u64 * rhs.mask_value() as u64;
let hi = (res >> 30) as u32 | signbit;
let lo = (res as u32 & Word::VALUE_MASK) | signbit;
(Word(hi), Word(lo))
}
pub const fn div(
num_hi: Word,
num_lo: Word,
denom: Word,
) -> (Word, Word, bool) {
if denom.is_zero() || num_hi.mask_value() >= denom.mask_value() {
return (Word::POS_ZERO, Word::POS_ZERO, true);
}
let num_abs = Word::dword_to_u64(num_hi, num_lo);
let denom_abs = denom.mask_value() as u64;
let quot_abs = (num_abs / denom_abs) as u32;
let quot_signbit = num_hi.mask_sign() ^ denom.mask_sign();
let quot = Word(quot_abs | quot_signbit);
let rem_abs = (num_abs % denom_abs) as u32;
let rem_signbit = num_hi.mask_sign();
let rem = Word(rem_abs | rem_signbit);
(quot, rem, false)
}
pub const fn shift_left(hi: Word, lo: Word, bytes: usize) -> (Word, Word) {
Word::dword_from_u64(
hi.mask_sign(),
lo.mask_sign(),
Word::dword_to_u64(hi, lo).wrapping_shl((bytes * 6) as u32),
)
}
pub const fn shift_right(
hi: Word,
lo: Word,
bytes: usize,
) -> (Word, Word) {
Word::dword_from_u64(
hi.mask_sign(),
lo.mask_sign(),
Word::dword_to_u64(hi, lo).wrapping_shr((bytes * 6) as u32),
)
}
pub const fn rotate_left(
hi: Word,
lo: Word,
bytes: usize,
) -> (Word, Word) {
let lbits = 6 * (bytes % 5);
let rbits = 60 - lbits;
let uval = Word::dword_to_u64(hi, lo);
Word::dword_from_u64(
hi.mask_sign(),
lo.mask_sign(),
uval << lbits | uval >> rbits,
)
}
pub const fn rotate_right(
hi: Word,
lo: Word,
bytes: usize,
) -> (Word, Word) {
let rbits = 6 * (bytes % 5);
let lbits = 60 - rbits;
let uval = Word::dword_to_u64(hi, lo);
Word::dword_from_u64(
hi.mask_sign(),
lo.mask_sign(),
uval << lbits | uval >> rbits,
)
}
pub const fn num(hi: Word, lo: Word) -> (Word, bool) {
const BYTE_MASK: u64 = Byte::VALUE_MASK as u64;
let h = hi.0 as u64;
let l = lo.0 as u64;
let value = 1000000000 * (((h >> 24) & BYTE_MASK) % 10)
+ 100000000 * (((h >> 18) & BYTE_MASK) % 10)
+ 10000000 * (((h >> 12) & BYTE_MASK) % 10)
+ 1000000 * (((h >> 6) & BYTE_MASK) % 10)
+ 100000 * ((h & BYTE_MASK) % 10)
+ 10000 * (((l >> 24) & BYTE_MASK) % 10)
+ 1000 * (((l >> 18) & BYTE_MASK) % 10)
+ 100 * (((l >> 12) & BYTE_MASK) % 10)
+ 10 * (((l >> 6) & BYTE_MASK) % 10)
+ ((l & BYTE_MASK) % 10);
let repr = (value as u32 & Word::VALUE_MASK) | hi.mask_sign();
let overflow = value > Word::VALUE_MASK as u64;
(Word(repr), overflow)
}
pub const fn char(hi: Word, lo: Word) -> (Word, Word) {
let mut value = hi.mask_value();
let mut bytes = [Byte::MIN; 10];
let mut index = 10;
while index != 0 {
index -= 1;
bytes[index] = Byte(30 + (value % 10) as u8);
value /= 10;
}
(
Word::from_sign_and_bytes(
hi.sign(),
[bytes[0], bytes[1], bytes[2], bytes[3], bytes[4]],
),
Word::from_sign_and_bytes(
lo.sign(),
[bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]],
),
)
}
const SIGN_MASK: u32 = 1 << 30;
const VALUE_MASK: u32 = (1 << 30) - 1;
const fn mask_sign(self) -> u32 {
self.0 & Word::SIGN_MASK
}
const fn mask_value(self) -> u32 {
self.0 & Word::VALUE_MASK
}
const fn dword_to_u64(hi: Word, lo: Word) -> u64 {
((hi.mask_value() as u64) << 30) | lo.mask_value() as u64
}
const fn dword_from_u64(
hi_signbit: u32,
lo_signbit: u32,
value: u64,
) -> (Word, Word) {
let hi_value = ((value >> 30) as u32) & Word::VALUE_MASK;
let lo_value = (value as u32) & Word::VALUE_MASK;
let hi_word = Word(hi_value | hi_signbit);
let lo_word = Word(lo_value | lo_signbit);
(hi_word, lo_word)
}
}
impl Neg for Word {
type Output = Word;
fn neg(self) -> Self::Output {
Word(self.0 ^ Word::SIGN_MASK)
}
}
impl PartialEq for Word {
fn eq(&self, other: &Self) -> bool {
self.to_i32() == other.to_i32()
}
}
impl Eq for Word {}
impl PartialOrd for Word {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Word {
fn cmp(&self, other: &Self) -> Ordering {
self.to_i32().cmp(&other.to_i32())
}
}
impl Hash for Word {
fn hash<H: Hasher>(&self, state: &mut H) {
self.to_i32().hash(state);
}
}
impl fmt::Display for Word {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_fmt(format_args!("{}{}", self.sign(), self.mask_value()))
}
}
#[repr(transparent)]
#[derive(
Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Hash,
)]
pub struct MemoryAddress(u16);
impl MemoryAddress {
pub const MIN: MemoryAddress = MemoryAddress(0);
pub const MAX: MemoryAddress = MemoryAddress(3999);
pub const unsafe fn from_u16_unchecked(value: u16) -> MemoryAddress {
debug_assert!(value <= MemoryAddress::MAX.0);
MemoryAddress(value)
}
pub const fn to_u16(self) -> u16 {
self.0
}
}
#[repr(transparent)]
#[derive(
Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Hash,
)]
pub struct LocationCounter(u16);
impl LocationCounter {
pub const MIN: LocationCounter = LocationCounter(0);
pub const MAX: LocationCounter =
LocationCounter(LocationCounter::VALUE_MASK);
pub const unsafe fn from_u16_unchecked(value: u16) -> LocationCounter {
debug_assert!(value <= LocationCounter::MAX.0);
LocationCounter(value)
}
pub const fn to_u16(self) -> u16 {
self.0
}
pub const fn increment(self) -> Option<LocationCounter> {
if self.0 == Self::MAX.0 { None } else { Some(Self(self.0 + 1)) }
}
const VALUE_MASK: u16 = (1 << 12) - 1;
}
macro_rules! impl_int_conversions {
(
main_type = $main_type:ty;
repr_type = $repr_type:ty;
main_from_repr_unchecked = $main_from_repr_unchecked:ident;
main_to_repr = $main_to_repr:ident;
from_T_for_main = $($from_T_for_main:ty),*;
try_from_T_for_main = $($try_from_T_for_main:ty),*;
from_main_for_T = $($from_main_for_T:ty),*;
try_from_main_for_T = $($try_from_main_for_T:ty),*;
) => {
impl From<$main_type> for $repr_type {
fn from(value: $main_type) -> Self {
value.$main_to_repr()
}
}
impl TryFrom<$repr_type> for $main_type {
type Error = TryFromIntError;
fn try_from(value: $repr_type) -> Result<Self, Self::Error> {
const MIN: $repr_type = <$main_type>::MIN.$main_to_repr();
const MAX: $repr_type = <$main_type>::MAX.$main_to_repr();
if matches!(value, MIN..=MAX) {
Ok(unsafe { <$main_type>::$main_from_repr_unchecked(value) })
} else {
Err(TryFromIntError(()))
}
}
}
$(
impl From<$from_T_for_main> for $main_type {
fn from(value: $from_T_for_main) -> Self {
let repr = <$repr_type>::from(value);
unsafe { <$main_type>::$main_from_repr_unchecked(repr) }
}
}
)*
$(
impl TryFrom<$try_from_T_for_main> for $main_type {
type Error = TryFromIntError;
fn try_from(value: $try_from_T_for_main) -> Result<Self, Self::Error> {
<$repr_type>::try_from(value)
.map_err(|_| TryFromIntError(()))
.and_then(<$main_type>::try_from)
}
}
)*
$(
impl From<$main_type> for $from_main_for_T {
fn from(value: $main_type) -> Self {
let repr = <$repr_type>::from(value);
<$from_main_for_T>::from(repr)
}
}
)*
$(
impl TryFrom<$main_type> for $try_from_main_for_T {
type Error = TryFromIntError;
fn try_from(value: $main_type) -> Result<Self, Self::Error> {
let repr = <$repr_type>::from(value);
<$try_from_main_for_T>::try_from(repr)
.map_err(|_| TryFromIntError(()))
}
}
)*
};
}
impl_int_conversions! {
main_type = Byte;
repr_type = u8;
main_from_repr_unchecked = from_u8_unchecked;
main_to_repr = to_u8;
from_T_for_main = ;
try_from_T_for_main = u16, u32, u64, u128, usize, i8, i16, i32, i64, i128,
isize, Short, Word, MemoryAddress, LocationCounter;
from_main_for_T = u16, u32, u64, u128, usize, i16, i32, i64, i128, isize;
try_from_main_for_T = ;
}
impl From<Byte> for i8 {
fn from(value: Byte) -> Self {
value.0 as i8
}
}
impl_int_conversions! {
main_type = Short;
repr_type = i16;
main_from_repr_unchecked = from_i16_unchecked;
main_to_repr = to_i16;
from_T_for_main = u8, i8, Byte, MemoryAddress, LocationCounter;
try_from_T_for_main = u16, u32, u64, u128, usize, i32, i64, i128, isize,
Word;
from_main_for_T = i32, i64, i128;
try_from_main_for_T = u8, u16, u32, u64, u128, usize, i8, isize;
}
impl_int_conversions! {
main_type = Word;
repr_type = i32;
main_from_repr_unchecked = from_i32_unchecked;
main_to_repr = to_i32;
from_T_for_main = u8, i8, u16, i16, Byte, Short, MemoryAddress,
LocationCounter;
try_from_T_for_main = u32, u64, u128, usize, i64, i128, isize;
from_main_for_T = i64, i128;
try_from_main_for_T = u8, u16, u32, u64, u128, usize, i8, i16, isize;
}
impl_int_conversions! {
main_type = MemoryAddress;
repr_type = u16;
main_from_repr_unchecked = from_u16_unchecked;
main_to_repr = to_u16;
from_T_for_main = u8, Byte;
try_from_T_for_main = u32, u64, u128, usize, i8, i16, i32, i64, i128,
isize, Short, Word, LocationCounter;
from_main_for_T = u32, u64, u128, i32, i64, i128;
try_from_main_for_T = u8, usize, i8, isize;
}
impl From<MemoryAddress> for i16 {
fn from(value: MemoryAddress) -> Self {
value.0 as i16
}
}
impl_int_conversions! {
main_type = LocationCounter;
repr_type = u16;
main_from_repr_unchecked = from_u16_unchecked;
main_to_repr = to_u16;
from_T_for_main = u8, Byte, MemoryAddress;
try_from_T_for_main = u32, u64, u128, usize, i8, i16, i32, i64, i128,
isize, Short, Word;
from_main_for_T = u32, u64, u128, i32, i64, i128;
try_from_main_for_T = u8, usize, i8, isize;
}
impl From<LocationCounter> for i16 {
fn from(value: LocationCounter) -> Self {
value.0 as i16
}
}