// SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use fayalite::prelude::*; #[hdl] pub enum FlagsMode { PowerISA(PRegFlagsPowerISA), X86(PRegFlagsX86), } #[hdl(cmp_eq)] pub struct PRegFlagsPowerISA {} impl PRegFlagsPowerISA { pub fn xer_ca(flags: impl ToExpr) -> Expr { flags.to_expr().pwr_ca_x86_cf } pub fn xer_ca32(flags: impl ToExpr) -> Expr { flags.to_expr().pwr_ca32_x86_af } pub fn xer_ov(flags: impl ToExpr) -> Expr { flags.to_expr().pwr_ov_x86_of } pub fn xer_ov32(flags: impl ToExpr) -> Expr { flags.to_expr().pwr_ov32_x86_df } /// both `CR.SO` and `XER.SO` since instructions that write to both always write the same value pub fn so(flags: impl ToExpr) -> Expr { flags.to_expr().pwr_so } pub fn cr_lt(flags: impl ToExpr) -> Expr { flags.to_expr().pwr_cr_lt_x86_sf } pub fn cr_gt(flags: impl ToExpr) -> Expr { flags.to_expr().pwr_cr_gt_x86_pf } pub fn cr_eq(flags: impl ToExpr) -> Expr { flags.to_expr().pwr_cr_eq_x86_zf } #[hdl] pub fn clear_unused(flags: impl ToExpr) { // list all flags explicitly so we don't miss handling any new flags #[hdl] let PRegFlags { pwr_ca_x86_cf: _, pwr_ca32_x86_af: _, pwr_ov_x86_of: _, pwr_ov32_x86_df: _, pwr_cr_lt_x86_sf: _, pwr_cr_gt_x86_pf: _, pwr_cr_eq_x86_zf: _, pwr_so: _, } = flags; } } #[hdl(cmp_eq)] pub struct PRegFlagsX86 {} impl PRegFlagsX86 { pub fn cf(flags: impl ToExpr) -> Expr { flags.to_expr().pwr_ca_x86_cf } pub fn zf(flags: impl ToExpr) -> Expr { flags.to_expr().pwr_cr_eq_x86_zf } pub fn sf(flags: impl ToExpr) -> Expr { flags.to_expr().pwr_cr_lt_x86_sf } pub fn of(flags: impl ToExpr) -> Expr { flags.to_expr().pwr_ov_x86_of } pub fn af(flags: impl ToExpr) -> Expr { flags.to_expr().pwr_ca32_x86_af } pub fn pf(flags: impl ToExpr) -> Expr { flags.to_expr().pwr_cr_gt_x86_pf } pub fn df(flags: impl ToExpr) -> Expr { flags.to_expr().pwr_ov32_x86_df } #[hdl] pub fn clear_unused(flags: impl ToExpr) { // list all flags explicitly so we don't miss handling any new flags #[hdl] let PRegFlags { pwr_ca_x86_cf: _, pwr_ca32_x86_af: _, pwr_ov_x86_of: _, pwr_ov32_x86_df: _, pwr_cr_lt_x86_sf: _, pwr_cr_gt_x86_pf: _, pwr_cr_eq_x86_zf: _, pwr_so: unused1, } = flags; connect(unused1, false); } } #[hdl(cmp_eq)] /// this is *not* the same as any particular ISA's flags register, /// on PowerISA it is a combination of some bits from XER with a single 4-bit CR field. /// /// Accessor functions depend on the ISA: /// /// * PowerISA: [`struct@PRegFlagsPowerISA`] /// * x86: [`struct@PRegFlagsX86`] pub struct PRegFlags { pwr_ca_x86_cf: Bool, pwr_ca32_x86_af: Bool, pwr_ov_x86_of: Bool, pwr_ov32_x86_df: Bool, pwr_cr_lt_x86_sf: Bool, pwr_cr_gt_x86_pf: Bool, pwr_cr_eq_x86_zf: Bool, pwr_so: Bool, } impl PRegFlags { /// if trying to set all fields individually, prefer using the individual accessor /// functions and [`PRegFlagsPowerISA::clear_unused()`]/[`PRegFlagsX86::clear_unused()`]/etc. #[hdl] pub fn zeroed() -> Expr { #[hdl] PRegFlags { pwr_ca_x86_cf: false, pwr_ca32_x86_af: false, pwr_ov_x86_of: false, pwr_ov32_x86_df: false, pwr_cr_lt_x86_sf: false, pwr_cr_gt_x86_pf: false, pwr_cr_eq_x86_zf: false, pwr_so: false, } } } #[hdl(cmp_eq)] /// Unit output register's value -- a combination of an integer/fp register /// and flags register and CR field. /// /// Register Renaming will independently rename the ISA-level integer/fp /// register, flags, and CR field portions. pub struct PRegValue { pub int_fp: UInt<64>, pub flags: PRegFlags, } impl PRegValue { #[hdl] pub fn zeroed() -> Expr { #[hdl] PRegValue { int_fp: 0u64, flags: PRegFlags::zeroed(), } } }