add branch instructions, no tests yet
All checks were successful
/ test (pull_request) Successful in 27m31s
All checks were successful
/ test (pull_request) Successful in 27m31s
This commit is contained in:
parent
1fc56e02f9
commit
2e05329c36
6 changed files with 84886 additions and 13307 deletions
|
|
@ -4,8 +4,8 @@
|
|||
use crate::{
|
||||
config::CpuConfig,
|
||||
instruction::{
|
||||
AddSubMOp, CompareMOp, CompareMode, LogicalMOp, MOp, MOpDestReg, MOpRegNum, MoveRegMOp,
|
||||
OutputIntegerMode,
|
||||
AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LogicalMOp, MOp, MOpDestReg,
|
||||
MOpRegNum, MoveRegMOp, OutputIntegerMode,
|
||||
},
|
||||
powerisa_instructions_xml::{
|
||||
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
|
||||
|
|
@ -179,6 +179,8 @@ macro_rules! impl_fields {
|
|||
impl_fields! {
|
||||
#[name = "BF"]
|
||||
struct FieldBF(FieldCrf);
|
||||
#[name = "BI"]
|
||||
struct FieldBI(FieldCrBit);
|
||||
#[name = "RA"]
|
||||
struct FieldRA(FieldGpr);
|
||||
#[name = "RB"]
|
||||
|
|
@ -187,6 +189,10 @@ impl_fields! {
|
|||
struct FieldRS(FieldGpr);
|
||||
#[name = "RT"]
|
||||
struct FieldRT(FieldGpr);
|
||||
#[name = "BD"]
|
||||
struct FieldBD(SInt<14>);
|
||||
#[name = "LI"]
|
||||
struct FieldLI(SInt<24>);
|
||||
#[name = "SI"]
|
||||
struct FieldSI(SInt<16>);
|
||||
#[name = "si0"]
|
||||
|
|
@ -201,8 +207,16 @@ impl_fields! {
|
|||
struct FieldAddPcISD1(UInt<5>);
|
||||
#[name = "d2"]
|
||||
struct FieldAddPcISD2(UInt<1>);
|
||||
#[name = "BH"]
|
||||
struct FieldBH(UInt<2>);
|
||||
#[name = "BO"]
|
||||
struct FieldBO(UInt<5>);
|
||||
#[name = "AA"]
|
||||
struct FieldAA(Bool);
|
||||
#[name = "L"]
|
||||
struct FieldL(Bool);
|
||||
#[name = "LK"]
|
||||
struct FieldLK(Bool);
|
||||
#[name = "OE"]
|
||||
struct FieldOE(Bool);
|
||||
#[name = "R"]
|
||||
|
|
@ -223,6 +237,12 @@ struct FieldCrf {
|
|||
reg_num: UInt<3>,
|
||||
}
|
||||
|
||||
/// condition register bit
|
||||
#[hdl]
|
||||
struct FieldCrBit {
|
||||
bit_num: UInt<5>,
|
||||
}
|
||||
|
||||
fn gpr(this: impl ToExpr<Type = FieldGpr>) -> Expr<MOpRegNum> {
|
||||
MOpRegNum::power_isa_gpr_reg(this.to_expr().reg_num)
|
||||
}
|
||||
|
|
@ -235,6 +255,26 @@ fn crf(this: impl ToExpr<Type = FieldCrf>) -> Expr<MOpRegNum> {
|
|||
MOpRegNum::power_isa_cr_reg(this.to_expr().reg_num)
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn cr_bit(cr_bit: impl ToExpr<Type = FieldCrBit>) -> (Expr<MOpRegNum>, Expr<ConditionMode>) {
|
||||
let cr_bit = cr_bit.to_expr();
|
||||
#[hdl]
|
||||
let condition_mode = wire();
|
||||
let field_bit = cr_bit.bit_num.cast_to_static::<UInt<2>>();
|
||||
let field_num = (cr_bit.bit_num >> 2).cast_to_static::<UInt<3>>();
|
||||
#[hdl]
|
||||
if field_bit.cmp_eq(0_hdl_u2) {
|
||||
connect(condition_mode, ConditionMode.SLt());
|
||||
} else if field_bit.cmp_eq(1_hdl_u2) {
|
||||
connect(condition_mode, ConditionMode.SGt());
|
||||
} else if field_bit.cmp_eq(2_hdl_u2) {
|
||||
connect(condition_mode, ConditionMode.Eq());
|
||||
} else {
|
||||
connect(condition_mode, ConditionMode.Overflow());
|
||||
}
|
||||
(MOpRegNum::power_isa_cr_reg(field_num), condition_mode)
|
||||
}
|
||||
|
||||
impl DecodeState {
|
||||
fn form(&self) -> &'static str {
|
||||
let mut title_words = self
|
||||
|
|
@ -439,7 +479,160 @@ impl DecodeState {
|
|||
}
|
||||
}
|
||||
fn decode_b_ba_bl_bla(&mut self) {
|
||||
// TODO
|
||||
self.decode_scope(|this, (FieldLI(li), FieldAA(aa), FieldLK(lk))| {
|
||||
connect(
|
||||
ArrayVec::len(this.output),
|
||||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
BranchMOp::branch_i(
|
||||
MOpDestReg::new(
|
||||
[if this.mnemonic.contains('l') {
|
||||
MOpRegNum::power_isa_lr_reg()
|
||||
} else {
|
||||
MOpRegNum::const_zero()
|
||||
}],
|
||||
[],
|
||||
),
|
||||
MOpRegNum::const_zero().value,
|
||||
(li << 2).cast_to_static(),
|
||||
!aa,
|
||||
lk,
|
||||
false,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
#[hdl]
|
||||
fn decode_bc_bclr_bcctr_bctar(&mut self) {
|
||||
let addr_reg = match self.mnemonic {
|
||||
"bc" | "bca" | "bcl" | "bcla" => None,
|
||||
"bclr" | "bclrl" => Some(MOpRegNum::power_isa_lr_reg()),
|
||||
"bcctr" | "bcctrl" => Some(MOpRegNum::power_isa_ctr_reg()),
|
||||
"bctar" | "bctarl" => Some(MOpRegNum::power_isa_tar_reg()),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let body = |this: &mut DecodeState,
|
||||
bo: Expr<UInt<5>>,
|
||||
bi: Expr<FieldCrBit>,
|
||||
is_ret: Expr<Bool>,
|
||||
bd: Option<Expr<SInt<14>>>,
|
||||
aa: Option<Expr<Bool>>,
|
||||
lk: Expr<Bool>| {
|
||||
let use_eq_for_ctr_compare = bo[1]; // BO_3 in specification
|
||||
let no_ctr = bo[2]; // BO_2 in specification
|
||||
let expected_cr_bit_value = bo[3]; // BO_1 in specification
|
||||
let no_cr_bit = bo[4]; // BO_0 in specification
|
||||
let (cr_field, condition_mode) = cr_bit(bi);
|
||||
#[hdl]
|
||||
let branch_mop = wire();
|
||||
#[hdl]
|
||||
let branch_lr_dest_reg = wire();
|
||||
connect(branch_lr_dest_reg, MOpRegNum::const_zero());
|
||||
#[hdl]
|
||||
if lk {
|
||||
connect(branch_lr_dest_reg, MOpRegNum::power_isa_lr_reg());
|
||||
}
|
||||
#[hdl]
|
||||
let branch_ctr_reg: MOpRegNum = wire();
|
||||
let dest = MOpDestReg::new([branch_lr_dest_reg], []);
|
||||
let src1 = addr_reg.unwrap_or_else(|| MOpRegNum::const_zero()).value;
|
||||
let imm = (bd.unwrap_or(0_hdl_i14) << 2).cast_to_static();
|
||||
let invert_src2_eq_zero = !use_eq_for_ctr_compare;
|
||||
let pc_relative = match aa {
|
||||
Some(aa) => !aa,
|
||||
None => addr_reg.is_none().to_expr(),
|
||||
};
|
||||
#[hdl]
|
||||
if no_cr_bit {
|
||||
connect(
|
||||
branch_mop,
|
||||
BranchMOp::branch_ctr(
|
||||
dest,
|
||||
src1,
|
||||
branch_ctr_reg.value,
|
||||
imm,
|
||||
invert_src2_eq_zero,
|
||||
pc_relative,
|
||||
lk,
|
||||
is_ret,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
connect(
|
||||
branch_mop,
|
||||
BranchMOp::branch_cond_ctr(
|
||||
dest,
|
||||
[cr_field.value, src1, branch_ctr_reg.value],
|
||||
imm,
|
||||
!expected_cr_bit_value,
|
||||
condition_mode,
|
||||
invert_src2_eq_zero,
|
||||
pc_relative,
|
||||
lk,
|
||||
is_ret,
|
||||
),
|
||||
);
|
||||
}
|
||||
#[hdl]
|
||||
if no_ctr {
|
||||
connect(
|
||||
ArrayVec::len(this.output),
|
||||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(this.output[0], branch_mop);
|
||||
connect(branch_ctr_reg, MOpRegNum::const_zero());
|
||||
} else {
|
||||
connect(
|
||||
ArrayVec::len(this.output),
|
||||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new([MOpRegNum::power_isa_ctr_reg()], []),
|
||||
[
|
||||
MOpRegNum::power_isa_ctr_reg().value,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
(-1).cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
);
|
||||
connect(this.output[1], branch_mop);
|
||||
connect(branch_ctr_reg, MOpRegNum::power_isa_ctr_reg());
|
||||
}
|
||||
};
|
||||
if addr_reg.is_some() {
|
||||
self.decode_scope(
|
||||
|this, (FieldBO(bo), FieldBI(bi), FieldBH(bh), FieldLK(lk))| {
|
||||
body(
|
||||
this,
|
||||
bo,
|
||||
bi,
|
||||
if this.mnemonic.starts_with("bclr") {
|
||||
bh.cmp_eq(0u8)
|
||||
} else {
|
||||
false.to_expr()
|
||||
},
|
||||
None,
|
||||
None,
|
||||
lk,
|
||||
)
|
||||
},
|
||||
);
|
||||
} else {
|
||||
self.decode_scope(
|
||||
|this, (FieldBO(bo), FieldBI(bi), FieldBD(bd), FieldAA(aa), FieldLK(lk))| {
|
||||
body(this, bo, bi, false.to_expr(), Some(bd), Some(aa), lk)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
fn decode_addi_paddi(&mut self) {
|
||||
|
|
@ -1165,18 +1358,12 @@ type DecodeFn = fn(&mut DecodeState);
|
|||
|
||||
const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
|
||||
(&["b", "ba", "bl", "bla"], DecodeState::decode_b_ba_bl_bla),
|
||||
(&["bc", "bca", "bcl", "bcla"], |_state| {
|
||||
// TODO
|
||||
}),
|
||||
(&["bclr", "bclrl"], |_state| {
|
||||
// TODO
|
||||
}),
|
||||
(&["bcctr", "bcctrl"], |_state| {
|
||||
// TODO
|
||||
}),
|
||||
(&["bctar", "bctarl"], |_state| {
|
||||
// TODO
|
||||
}),
|
||||
(
|
||||
&[
|
||||
"bc", "bca", "bcl", "bcla", "bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl",
|
||||
],
|
||||
DecodeState::decode_bc_bclr_bcctr_bctar,
|
||||
),
|
||||
(
|
||||
&[
|
||||
"crand", "crnand", "cror", "crxor", "crnor", "creqv", "crandc", "crorc",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
use crate::{unit::UnitMOp, util::range_u32_len};
|
||||
use fayalite::{
|
||||
expr::{HdlPartialEqImpl, ops::ArrayLiteral},
|
||||
intern::Interned,
|
||||
intern::{Intern, InternSlice, Interned},
|
||||
module::wire_with_loc,
|
||||
prelude::*,
|
||||
ty::StaticType,
|
||||
|
|
@ -1101,13 +1101,195 @@ impl<DestReg: Type, SrcRegWidth: Size> CompareMOp<DestReg, SrcRegWidth, ConstUsi
|
|||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub enum ConditionMode {
|
||||
Eq,
|
||||
ULt,
|
||||
UGt,
|
||||
SLt,
|
||||
SGt,
|
||||
Sign,
|
||||
Overflow,
|
||||
Parity,
|
||||
}
|
||||
|
||||
impl HdlPartialEqImpl<Self> for ConditionMode {
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
rhs: Self,
|
||||
rhs_value: Cow<'_, Self::SimValue>,
|
||||
) -> bool {
|
||||
SimValue::opaque(&SimValue::from_value(lhs, lhs_value.into_owned()))
|
||||
== SimValue::opaque(&SimValue::from_value(rhs, rhs_value.into_owned()))
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_sim_value_eq(
|
||||
lhs: Cow<'_, SimValue<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_sim_value_ne(
|
||||
lhs: Cow<'_, SimValue<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
|
||||
}
|
||||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> BranchMOp<NewDestReg, NewSrcRegWidth>)]
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> BranchMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct BranchMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
/// `src0` is the value used for reading flags from.
|
||||
/// `src1 + imm + if pc_relative { pc } else { 0 }` is the target address.
|
||||
/// `src2` (if present) is the counter to compare against zero.
|
||||
/// The branch is taken only if all of `src2` (if present) and `src0`'s conditions pass
|
||||
/// The output value is the next instruction's address used for a return address when this is a call.
|
||||
pub struct BranchMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
|
||||
#[common]
|
||||
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, ConstUsize<2>>,
|
||||
pub lut: UInt<4>,
|
||||
pub common: CommonMOp<ConstUsize<0>, DestReg, SrcRegWidth, SrcCount>,
|
||||
pub invert_src0_cond: Bool,
|
||||
pub src0_cond_mode: ConditionMode,
|
||||
/// `src2`'s condition passes if `src2`'s value `== 0`.
|
||||
/// However, if `invert_src2_eq_zero` is set, then the comparison is instead `!= 0`.
|
||||
pub invert_src2_eq_zero: Bool,
|
||||
pub pc_relative: Bool,
|
||||
pub is_call: Bool,
|
||||
pub is_ret: Bool,
|
||||
}
|
||||
}
|
||||
|
||||
impl<DestReg: Type, SrcRegWidth: Size> BranchMOp<DestReg, SrcRegWidth, ConstUsize<2>> {
|
||||
#[hdl]
|
||||
pub fn branch_cond_i<Target: MOpTrait>(
|
||||
dest: impl ToExpr<Type = DestReg>,
|
||||
src: impl ToExpr<Type = Array<UIntType<SrcRegWidth>, 2>>,
|
||||
imm: impl ToExpr<Type = SInt<{ COMMON_MOP_2_IMM_WIDTH }>>,
|
||||
invert_src0_cond: impl ToExpr<Type = Bool>,
|
||||
src0_cond_mode: impl ToExpr<Type = ConditionMode>,
|
||||
pc_relative: impl ToExpr<Type = Bool>,
|
||||
is_call: impl ToExpr<Type = Bool>,
|
||||
is_ret: impl ToExpr<Type = Bool>,
|
||||
) -> Expr<Target>
|
||||
where
|
||||
Self: MOpInto<Target>,
|
||||
{
|
||||
MOpInto::mop_into(
|
||||
#[hdl]
|
||||
BranchMOp {
|
||||
common: CommonMOp::new(0_hdl_u0, dest, src, Expr::as_dyn_int(imm.to_expr())),
|
||||
invert_src0_cond,
|
||||
src0_cond_mode,
|
||||
invert_src2_eq_zero: false,
|
||||
pc_relative,
|
||||
is_call,
|
||||
is_ret,
|
||||
},
|
||||
)
|
||||
}
|
||||
#[hdl]
|
||||
pub fn branch_i<Target: MOpTrait>(
|
||||
dest: impl ToExpr<Type = DestReg>,
|
||||
src1: impl ToExpr<Type = UIntType<SrcRegWidth>>,
|
||||
imm: impl ToExpr<Type = SInt<{ COMMON_MOP_2_IMM_WIDTH }>>,
|
||||
pc_relative: impl ToExpr<Type = Bool>,
|
||||
is_call: impl ToExpr<Type = Bool>,
|
||||
is_ret: impl ToExpr<Type = Bool>,
|
||||
) -> Expr<Target>
|
||||
where
|
||||
Self: MOpInto<Target>,
|
||||
{
|
||||
let src1 = src1.to_expr();
|
||||
Self::branch_cond_i(
|
||||
dest,
|
||||
ArrayLiteral::new(
|
||||
src1.ty(),
|
||||
[src1.ty().zero().to_expr(), src1]
|
||||
.into_iter()
|
||||
.map(Expr::canonical)
|
||||
.collect(),
|
||||
),
|
||||
imm,
|
||||
true,
|
||||
ConditionMode.ULt(),
|
||||
pc_relative,
|
||||
is_call,
|
||||
is_ret,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<DestReg: Type, SrcRegWidth: Size> BranchMOp<DestReg, SrcRegWidth, ConstUsize<3>> {
|
||||
#[hdl]
|
||||
pub fn branch_cond_ctr<Target: MOpTrait>(
|
||||
dest: impl ToExpr<Type = DestReg>,
|
||||
src: impl ToExpr<Type = Array<UIntType<SrcRegWidth>, 3>>,
|
||||
imm: impl ToExpr<Type = SInt<{ COMMON_MOP_3_IMM_WIDTH }>>,
|
||||
invert_src0_cond: impl ToExpr<Type = Bool>,
|
||||
src0_cond_mode: impl ToExpr<Type = ConditionMode>,
|
||||
invert_src2_eq_zero: impl ToExpr<Type = Bool>,
|
||||
pc_relative: impl ToExpr<Type = Bool>,
|
||||
is_call: impl ToExpr<Type = Bool>,
|
||||
is_ret: impl ToExpr<Type = Bool>,
|
||||
) -> Expr<Target>
|
||||
where
|
||||
Self: MOpInto<Target>,
|
||||
{
|
||||
MOpInto::mop_into(
|
||||
#[hdl]
|
||||
BranchMOp {
|
||||
common: CommonMOp::new(0_hdl_u0, dest, src, Expr::as_dyn_int(imm.to_expr())),
|
||||
invert_src0_cond,
|
||||
src0_cond_mode,
|
||||
invert_src2_eq_zero,
|
||||
pc_relative,
|
||||
is_call,
|
||||
is_ret,
|
||||
},
|
||||
)
|
||||
}
|
||||
#[hdl]
|
||||
pub fn branch_ctr<Target: MOpTrait>(
|
||||
dest: impl ToExpr<Type = DestReg>,
|
||||
src1: impl ToExpr<Type = UIntType<SrcRegWidth>>,
|
||||
src2: impl ToExpr<Type = UIntType<SrcRegWidth>>,
|
||||
imm: impl ToExpr<Type = SInt<{ COMMON_MOP_3_IMM_WIDTH }>>,
|
||||
invert_src2_eq_zero: impl ToExpr<Type = Bool>,
|
||||
pc_relative: impl ToExpr<Type = Bool>,
|
||||
is_call: impl ToExpr<Type = Bool>,
|
||||
is_ret: impl ToExpr<Type = Bool>,
|
||||
) -> Expr<Target>
|
||||
where
|
||||
Self: MOpInto<Target>,
|
||||
{
|
||||
let src1 = src1.to_expr();
|
||||
Self::branch_cond_ctr(
|
||||
dest,
|
||||
ArrayLiteral::new(
|
||||
src1.ty(),
|
||||
[src1.ty().zero().to_expr(), src1, src2.to_expr()]
|
||||
.into_iter()
|
||||
.map(Expr::canonical)
|
||||
.collect(),
|
||||
),
|
||||
imm,
|
||||
true,
|
||||
ConditionMode.ULt(),
|
||||
invert_src2_eq_zero,
|
||||
pc_relative,
|
||||
is_call,
|
||||
is_ret,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1121,6 +1303,8 @@ mop_enum! {
|
|||
LogicalI(LogicalMOp<DestReg, SrcRegWidth, ConstUsize<1>>),
|
||||
Compare(CompareMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
|
||||
CompareI(CompareMOp<DestReg, SrcRegWidth, ConstUsize<1>>),
|
||||
Branch(BranchMOp<DestReg, SrcRegWidth, ConstUsize<3>>),
|
||||
BranchI(BranchMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,8 +27,29 @@ pub struct PowerIsaCrBitNum {
|
|||
|
||||
impl MOpRegNum {
|
||||
pub const POWER_ISA_LR_REG_NUM: u32 = 1;
|
||||
#[hdl]
|
||||
pub fn power_isa_lr_reg() -> Expr<Self> {
|
||||
#[hdl]
|
||||
Self {
|
||||
value: Self::POWER_ISA_LR_REG_NUM.cast_to_static::<UInt<_>>(),
|
||||
}
|
||||
}
|
||||
pub const POWER_ISA_CTR_REG_NUM: u32 = 2;
|
||||
#[hdl]
|
||||
pub fn power_isa_ctr_reg() -> Expr<Self> {
|
||||
#[hdl]
|
||||
Self {
|
||||
value: Self::POWER_ISA_CTR_REG_NUM.cast_to_static::<UInt<_>>(),
|
||||
}
|
||||
}
|
||||
pub const POWER_ISA_TAR_REG_NUM: u32 = 3;
|
||||
#[hdl]
|
||||
pub fn power_isa_tar_reg() -> Expr<Self> {
|
||||
#[hdl]
|
||||
Self {
|
||||
value: Self::POWER_ISA_TAR_REG_NUM.cast_to_static::<UInt<_>>(),
|
||||
}
|
||||
}
|
||||
|
||||
/// SO, OV, and OV32 XER bits -- in [`PRegValue.flags`]
|
||||
///
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
use crate::{
|
||||
config::CpuConfig,
|
||||
instruction::{
|
||||
AddSubMOp, AluBranchMOp, AluCommonMOp, COMMON_MOP_SRC_LEN, CommonMOp, CompareMOp,
|
||||
LogicalMOp, MOpTrait, OutputIntegerMode, RenamedMOp, UnitOutRegNum,
|
||||
AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOp,
|
||||
CompareMOp, LogicalMOp, MOpTrait, OutputIntegerMode, RenamedMOp, UnitOutRegNum,
|
||||
},
|
||||
register::{FlagsMode, PRegFlagsPowerISA, PRegFlagsX86, PRegValue},
|
||||
unit::{
|
||||
|
|
@ -272,6 +272,21 @@ fn compare<SrcCount: KnownSize>(
|
|||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn branch<SrcCount: KnownSize>(
|
||||
mop: Expr<BranchMOp<UnitOutRegNum<DynSize>, DynSize, SrcCount>>,
|
||||
pc: Expr<UInt<64>>,
|
||||
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_module]
|
||||
pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
||||
#[hdl]
|
||||
|
|
@ -415,6 +430,42 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
|||
},
|
||||
),
|
||||
),
|
||||
AluBranchMOp::<_, _>::Branch(mop) => connect(
|
||||
unit_base.execute_end,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
ExecuteEnd::<_, _> {
|
||||
unit_output: #[hdl]
|
||||
UnitOutput::<_, _> {
|
||||
which: MOpTrait::dest_reg(mop),
|
||||
result: UnitResult[()].Completed(branch(
|
||||
mop,
|
||||
pc,
|
||||
global_state.flags_mode,
|
||||
src_values,
|
||||
)),
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
AluBranchMOp::<_, _>::BranchI(mop) => connect(
|
||||
unit_base.execute_end,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
ExecuteEnd::<_, _> {
|
||||
unit_output: #[hdl]
|
||||
UnitOutput::<_, _> {
|
||||
which: MOpTrait::dest_reg(mop),
|
||||
result: UnitResult[()].Completed(branch(
|
||||
mop,
|
||||
pc,
|
||||
global_state.flags_mode,
|
||||
src_values,
|
||||
)),
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue