forked from libre-chip/cpu
Compare commits
2 commits
59874b9b29
...
faa8dde774
| Author | SHA1 | Date | |
|---|---|---|---|
| faa8dde774 | |||
| 1db65ae753 |
6 changed files with 74970 additions and 120519 deletions
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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