forked from libre-chip/cpu
add branch instructions, no tests yet
This commit is contained in:
parent
1fc56e02f9
commit
2e05329c36
6 changed files with 84886 additions and 13307 deletions
|
|
@ -4,8 +4,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
config::CpuConfig,
|
config::CpuConfig,
|
||||||
instruction::{
|
instruction::{
|
||||||
AddSubMOp, CompareMOp, CompareMode, LogicalMOp, MOp, MOpDestReg, MOpRegNum, MoveRegMOp,
|
AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LogicalMOp, MOp, MOpDestReg,
|
||||||
OutputIntegerMode,
|
MOpRegNum, MoveRegMOp, OutputIntegerMode,
|
||||||
},
|
},
|
||||||
powerisa_instructions_xml::{
|
powerisa_instructions_xml::{
|
||||||
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
|
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
|
||||||
|
|
@ -179,6 +179,8 @@ macro_rules! impl_fields {
|
||||||
impl_fields! {
|
impl_fields! {
|
||||||
#[name = "BF"]
|
#[name = "BF"]
|
||||||
struct FieldBF(FieldCrf);
|
struct FieldBF(FieldCrf);
|
||||||
|
#[name = "BI"]
|
||||||
|
struct FieldBI(FieldCrBit);
|
||||||
#[name = "RA"]
|
#[name = "RA"]
|
||||||
struct FieldRA(FieldGpr);
|
struct FieldRA(FieldGpr);
|
||||||
#[name = "RB"]
|
#[name = "RB"]
|
||||||
|
|
@ -187,6 +189,10 @@ impl_fields! {
|
||||||
struct FieldRS(FieldGpr);
|
struct FieldRS(FieldGpr);
|
||||||
#[name = "RT"]
|
#[name = "RT"]
|
||||||
struct FieldRT(FieldGpr);
|
struct FieldRT(FieldGpr);
|
||||||
|
#[name = "BD"]
|
||||||
|
struct FieldBD(SInt<14>);
|
||||||
|
#[name = "LI"]
|
||||||
|
struct FieldLI(SInt<24>);
|
||||||
#[name = "SI"]
|
#[name = "SI"]
|
||||||
struct FieldSI(SInt<16>);
|
struct FieldSI(SInt<16>);
|
||||||
#[name = "si0"]
|
#[name = "si0"]
|
||||||
|
|
@ -201,8 +207,16 @@ impl_fields! {
|
||||||
struct FieldAddPcISD1(UInt<5>);
|
struct FieldAddPcISD1(UInt<5>);
|
||||||
#[name = "d2"]
|
#[name = "d2"]
|
||||||
struct FieldAddPcISD2(UInt<1>);
|
struct FieldAddPcISD2(UInt<1>);
|
||||||
|
#[name = "BH"]
|
||||||
|
struct FieldBH(UInt<2>);
|
||||||
|
#[name = "BO"]
|
||||||
|
struct FieldBO(UInt<5>);
|
||||||
|
#[name = "AA"]
|
||||||
|
struct FieldAA(Bool);
|
||||||
#[name = "L"]
|
#[name = "L"]
|
||||||
struct FieldL(Bool);
|
struct FieldL(Bool);
|
||||||
|
#[name = "LK"]
|
||||||
|
struct FieldLK(Bool);
|
||||||
#[name = "OE"]
|
#[name = "OE"]
|
||||||
struct FieldOE(Bool);
|
struct FieldOE(Bool);
|
||||||
#[name = "R"]
|
#[name = "R"]
|
||||||
|
|
@ -223,6 +237,12 @@ struct FieldCrf {
|
||||||
reg_num: UInt<3>,
|
reg_num: UInt<3>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// condition register bit
|
||||||
|
#[hdl]
|
||||||
|
struct FieldCrBit {
|
||||||
|
bit_num: UInt<5>,
|
||||||
|
}
|
||||||
|
|
||||||
fn gpr(this: impl ToExpr<Type = FieldGpr>) -> Expr<MOpRegNum> {
|
fn gpr(this: impl ToExpr<Type = FieldGpr>) -> Expr<MOpRegNum> {
|
||||||
MOpRegNum::power_isa_gpr_reg(this.to_expr().reg_num)
|
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)
|
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 {
|
impl DecodeState {
|
||||||
fn form(&self) -> &'static str {
|
fn form(&self) -> &'static str {
|
||||||
let mut title_words = self
|
let mut title_words = self
|
||||||
|
|
@ -439,7 +479,160 @@ impl DecodeState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn decode_b_ba_bl_bla(&mut self) {
|
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]
|
#[hdl]
|
||||||
fn decode_addi_paddi(&mut self) {
|
fn decode_addi_paddi(&mut self) {
|
||||||
|
|
@ -1165,18 +1358,12 @@ type DecodeFn = fn(&mut DecodeState);
|
||||||
|
|
||||||
const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
|
const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
|
||||||
(&["b", "ba", "bl", "bla"], DecodeState::decode_b_ba_bl_bla),
|
(&["b", "ba", "bl", "bla"], DecodeState::decode_b_ba_bl_bla),
|
||||||
(&["bc", "bca", "bcl", "bcla"], |_state| {
|
(
|
||||||
// TODO
|
&[
|
||||||
}),
|
"bc", "bca", "bcl", "bcla", "bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl",
|
||||||
(&["bclr", "bclrl"], |_state| {
|
],
|
||||||
// TODO
|
DecodeState::decode_bc_bclr_bcctr_bctar,
|
||||||
}),
|
),
|
||||||
(&["bcctr", "bcctrl"], |_state| {
|
|
||||||
// TODO
|
|
||||||
}),
|
|
||||||
(&["bctar", "bctarl"], |_state| {
|
|
||||||
// TODO
|
|
||||||
}),
|
|
||||||
(
|
(
|
||||||
&[
|
&[
|
||||||
"crand", "crnand", "cror", "crxor", "crnor", "creqv", "crandc", "crorc",
|
"crand", "crnand", "cror", "crxor", "crnor", "creqv", "crandc", "crorc",
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
use crate::{unit::UnitMOp, util::range_u32_len};
|
use crate::{unit::UnitMOp, util::range_u32_len};
|
||||||
use fayalite::{
|
use fayalite::{
|
||||||
expr::{HdlPartialEqImpl, ops::ArrayLiteral},
|
expr::{HdlPartialEqImpl, ops::ArrayLiteral},
|
||||||
intern::Interned,
|
intern::{Intern, InternSlice, Interned},
|
||||||
module::wire_with_loc,
|
module::wire_with_loc,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
ty::StaticType,
|
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! {
|
common_mop_struct! {
|
||||||
#[mapped(<NewDestReg, NewSrcRegWidth> BranchMOp<NewDestReg, NewSrcRegWidth>)]
|
#[mapped(<NewDestReg, NewSrcRegWidth> BranchMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
|
||||||
#[hdl(cmp_eq)]
|
#[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]
|
#[common]
|
||||||
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, ConstUsize<2>>,
|
pub common: CommonMOp<ConstUsize<0>, DestReg, SrcRegWidth, SrcCount>,
|
||||||
pub lut: UInt<4>,
|
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>>),
|
LogicalI(LogicalMOp<DestReg, SrcRegWidth, ConstUsize<1>>),
|
||||||
Compare(CompareMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
|
Compare(CompareMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
|
||||||
CompareI(CompareMOp<DestReg, SrcRegWidth, ConstUsize<1>>),
|
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 {
|
impl MOpRegNum {
|
||||||
pub const POWER_ISA_LR_REG_NUM: u32 = 1;
|
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;
|
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;
|
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`]
|
/// SO, OV, and OV32 XER bits -- in [`PRegValue.flags`]
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
config::CpuConfig,
|
config::CpuConfig,
|
||||||
instruction::{
|
instruction::{
|
||||||
AddSubMOp, AluBranchMOp, AluCommonMOp, COMMON_MOP_SRC_LEN, CommonMOp, CompareMOp,
|
AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOp,
|
||||||
LogicalMOp, MOpTrait, OutputIntegerMode, RenamedMOp, UnitOutRegNum,
|
CompareMOp, LogicalMOp, MOpTrait, OutputIntegerMode, RenamedMOp, UnitOutRegNum,
|
||||||
},
|
},
|
||||||
register::{FlagsMode, PRegFlagsPowerISA, PRegFlagsX86, PRegValue},
|
register::{FlagsMode, PRegFlagsPowerISA, PRegFlagsX86, PRegValue},
|
||||||
unit::{
|
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]
|
#[hdl_module]
|
||||||
pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
||||||
#[hdl]
|
#[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