forked from libre-chip/cpu
implement decoding shifts: s[lr][wd][.] and sra[wd][i][.]
This commit is contained in:
parent
59874b9b29
commit
1db65ae753
6 changed files with 11897 additions and 253 deletions
|
|
@ -6,7 +6,8 @@ use crate::{
|
||||||
instruction::{
|
instruction::{
|
||||||
AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LoadMOp, LoadStoreConversion,
|
AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LoadMOp, LoadStoreConversion,
|
||||||
LoadStoreWidth, LogicalFlagsMOp, LogicalFlagsMOpImm, LogicalMOp, Lut4, MOp, MOpDestReg,
|
LoadStoreWidth, LogicalFlagsMOp, LogicalFlagsMOpImm, LogicalMOp, Lut4, MOp, MOpDestReg,
|
||||||
MOpRegNum, MoveRegMOp, OutputIntegerMode, StoreMOp,
|
MOpRegNum, MoveRegMOp, OutputIntegerMode, ShiftRotateMOp, ShiftRotateMOpImm,
|
||||||
|
ShiftRotateMode, StoreMOp,
|
||||||
},
|
},
|
||||||
powerisa_instructions_xml::{
|
powerisa_instructions_xml::{
|
||||||
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
|
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
|
||||||
|
|
@ -14,7 +15,10 @@ use crate::{
|
||||||
register::{
|
register::{
|
||||||
PRegFlags, PRegFlagsPowerISA, PRegFlagsPowerISAView, PRegFlagsViewTrait, ViewUnused,
|
PRegFlags, PRegFlagsPowerISA, PRegFlagsPowerISAView, PRegFlagsViewTrait, ViewUnused,
|
||||||
},
|
},
|
||||||
util::array_vec::{ArrayVec, Length},
|
util::{
|
||||||
|
Rotate,
|
||||||
|
array_vec::{ArrayVec, Length},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use fayalite::{
|
use fayalite::{
|
||||||
int::{BoolOrIntType, UIntInRange},
|
int::{BoolOrIntType, UIntInRange},
|
||||||
|
|
@ -22,7 +26,10 @@ use fayalite::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
ty::StaticType,
|
ty::StaticType,
|
||||||
};
|
};
|
||||||
use std::{collections::BTreeMap, ops::RangeInclusive};
|
use std::{
|
||||||
|
collections::{BTreeMap, btree_map::Entry},
|
||||||
|
ops::RangeInclusive,
|
||||||
|
};
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
const FP_MNEMONICS: &[&str] = &[
|
const FP_MNEMONICS: &[&str] = &[
|
||||||
|
|
@ -218,6 +225,10 @@ impl_fields! {
|
||||||
struct FieldDS(SInt<14>);
|
struct FieldDS(SInt<14>);
|
||||||
#[name = "LI"]
|
#[name = "LI"]
|
||||||
struct FieldLI(SInt<24>);
|
struct FieldLI(SInt<24>);
|
||||||
|
#[name = "SH"]
|
||||||
|
struct FieldSH(UInt<5>);
|
||||||
|
#[name = "sh"]
|
||||||
|
struct FieldSh(UInt<6>);
|
||||||
#[name = "SI"]
|
#[name = "SI"]
|
||||||
struct FieldSI(SInt<16>);
|
struct FieldSI(SInt<16>);
|
||||||
#[name = "si0"]
|
#[name = "si0"]
|
||||||
|
|
@ -397,6 +408,20 @@ impl DecodeState {
|
||||||
fields_inner: &'static InstructionBitFieldsInner,
|
fields_inner: &'static InstructionBitFieldsInner,
|
||||||
) {
|
) {
|
||||||
let mut last_start = word.ty().width();
|
let mut last_start = word.ty().width();
|
||||||
|
struct FieldPieces {
|
||||||
|
filled_pieces: Vec<Expr<UInt>>,
|
||||||
|
piece_count: usize,
|
||||||
|
}
|
||||||
|
let mut fields_pieces = BTreeMap::new();
|
||||||
|
for bit_field in fields_inner.fields() {
|
||||||
|
fields_pieces
|
||||||
|
.entry(Self::bit_field_name(bit_field.name()))
|
||||||
|
.or_insert_with(|| FieldPieces {
|
||||||
|
filled_pieces: Vec::with_capacity(1),
|
||||||
|
piece_count: 0,
|
||||||
|
})
|
||||||
|
.piece_count += 1;
|
||||||
|
}
|
||||||
for bit_field in fields_inner.fields().iter().rev() {
|
for bit_field in fields_inner.fields().iter().rev() {
|
||||||
let bit_number_text = match bit_field.bit_number().text() {
|
let bit_number_text = match bit_field.bit_number().text() {
|
||||||
"3031" => "30 31",
|
"3031" => "30 31",
|
||||||
|
|
@ -436,6 +461,10 @@ impl DecodeState {
|
||||||
if name.contains(char::is_alphabetic) {
|
if name.contains(char::is_alphabetic) {
|
||||||
for (cond_name, cond_value) in self.conditions() {
|
for (cond_name, cond_value) in self.conditions() {
|
||||||
if name == cond_name {
|
if name == cond_name {
|
||||||
|
assert_eq!(
|
||||||
|
fields_pieces[name].piece_count, 1,
|
||||||
|
"can't apply conditions to a field with more than one piece: name {name:?}",
|
||||||
|
);
|
||||||
name = cond_value;
|
name = cond_value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -444,15 +473,33 @@ impl DecodeState {
|
||||||
if name == "any value*" || name.bytes().all(|b| b == b'/') {
|
if name == "any value*" || name.bytes().all(|b| b == b'/') {
|
||||||
// wildcard
|
// wildcard
|
||||||
} else if name.contains(char::is_alphabetic) {
|
} else if name.contains(char::is_alphabetic) {
|
||||||
let wire = wire_with_loc(
|
let Some(field_pieces) = fields_pieces.get_mut(name) else {
|
||||||
&format!("{}_{name}", self.mnemonic)
|
unreachable!();
|
||||||
.replace(|c: char| !c.is_ascii_alphanumeric(), "_"),
|
};
|
||||||
SourceLocation::caller(),
|
field_pieces.filled_pieces.push(field);
|
||||||
field.ty(),
|
if field_pieces.filled_pieces.len() == field_pieces.piece_count {
|
||||||
);
|
let wire = wire_with_loc(
|
||||||
connect(wire, field);
|
&format!("{}_{name}", self.mnemonic)
|
||||||
if fields.insert(name, wire).is_some() {
|
.replace(|c: char| !c.is_ascii_alphanumeric(), "_"),
|
||||||
panic!("duplicate field name: {name:?}\nheader: {:#?}", self.header);
|
SourceLocation::caller(),
|
||||||
|
UInt[field_pieces
|
||||||
|
.filled_pieces
|
||||||
|
.iter()
|
||||||
|
.map(|v| v.ty().width())
|
||||||
|
.sum::<usize>()],
|
||||||
|
);
|
||||||
|
// filled_pieces are in lsb to msb order
|
||||||
|
let mut filled_pieces = field_pieces.filled_pieces.drain(..);
|
||||||
|
let Some(mut value) = filled_pieces.next() else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
let mut shift = value.ty().width();
|
||||||
|
for next_value in filled_pieces {
|
||||||
|
value = value | (next_value << shift);
|
||||||
|
shift += next_value.ty().width();
|
||||||
|
}
|
||||||
|
connect(wire, value);
|
||||||
|
fields.insert(name, wire);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let value: u32 = name.parse().expect("bit field name must have at least one letter, be all `/`, or be a valid decimal number");
|
let value: u32 = name.parse().expect("bit field name must have at least one letter, be all `/`, or be a valid decimal number");
|
||||||
|
|
@ -1856,6 +1903,139 @@ impl DecodeState {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
/// for `slw[.]/srw[.]/srawi[.]/sraw[.]/sld[.]/sradi[.]/srd[.]/srad[.]`
|
||||||
|
#[hdl]
|
||||||
|
fn decode_shift(&mut self) {
|
||||||
|
let (is_32bit, is_signed, is_right_shift, is_immediate) =
|
||||||
|
match self.mnemonic.trim_end_matches('.') {
|
||||||
|
"slw" => (true, false, false, false),
|
||||||
|
"srw" => (true, false, true, false),
|
||||||
|
"srawi" => (true, true, true, true),
|
||||||
|
"sraw" => (true, true, true, false),
|
||||||
|
"sld" => (false, false, false, false),
|
||||||
|
"sradi" => (false, true, true, true),
|
||||||
|
"srd" => (false, false, true, false),
|
||||||
|
"srad" => (false, true, true, false),
|
||||||
|
_ => unreachable!("{:?}", self.mnemonic),
|
||||||
|
};
|
||||||
|
if is_immediate {
|
||||||
|
assert!(is_signed);
|
||||||
|
assert!(is_right_shift);
|
||||||
|
assert_eq!(self.arguments, Some("RA,RS,SH"));
|
||||||
|
if is_32bit {
|
||||||
|
self.decode_scope(
|
||||||
|
|this, (FieldRA(ra), FieldRS(rs), FieldSH(sh), FieldRc(rc))| {
|
||||||
|
// TODO: handle SO propagation
|
||||||
|
connect(
|
||||||
|
ArrayVec::len(this.output),
|
||||||
|
1usize.cast_to_static::<Length<_>>(),
|
||||||
|
);
|
||||||
|
connect(
|
||||||
|
this.output[0],
|
||||||
|
ShiftRotateMOp::shift_rotate(
|
||||||
|
MOpDestReg::new(
|
||||||
|
[gpr(ra), MOpRegNum::power_isa_xer_ca_ca32_reg()],
|
||||||
|
[(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc)],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
gpr(rs).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
#[hdl]
|
||||||
|
ShiftRotateMOpImm {
|
||||||
|
shift_rotate_amount: HdlSome(sh.cast_to_static::<UInt<_>>()),
|
||||||
|
shift_rotate_right: true,
|
||||||
|
dest_logic_op: HdlNone(),
|
||||||
|
},
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
ShiftRotateMode.SignExt32To64BitThenShift(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
self.decode_scope(
|
||||||
|
|this, (FieldRA(ra), FieldRS(rs), FieldSh(sh), FieldRc(rc))| {
|
||||||
|
// TODO: handle SO propagation
|
||||||
|
connect(
|
||||||
|
ArrayVec::len(this.output),
|
||||||
|
1usize.cast_to_static::<Length<_>>(),
|
||||||
|
);
|
||||||
|
connect(
|
||||||
|
this.output[0],
|
||||||
|
ShiftRotateMOp::shift_rotate(
|
||||||
|
MOpDestReg::new(
|
||||||
|
[gpr(ra), MOpRegNum::power_isa_xer_ca_ca32_reg()],
|
||||||
|
[(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc)],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
gpr(rs).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
#[hdl]
|
||||||
|
ShiftRotateMOpImm {
|
||||||
|
shift_rotate_amount: HdlSome(sh.rotate_right(1)),
|
||||||
|
shift_rotate_right: true,
|
||||||
|
dest_logic_op: HdlNone(),
|
||||||
|
},
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
ShiftRotateMode.ShiftSigned64(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert_eq!(self.arguments, Some("RA,RS,RB"));
|
||||||
|
self.decode_scope(
|
||||||
|
|this, (FieldRA(ra), FieldRS(rs), FieldRB(rb), FieldRc(rc))| {
|
||||||
|
// TODO: handle SO propagation
|
||||||
|
connect(
|
||||||
|
ArrayVec::len(this.output),
|
||||||
|
1usize.cast_to_static::<Length<_>>(),
|
||||||
|
);
|
||||||
|
connect(
|
||||||
|
this.output[0],
|
||||||
|
ShiftRotateMOp::shift_rotate(
|
||||||
|
MOpDestReg::new(
|
||||||
|
[
|
||||||
|
gpr(ra),
|
||||||
|
if is_signed && is_right_shift {
|
||||||
|
MOpRegNum::power_isa_xer_ca_ca32_reg()
|
||||||
|
} else {
|
||||||
|
MOpRegNum::const_zero()
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc)],
|
||||||
|
),
|
||||||
|
if !is_signed && is_right_shift {
|
||||||
|
[MOpRegNum::const_zero().value, gpr(rs).value, gpr(rb).value]
|
||||||
|
} else {
|
||||||
|
[gpr(rs).value, MOpRegNum::const_zero().value, gpr(rb).value]
|
||||||
|
},
|
||||||
|
#[hdl]
|
||||||
|
ShiftRotateMOpImm {
|
||||||
|
shift_rotate_amount: HdlNone(),
|
||||||
|
shift_rotate_right: is_right_shift,
|
||||||
|
dest_logic_op: HdlNone(),
|
||||||
|
},
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
match (is_32bit, is_signed, is_right_shift) {
|
||||||
|
(false, _, false) => ShiftRotateMode.FunnelShift2x64Bit(),
|
||||||
|
(false, false, true) => ShiftRotateMode.FunnelShift2x64Bit(),
|
||||||
|
(false, true, true) => ShiftRotateMode.ShiftSigned64(),
|
||||||
|
(true, _, false) => ShiftRotateMode.FunnelShift2x32Bit(),
|
||||||
|
(true, false, true) => ShiftRotateMode.FunnelShift2x32Bit(),
|
||||||
|
(true, true, true) => ShiftRotateMode.SignExt32To64BitThenShift(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
/// for `mcrxrx`
|
/// for `mcrxrx`
|
||||||
#[hdl]
|
#[hdl]
|
||||||
fn decode_mcrxrx(&mut self) {
|
fn decode_mcrxrx(&mut self) {
|
||||||
|
|
@ -2084,9 +2264,7 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
|
||||||
"slw", "slw.", "srw", "srw.", "srawi", "srawi.", "sraw", "sraw.", "sld", "sld.",
|
"slw", "slw.", "srw", "srw.", "srawi", "srawi.", "sraw", "sraw.", "sld", "sld.",
|
||||||
"sradi", "sradi.", "srd", "srd.", "srad", "srad.",
|
"sradi", "sradi.", "srd", "srd.", "srad", "srad.",
|
||||||
],
|
],
|
||||||
|_state| {
|
DecodeState::decode_shift,
|
||||||
// TODO
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
(&["extswsli", "extswsli."], |_state| {
|
(&["extswsli", "extswsli."], |_state| {
|
||||||
// TODO
|
// TODO
|
||||||
|
|
|
||||||
|
|
@ -1605,17 +1605,22 @@ impl<DestReg: Type, SrcRegWidth: Size> LogicalMOp<DestReg, SrcRegWidth, ConstUsi
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
pub enum ShiftRotateMode {
|
pub enum ShiftRotateMode {
|
||||||
/// like `llvm.fsh[lr].i8(src0, src1, src2)`
|
/// like `llvm.fsh[lr].i8(src0, src1, shift_rotate_amount.unwrap_or(src2))`
|
||||||
FunnelShift2x8Bit,
|
FunnelShift2x8Bit,
|
||||||
/// like `llvm.fsh[lr].i16(src0, src1, src2)`
|
/// like `llvm.fsh[lr].i16(src0, src1, shift_rotate_amount.unwrap_or(src2))`
|
||||||
FunnelShift2x16Bit,
|
FunnelShift2x16Bit,
|
||||||
/// like `llvm.fsh[lr].i32(src0, src1, src2)`
|
/// like `llvm.fsh[lr].i32(src0, src1, shift_rotate_amount.unwrap_or(src2))`
|
||||||
FunnelShift2x32Bit,
|
FunnelShift2x32Bit,
|
||||||
/// like `llvm.fsh[lr].i64(src0, src1, src2)`
|
/// like `llvm.fsh[lr].i64(src0, src1, shift_rotate_amount.unwrap_or(src2))`
|
||||||
FunnelShift2x64Bit,
|
FunnelShift2x64Bit,
|
||||||
|
/// `shift(src0 as i8 as i64, shift_rotate_amount.unwrap_or(src2))`
|
||||||
SignExt8To64BitThenShift,
|
SignExt8To64BitThenShift,
|
||||||
|
/// `shift(src0 as i16 as i64, shift_rotate_amount.unwrap_or(src2))`
|
||||||
SignExt16To64BitThenShift,
|
SignExt16To64BitThenShift,
|
||||||
|
/// `shift(src0 as i32 as i64, shift_rotate_amount.unwrap_or(src2))`
|
||||||
SignExt32To64BitThenShift,
|
SignExt32To64BitThenShift,
|
||||||
|
/// `shift(src0 as i64, shift_rotate_amount.unwrap_or(src2))`
|
||||||
|
ShiftSigned64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HdlPartialEqImpl<Self> for ShiftRotateMode {
|
impl HdlPartialEqImpl<Self> for ShiftRotateMode {
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,54 @@ pub trait Rotate<Amount> {
|
||||||
fn rotate_right(&self, amount: Amount) -> Self::Output;
|
fn rotate_right(&self, amount: Amount) -> Self::Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<VSz: Size> Rotate<usize> for Expr<UIntType<VSz>> {
|
||||||
|
type Output = Self;
|
||||||
|
/// like [`usize::rotate_left`]
|
||||||
|
fn rotate_left(&self, amount: usize) -> Self::Output {
|
||||||
|
if self.ty().width() == 0 {
|
||||||
|
return *self;
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().width();
|
||||||
|
let l = *self << amount;
|
||||||
|
let r = *self >> (self.ty().width() - amount);
|
||||||
|
(l | r).cast_to(self.ty())
|
||||||
|
}
|
||||||
|
/// like [`usize::rotate_right`]
|
||||||
|
fn rotate_right(&self, amount: usize) -> Self::Output {
|
||||||
|
if self.ty().width() == 0 {
|
||||||
|
return *self;
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().width();
|
||||||
|
let l = *self << (self.ty().width() - amount);
|
||||||
|
let r = *self >> amount;
|
||||||
|
(l | r).cast_to(self.ty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<VSz: Size> Rotate<usize> for SimValue<UIntType<VSz>> {
|
||||||
|
type Output = Self;
|
||||||
|
/// like [`usize::rotate_left`]
|
||||||
|
fn rotate_left(&self, amount: usize) -> Self::Output {
|
||||||
|
if self.ty().width() == 0 {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().width();
|
||||||
|
let l = self << amount;
|
||||||
|
let r = self >> (self.ty().width() - amount);
|
||||||
|
(l | r).cast_to(self.ty())
|
||||||
|
}
|
||||||
|
/// like [`usize::rotate_right`]
|
||||||
|
fn rotate_right(&self, amount: usize) -> Self::Output {
|
||||||
|
if self.ty().width() == 0 {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().width();
|
||||||
|
let l = self << (self.ty().width() - amount);
|
||||||
|
let r = self >> amount;
|
||||||
|
(l | r).cast_to(self.ty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<VSz: Size, ASz: Size> Rotate<Expr<UIntType<ASz>>> for Expr<UIntType<VSz>> {
|
impl<VSz: Size, ASz: Size> Rotate<Expr<UIntType<ASz>>> for Expr<UIntType<VSz>> {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
/// like [`usize::rotate_left`]
|
/// like [`usize::rotate_left`]
|
||||||
|
|
@ -176,3 +224,59 @@ impl<T: Type, N: Size, AmountSize: Size> Rotate<SimValue<UIntType<AmountSize>>>
|
||||||
retval
|
retval
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Type, N: Size> Rotate<usize> for Expr<ArrayType<T, N>> {
|
||||||
|
type Output = Self;
|
||||||
|
/// like [`<[T]>::rotate_left`](slice::rotate_left)
|
||||||
|
fn rotate_left(&self, amount: usize) -> Self::Output {
|
||||||
|
if self.ty().len() == 0 {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().len();
|
||||||
|
let mut retval = Vec::from_iter(*self);
|
||||||
|
retval.rotate_left(amount);
|
||||||
|
ArrayLiteral::new(
|
||||||
|
self.ty().element(),
|
||||||
|
retval.into_iter().map(Expr::canonical).collect(),
|
||||||
|
)
|
||||||
|
.to_expr()
|
||||||
|
}
|
||||||
|
/// like [`<[T]>::rotate_right`](slice::rotate_right)
|
||||||
|
fn rotate_right(&self, amount: usize) -> Self::Output {
|
||||||
|
if self.ty().len() == 0 {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().len();
|
||||||
|
let mut retval = Vec::from_iter(*self);
|
||||||
|
retval.rotate_right(amount);
|
||||||
|
ArrayLiteral::new(
|
||||||
|
self.ty().element(),
|
||||||
|
retval.into_iter().map(Expr::canonical).collect(),
|
||||||
|
)
|
||||||
|
.to_expr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Type, N: Size> Rotate<usize> for SimValue<ArrayType<T, N>> {
|
||||||
|
type Output = Self;
|
||||||
|
/// like [`<[T]>::rotate_left`](slice::rotate_left)
|
||||||
|
fn rotate_left(&self, amount: usize) -> Self::Output {
|
||||||
|
if self.ty().len() == 0 {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().len();
|
||||||
|
let mut retval = self.clone();
|
||||||
|
AsMut::<[SimValue<T>]>::as_mut(&mut SimValue::value_mut(&mut retval)).rotate_left(amount);
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
/// like [`<[T]>::rotate_right`](slice::rotate_right)
|
||||||
|
fn rotate_right(&self, amount: usize) -> Self::Output {
|
||||||
|
if self.ty().len() == 0 {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().len();
|
||||||
|
let mut retval = self.clone();
|
||||||
|
AsMut::<[SimValue<T>]>::as_mut(&mut SimValue::value_mut(&mut retval)).rotate_right(amount);
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -11,6 +11,7 @@ mod fixed_point_arithmetic;
|
||||||
mod fixed_point_compare;
|
mod fixed_point_compare;
|
||||||
mod fixed_point_load;
|
mod fixed_point_load;
|
||||||
mod fixed_point_logical;
|
mod fixed_point_logical;
|
||||||
|
mod fixed_point_rotate_and_shift;
|
||||||
mod fixed_point_store;
|
mod fixed_point_store;
|
||||||
mod move_to_from_system_register;
|
mod move_to_from_system_register;
|
||||||
mod prefixed_no_operation;
|
mod prefixed_no_operation;
|
||||||
|
|
@ -143,6 +144,9 @@ pub fn test_cases() -> Vec<TestCase> {
|
||||||
fixed_point_arithmetic::test_cases_book_i_3_3_9_fixed_point_arithmetic(&mut retval);
|
fixed_point_arithmetic::test_cases_book_i_3_3_9_fixed_point_arithmetic(&mut retval);
|
||||||
fixed_point_compare::test_cases_book_i_3_3_10_fixed_point_compare(&mut retval);
|
fixed_point_compare::test_cases_book_i_3_3_10_fixed_point_compare(&mut retval);
|
||||||
fixed_point_logical::test_cases_book_i_3_3_13_fixed_point_logical(&mut retval);
|
fixed_point_logical::test_cases_book_i_3_3_13_fixed_point_logical(&mut retval);
|
||||||
|
fixed_point_rotate_and_shift::test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(
|
||||||
|
&mut retval,
|
||||||
|
);
|
||||||
move_to_from_system_register::test_cases_book_i_3_3_19_move_to_from_system_register(
|
move_to_from_system_register::test_cases_book_i_3_3_19_move_to_from_system_register(
|
||||||
&mut retval,
|
&mut retval,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,364 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::test_cases::{TestCase, insn_single};
|
||||||
|
use cpu::instruction::{
|
||||||
|
AddSubMOp, MOpDestReg, MOpRegNum, OutputIntegerMode, ShiftRotateMOp, ShiftRotateMOpImm,
|
||||||
|
ShiftRotateMode,
|
||||||
|
};
|
||||||
|
use fayalite::prelude::*;
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
fn shift_imm(amount: Option<u8>, shift_right: bool) -> Expr<ShiftRotateMOpImm> {
|
||||||
|
#[hdl]
|
||||||
|
ShiftRotateMOpImm {
|
||||||
|
shift_rotate_amount: if let Some(amount) = amount {
|
||||||
|
HdlSome(amount.cast_to_static::<UInt<_>>())
|
||||||
|
} else {
|
||||||
|
HdlNone()
|
||||||
|
},
|
||||||
|
shift_rotate_right: shift_right,
|
||||||
|
dest_logic_op: HdlNone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// covers instructions in PowerISA v3.1C Book I 3.3.14 Fixed-Point Rotate and Shift Instructions
|
||||||
|
pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<TestCase>) {
|
||||||
|
// TODO: rotate instructions
|
||||||
|
|
||||||
|
macro_rules! shift_left {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $dest:literal, $src:literal, $amount:literal;
|
||||||
|
$encoding:literal;
|
||||||
|
$shift_rotate_mode:ident;
|
||||||
|
) => {{
|
||||||
|
retval.push(insn_single(
|
||||||
|
concat!(
|
||||||
|
$mnemonic,
|
||||||
|
" ",
|
||||||
|
stringify!($dest),
|
||||||
|
", ",
|
||||||
|
stringify!($src),
|
||||||
|
", ",
|
||||||
|
stringify!($amount)
|
||||||
|
),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
ShiftRotateMOp::shift_rotate(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($src).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($amount).value,
|
||||||
|
],
|
||||||
|
shift_imm(None, false),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
ShiftRotateMode.$shift_rotate_mode(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
concat!(
|
||||||
|
$mnemonic,
|
||||||
|
". ",
|
||||||
|
stringify!($dest),
|
||||||
|
", ",
|
||||||
|
stringify!($src),
|
||||||
|
", ",
|
||||||
|
stringify!($amount)
|
||||||
|
),
|
||||||
|
$encoding | 1,
|
||||||
|
None,
|
||||||
|
ShiftRotateMOp::shift_rotate(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[MOpRegNum::power_isa_gpr_reg_num($dest)],
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($src).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($amount).value,
|
||||||
|
],
|
||||||
|
shift_imm(None, false),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
ShiftRotateMode.$shift_rotate_mode(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
macro_rules! shift_right_unsigned {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $dest:literal, $src:literal, $amount:literal;
|
||||||
|
$encoding:literal;
|
||||||
|
$shift_rotate_mode:ident;
|
||||||
|
) => {{
|
||||||
|
retval.push(insn_single(
|
||||||
|
concat!(
|
||||||
|
$mnemonic,
|
||||||
|
" ",
|
||||||
|
stringify!($dest),
|
||||||
|
", ",
|
||||||
|
stringify!($src),
|
||||||
|
", ",
|
||||||
|
stringify!($amount)
|
||||||
|
),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
ShiftRotateMOp::shift_rotate(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($src).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($amount).value,
|
||||||
|
],
|
||||||
|
shift_imm(None, true),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
ShiftRotateMode.$shift_rotate_mode(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
concat!(
|
||||||
|
$mnemonic,
|
||||||
|
". ",
|
||||||
|
stringify!($dest),
|
||||||
|
", ",
|
||||||
|
stringify!($src),
|
||||||
|
", ",
|
||||||
|
stringify!($amount)
|
||||||
|
),
|
||||||
|
$encoding | 1,
|
||||||
|
None,
|
||||||
|
ShiftRotateMOp::shift_rotate(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[MOpRegNum::power_isa_gpr_reg_num($dest)],
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($src).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($amount).value,
|
||||||
|
],
|
||||||
|
shift_imm(None, true),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
ShiftRotateMode.$shift_rotate_mode(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
macro_rules! shift_right_signed {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $dest:literal, $src:literal, $amount:literal;
|
||||||
|
$encoding:literal;
|
||||||
|
$shift_rotate_mode:ident;
|
||||||
|
) => {{
|
||||||
|
retval.push(insn_single(
|
||||||
|
concat!(
|
||||||
|
$mnemonic,
|
||||||
|
" ",
|
||||||
|
stringify!($dest),
|
||||||
|
", ",
|
||||||
|
stringify!($src),
|
||||||
|
", ",
|
||||||
|
stringify!($amount)
|
||||||
|
),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
ShiftRotateMOp::shift_rotate(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_num($dest),
|
||||||
|
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||||
|
],
|
||||||
|
&[],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($src).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($amount).value,
|
||||||
|
],
|
||||||
|
shift_imm(None, true),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
ShiftRotateMode.$shift_rotate_mode(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
concat!(
|
||||||
|
$mnemonic,
|
||||||
|
". ",
|
||||||
|
stringify!($dest),
|
||||||
|
", ",
|
||||||
|
stringify!($src),
|
||||||
|
", ",
|
||||||
|
stringify!($amount)
|
||||||
|
),
|
||||||
|
$encoding | 1,
|
||||||
|
None,
|
||||||
|
ShiftRotateMOp::shift_rotate(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_num($dest),
|
||||||
|
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||||
|
],
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($src).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($amount).value,
|
||||||
|
],
|
||||||
|
shift_imm(None, true),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
ShiftRotateMode.$shift_rotate_mode(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
macro_rules! shift_right_signed_imm {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $dest:literal, $src:literal, $amount:literal;
|
||||||
|
$encoding:literal;
|
||||||
|
$shift_rotate_mode:ident;
|
||||||
|
) => {{
|
||||||
|
retval.push(insn_single(
|
||||||
|
concat!(
|
||||||
|
$mnemonic,
|
||||||
|
" ",
|
||||||
|
stringify!($dest),
|
||||||
|
", ",
|
||||||
|
stringify!($src),
|
||||||
|
", ",
|
||||||
|
stringify!($amount)
|
||||||
|
),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
ShiftRotateMOp::shift_rotate(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_num($dest),
|
||||||
|
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||||
|
],
|
||||||
|
&[],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($src).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
shift_imm(Some($amount), true),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
ShiftRotateMode.$shift_rotate_mode(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
concat!(
|
||||||
|
$mnemonic,
|
||||||
|
". ",
|
||||||
|
stringify!($dest),
|
||||||
|
", ",
|
||||||
|
stringify!($src),
|
||||||
|
", ",
|
||||||
|
stringify!($amount)
|
||||||
|
),
|
||||||
|
$encoding | 1,
|
||||||
|
None,
|
||||||
|
ShiftRotateMOp::shift_rotate(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_num($dest),
|
||||||
|
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||||
|
],
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($src).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
shift_imm(Some($amount), true),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
ShiftRotateMode.$shift_rotate_mode(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
shift_left! {
|
||||||
|
"slw" 3, 4, 5;
|
||||||
|
0x7c832830;
|
||||||
|
FunnelShift2x32Bit;
|
||||||
|
}
|
||||||
|
shift_right_unsigned! {
|
||||||
|
"srw" 3, 4, 5;
|
||||||
|
0x7c832c30;
|
||||||
|
FunnelShift2x32Bit;
|
||||||
|
}
|
||||||
|
shift_right_signed_imm! {
|
||||||
|
"srawi" 3, 4, 0;
|
||||||
|
0x7c830670;
|
||||||
|
SignExt32To64BitThenShift;
|
||||||
|
}
|
||||||
|
shift_right_signed_imm! {
|
||||||
|
"srawi" 3, 4, 5;
|
||||||
|
0x7c832e70;
|
||||||
|
SignExt32To64BitThenShift;
|
||||||
|
}
|
||||||
|
shift_right_signed_imm! {
|
||||||
|
"srawi" 3, 4, 16;
|
||||||
|
0x7c838670;
|
||||||
|
SignExt32To64BitThenShift;
|
||||||
|
}
|
||||||
|
shift_right_signed_imm! {
|
||||||
|
"srawi" 3, 4, 31;
|
||||||
|
0x7c83fe70;
|
||||||
|
SignExt32To64BitThenShift;
|
||||||
|
}
|
||||||
|
shift_right_signed! {
|
||||||
|
"sraw" 3, 4, 5;
|
||||||
|
0x7c832e30;
|
||||||
|
SignExt32To64BitThenShift;
|
||||||
|
}
|
||||||
|
shift_left! {
|
||||||
|
"sld" 3, 4, 5;
|
||||||
|
0x7c832836;
|
||||||
|
FunnelShift2x64Bit;
|
||||||
|
}
|
||||||
|
shift_right_unsigned! {
|
||||||
|
"srd" 3, 4, 5;
|
||||||
|
0x7c832c36;
|
||||||
|
FunnelShift2x64Bit;
|
||||||
|
}
|
||||||
|
shift_right_signed_imm! {
|
||||||
|
"sradi" 3, 4, 0;
|
||||||
|
0x7c830674;
|
||||||
|
ShiftSigned64;
|
||||||
|
}
|
||||||
|
shift_right_signed_imm! {
|
||||||
|
"sradi" 3, 4, 5;
|
||||||
|
0x7c832e74;
|
||||||
|
ShiftSigned64;
|
||||||
|
}
|
||||||
|
shift_right_signed_imm! {
|
||||||
|
"sradi" 3, 4, 16;
|
||||||
|
0x7c838674;
|
||||||
|
ShiftSigned64;
|
||||||
|
}
|
||||||
|
shift_right_signed_imm! {
|
||||||
|
"sradi" 3, 4, 31;
|
||||||
|
0x7c83fe74;
|
||||||
|
ShiftSigned64;
|
||||||
|
}
|
||||||
|
shift_right_signed_imm! {
|
||||||
|
"sradi" 3, 4, 32;
|
||||||
|
0x7c830676;
|
||||||
|
ShiftSigned64;
|
||||||
|
}
|
||||||
|
shift_right_signed_imm! {
|
||||||
|
"sradi" 3, 4, 63;
|
||||||
|
0x7c83fe76;
|
||||||
|
ShiftSigned64;
|
||||||
|
}
|
||||||
|
shift_right_signed! {
|
||||||
|
"srad" 3, 4, 5;
|
||||||
|
0x7c832e34;
|
||||||
|
ShiftSigned64;
|
||||||
|
}
|
||||||
|
// TODO: extswsli
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue