Compare commits

...

2 commits

6 changed files with 74970 additions and 120519 deletions

View file

@ -6,7 +6,8 @@ use crate::{
instruction::{
AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LoadMOp, LoadStoreConversion,
LoadStoreWidth, LogicalFlagsMOp, LogicalFlagsMOpImm, LogicalMOp, Lut4, MOp, MOpDestReg,
MOpRegNum, MoveRegMOp, OutputIntegerMode, StoreMOp,
MOpRegNum, MoveRegMOp, OutputIntegerMode, ShiftRotateMOp, ShiftRotateMOpImm,
ShiftRotateMode, StoreMOp,
},
powerisa_instructions_xml::{
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
@ -14,15 +15,16 @@ use crate::{
register::{
PRegFlags, PRegFlagsPowerISA, PRegFlagsPowerISAView, PRegFlagsViewTrait, ViewUnused,
},
util::array_vec::{ArrayVec, Length},
util::{
Rotate,
array_vec::{ArrayVec, Length},
},
};
use fayalite::{
int::{BoolOrIntType, UIntInRange},
module::wire_with_loc,
prelude::*,
ty::StaticType,
use fayalite::{int::UIntInRange, module::wire_with_loc, prelude::*, ty::StaticType};
use std::{
collections::{BTreeMap, HashMap, hash_map::Entry},
ops::RangeInclusive,
};
use std::{collections::BTreeMap, ops::RangeInclusive};
#[rustfmt::skip]
const FP_MNEMONICS: &[&str] = &[
@ -129,7 +131,7 @@ const VSX_MNEMONICS: &[&str] = &[
];
#[derive(Debug)]
struct DecodeState {
struct DecodeState<'a> {
mnemonic: &'static str,
arguments: Option<&'static str>,
conditions: Option<&'static str>,
@ -140,6 +142,7 @@ struct DecodeState {
first_input: Expr<UInt<32>>,
second_input: Expr<HdlOption<UInt<32>>>,
second_input_used: Expr<Bool>,
field_wires: &'a mut HashMap<String, HashMap<Expr<UInt>, Expr<UInt>>>,
}
trait FieldSet {
@ -218,6 +221,10 @@ impl_fields! {
struct FieldDS(SInt<14>);
#[name = "LI"]
struct FieldLI(SInt<24>);
#[name = "SH"]
struct FieldSH(UInt<5>);
#[name = "sh"]
struct FieldSh(UInt<6>);
#[name = "SI"]
struct FieldSI(SInt<16>);
#[name = "si0"]
@ -309,7 +316,7 @@ fn cr_bit_flag_index(
(MOpRegNum::power_isa_cr_reg(field_num), flag_index)
}
impl DecodeState {
impl DecodeState<'_> {
fn form(&self) -> &'static str {
let mut title_words = self
.header
@ -388,6 +395,26 @@ impl DecodeState {
(var.trim(), value.trim())
})
}
fn get_field_wire(&mut self, value: Expr<UInt>, name: &str) -> Expr<UInt> {
let form = self.form();
let width = value.ty().width();
let wire_name =
format!("{form}_{name}_{width}").replace(|c: char| !c.is_ascii_alphanumeric(), "_");
match self
.field_wires
.entry(wire_name.clone())
.or_default()
.entry(value)
{
Entry::Vacant(entry) => {
let wire = wire_with_loc(&wire_name, SourceLocation::caller(), value.ty());
connect(wire, value);
entry.insert(wire);
wire
}
Entry::Occupied(entry) => *entry.get(),
}
}
#[hdl]
fn decode_word(
&mut self,
@ -397,6 +424,20 @@ impl DecodeState {
fields_inner: &'static InstructionBitFieldsInner,
) {
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() {
let bit_number_text = match bit_field.bit_number().text() {
"3031" => "30 31",
@ -436,6 +477,10 @@ impl DecodeState {
if name.contains(char::is_alphabetic) {
for (cond_name, cond_value) in self.conditions() {
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;
break;
}
@ -444,15 +489,25 @@ impl DecodeState {
if name == "any value*" || name.bytes().all(|b| b == b'/') {
// wildcard
} else if name.contains(char::is_alphabetic) {
let wire = wire_with_loc(
&format!("{}_{name}", self.mnemonic)
.replace(|c: char| !c.is_ascii_alphanumeric(), "_"),
SourceLocation::caller(),
field.ty(),
);
connect(wire, field);
if fields.insert(name, wire).is_some() {
panic!("duplicate field name: {name:?}\nheader: {:#?}", self.header);
let Some(field_pieces) = fields_pieces.get_mut(name) else {
unreachable!();
};
field_pieces.filled_pieces.push(field);
if field_pieces.filled_pieces.len() == field_pieces.piece_count {
let filled_pieces = std::mem::take(&mut field_pieces.filled_pieces);
// filled_pieces are in lsb to msb order
let mut filled_pieces = filled_pieces.into_iter();
let Some(mut value) = filled_pieces.next() else {
unreachable!();
};
let mut value_width = value.ty().width();
for next_value in filled_pieces {
value = value | (next_value << value_width);
value_width += next_value.ty().width();
}
value = value.cast_to(UInt[value_width]);
let wire = self.get_field_wire(value, name);
fields.insert(name, wire);
}
} else {
let value: u32 = name.parse().expect("bit field name must have at least one letter, be all `/`, or be a valid decimal number");
@ -476,8 +531,8 @@ impl DecodeState {
let mut f = Some(f);
#[hdl]
#[track_caller]
fn run<FS: FieldSet, F: FnOnce(&mut DecodeState, FS)>(
this: &mut DecodeState,
fn run<'a, FS: FieldSet, F: FnOnce(&mut DecodeState<'a>, FS)>(
this: &mut DecodeState<'a>,
matches: Expr<Bool>,
fields: &mut BTreeMap<&str, Expr<UInt>>,
f: &mut Option<F>,
@ -1856,6 +1911,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`
#[hdl]
fn decode_mcrxrx(&mut self) {
@ -1902,23 +2090,25 @@ impl DecodeState {
}
}
type DecodeFn = fn(&mut DecodeState);
type DecodeFn = fn(&mut DecodeState<'_>);
const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
(&["b", "ba", "bl", "bla"], DecodeState::decode_b_ba_bl_bla),
(&["b", "ba", "bl", "bla"], |state| {
DecodeState::decode_b_ba_bl_bla(state)
}),
(
&[
"bc", "bca", "bcl", "bcla", "bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl",
],
DecodeState::decode_bc_bclr_bcctr_bctar,
|state| DecodeState::decode_bc_bclr_bcctr_bctar(state),
),
(
&[
"crand", "crnand", "cror", "crxor", "crnor", "creqv", "crandc", "crorc",
],
DecodeState::decode_crand_crnand_cror_crxor_crnor_creqv_crandc_crorc,
|state| DecodeState::decode_crand_crnand_cror_crxor_crnor_creqv_crandc_crorc(state),
),
(&["mcrf"], DecodeState::decode_mcrf),
(&["mcrf"], |state| DecodeState::decode_mcrf(state)),
(&["sc", "scv"], |_state| {
// TODO
}),
@ -1928,14 +2118,14 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
"plha", "lhax", "lhau", "lhaux", "lwz", "plwz", "lwzx", "lwzu", "lwzux", "lwa", "plwa",
"lwax", "lwaux", "ld", "pld", "ldx", "ldu", "ldux",
],
DecodeState::decode_load_8_16_32_64_bit,
|state| DecodeState::decode_load_8_16_32_64_bit(state),
),
(
&[
"stb", "pstb", "stbx", "stbu", "stbux", "sth", "psth", "sthx", "sthu", "sthux", "stw",
"pstw", "stwx", "stwu", "stwux", "std", "pstd", "stdx", "stdu", "stdux",
],
DecodeState::decode_store_8_16_32_64_bit,
|state| DecodeState::decode_store_8_16_32_64_bit(state),
),
(&["lq", "plq", "stq", "pstq"], |_state| {
// TODO
@ -1952,43 +2142,46 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
(&["lswi", "lswx", "stswi", "stswx"], |_state| {
// load/store string are intentionally not implemented
}),
(&["addi", "paddi"], DecodeState::decode_addi_paddi),
(&["addis"], DecodeState::decode_addis),
(&["addpcis"], DecodeState::decode_addpcis),
(&["add", "add.", "addo", "addo."], DecodeState::decode_add),
(&["addic", "addic."], DecodeState::decode_addic),
(
&["subf", "subf.", "subfo", "subfo."],
DecodeState::decode_subf_subfc,
),
(&["subfic"], DecodeState::decode_subfic),
(
&["addc", "addc.", "addco", "addco."],
DecodeState::decode_addc,
),
(
&["subfc", "subfc.", "subfco", "subfco."],
DecodeState::decode_subf_subfc,
),
(
&["adde", "adde.", "addeo", "addeo."],
DecodeState::decode_adde,
),
(
&["subfe", "subfe.", "subfeo", "subfeo."],
DecodeState::decode_subfe,
),
(&["addi", "paddi"], |state| {
DecodeState::decode_addi_paddi(state)
}),
(&["addis"], |state| DecodeState::decode_addis(state)),
(&["addpcis"], |state| DecodeState::decode_addpcis(state)),
(&["add", "add.", "addo", "addo."], |state| {
DecodeState::decode_add(state)
}),
(&["addic", "addic."], |state| {
DecodeState::decode_addic(state)
}),
(&["subf", "subf.", "subfo", "subfo."], |state| {
DecodeState::decode_subf_subfc(state)
}),
(&["subfic"], |state| DecodeState::decode_subfic(state)),
(&["addc", "addc.", "addco", "addco."], |state| {
DecodeState::decode_addc(state)
}),
(&["subfc", "subfc.", "subfco", "subfco."], |state| {
DecodeState::decode_subf_subfc(state)
}),
(&["adde", "adde.", "addeo", "addeo."], |state| {
DecodeState::decode_adde(state)
}),
(&["subfe", "subfe.", "subfeo", "subfeo."], |state| {
DecodeState::decode_subfe(state)
}),
(
&[
"addme", "addme.", "addmeo", "addmeo.", "addze", "addze.", "addzeo", "addzeo.",
"subfme", "subfme.", "subfmeo", "subfmeo.", "subfze", "subfze.", "subfzeo", "subfzeo.",
],
DecodeState::decode_addme_subfme_addze_subfze,
|state| DecodeState::decode_addme_subfme_addze_subfze(state),
),
(&["addex"], |_state| {
// TODO
}),
(&["neg", "neg.", "nego", "nego."], DecodeState::decode_neg),
(&["neg", "neg.", "nego", "nego."], |state| {
DecodeState::decode_neg(state)
}),
(
&[
"mulli", "mullw", "mullw.", "mullwo", "mullwo.", "mulhw", "mulhw.", "mulhwu", "mulhwu.",
@ -2029,12 +2222,12 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
// TODO
},
),
(&["cmpi"], DecodeState::decode_cmpi),
(&["cmp"], DecodeState::decode_cmp),
(&["cmpli"], DecodeState::decode_cmpli),
(&["cmpl"], DecodeState::decode_cmpl),
(&["cmprb"], DecodeState::decode_cmprb),
(&["cmpeqb"], DecodeState::decode_cmpeqb),
(&["cmpi"], |state| DecodeState::decode_cmpi(state)),
(&["cmp"], |state| DecodeState::decode_cmp(state)),
(&["cmpli"], |state| DecodeState::decode_cmpli(state)),
(&["cmpl"], |state| DecodeState::decode_cmpl(state)),
(&["cmprb"], |state| DecodeState::decode_cmprb(state)),
(&["cmpeqb"], |state| DecodeState::decode_cmpeqb(state)),
(&["twi", "tw", "tdi", "td"], |_state| {
// TODO
}),
@ -2043,18 +2236,18 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
}),
(
&["andi.", "andis.", "ori", "oris", "xori", "xoris"],
DecodeState::decode_andis_oris_xoris,
|state| DecodeState::decode_andis_oris_xoris(state),
),
(
&[
"and", "and.", "xor", "xor.", "nand", "nand.", "or", "or.", "orc", "orc.", "nor",
"nor.", "eqv", "eqv.", "andc", "andc.",
],
DecodeState::decode_and_xor_nand_or_orc_nor_eqv_andc,
|state| DecodeState::decode_and_xor_nand_or_orc_nor_eqv_andc(state),
),
(
&["extsb", "extsb.", "extsh", "extsh.", "extsw", "extsw."],
DecodeState::decode_extsb_extsh_extsw,
|state| DecodeState::decode_extsb_extsh_extsw(state),
),
(&["cmpb"], |_state| {
// TODO
@ -2084,9 +2277,7 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
"slw", "slw.", "srw", "srw.", "srawi", "srawi.", "sraw", "sraw.", "sld", "sld.",
"sradi", "sradi.", "srd", "srd.", "srad", "srad.",
],
|_state| {
// TODO
},
|state| DecodeState::decode_shift(state),
),
(&["extswsli", "extswsli."], |_state| {
// TODO
@ -2114,7 +2305,7 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
// TODO
},
),
(&["mcrxrx"], DecodeState::decode_mcrxrx),
(&["mcrxrx"], |state| DecodeState::decode_mcrxrx(state)),
(
&[
"mtocrf", "mtcrf", "mfocrf", "mfcr", "setb", "setbc", "setbcr", "setnbc", "setnbcr",
@ -2123,7 +2314,7 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
// TODO
},
),
(&["pnop"], DecodeState::decode_pnop),
(&["pnop"], |state| DecodeState::decode_pnop(state)),
(FP_MNEMONICS, |_state| {
// TODO(FP)
}),
@ -2217,6 +2408,7 @@ pub fn decode_one_insn() {
assert!(!duplicate, "duplicate mnemonic in DECODE_FNS: {mnemonic:?}");
}
}
let mut field_wires = Default::default();
for insn in Instructions::get().instructions() {
for header in insn.header() {
for mnemonic_line in header.mnemonics().lines() {
@ -2260,6 +2452,7 @@ pub fn decode_one_insn() {
first_input,
second_input,
second_input_used,
field_wires: &mut field_wires,
});
}
}

View file

@ -1605,17 +1605,22 @@ impl<DestReg: Type, SrcRegWidth: Size> LogicalMOp<DestReg, SrcRegWidth, ConstUsi
#[hdl]
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,
/// like `llvm.fsh[lr].i16(src0, src1, src2)`
/// like `llvm.fsh[lr].i16(src0, src1, shift_rotate_amount.unwrap_or(src2))`
FunnelShift2x16Bit,
/// like `llvm.fsh[lr].i32(src0, src1, src2)`
/// like `llvm.fsh[lr].i32(src0, src1, shift_rotate_amount.unwrap_or(src2))`
FunnelShift2x32Bit,
/// like `llvm.fsh[lr].i64(src0, src1, src2)`
/// like `llvm.fsh[lr].i64(src0, src1, shift_rotate_amount.unwrap_or(src2))`
FunnelShift2x64Bit,
/// `shift(src0 as i8 as i64, shift_rotate_amount.unwrap_or(src2))`
SignExt8To64BitThenShift,
/// `shift(src0 as i16 as i64, shift_rotate_amount.unwrap_or(src2))`
SignExt16To64BitThenShift,
/// `shift(src0 as i32 as i64, shift_rotate_amount.unwrap_or(src2))`
SignExt32To64BitThenShift,
/// `shift(src0 as i64, shift_rotate_amount.unwrap_or(src2))`
ShiftSigned64,
}
impl HdlPartialEqImpl<Self> for ShiftRotateMode {

View file

@ -38,6 +38,54 @@ pub trait Rotate<Amount> {
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>> {
type Output = Self;
/// like [`usize::rotate_left`]
@ -176,3 +224,59 @@ impl<T: Type, N: Size, AmountSize: Size> Rotate<SimValue<UIntType<AmountSize>>>
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

View file

@ -11,6 +11,7 @@ mod fixed_point_arithmetic;
mod fixed_point_compare;
mod fixed_point_load;
mod fixed_point_logical;
mod fixed_point_rotate_and_shift;
mod fixed_point_store;
mod move_to_from_system_register;
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_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_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(
&mut retval,
);

View file

@ -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
}