forked from libre-chip/cpu
Compare commits
2 commits
3a35a698e2
...
c9a3de19b7
| Author | SHA1 | Date | |
|---|---|---|---|
| c9a3de19b7 | |||
| 7ebcd5de1e |
6 changed files with 6377 additions and 2190 deletions
|
|
@ -1,22 +1,19 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::instruction::{
|
||||
AddSubMOp, CompareMOp, CompareMode, MOpDestReg, MOpRegNum, OutputIntegerMode,
|
||||
};
|
||||
use crate::powerisa_instructions_xml::{
|
||||
InstructionBitFieldName, InstructionBitFieldsInner, TextLineItem,
|
||||
};
|
||||
use crate::util::array_vec::Length;
|
||||
use crate::{
|
||||
config::CpuConfig, instruction::MOp, powerisa_instructions_xml::Instructions,
|
||||
util::array_vec::ArrayVec,
|
||||
config::CpuConfig,
|
||||
instruction::{
|
||||
AddSubMOp, CompareMOp, CompareMode, LogicalMOp, MOp, MOpDestReg, MOpRegNum, MoveRegMOp,
|
||||
OutputIntegerMode,
|
||||
},
|
||||
powerisa_instructions_xml::{
|
||||
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
|
||||
},
|
||||
util::array_vec::{ArrayVec, Length},
|
||||
};
|
||||
use fayalite::module::wire_with_loc;
|
||||
use fayalite::prelude::*;
|
||||
use fayalite::ty::StaticType;
|
||||
use std::collections::BTreeMap;
|
||||
use std::ops::RangeInclusive;
|
||||
use fayalite::{module::wire_with_loc, prelude::*, ty::StaticType};
|
||||
use std::{collections::BTreeMap, ops::RangeInclusive};
|
||||
|
||||
#[rustfmt::skip]
|
||||
const FP_MNEMONICS: &[&str] = &[
|
||||
|
|
@ -122,6 +119,7 @@ const VSX_MNEMONICS: &[&str] = &[
|
|||
"xxspltiw", "xxspltw", "xxperm", "xxpermr", "xxsldwi", "xxgenpcvdm", "xxgenpcvwm", "lxvkq", "xvtlsbb",
|
||||
];
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DecodeState {
|
||||
mnemonic: &'static str,
|
||||
arguments: Option<&'static str>,
|
||||
|
|
@ -185,6 +183,8 @@ impl_fields! {
|
|||
struct FieldRA(FieldGpr);
|
||||
#[name = "RB"]
|
||||
struct FieldRB(FieldGpr);
|
||||
#[name = "RS"]
|
||||
struct FieldRS(FieldGpr);
|
||||
#[name = "RT"]
|
||||
struct FieldRT(FieldGpr);
|
||||
#[name = "SI"]
|
||||
|
|
@ -1024,6 +1024,103 @@ impl DecodeState {
|
|||
);
|
||||
});
|
||||
}
|
||||
/// for `andi[s]./ori[s]/xori[s]`
|
||||
#[hdl]
|
||||
fn decode_andis_oris_xoris(&mut self) {
|
||||
assert_eq!(self.arguments, Some("RA,RS,UI"), "{self:?}");
|
||||
let lut = match self.mnemonic {
|
||||
"andi." | "andis." => LogicalMOp::lut_from_fn(|[a, b]| a & b),
|
||||
"ori" | "oris" => LogicalMOp::lut_from_fn(|[a, b]| a | b),
|
||||
"xori" | "xoris" => LogicalMOp::lut_from_fn(|[a, b]| a ^ b),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.decode_scope(|this, (FieldRS(rs), FieldRA(ra), FieldUI(ui))| {
|
||||
// TODO: handle SO propagation
|
||||
connect(
|
||||
ArrayVec::len(this.output),
|
||||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
LogicalMOp::logical_i(
|
||||
MOpDestReg::new(
|
||||
[gpr(ra)],
|
||||
[(
|
||||
MOpRegNum::POWER_ISA_CR_0_REG_NUM,
|
||||
this.mnemonic.contains('.').to_expr(),
|
||||
)],
|
||||
),
|
||||
[gpr(rs).value],
|
||||
if this.mnemonic.contains('s') {
|
||||
(ui << 16).cast_to_static::<SInt<_>>()
|
||||
} else {
|
||||
ui.cast_to_static::<SInt<_>>()
|
||||
},
|
||||
OutputIntegerMode.Full64(),
|
||||
lut,
|
||||
),
|
||||
);
|
||||
if this.mnemonic == "ori" {
|
||||
#[hdl]
|
||||
if rs.reg_num.cmp_eq(0u8) & ra.reg_num.cmp_eq(0u8) & ui.cmp_eq(0u8) {
|
||||
// found `nop`, remove at decode time
|
||||
connect(
|
||||
ArrayVec::len(this.output),
|
||||
0usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
/// for `and[.]/xor[.]/nand[.]/or[.]/orc[.]/nor[.]/eqv[.]/andc[.]`
|
||||
#[hdl]
|
||||
fn decode_and_xor_nand_or_orc_nor_eqv_andc(&mut self) {
|
||||
assert_eq!(self.arguments, Some("RA,RS,RB"));
|
||||
let lut = match self.mnemonic.trim_end_matches('.') {
|
||||
"and" => LogicalMOp::lut_from_fn(|[a, b]| a & b),
|
||||
"xor" => LogicalMOp::lut_from_fn(|[a, b]| a ^ b),
|
||||
"nand" => LogicalMOp::lut_from_fn(|[a, b]| !(a & b)),
|
||||
"or" => LogicalMOp::lut_from_fn(|[a, b]| a | b),
|
||||
"orc" => LogicalMOp::lut_from_fn(|[a, b]| a | !b),
|
||||
"nor" => LogicalMOp::lut_from_fn(|[a, b]| !(a | b)),
|
||||
"eqv" => LogicalMOp::lut_from_fn(|[a, b]| a == b),
|
||||
"andc" => LogicalMOp::lut_from_fn(|[a, b]| a & !b),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
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],
|
||||
LogicalMOp::logical(
|
||||
MOpDestReg::new([gpr(ra)], [(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc)]),
|
||||
[gpr(rs).value, gpr(rb).value],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
lut,
|
||||
),
|
||||
);
|
||||
if this.mnemonic == "or" {
|
||||
#[hdl]
|
||||
if rs.reg_num.cmp_eq(rb.reg_num) & !rc {
|
||||
// found `mr`
|
||||
connect(
|
||||
this.output[0],
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new([gpr(ra)], []),
|
||||
[gpr(rs).value],
|
||||
0i8.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
type DecodeFn = fn(&mut DecodeState);
|
||||
|
|
@ -1179,15 +1276,16 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
|
|||
(&["isel"], |_state| {
|
||||
// TODO
|
||||
}),
|
||||
(
|
||||
&["andi.", "andis.", "ori", "oris", "xori", "xoris"],
|
||||
DecodeState::decode_andis_oris_xoris,
|
||||
),
|
||||
(
|
||||
&[
|
||||
"andi.", "andis.", "ori", "oris", "xori", "xoris", "and", "and.", "xor", "xor.",
|
||||
"nand", "nand.", "or", "or.", "orc", "orc.", "nor", "nor.", "eqv", "eqv.", "andc",
|
||||
"andc.",
|
||||
"and", "and.", "xor", "xor.", "nand", "nand.", "or", "or.", "orc", "orc.", "nor",
|
||||
"nor.", "eqv", "eqv.", "andc", "andc.",
|
||||
],
|
||||
|_state| {
|
||||
// TODO
|
||||
},
|
||||
DecodeState::decode_and_xor_nand_or_orc_nor_eqv_andc,
|
||||
),
|
||||
(&["extsb", "extsb.", "extsh", "extsh."], |_state| {
|
||||
// TODO
|
||||
|
|
@ -1367,13 +1465,13 @@ pub fn decode_one_insn() {
|
|||
let mut conditions;
|
||||
if let Some((mnemonic_, rest)) = mnemonic_line.split_once(char::is_whitespace) {
|
||||
mnemonic = mnemonic_;
|
||||
if let Some((arguments_, rest)) =
|
||||
rest.trim_start().split_once(char::is_whitespace)
|
||||
{
|
||||
let rest = rest.trim_start();
|
||||
if let Some((arguments_, rest)) = rest.split_once(char::is_whitespace) {
|
||||
arguments = Some(arguments_);
|
||||
conditions = Some(rest.trim_start()).filter(|v| !v.is_empty());
|
||||
} else {
|
||||
arguments = None;
|
||||
assert!(!rest.starts_with('('));
|
||||
arguments = Some(rest).filter(|v| !v.is_empty());
|
||||
conditions = None;
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -8,11 +8,18 @@ use fayalite::{
|
|||
prelude::*,
|
||||
ty::StaticType,
|
||||
};
|
||||
use std::{borrow::Cow, fmt, marker::PhantomData, ops::Range};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fmt,
|
||||
marker::PhantomData,
|
||||
ops::{ControlFlow, Range},
|
||||
};
|
||||
|
||||
pub mod power_isa;
|
||||
|
||||
pub trait MOpInto<Target: MOpTrait>: MOpTrait {
|
||||
pub trait MOpInto<Target: MOpTrait>:
|
||||
MOpTrait<SrcRegWidth = Target::SrcRegWidth, DestReg = Target::DestReg>
|
||||
{
|
||||
fn mop_into_ty(self) -> Target;
|
||||
fn mop_into(this: Expr<Self>) -> Expr<Target>;
|
||||
}
|
||||
|
|
@ -26,6 +33,52 @@ impl<T: MOpTrait> MOpInto<T> for T {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait MOpVariantVisitOps {
|
||||
type MOp: MOpTrait<
|
||||
DestReg = <Self::Target as MOpTrait>::DestReg,
|
||||
SrcRegWidth = <Self::Target as MOpTrait>::SrcRegWidth,
|
||||
>;
|
||||
type Target: MOpTrait;
|
||||
fn mop_ty(&self) -> &Self::MOp;
|
||||
fn target_ty(&self) -> &Self::Target;
|
||||
fn path() -> Vec<&'static str>;
|
||||
fn mop_into_target(&self, mop: Expr<Self::MOp>) -> Expr<Self::Target>;
|
||||
}
|
||||
|
||||
impl<T: MOpTrait> MOpVariantVisitOps for T {
|
||||
type MOp = T;
|
||||
type Target = T;
|
||||
fn mop_ty(&self) -> &Self::MOp {
|
||||
self
|
||||
}
|
||||
fn target_ty(&self) -> &Self::Target {
|
||||
self
|
||||
}
|
||||
fn path() -> Vec<&'static str> {
|
||||
Vec::new()
|
||||
}
|
||||
fn mop_into_target(&self, mop: Expr<Self::MOp>) -> Expr<Self::Target> {
|
||||
assert_eq!(*self, mop.ty());
|
||||
mop
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MOpVariantVisitor<Target: MOpTrait> {
|
||||
type Break;
|
||||
fn visit_variant<VisitOps: ?Sized + MOpVariantVisitOps<Target = Target, MOp: CommonMOpTrait>>(
|
||||
&mut self,
|
||||
visit_ops: &VisitOps,
|
||||
) -> ControlFlow<Self::Break>;
|
||||
}
|
||||
|
||||
pub trait MOpVisitVariants: MOpTrait {
|
||||
fn visit_variants<V, VisitOps>(visitor: &mut V, visit_ops: &VisitOps) -> ControlFlow<V::Break>
|
||||
where
|
||||
V: ?Sized + MOpVariantVisitor<VisitOps::Target>,
|
||||
VisitOps: ?Sized + MOpVariantVisitOps<MOp = Self>,
|
||||
VisitOps::Target: MOpTrait<DestReg = Self::DestReg, SrcRegWidth = Self::SrcRegWidth>;
|
||||
}
|
||||
|
||||
pub trait MOpTrait: Type {
|
||||
type Mapped<NewDestReg: Type, NewSrcRegWidth: Size>: MOpTrait<DestReg = NewDestReg, SrcRegWidth = NewSrcRegWidth>;
|
||||
type DestReg: Type;
|
||||
|
|
@ -161,6 +214,17 @@ impl<T: CommonMOpTrait> MOpTrait for T {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: CommonMOpTrait> MOpVisitVariants for T {
|
||||
fn visit_variants<V, VisitOps>(visitor: &mut V, visit_ops: &VisitOps) -> ControlFlow<V::Break>
|
||||
where
|
||||
V: ?Sized + MOpVariantVisitor<VisitOps::Target>,
|
||||
VisitOps: ?Sized + MOpVariantVisitOps<MOp = Self>,
|
||||
VisitOps::Target: MOpTrait<DestReg = Self::DestReg, SrcRegWidth = Self::SrcRegWidth>,
|
||||
{
|
||||
visitor.visit_variant(visit_ops)
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub enum OutputIntegerMode {
|
||||
Full64,
|
||||
|
|
@ -456,6 +520,7 @@ macro_rules! mop_enum {
|
|||
$SrcRegWidth:ident: Size
|
||||
$(, #[MOp(get_ty = $mop_types_get_ty:expr)] $MOpTypes:ident: Type)*
|
||||
$(, #[Size(get_size = $sizes_get_size:expr)] $Sizes:ident: Size)*
|
||||
$(, #[MOpVisitVariants] [$($visit_variants_bounds:tt)*])?
|
||||
> {
|
||||
$(#[$($first_variant_meta:tt)*])*
|
||||
$FirstVariant:ident($first_ty:ty),
|
||||
|
|
@ -489,6 +554,30 @@ macro_rules! mop_enum {
|
|||
}
|
||||
}
|
||||
|
||||
mop_enum! {
|
||||
@impl_visit_variants [
|
||||
enum $MOp<
|
||||
$DestReg: Type,
|
||||
$SrcRegWidth: Size
|
||||
$(, #[MOp] $MOpTypes: Type)*
|
||||
$(, #[Size(get_size = $sizes_get_size)] $Sizes: Size)*
|
||||
$(, #[MOpVisitVariants] [$($visit_variants_bounds)*])?
|
||||
>
|
||||
]
|
||||
enum $MOp<
|
||||
$DestReg: Type,
|
||||
$SrcRegWidth: Size
|
||||
$(, #[MOp] $MOpTypes: Type)*
|
||||
$(, #[Size] $Sizes: Size)*
|
||||
$(, #[MOpVisitVariants] [$($visit_variants_bounds)*])?
|
||||
> {
|
||||
$FirstVariant($first_ty),
|
||||
$(
|
||||
$Variant($ty),
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
$DestReg: Type,
|
||||
$SrcRegWidth: Size,
|
||||
|
|
@ -568,6 +657,109 @@ macro_rules! mop_enum {
|
|||
}
|
||||
}
|
||||
};
|
||||
(
|
||||
@impl_visit_variants $visit_variant_args:tt
|
||||
enum $MOp:ident<
|
||||
$DestReg:ident: Type,
|
||||
$SrcRegWidth:ident: Size
|
||||
$(, #[MOp] $MOpTypes:ident: Type)*
|
||||
$(, #[Size] $Sizes:ident: Size)*
|
||||
$(, #[MOpVisitVariants] [$($visit_variants_bounds:tt)*])?
|
||||
> {
|
||||
$(
|
||||
$Variant:ident($ty:ty),
|
||||
)*
|
||||
}
|
||||
) => {
|
||||
const _: () = {
|
||||
mod variant_visit_ops {
|
||||
$(
|
||||
#[derive(Copy, Clone)]
|
||||
pub(super) struct $Variant<VisitOps>(pub(super) VisitOps);
|
||||
)*
|
||||
}
|
||||
|
||||
$(mop_enum! {
|
||||
@impl_visit_variant $visit_variant_args
|
||||
#[variant_ty = $ty]
|
||||
struct variant_visit_ops::$Variant<_>(_);
|
||||
})*
|
||||
|
||||
impl<
|
||||
$DestReg: Type,
|
||||
$SrcRegWidth: Size,
|
||||
$($MOpTypes: Type + MOpTrait<DestReg = $DestReg, SrcRegWidth = $SrcRegWidth>,)*
|
||||
$($Sizes: Size,)*
|
||||
> MOpVisitVariants for $MOp<
|
||||
$DestReg,
|
||||
$SrcRegWidth,
|
||||
$($MOpTypes,)*
|
||||
$($Sizes,)*
|
||||
>
|
||||
where
|
||||
$($($visit_variants_bounds)*)?
|
||||
{
|
||||
fn visit_variants<V, VisitOps>(visitor: &mut V, visit_ops: &VisitOps) -> ControlFlow<V::Break>
|
||||
where
|
||||
V: ?Sized + MOpVariantVisitor<VisitOps::Target>,
|
||||
VisitOps: ?Sized + MOpVariantVisitOps<MOp = Self>,
|
||||
VisitOps::Target: MOpTrait<DestReg = Self::DestReg, SrcRegWidth = Self::SrcRegWidth>,
|
||||
{
|
||||
$(MOpVisitVariants::visit_variants(visitor, &variant_visit_ops::$Variant(visit_ops))?;)*
|
||||
std::ops::ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
(
|
||||
@impl_visit_variant [
|
||||
enum $MOp:ident<
|
||||
$DestReg:ident: Type,
|
||||
$SrcRegWidth:ident: Size
|
||||
$(, #[MOp] $MOpTypes:ident: Type)*
|
||||
$(, #[Size(get_size = $sizes_get_size:expr)] $Sizes:ident: Size)*
|
||||
$(, #[MOpVisitVariants] [$($visit_variants_bounds:tt)*])?
|
||||
>
|
||||
]
|
||||
#[variant_ty = $ty:ty]
|
||||
struct $variant_visit_ops:ident::$Variant:ident<_>(_);
|
||||
) => {
|
||||
impl<
|
||||
$DestReg: Type,
|
||||
$SrcRegWidth: Size,
|
||||
$($MOpTypes: Type + MOpTrait<DestReg = $DestReg, SrcRegWidth = $SrcRegWidth>,)*
|
||||
$($Sizes: Size,)*
|
||||
VisitOps,
|
||||
> MOpVariantVisitOps for $variant_visit_ops::$Variant<&'_ VisitOps>
|
||||
where
|
||||
VisitOps: ?Sized + MOpVariantVisitOps<MOp = $MOp<
|
||||
$DestReg,
|
||||
$SrcRegWidth,
|
||||
$($MOpTypes,)*
|
||||
$($Sizes,)*
|
||||
>>,
|
||||
VisitOps::Target: MOpTrait<DestReg = $DestReg, SrcRegWidth = $SrcRegWidth>,
|
||||
{
|
||||
type MOp = $ty;
|
||||
type Target = VisitOps::Target;
|
||||
fn mop_ty(&self) -> &Self::MOp {
|
||||
&self.0.mop_ty().$Variant
|
||||
}
|
||||
fn target_ty(&self) -> &Self::Target {
|
||||
self.0.target_ty()
|
||||
}
|
||||
fn path() -> Vec<&'static str> {
|
||||
let mut retval = VisitOps::path();
|
||||
retval.push(stringify!($Variant));
|
||||
retval
|
||||
}
|
||||
fn mop_into_target(&self, mop: Expr<Self::MOp>) -> Expr<Self::Target> {
|
||||
let mop_ty = self.0.mop_ty();
|
||||
assert_eq!(mop_ty.$Variant, mop.ty());
|
||||
self.0.mop_into_target(mop_ty.$Variant(mop))
|
||||
}
|
||||
}
|
||||
};
|
||||
(
|
||||
@impl_variants
|
||||
#[impl_mop_into = true]
|
||||
|
|
@ -595,9 +787,10 @@ macro_rules! mop_enum {
|
|||
$Variant:ident($ty:ty),
|
||||
}
|
||||
) => {
|
||||
impl<$DestReg: Type, $SrcRegWidth: Size, Target: MOpTrait, $($Sizes: Size,)*> MOpInto<Target> for $ty
|
||||
impl<$DestReg: Type, $SrcRegWidth: Size, Target, $($Sizes: Size,)*> MOpInto<Target> for $ty
|
||||
where
|
||||
$MOp<$DestReg, $SrcRegWidth, $($Sizes,)*>: MOpInto<Target>
|
||||
$MOp<$DestReg, $SrcRegWidth, $($Sizes,)*>: MOpInto<Target>,
|
||||
Target: MOpTrait<DestReg = $DestReg, SrcRegWidth = $SrcRegWidth>,
|
||||
{
|
||||
fn mop_into_ty(self) -> Target {
|
||||
MOpInto::mop_into_ty($MOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)]$([$sizes_get_size(self)])*)
|
||||
|
|
@ -701,16 +894,48 @@ impl<DestReg: Type, SrcRegWidth: Size> AddSubMOp<DestReg, SrcRegWidth, ConstUsiz
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> LogicalMOp<NewDestReg, NewSrcRegWidth>)]
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> LogicalMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct LogicalMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
/// computes the output like so:
|
||||
/// ```
|
||||
/// fn logical_output(src: [u64; 2], lut: u8) -> u64 {
|
||||
/// let mut output = 0u64;
|
||||
/// for i in 0..64 {
|
||||
/// let mask = 1 << i;
|
||||
/// let mut lut_index = 0;
|
||||
/// if (src[0] & mask) != 0 {
|
||||
/// lut_index |= 1;
|
||||
/// }
|
||||
/// if (src[1] & mask) != 0 {
|
||||
/// lut_index |= 2;
|
||||
/// }
|
||||
/// if (lut & (1 << lut_index)) != 0 {
|
||||
/// output |= mask;
|
||||
/// }
|
||||
/// }
|
||||
/// output
|
||||
/// }
|
||||
/// ```
|
||||
pub struct LogicalMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
|
||||
#[common]
|
||||
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, ConstUsize<2>>,
|
||||
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, SrcCount>,
|
||||
pub lut: UInt<4>,
|
||||
}
|
||||
}
|
||||
|
||||
impl<DestReg: Type, SrcRegWidth: Size> LogicalMOp<DestReg, SrcRegWidth> {
|
||||
impl LogicalMOp<MOpDestReg, ConstUsize<{ MOpRegNum::WIDTH }>, ConstUsize<2>> {
|
||||
pub fn lut_from_fn(f: impl Fn([bool; 2]) -> bool) -> UIntValue<ConstUsize<4>> {
|
||||
let mut retval = 0u8;
|
||||
for lut_index in 0..4 {
|
||||
if f([(lut_index & 1) != 0, (lut_index & 2) != 0]) {
|
||||
retval |= 1 << lut_index;
|
||||
}
|
||||
}
|
||||
retval.cast_to_static::<UInt<4>>()
|
||||
}
|
||||
}
|
||||
|
||||
impl<DestReg: Type, SrcRegWidth: Size> LogicalMOp<DestReg, SrcRegWidth, ConstUsize<2>> {
|
||||
#[hdl]
|
||||
pub fn logical<Target: MOpTrait>(
|
||||
dest: impl ToExpr<Type = DestReg>,
|
||||
|
|
@ -736,6 +961,32 @@ impl<DestReg: Type, SrcRegWidth: Size> LogicalMOp<DestReg, SrcRegWidth> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<DestReg: Type, SrcRegWidth: Size> LogicalMOp<DestReg, SrcRegWidth, ConstUsize<1>> {
|
||||
#[hdl]
|
||||
pub fn logical_i<Target: MOpTrait>(
|
||||
dest: impl ToExpr<Type = DestReg>,
|
||||
src: impl ToExpr<Type = Array<UIntType<SrcRegWidth>, 1>>,
|
||||
imm: impl ToExpr<Type = SInt<{ COMMON_MOP_1_IMM_WIDTH }>>,
|
||||
output_integer_mode: impl ToExpr<Type = OutputIntegerMode>,
|
||||
lut: impl ToExpr<Type = UInt<4>>,
|
||||
) -> Expr<Target>
|
||||
where
|
||||
Self: MOpInto<Target>,
|
||||
{
|
||||
MOpInto::mop_into(
|
||||
#[hdl]
|
||||
LogicalMOp {
|
||||
alu_common: #[hdl]
|
||||
AluCommonMOp {
|
||||
common: CommonMOp::new(0_hdl_u0, dest, src, Expr::as_dyn_int(imm.to_expr())),
|
||||
output_integer_mode,
|
||||
},
|
||||
lut,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub enum CompareMode {
|
||||
U64,
|
||||
|
|
@ -866,7 +1117,8 @@ mop_enum! {
|
|||
pub enum AluBranchMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
AddSub(AddSubMOp<DestReg, SrcRegWidth, ConstUsize<3>>),
|
||||
AddSubI(AddSubMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
|
||||
Logical(LogicalMOp<DestReg, SrcRegWidth>),
|
||||
Logical(LogicalMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
|
||||
LogicalI(LogicalMOp<DestReg, SrcRegWidth, ConstUsize<1>>),
|
||||
Compare(CompareMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
|
||||
CompareI(CompareMOp<DestReg, SrcRegWidth, ConstUsize<1>>),
|
||||
}
|
||||
|
|
@ -930,8 +1182,8 @@ mop_enum! {
|
|||
#[impl_mop_into = true]
|
||||
#[hdl]
|
||||
pub enum LoadStoreMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
Load(CommonMOp<ConstUsize<1>, DestReg, SrcRegWidth, ConstUsize<0>>),
|
||||
Store(CommonMOp<ConstUsize<1>, DestReg, SrcRegWidth, ConstUsize<1>>),
|
||||
Load(CommonMOp<ConstUsize<2>, DestReg, SrcRegWidth, ConstUsize<0>>),
|
||||
Store(CommonMOp<ConstUsize<2>, DestReg, SrcRegWidth, ConstUsize<1>>),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -940,7 +1192,49 @@ common_mop_struct! {
|
|||
#[hdl(cmp_eq)]
|
||||
pub struct MoveRegMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
#[common]
|
||||
pub common: CommonMOp<ConstUsize<2>, DestReg, SrcRegWidth, ConstUsize<1>>,
|
||||
pub common: CommonMOp<ConstUsize<3>, DestReg, SrcRegWidth, ConstUsize<1>>,
|
||||
}
|
||||
}
|
||||
|
||||
impl<DestReg: Type, SrcRegWidth: Size, Target> MOpInto<Target> for MoveRegMOp<DestReg, SrcRegWidth>
|
||||
where
|
||||
UnitMOp<DestReg, SrcRegWidth, Self>: MOpInto<Target>,
|
||||
Target: MOpTrait<DestReg = DestReg, SrcRegWidth = SrcRegWidth>,
|
||||
{
|
||||
fn mop_into_ty(self) -> Target {
|
||||
MOpInto::mop_into_ty(
|
||||
UnitMOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)][self],
|
||||
)
|
||||
}
|
||||
fn mop_into(this: Expr<Self>) -> Expr<Target> {
|
||||
MOpInto::mop_into(
|
||||
MOpInto::<UnitMOp<DestReg, SrcRegWidth, Self>>::mop_into_ty(this.ty())
|
||||
.TransformedMove(this),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<DestReg: Type, SrcRegWidth: Size> MoveRegMOp<DestReg, SrcRegWidth> {
|
||||
#[hdl]
|
||||
pub fn move_reg<Target: MOpTrait>(
|
||||
dest: impl ToExpr<Type = DestReg>,
|
||||
src: impl ToExpr<Type = Array<UIntType<SrcRegWidth>, 1>>,
|
||||
imm: impl ToExpr<Type = SInt<{ COMMON_MOP_1_IMM_WIDTH }>>,
|
||||
) -> Expr<Target>
|
||||
where
|
||||
Self: MOpInto<Target>,
|
||||
{
|
||||
MOpInto::mop_into(
|
||||
#[hdl]
|
||||
MoveRegMOp {
|
||||
common: CommonMOp::new(
|
||||
0.cast_to_static::<UInt<_>>(),
|
||||
dest,
|
||||
src,
|
||||
Expr::as_dyn_int(imm.to_expr()),
|
||||
),
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1310,3 +1604,115 @@ pub type MOp = UnitMOp<
|
|||
#[hdl]
|
||||
pub type RenamedMOp<DestReg: Type, SrcRegWidth: Size> =
|
||||
UnitMOp<DestReg, SrcRegWidth, L2RegisterFileMOp<DestReg, SrcRegWidth>>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::{convert::Infallible, fmt::Write, usize};
|
||||
|
||||
#[test]
|
||||
fn ensure_reg_fields_are_in_the_same_place() {
|
||||
struct Visitor {
|
||||
dest_reg_offset: Option<(usize, String)>,
|
||||
max_dest_reg_offset: usize,
|
||||
min_prefix_pad: usize,
|
||||
errors: Option<String>,
|
||||
}
|
||||
impl MOpVariantVisitor<MOp> for Visitor {
|
||||
type Break = Infallible;
|
||||
fn visit_variant<
|
||||
VisitOps: ?Sized + MOpVariantVisitOps<Target = MOp, MOp: CommonMOpTrait>,
|
||||
>(
|
||||
&mut self,
|
||||
visit_ops: &VisitOps,
|
||||
) -> ControlFlow<Self::Break> {
|
||||
self.min_prefix_pad = self
|
||||
.min_prefix_pad
|
||||
.min(<VisitOps::MOp as CommonMOpTrait>::PrefixPad::VALUE);
|
||||
let variant = visit_ops.mop_ty();
|
||||
let zeroed_variant = UInt[variant.canonical().bit_width()]
|
||||
.zero()
|
||||
.cast_bits_to(*variant);
|
||||
let mut common_mop = CommonMOpTrait::common_mop(&zeroed_variant).into_sim_value();
|
||||
SimValue::bits_mut(&mut common_mop.dest)
|
||||
.bits_mut()
|
||||
.fill(false);
|
||||
let with_zeros = visit_ops
|
||||
.mop_into_target(Expr::from_canonical(Expr::canonical(
|
||||
CommonMOpTrait::with_common_mop(&zeroed_variant, &common_mop),
|
||||
)))
|
||||
.into_sim_value();
|
||||
SimValue::bits_mut(&mut common_mop.dest)
|
||||
.bits_mut()
|
||||
.fill(true);
|
||||
let with_ones = visit_ops
|
||||
.mop_into_target(Expr::from_canonical(Expr::canonical(
|
||||
CommonMOpTrait::with_common_mop(&zeroed_variant, &common_mop),
|
||||
)))
|
||||
.into_sim_value();
|
||||
let mut dest_reg_offset = None;
|
||||
for (i, (a, b)) in SimValue::bits(&with_zeros)
|
||||
.bits()
|
||||
.iter()
|
||||
.by_vals()
|
||||
.zip(SimValue::bits(&with_ones).bits().iter().by_vals())
|
||||
.enumerate()
|
||||
{
|
||||
if a != b {
|
||||
dest_reg_offset = Some(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let Some(dest_reg_offset) = dest_reg_offset else {
|
||||
panic!("no dest reg offset: {variant:#?}");
|
||||
};
|
||||
self.max_dest_reg_offset = self.max_dest_reg_offset.max(dest_reg_offset);
|
||||
if let Some((first_dest_reg_offset, _)) = self.dest_reg_offset {
|
||||
if first_dest_reg_offset != dest_reg_offset {
|
||||
writeln!(
|
||||
self.errors.get_or_insert_default(),
|
||||
"dest_reg_offset {dest_reg_offset} doesn't match first \
|
||||
variant's dest_reg_offset {first_dest_reg_offset}\n\
|
||||
variant's path: {:?}\n\
|
||||
variant: {variant:#?}\n",
|
||||
VisitOps::path(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
} else {
|
||||
self.dest_reg_offset = Some((
|
||||
dest_reg_offset,
|
||||
format!(
|
||||
"first variant's path: {:?}\nfirst variant: {variant:#?}",
|
||||
VisitOps::path()
|
||||
),
|
||||
));
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
let mut visitor = Visitor {
|
||||
dest_reg_offset: None,
|
||||
max_dest_reg_offset: 0,
|
||||
min_prefix_pad: usize::MAX,
|
||||
errors: None,
|
||||
};
|
||||
let ControlFlow::Continue(()) = MOp::visit_variants(&mut visitor, &MOp);
|
||||
let Visitor {
|
||||
dest_reg_offset: Some((_, first_variant)),
|
||||
max_dest_reg_offset,
|
||||
min_prefix_pad,
|
||||
errors,
|
||||
} = visitor
|
||||
else {
|
||||
panic!("no variants");
|
||||
};
|
||||
println!("max_dest_reg_offset: {max_dest_reg_offset}");
|
||||
println!("min_prefix_pad: {min_prefix_pad}");
|
||||
println!("{first_variant}");
|
||||
if let Some(errors) = errors {
|
||||
panic!("{errors}");
|
||||
}
|
||||
assert_eq!(min_prefix_pad, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@
|
|||
use crate::{
|
||||
config::CpuConfig,
|
||||
instruction::{
|
||||
AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpRegNum, MOpTrait, RenamedMOp,
|
||||
UnitOutRegNum, mop_enum,
|
||||
AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpRegNum, MOpTrait,
|
||||
MOpVariantVisitOps, MOpVariantVisitor, MOpVisitVariants, RenamedMOp, UnitOutRegNum,
|
||||
mop_enum,
|
||||
},
|
||||
register::{FlagsMode, PRegValue},
|
||||
unit::unit_base::UnitToRegAlloc,
|
||||
|
|
@ -16,6 +17,7 @@ use fayalite::{
|
|||
prelude::*,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
pub mod alu_branch;
|
||||
pub mod unit_base;
|
||||
|
|
@ -83,7 +85,15 @@ macro_rules! all_units {
|
|||
#[impl_mop_into = false]
|
||||
#[hdl]
|
||||
$(#[$enum_meta])*
|
||||
$vis enum $UnitMOpEnum<$DestReg: Type, $SrcRegWidth: Size, #[MOp(get_ty = $transformed_move_op_get_ty)] $TransformedMoveOp: Type> {
|
||||
$vis enum $UnitMOpEnum<
|
||||
$DestReg: Type,
|
||||
$SrcRegWidth: Size,
|
||||
#[MOp(get_ty = $transformed_move_op_get_ty)] $TransformedMoveOp: Type,
|
||||
#[MOpVisitVariants] [
|
||||
$TransformedMoveOp: MOpVisitVariants<DestReg = $DestReg, SrcRegWidth = $SrcRegWidth>,
|
||||
$($Op: MOpVisitVariants<DestReg = $DestReg, SrcRegWidth = $SrcRegWidth>,)*
|
||||
]
|
||||
> {
|
||||
$(
|
||||
$(#[$variant_meta])*
|
||||
$Unit($Op),
|
||||
|
|
|
|||
|
|
@ -232,7 +232,21 @@ fn add_sub<SrcCount: KnownSize>(
|
|||
|
||||
#[hdl]
|
||||
fn logical(
|
||||
mop: Expr<LogicalMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
||||
mop: Expr<LogicalMOp<UnitOutRegNum<DynSize>, DynSize, ConstUsize<2>>>,
|
||||
flags_mode: Expr<FlagsMode>,
|
||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||
) -> Expr<UnitResultCompleted<()>> {
|
||||
// TODO: finish
|
||||
#[hdl]
|
||||
UnitResultCompleted::<_> {
|
||||
value: PRegValue::zeroed(),
|
||||
extra_out: (),
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn logical_i(
|
||||
mop: Expr<LogicalMOp<UnitOutRegNum<DynSize>, DynSize, ConstUsize<1>>>,
|
||||
flags_mode: Expr<FlagsMode>,
|
||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||
) -> Expr<UnitResultCompleted<()>> {
|
||||
|
|
@ -350,6 +364,23 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
|||
},
|
||||
),
|
||||
),
|
||||
AluBranchMOp::<_, _>::LogicalI(mop) => connect(
|
||||
unit_base.execute_end,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
ExecuteEnd::<_, _> {
|
||||
unit_output: #[hdl]
|
||||
UnitOutput::<_, _> {
|
||||
which: MOpTrait::dest_reg(mop),
|
||||
result: UnitResult[()].Completed(logical_i(
|
||||
mop,
|
||||
global_state.flags_mode,
|
||||
src_values,
|
||||
)),
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
AluBranchMOp::<_, _>::Compare(mop) => connect(
|
||||
unit_base.execute_end,
|
||||
HdlSome(
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -4,7 +4,8 @@
|
|||
use cpu::{
|
||||
decoder::simple_power_isa::decode_one_insn,
|
||||
instruction::{
|
||||
AddSubMOp, CompareMOp, CompareMode, MOp, MOpDestReg, MOpRegNum, OutputIntegerMode,
|
||||
AddSubMOp, CompareMOp, CompareMode, LogicalMOp, MOp, MOpDestReg, MOpRegNum, MoveRegMOp,
|
||||
OutputIntegerMode,
|
||||
},
|
||||
util::array_vec::ArrayVec,
|
||||
};
|
||||
|
|
@ -52,6 +53,19 @@ impl fmt::Debug for TestCase {
|
|||
fn test_cases() -> Vec<TestCase> {
|
||||
let mut retval = Vec::new();
|
||||
#[track_caller]
|
||||
fn insn_empty(mnemonic: &'static str, first_input: u32, second_input: Option<u32>) -> TestCase {
|
||||
let zero_mop = UInt::new_dyn(MOp.canonical().bit_width())
|
||||
.zero()
|
||||
.cast_bits_to(MOp);
|
||||
TestCase {
|
||||
mnemonic,
|
||||
first_input,
|
||||
second_input,
|
||||
output: ArrayVec::new_sim(ArrayVec[MOp][ConstUsize], &zero_mop),
|
||||
loc: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
#[track_caller]
|
||||
fn insn_single(
|
||||
mnemonic: &'static str,
|
||||
first_input: u32,
|
||||
|
|
@ -68,7 +82,7 @@ fn test_cases() -> Vec<TestCase> {
|
|||
mnemonic,
|
||||
first_input,
|
||||
second_input,
|
||||
output: single_storage.clone(),
|
||||
output: single_storage,
|
||||
loc: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
|
|
@ -663,6 +677,221 @@ fn test_cases() -> Vec<TestCase> {
|
|||
CompareMode::CmpEqB(),
|
||||
),
|
||||
));
|
||||
macro_rules! insn_logic_i {
|
||||
(
|
||||
$mnemonic:literal $dest:literal, $src:literal, $imm:literal;
|
||||
$encoding:literal;
|
||||
|[$a:ident, $b:ident]| $lut_fn:expr;
|
||||
) => {
|
||||
retval.push(insn_single(
|
||||
concat!(
|
||||
$mnemonic,
|
||||
" ",
|
||||
stringify!($dest),
|
||||
", ",
|
||||
stringify!($src),
|
||||
", ",
|
||||
stringify!($imm)
|
||||
),
|
||||
$encoding,
|
||||
None,
|
||||
LogicalMOp::logical_i(
|
||||
MOpDestReg::new_sim(
|
||||
&[MOpRegNum::power_isa_gpr_reg_num($dest)],
|
||||
if $mnemonic.contains('.') {
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM]
|
||||
} else {
|
||||
&[]
|
||||
},
|
||||
),
|
||||
[MOpRegNum::power_isa_gpr_reg(
|
||||
($src as u8).cast_to_static::<UInt<_>>().to_expr(),
|
||||
)
|
||||
.value],
|
||||
(($imm as u32) << if $mnemonic.contains('s') { 16 } else { 0 })
|
||||
.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
LogicalMOp::lut_from_fn(|[$a, $b]| $lut_fn),
|
||||
),
|
||||
));
|
||||
};
|
||||
}
|
||||
insn_logic_i! {
|
||||
"andi." 3, 4, 0x89ab;
|
||||
0x708389ab;
|
||||
|[a, b]| a & b;
|
||||
}
|
||||
insn_logic_i! {
|
||||
"andis." 3, 4, 0x89ab;
|
||||
0x748389ab;
|
||||
|[a, b]| a & b;
|
||||
}
|
||||
insn_logic_i! {
|
||||
"ori" 3, 4, 0x89ab;
|
||||
0x608389ab;
|
||||
|[a, b]| a | b;
|
||||
}
|
||||
// ensure nop decodes to zero instructions
|
||||
retval.push(insn_empty("ori 0, 0, 0", 0x60000000, None));
|
||||
insn_logic_i! {
|
||||
"oris" 3, 4, 0x89ab;
|
||||
0x648389ab;
|
||||
|[a, b]| a | b;
|
||||
}
|
||||
insn_logic_i! {
|
||||
"xori" 3, 4, 0x89ab;
|
||||
0x688389ab;
|
||||
|[a, b]| a ^ b;
|
||||
}
|
||||
insn_logic_i! {
|
||||
"xori" 0, 0, 0; // ensure xnop actually decodes to a normal ALU instruction
|
||||
0x68000000;
|
||||
|[a, b]| a ^ b;
|
||||
}
|
||||
insn_logic_i! {
|
||||
"xoris" 3, 4, 0x89ab;
|
||||
0x6c8389ab;
|
||||
|[a, b]| a ^ b;
|
||||
}
|
||||
macro_rules! insn_logic {
|
||||
(
|
||||
$mnemonic:literal $dest:literal, $src0:literal, $src1:literal;
|
||||
$encoding:literal;
|
||||
|[$a:ident, $b:ident]| $lut_fn:expr;
|
||||
) => {
|
||||
retval.push(insn_single(
|
||||
concat!(
|
||||
$mnemonic,
|
||||
" ",
|
||||
stringify!($dest),
|
||||
", ",
|
||||
stringify!($src0),
|
||||
", ",
|
||||
stringify!($src1)
|
||||
),
|
||||
$encoding,
|
||||
None,
|
||||
LogicalMOp::logical(
|
||||
MOpDestReg::new_sim(
|
||||
&[MOpRegNum::power_isa_gpr_reg_num($dest)],
|
||||
if $mnemonic.contains('.') {
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM]
|
||||
} else {
|
||||
&[]
|
||||
},
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg(
|
||||
($src0 as u8).cast_to_static::<UInt<_>>().to_expr(),
|
||||
)
|
||||
.value,
|
||||
MOpRegNum::power_isa_gpr_reg(
|
||||
($src1 as u8).cast_to_static::<UInt<_>>().to_expr(),
|
||||
)
|
||||
.value,
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
LogicalMOp::lut_from_fn(|[$a, $b]| $lut_fn),
|
||||
),
|
||||
));
|
||||
};
|
||||
}
|
||||
insn_logic! {
|
||||
"and" 3, 4, 5;
|
||||
0x7c832838;
|
||||
|[a, b]| a & b;
|
||||
}
|
||||
insn_logic! {
|
||||
"and." 3, 4, 5;
|
||||
0x7c832839;
|
||||
|[a, b]| a & b;
|
||||
}
|
||||
insn_logic! {
|
||||
"xor" 3, 4, 5;
|
||||
0x7c832a78;
|
||||
|[a, b]| a ^ b;
|
||||
}
|
||||
insn_logic! {
|
||||
"xor." 3, 4, 5;
|
||||
0x7c832a79;
|
||||
|[a, b]| a ^ b;
|
||||
}
|
||||
insn_logic! {
|
||||
"nand" 3, 4, 5;
|
||||
0x7c832bb8;
|
||||
|[a, b]| !(a & b);
|
||||
}
|
||||
insn_logic! {
|
||||
"nand." 3, 4, 5;
|
||||
0x7c832bb9;
|
||||
|[a, b]| !(a & b);
|
||||
}
|
||||
insn_logic! {
|
||||
"or" 3, 4, 5;
|
||||
0x7c832b78;
|
||||
|[a, b]| a | b;
|
||||
}
|
||||
retval.push(insn_single(
|
||||
"or 3, 4, 4", // mr 3, 4
|
||||
0x7c832378,
|
||||
None,
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
));
|
||||
insn_logic! {
|
||||
"or." 3, 4, 5;
|
||||
0x7c832b79;
|
||||
|[a, b]| a | b;
|
||||
}
|
||||
insn_logic! {
|
||||
"or." 3, 4, 4; // mr. 3, 4
|
||||
0x7c832379;
|
||||
|[a, b]| a | b;
|
||||
}
|
||||
insn_logic! {
|
||||
"orc" 3, 4, 5;
|
||||
0x7c832b38;
|
||||
|[a, b]| a | !b;
|
||||
}
|
||||
insn_logic! {
|
||||
"orc." 3, 4, 5;
|
||||
0x7c832b39;
|
||||
|[a, b]| a | !b;
|
||||
}
|
||||
insn_logic! {
|
||||
"nor" 3, 4, 5;
|
||||
0x7c8328f8;
|
||||
|[a, b]| !(a | b);
|
||||
}
|
||||
insn_logic! {
|
||||
"nor." 3, 4, 5;
|
||||
0x7c8328f9;
|
||||
|[a, b]| !(a | b);
|
||||
}
|
||||
insn_logic! {
|
||||
"eqv" 3, 4, 5;
|
||||
0x7c832a38;
|
||||
|[a, b]| a == b;
|
||||
}
|
||||
insn_logic! {
|
||||
"eqv." 3, 4, 5;
|
||||
0x7c832a39;
|
||||
|[a, b]| a == b;
|
||||
}
|
||||
insn_logic! {
|
||||
"andc" 3, 4, 5;
|
||||
0x7c832878;
|
||||
|[a, b]| a & !b;
|
||||
}
|
||||
insn_logic! {
|
||||
"andc." 3, 4, 5;
|
||||
0x7c832879;
|
||||
|[a, b]| a & !b;
|
||||
}
|
||||
retval
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue