From 62512960c33076b610aca65070c1b0e698984486 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Thu, 15 Jan 2026 16:10:03 -0800 Subject: [PATCH] decode some more add instructions --- crates/cpu/src/decoder/simple_power_isa.rs | 344 ++++++++++--- crates/cpu/src/instruction.rs | 45 ++ crates/cpu/src/instruction/power_isa.rs | 136 ++++- crates/cpu/tests/expected/decode_one_insn.vcd | 465 +++++++++++++++++- crates/cpu/tests/simple_power_isa_decoder.rs | 115 ++++- 5 files changed, 1028 insertions(+), 77 deletions(-) diff --git a/crates/cpu/src/decoder/simple_power_isa.rs b/crates/cpu/src/decoder/simple_power_isa.rs index c4f3761..c2e08f6 100644 --- a/crates/cpu/src/decoder/simple_power_isa.rs +++ b/crates/cpu/src/decoder/simple_power_isa.rs @@ -166,7 +166,10 @@ macro_rules! impl_fields { impl FieldSet for $Struct { #[track_caller] fn get(fields: &mut BTreeMap<&str, Expr>) -> Self { - Self(fields[$name].cast_bits_to(StaticType::TYPE)) + let Some(v) = fields.get($name) else { + panic!("field {:?} not found", $name); + }; + Self(v.cast_bits_to(StaticType::TYPE)) } } )* @@ -175,31 +178,36 @@ macro_rules! impl_fields { impl_fields! { #[name = "RA"] - struct FieldRA(UInt<5>); + struct FieldRA(FieldGpr); + #[name = "RB"] + struct FieldRB(FieldGpr); #[name = "RT"] - struct FieldRT(UInt<5>); + struct FieldRT(FieldGpr); #[name = "SI"] struct FieldSI(SInt<16>); + #[name = "d0"] + struct FieldAddPcISD0(SInt<10>); + #[name = "d1"] + struct FieldAddPcISD1(UInt<5>); + #[name = "d2"] + struct FieldAddPcISD2(UInt<1>); + #[name = "OE"] + struct FieldOE(Bool); + #[name = "Rc"] + struct FieldRc(Bool); } #[hdl] -fn translate_gpr(v: Expr>) -> Expr { - #[hdl] - MOpRegNum { - value: (v + MOpRegNum::POWER_ISA_GPR_REG_NUMS.start).cast_to_static::>(), - } +struct FieldGpr { + reg_num: UInt<5>, } -#[hdl] -fn translate_gpr_or_zero(v: Expr>) -> Expr { - #[hdl] - let translate_gpr_or_zero = wire(); - connect(translate_gpr_or_zero, translate_gpr(v)); - #[hdl] - if v.cmp_eq(0u8) { - connect(translate_gpr_or_zero, MOpRegNum::const_zero()); - } - translate_gpr_or_zero +fn gpr(this: impl ToExpr) -> Expr { + MOpRegNum::power_isa_gpr_reg(this.to_expr().reg_num) +} + +fn gpr_or_zero(this: impl ToExpr) -> Expr { + MOpRegNum::power_isa_gpr_or_zero_reg(this.to_expr().reg_num) } impl DecodeState { @@ -318,6 +326,7 @@ impl DecodeState { last_start = *msb0_bit_range.start(); let field = Self::msb0_bit_range(word, msb0_bit_range); let mut name = Self::bit_field_name(bit_field.name()); + let orig_name = name; if name.contains(char::is_alphabetic) { for (cond_name, cond_value) in self.conditions() { if name == cond_name { @@ -342,6 +351,14 @@ impl DecodeState { } else { let value: u32 = name.parse().expect("bit field name must have at least one letter, be all `/`, or be a valid decimal number"); *matches = *matches & field.cmp_eq(value); + if orig_name.contains(char::is_alphabetic) { + if fields + .insert(orig_name, value.cast_to(field.ty()).to_expr()) + .is_some() + { + panic!("duplicate field name: {name:?}\nheader: {:#?}", self.header); + } + } } } } @@ -351,18 +368,24 @@ impl DecodeState { let mut fields = BTreeMap::new(); let mut matches = true.to_expr(); let mut f = Some(f); - let mut run = - |this: &mut Self, matches: Expr, fields: &mut BTreeMap<&str, Expr>| { - #[hdl] - if matches { - connect( - this.second_input_used, - this.header.bit_fields().prefix().is_some(), - ); - connect(this.is_illegal, false); - f.take().expect("known to be Some")(this, FS::get(fields)); - } - }; + #[hdl] + #[track_caller] + fn run( + this: &mut DecodeState, + matches: Expr, + fields: &mut BTreeMap<&str, Expr>, + f: &mut Option, + ) { + #[hdl] + if matches { + connect( + this.second_input_used, + this.header.bit_fields().prefix().is_some(), + ); + connect(this.is_illegal, false); + f.take().expect("known to be Some")(this, FS::get(fields)); + } + } if let Some(prefix) = self.header.bit_fields().prefix() { #[hdl] if let HdlSome(prefix_word) = self.second_input { @@ -378,7 +401,7 @@ impl DecodeState { self.first_input, self.header.bit_fields().fields_inner(), ); - run(self, matches, &mut fields); + run(self, matches, &mut fields, &mut f); } } else { self.decode_word( @@ -387,7 +410,7 @@ impl DecodeState { self.first_input, self.header.bit_fields().fields_inner(), ); - run(self, matches, &mut fields); + run(self, matches, &mut fields, &mut f); } } fn decode_b_ba_bl_bla(&mut self) { @@ -405,16 +428,9 @@ impl DecodeState { connect( this.output[0], AddSubMOp::add_sub_i( + MOpDestReg::new([gpr(rt)], []), #[hdl] - MOpDestReg { - normal_regs: [translate_gpr(rt), MOpRegNum::const_zero()], - flag_regs: [HdlNone(); _], - }, - #[hdl] - [ - translate_gpr_or_zero(ra).value, - MOpRegNum::const_zero().value, - ], + [gpr_or_zero(ra).value, MOpRegNum::const_zero().value], si.cast_to_static(), OutputIntegerMode.Full64(), false, @@ -431,6 +447,204 @@ impl DecodeState { _ => unreachable!("{:?}", self.mnemonic), } } + #[hdl] + fn decode_addis(&mut self) { + self.decode_scope(|this, (FieldRT(rt), FieldRA(ra), FieldSI(si))| { + connect( + ArrayVec::len(this.output), + 1usize.cast_to_static::>(), + ); + connect( + this.output[0], + AddSubMOp::add_sub_i( + MOpDestReg::new([gpr(rt)], []), + #[hdl] + [gpr_or_zero(ra).value, MOpRegNum::const_zero().value], + (si << 16).cast_to_static(), + OutputIntegerMode.Full64(), + false, + false, + false, + false, + ), + ); + }); + } + #[hdl] + fn decode_addpcis(&mut self) { + self.decode_scope( + |this, (FieldRT(rt), FieldAddPcISD0(d0), FieldAddPcISD1(d1), FieldAddPcISD2(d2))| { + connect( + ArrayVec::len(this.output), + 1usize.cast_to_static::>(), + ); + let d = (d0 << 6) + + (d1 << 1).cast_to_static::>() + + d2.cast_to_static::>(); + connect( + this.output[0], + AddSubMOp::add_sub_i( + MOpDestReg::new([gpr(rt)], []), + #[hdl] + [MOpRegNum::const_zero().value; 2], + (4i8 + (d << 16)).cast_to_static(), + OutputIntegerMode.Full64(), + false, + false, + false, + true, + ), + ); + }, + ); + } + /// for `add[o][.]` + #[hdl] + fn decode_add(&mut self) { + self.decode_scope( + |this, (FieldRT(rt), FieldRA(ra), FieldRB(rb), FieldOE(oe), FieldRc(rc))| { + // TODO: handle SO propagation + connect( + ArrayVec::len(this.output), + 1usize.cast_to_static::>(), + ); + connect( + this.output[0], + AddSubMOp::add_sub( + MOpDestReg::new( + [gpr(rt)], + [ + (MOpRegNum::POWER_ISA_XER_SO_OV_OV32_REG_NUM, oe), + (MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc), + ], + ), + #[hdl] + [gpr(ra).value, gpr(rb).value, MOpRegNum::const_zero().value], + 0i8.cast_to_static::>(), + OutputIntegerMode.Full64(), + false, + false, + false, + false, + ), + ); + }, + ); + } + /// for `addic[.]` + #[hdl] + fn decode_addic(&mut self) { + self.decode_scope(|this, (FieldRT(rt), FieldRA(ra), FieldSI(si))| { + connect( + ArrayVec::len(this.output), + 1usize.cast_to_static::>(), + ); + connect( + this.output[0], + AddSubMOp::add_sub_i( + MOpDestReg::new( + [gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()], + [( + MOpRegNum::POWER_ISA_CR_0_REG_NUM, + self.mnemonic.ends_with('.').to_expr(), + )], + ), + #[hdl] + [gpr(ra).value, MOpRegNum::const_zero().value], + si.cast_to_static(), + OutputIntegerMode.Full64(), + false, + false, + false, + false, + ), + ); + }); + } + /// for `subf[o][.]` + #[hdl] + fn decode_subf(&mut self) { + // TODO + } + #[hdl] + fn decode_subfic(&mut self) { + // TODO + } + /// for `addc[o][.]` + #[hdl] + fn decode_addc(&mut self) { + self.decode_scope( + |this, (FieldRT(rt), FieldRA(ra), FieldRB(rb), FieldOE(oe), FieldRc(rc))| { + // TODO: handle SO propagation + connect( + ArrayVec::len(this.output), + 1usize.cast_to_static::>(), + ); + connect( + this.output[0], + AddSubMOp::add_sub( + MOpDestReg::new( + [gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()], + [ + (MOpRegNum::POWER_ISA_XER_SO_OV_OV32_REG_NUM, oe), + (MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc), + ], + ), + #[hdl] + [gpr(ra).value, gpr(rb).value, MOpRegNum::const_zero().value], + 0i8.cast_to_static::>(), + OutputIntegerMode.Full64(), + false, + false, + false, + false, + ), + ); + }, + ); + } + /// for `subfc[o][.]` + #[hdl] + fn decode_subfc(&mut self) { + // TODO + } + /// for `adde[o][.]` + #[hdl] + fn decode_adde(&mut self) { + self.decode_scope( + |this, (FieldRT(rt), FieldRA(ra), FieldRB(rb), FieldOE(oe), FieldRc(rc))| { + // TODO: handle SO propagation + connect( + ArrayVec::len(this.output), + 1usize.cast_to_static::>(), + ); + connect( + this.output[0], + AddSubMOp::add_sub( + MOpDestReg::new( + [gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()], + [ + (MOpRegNum::POWER_ISA_XER_SO_OV_OV32_REG_NUM, oe), + (MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc), + ], + ), + #[hdl] + [ + gpr(ra).value, + MOpRegNum::power_isa_xer_ca_ca32_reg().value, + gpr(rb).value, + ], + 0i8.cast_to_static::>(), + OutputIntegerMode.Full64(), + false, + true, + false, + false, + ), + ); + }, + ); + } } type DecodeFn = fn(&mut DecodeState); @@ -498,33 +712,27 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[ // load/store string are intentionally not implemented }), (&["addi", "paddi"], DecodeState::decode_addi_paddi), - (&["addis"], |_state| { - // TODO - }), - (&["addpcis"], |_state| { - // TODO - }), - (&["add", "add.", "addo", "addo."], |_state| { - // TODO - }), - (&["addic", "addic."], |_state| { - // TODO - }), - (&["subf", "subf.", "subfo", "subfo."], |_state| { - // TODO - }), - (&["subfic"], |_state| { - // TODO - }), - (&["addc", "addc.", "addco", "addco."], |_state| { - // TODO - }), - (&["subfc", "subfc.", "subfco", "subfco."], |_state| { - // TODO - }), - (&["adde", "adde.", "addeo", "addeo."], |_state| { - // TODO - }), + (&["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, + ), + (&["subfic"], DecodeState::decode_subfic), + ( + &["addc", "addc.", "addco", "addco."], + DecodeState::decode_addc, + ), + ( + &["subfc", "subfc.", "subfco", "subfco."], + DecodeState::decode_subfc, + ), + ( + &["adde", "adde.", "addeo", "addeo."], + DecodeState::decode_adde, + ), (&["subfe", "subfe.", "subfeo", "subfeo."], |_state| { // TODO }), diff --git a/crates/cpu/src/instruction.rs b/crates/cpu/src/instruction.rs index f70fe28..6f6ab75 100644 --- a/crates/cpu/src/instruction.rs +++ b/crates/cpu/src/instruction.rs @@ -4,6 +4,7 @@ use crate::{unit::UnitMOp, util::range_u32_len}; use fayalite::{ expr::{HdlPartialEqImpl, ops::ArrayLiteral}, intern::Interned, + module::wire_with_loc, prelude::*, ty::StaticType, }; @@ -983,6 +984,50 @@ impl MOpDestReg { flag_regs: flag_regs_sim, } } + #[hdl] + #[track_caller] + pub fn new( + normal_regs: impl IntoIterator>, + flag_regs: impl IntoIterator)>, + ) -> Expr { + let mut normal_regs_array = [MOpRegNum::const_zero(); Self::NORMAL_REG_COUNT]; + const FLAG_REG_COUNT: usize = range_u32_len(&MOpRegNum::FLAG_REG_NUMS); + let mut used_flag_regs = [false; FLAG_REG_COUNT]; + let mut flag_regs_array = [HdlNone(); FLAG_REG_COUNT]; + for (i, normal_reg) in normal_regs.into_iter().enumerate() { + assert!(i < Self::NORMAL_REG_COUNT, "too many normal regs"); + normal_regs_array[i] = normal_reg; + } + for (flag_reg_num, flag_reg_enabled) in flag_regs { + let Some(index) = { MOpRegNum::FLAG_REG_NUMS }.position(|v| flag_reg_num == v) else { + panic!( + "flag reg number {flag_reg_num} is out of range, supported range is: {:?}", + MOpRegNum::FLAG_REG_NUMS + ); + }; + assert!( + !used_flag_regs[index], + "duplicate flag reg number {flag_reg_num}" + ); + used_flag_regs[index] = true; + let wire = wire_with_loc( + &format!("flag_reg_{index}"), + SourceLocation::caller(), + StaticType::TYPE, + ); + connect(wire, HdlNone()); + #[hdl] + if flag_reg_enabled { + connect(wire, HdlSome(())); + } + flag_regs_array[index] = wire; + } + #[hdl] + Self { + normal_regs: normal_regs_array, + flag_regs: flag_regs_array, + } + } } #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] diff --git a/crates/cpu/src/instruction/power_isa.rs b/crates/cpu/src/instruction/power_isa.rs index de9b47c..774e76c 100644 --- a/crates/cpu/src/instruction/power_isa.rs +++ b/crates/cpu/src/instruction/power_isa.rs @@ -29,24 +29,150 @@ impl MOpRegNum { pub const POWER_ISA_LR_REG_NUM: u32 = 1; pub const POWER_ISA_CTR_REG_NUM: u32 = 2; pub const POWER_ISA_TAR_REG_NUM: u32 = 3; - /// XER bits are stored in [`PRegValue.flags`], bits that don't exist in [`PRegValue.flags`] are stored in [`PRegValue.int_fp`] + + /// SO, OV, and OV32 XER bits -- in [`PRegValue.flags`] /// /// [`PRegValue.flags`]: struct@crate::register::PRegValue - /// [`PRegValue.int_fp`]: struct@crate::register::PRegValue - pub const POWER_ISA_XER_REG_NUM: u32 = 4; + pub const POWER_ISA_XER_SO_OV_OV32_REG_NUM: u32 = + range_u32_nth_or_panic(&Self::FLAG_REG_NUMS, 0); + /// CA and CA32 XER bits -- in [`PRegValue.flags`] + /// + /// [`PRegValue.flags`]: struct@crate::register::PRegValue + pub const POWER_ISA_XER_CA_CA32_REG_NUM: u32 = 4; + /// only the XER bits that don't exist in [`PRegValue.flags`] + /// + /// [`PRegValue.flags`]: struct@crate::register::PRegValue + pub const POWER_ISA_XER_OTHER_REG_NUM: u32 = 5; - pub const POWER_ISA_CR_REG_NUMS: Range = 8..16; + /// SO, OV, and OV32 XER bits -- in [`PRegValue.flags`] + /// + /// [`PRegValue.flags`]: struct@crate::register::PRegValue + #[hdl] + pub fn power_isa_xer_so_ov_ov32_reg() -> Expr { + #[hdl] + Self { + value: Self::POWER_ISA_XER_SO_OV_OV32_REG_NUM.cast_to_static::>(), + } + } + /// CA and CA32 XER bits -- in [`PRegValue.flags`] + /// + /// [`PRegValue.flags`]: struct@crate::register::PRegValue + #[hdl] + pub fn power_isa_xer_ca_ca32_reg() -> Expr { + #[hdl] + Self { + value: Self::POWER_ISA_XER_CA_CA32_REG_NUM.cast_to_static::>(), + } + } + /// only the XER bits that don't exist in [`PRegValue.flags`] + /// + /// [`PRegValue.flags`]: struct@crate::register::PRegValue + #[hdl] + pub fn power_isa_xer_other_reg() -> Expr { + #[hdl] + Self { + value: Self::POWER_ISA_XER_OTHER_REG_NUM.cast_to_static::>(), + } + } + + pub const POWER_ISA_CR_0_REG_NUM: u32 = range_u32_nth_or_panic(&Self::FLAG_REG_NUMS, 1); + pub const POWER_ISA_CR_1_THRU_7_REG_NUMS: Range = 9..16; pub const fn power_isa_cr_reg_num(index: usize) -> u32 { - range_u32_nth_or_panic(&Self::POWER_ISA_CR_REG_NUMS, index) + if index == 0 { + Self::POWER_ISA_CR_0_REG_NUM + } else { + range_u32_nth_or_panic(&Self::POWER_ISA_CR_1_THRU_7_REG_NUMS, index - 1) + } + } + #[hdl] + pub fn power_isa_cr_reg(field_num: Expr>) -> Expr { + #[hdl] + let power_isa_cr_reg: Self = wire(); + #[hdl] + if field_num.cmp_eq(0u8) { + connect_any(power_isa_cr_reg.value, Self::POWER_ISA_CR_0_REG_NUM); + } else { + connect_any( + power_isa_cr_reg.value, + Self::POWER_ISA_CR_1_THRU_7_REG_NUMS.start + field_num, + ); + } + power_isa_cr_reg + } + #[hdl] + pub fn power_isa_cr_reg_sim(field_num: &SimValue>) -> SimValue { + #[hdl(sim)] + Self { + value: Self::power_isa_cr_reg_num( + field_num.cast_to_static::>().as_int() as usize + ) + .cast_to_static::>(), + } } pub const POWER_ISA_GPR_REG_NUMS: Range = 32..64; pub const fn power_isa_gpr_reg_num(index: usize) -> u32 { range_u32_nth_or_panic(&Self::POWER_ISA_GPR_REG_NUMS, index) } + #[hdl] + pub fn power_isa_gpr_reg(reg_num: Expr>) -> Expr { + #[hdl] + Self { + value: (Self::POWER_ISA_GPR_REG_NUMS.start + reg_num).cast_to_static::>(), + } + } + #[hdl] + pub fn power_isa_gpr_reg_sim(reg_num: &SimValue>) -> SimValue { + #[hdl(sim)] + Self { + value: (Self::POWER_ISA_GPR_REG_NUMS.start + reg_num).cast_to_static::>(), + } + } + pub const fn power_isa_gpr_or_zero_reg_num(index: usize) -> u32 { + if index == 0 { + Self::CONST_ZERO_REG_NUM + } else { + Self::power_isa_gpr_reg_num(index) + } + } + #[hdl] + pub fn power_isa_gpr_or_zero_reg(reg_num: Expr>) -> Expr { + #[hdl] + let power_isa_gpr_or_zero_reg: Self = wire(); + connect(power_isa_gpr_or_zero_reg, Self::power_isa_gpr_reg(reg_num)); + #[hdl] + if reg_num.cmp_eq(0u8) { + connect(power_isa_gpr_or_zero_reg, Self::const_zero()); + } + power_isa_gpr_or_zero_reg + } + #[hdl] + pub fn power_isa_gpr_or_zero_reg_sim(reg_num: &SimValue>) -> SimValue { + #[hdl(sim)] + Self { + value: Self::power_isa_gpr_or_zero_reg_num( + reg_num.cast_to_static::>().as_int() as usize, + ) + .cast_to_static::>(), + } + } pub const POWER_ISA_FPR_REG_NUMS: Range = 64..96; pub const fn power_isa_fpr_reg_num(index: usize) -> u32 { range_u32_nth_or_panic(&Self::POWER_ISA_FPR_REG_NUMS, index) } + #[hdl] + pub fn power_isa_fpr_reg(reg_num: Expr>) -> Expr { + #[hdl] + Self { + value: (Self::POWER_ISA_FPR_REG_NUMS.start + reg_num).cast_to_static::>(), + } + } + #[hdl] + pub fn power_isa_fpr_reg_sim(reg_num: &SimValue>) -> SimValue { + #[hdl(sim)] + Self { + value: (Self::POWER_ISA_FPR_REG_NUMS.start + reg_num).cast_to_static::>(), + } + } } diff --git a/crates/cpu/tests/expected/decode_one_insn.vcd b/crates/cpu/tests/expected/decode_one_insn.vcd index 110c3ee..fb5f75f 100644 --- a/crates/cpu/tests/expected/decode_one_insn.vcd +++ b/crates/cpu/tests/expected/decode_one_insn.vcd @@ -496,9 +496,191 @@ $var wire 1 _" second_input_used $end $var wire 16 `" addi_SI $end $var wire 5 a" addi_RA $end $var wire 5 b" addi_RT $end -$scope struct translate_gpr_or_zero $end +$scope struct power_isa_gpr_or_zero_reg $end $var wire 8 c" value $end $upscope $end +$var wire 16 d" addis_SI $end +$var wire 5 e" addis_RA $end +$var wire 5 f" addis_RT $end +$scope struct power_isa_gpr_or_zero_reg_2 $end +$var wire 8 g" value $end +$upscope $end +$var wire 1 h" addpcis_d2 $end +$var wire 10 i" addpcis_d0 $end +$var wire 5 j" addpcis_d1 $end +$var wire 5 k" addpcis_RT $end +$var wire 5 l" add_RB $end +$var wire 5 m" add_RA $end +$var wire 5 n" add_RT $end +$scope struct flag_reg_0 $end +$var string 1 o" \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$scope struct flag_reg_1 $end +$var string 1 p" \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$var wire 5 q" add__RB $end +$var wire 5 r" add__RA $end +$var wire 5 s" add__RT $end +$scope struct flag_reg_0_2 $end +$var string 1 t" \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$scope struct flag_reg_1_2 $end +$var string 1 u" \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$var wire 5 v" addo_RB $end +$var wire 5 w" addo_RA $end +$var wire 5 x" addo_RT $end +$scope struct flag_reg_0_3 $end +$var string 1 y" \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$scope struct flag_reg_1_3 $end +$var string 1 z" \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$var wire 5 {" addo__RB $end +$var wire 5 |" addo__RA $end +$var wire 5 }" addo__RT $end +$scope struct flag_reg_0_4 $end +$var string 1 ~" \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$scope struct flag_reg_1_4 $end +$var string 1 !# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$var wire 16 "# addic_SI $end +$var wire 5 ## addic_RA $end +$var wire 5 $# addic_RT $end +$scope struct flag_reg_1_5 $end +$var string 1 %# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$var wire 16 &# addic__SI $end +$var wire 5 '# addic__RA $end +$var wire 5 (# addic__RT $end +$scope struct flag_reg_1_6 $end +$var string 1 )# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$var wire 5 *# addc_RB $end +$var wire 5 +# addc_RA $end +$var wire 5 ,# addc_RT $end +$scope struct flag_reg_0_5 $end +$var string 1 -# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$scope struct flag_reg_1_7 $end +$var string 1 .# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$var wire 5 /# addc__RB $end +$var wire 5 0# addc__RA $end +$var wire 5 1# addc__RT $end +$scope struct flag_reg_0_6 $end +$var string 1 2# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$scope struct flag_reg_1_8 $end +$var string 1 3# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$var wire 5 4# addco_RB $end +$var wire 5 5# addco_RA $end +$var wire 5 6# addco_RT $end +$scope struct flag_reg_0_7 $end +$var string 1 7# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$scope struct flag_reg_1_9 $end +$var string 1 8# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$var wire 5 9# addco__RB $end +$var wire 5 :# addco__RA $end +$var wire 5 ;# addco__RT $end +$scope struct flag_reg_0_8 $end +$var string 1 <# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$scope struct flag_reg_1_10 $end +$var string 1 =# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$var wire 5 ># adde_RB $end +$var wire 5 ?# adde_RA $end +$var wire 5 @# adde_RT $end +$scope struct flag_reg_0_9 $end +$var string 1 A# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$scope struct flag_reg_1_11 $end +$var string 1 B# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$var wire 5 C# adde__RB $end +$var wire 5 D# adde__RA $end +$var wire 5 E# adde__RT $end +$scope struct flag_reg_0_10 $end +$var string 1 F# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$scope struct flag_reg_1_12 $end +$var string 1 G# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$var wire 5 H# addeo_RB $end +$var wire 5 I# addeo_RA $end +$var wire 5 J# addeo_RT $end +$scope struct flag_reg_0_11 $end +$var string 1 K# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$scope struct flag_reg_1_13 $end +$var string 1 L# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$var wire 5 M# addeo__RB $end +$var wire 5 N# addeo__RA $end +$var wire 5 O# addeo__RT $end +$scope struct flag_reg_0_12 $end +$var string 1 P# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end +$scope struct flag_reg_1_14 $end +$var string 1 Q# \$tag $end +$scope struct HdlSome $end +$upscope $end +$upscope $end $upscope $end $enddefinitions $end $dumpvars @@ -663,5 +845,286 @@ b1001000110100 `" b100 a" b11 b" b100100 c" +b1001000110100 d" +b100 e" +b11 f" +b100100 g" +0h" +b1001000 i" +b100 j" +b11 k" +b10 l" +b100 m" +b11 n" +sHdlNone\x20(0) o" +sHdlNone\x20(0) p" +b10 q" +b100 r" +b11 s" +sHdlNone\x20(0) t" +sHdlSome\x20(1) u" +b10 v" +b100 w" +b11 x" +sHdlSome\x20(1) y" +sHdlNone\x20(0) z" +b10 {" +b100 |" +b11 }" +sHdlSome\x20(1) ~" +sHdlSome\x20(1) !# +b1001000110100 "# +b100 ## +b11 $# +sHdlNone\x20(0) %# +b1001000110100 &# +b100 '# +b11 (# +sHdlSome\x20(1) )# +b10 *# +b100 +# +b11 ,# +sHdlNone\x20(0) -# +sHdlNone\x20(0) .# +b10 /# +b100 0# +b11 1# +sHdlNone\x20(0) 2# +sHdlSome\x20(1) 3# +b10 4# +b100 5# +b11 6# +sHdlSome\x20(1) 7# +sHdlNone\x20(0) 8# +b10 9# +b100 :# +b11 ;# +sHdlSome\x20(1) <# +sHdlSome\x20(1) =# +b10 ># +b100 ?# +b11 @# +sHdlNone\x20(0) A# +sHdlNone\x20(0) B# +b10 C# +b100 D# +b11 E# +sHdlNone\x20(0) F# +sHdlSome\x20(1) G# +b10 H# +b100 I# +b11 J# +sHdlSome\x20(1) K# +sHdlNone\x20(0) L# +b10 M# +b100 N# +b11 O# +sHdlSome\x20(1) P# +sHdlSome\x20(1) Q# $end #1000000 +b1001 * +b1101000000000000000000 + +b1001 9 +b1101000000000000000000 : +b1001 H +b1101000000000000000000 I +b1001 T +b1101000000000000000000 U +b1001 _ +b1101000000000000000000 ` +b1001 i +b1101000000000000000000 j +b111100011001000001001000110100 \" +#2000000 +b0 ( +b1101000000000000000100 + +11 +b0 7 +b1101000000000000000100 : +1@ +b0 F +b1101000000000000000100 I +b1000 L +b0 R +b1101000000000000000100 U +b0 ] +b1101000000000000000100 ` +b0 g +b1101000000000000000100 j +b1001100011110100001001000000100 \" +b1001000000100 `" +b11010 a" +b111010 c" +b1001000000100 d" +b11010 e" +b111010 g" +b11010 j" +b11010 m" +b11010 r" +b11010 w" +b11010 |" +b1001000000100 "# +b11010 ## +b1001000000100 &# +b11010 '# +b11010 +# +b11010 0# +b11010 5# +b11010 :# +b11010 ?# +b11010 D# +b11010 I# +b11010 N# +#3000000 +sAddSub\x20(0) " +sHdlSome\x20(1) ' +b100100 ( +b100101 ) +b0 * +b0 + +01 +sHdlSome\x20(1) 6 +b100100 7 +b100101 8 +b0 9 +b0 : +0@ +sHdlSome\x20(1) E +b100100 F +b100101 G +b0 H +b0 I +b0 L +b0 M +sHdlSome\x20(1) Q +b100100 R +b100101 S +b0 T +b0 U +sLoad\x20(0) W +sHdlSome\x20(1) \ +b100100 ] +b100101 ^ +b0 _ +b0 ` +sHdlSome\x20(1) f +b100100 g +b100101 h +b0 i +b0 j +b1111100011001000010101000010101 \" +b10101000010101 `" +b100 a" +b100100 c" +b10101000010101 d" +b100 e" +b100100 g" +1h" +b10101000 i" +b100 j" +b101 l" +b100 m" +b101 q" +b100 r" +b101 v" +b100 w" +b101 {" +b100 |" +b10101000010101 "# +b100 ## +b10101000010101 &# +b100 '# +b101 *# +b100 +# +b101 /# +b100 0# +b101 4# +b100 5# +b101 9# +b100 :# +b101 ># +b100 ?# +b101 C# +b100 D# +b101 H# +b100 I# +b101 M# +b100 N# +#4000000 +sAddSubI\x20(1) " +b100 % +b0 ) +b1001000110100 + +b100 4 +b0 8 +b1001000110100 : +b100 C +b0 G +b1001000110100 I +b1 M +b100 O +b0 S +b1001000110100 U +sStore\x20(1) W +b100 Z +b0 ^ +b1001000110100 ` +b100 d +b0 h +b1001000110100 j +b110100011001000001001000110100 \" +b1001000110100 `" +b1001000110100 d" +0h" +b1001000 i" +b10 l" +b10 q" +b10 v" +b10 {" +b1001000110100 "# +b1001000110100 &# +b10 *# +b10 /# +b10 4# +b10 9# +b10 ># +b10 C# +b10 H# +b10 M# +#5000000 +sAddSub\x20(0) " +b100101 ) +b0 + +b100101 8 +b0 : +b100101 G +b0 I +b0 M +b100101 S +b0 U +sLoad\x20(0) W +b100101 ^ +b0 ` +b100101 h +b0 j +b1111100011001000010100000010101 \" +b10100000010101 `" +b10100000010101 d" +1h" +b10100000 i" +b101 l" +b101 q" +b101 v" +b101 {" +b10100000010101 "# +b10100000010101 &# +b101 *# +b101 /# +b101 4# +b101 9# +b101 ># +b101 C# +b101 H# +b101 M# +#6000000 diff --git a/crates/cpu/tests/simple_power_isa_decoder.rs b/crates/cpu/tests/simple_power_isa_decoder.rs index dd0c5d5..eaf82b3 100644 --- a/crates/cpu/tests/simple_power_isa_decoder.rs +++ b/crates/cpu/tests/simple_power_isa_decoder.rs @@ -75,10 +75,10 @@ fn test_cases() -> Vec { 0x38641234, None, AddSubMOp::add_sub_i( - MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_GPR_REG_NUMS.start + 3], &[]), + MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]), [ - (MOpRegNum::POWER_ISA_GPR_REG_NUMS.start + 4).cast_to_static::>(), - MOpRegNum::CONST_ZERO_REG_NUM.cast_to_static::>(), + MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value, + MOpRegNum::const_zero().value, ], 0x1234.cast_to_static::>(), #[hdl(sim)] @@ -89,6 +89,115 @@ fn test_cases() -> Vec { false, ), )); + retval.push(insn_single( + "addis 3, 4, 0x1234", + 0x3C641234, + None, + AddSubMOp::add_sub_i( + MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]), + [ + MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value, + MOpRegNum::const_zero().value, + ], + 0x12340000.cast_to_static::>(), + #[hdl(sim)] + OutputIntegerMode::Full64(), + false, + false, + false, + false, + ), + )); + retval.push(insn_single( + "addpcis 3, 0x1234", + 0x4c7a1204, + None, + AddSubMOp::add_sub_i( + MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]), + [MOpRegNum::const_zero().value; _], + 0x12340004.cast_to_static::>(), + #[hdl(sim)] + OutputIntegerMode::Full64(), + false, + false, + false, + true, + ), + )); + retval.push(insn_single( + "add. 3, 4, 5", + 0x7c642a15, + None, + AddSubMOp::add_sub( + MOpDestReg::new_sim( + &[MOpRegNum::power_isa_gpr_reg_num(3)], + &[MOpRegNum::POWER_ISA_CR_0_REG_NUM], + ), + [ + MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value, + MOpRegNum::power_isa_gpr_reg(5_hdl_u5).value, + MOpRegNum::const_zero().value, + ], + 0.cast_to_static::>(), + #[hdl(sim)] + OutputIntegerMode::Full64(), + false, + false, + false, + false, + ), + )); + retval.push(insn_single( + "addic. 3, 4, 0x1234", + 0x34641234, + None, + AddSubMOp::add_sub_i( + MOpDestReg::new_sim( + &[ + MOpRegNum::power_isa_gpr_reg_num(3), + MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM, + ], + &[MOpRegNum::POWER_ISA_CR_0_REG_NUM], + ), + [ + MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value, + MOpRegNum::const_zero().value, + ], + 0x1234.cast_to_static::>(), + #[hdl(sim)] + OutputIntegerMode::Full64(), + false, + false, + false, + false, + ), + )); + retval.push(insn_single( + "addc. 3, 4, 5", + 0x7c642815, + None, + AddSubMOp::add_sub( + MOpDestReg::new_sim( + &[ + MOpRegNum::power_isa_gpr_reg_num(3), + MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM, + ], + &[MOpRegNum::POWER_ISA_CR_0_REG_NUM], + ), + [ + MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value, + MOpRegNum::power_isa_gpr_reg(5_hdl_u5).value, + MOpRegNum::const_zero().value, + ], + 0.cast_to_static::>(), + #[hdl(sim)] + OutputIntegerMode::Full64(), + false, + false, + false, + false, + ), + )); retval }