unsigned int mr : 1;
unsigned int RG : 1;
unsigned int crm : 1;
+ unsigned int bc_all : 1;
+ unsigned int bc_lru : 1;
+ unsigned int bc_brc : 1;
+ unsigned int bc_svstep : 1;
+ unsigned int bc_vsb : 1;
+ unsigned int bc_vlset : 1;
+ unsigned int bc_vli : 1;
+ unsigned int bc_snz : 1;
};
#define SVP64_RC1_ACTIVE (1U << 3U)
}
static void
-svp64_validate (struct svp64_ctx *svp64)
+svp64_validate_and_fix_mode_bc (struct svp64_ctx *svp64)
+{
+ /*
+ * Create mode and (overridden) src/dst widths.
+ * TODO: sanity-check BC modes.
+ */
+ svp64->sv_mode = ((svp64->bc_svstep << SVP64_MODE_MOD2_MSB) |
+ (svp64->bc_vlset << SVP64_MODE_MOD2_LSB) |
+ (svp64->bc_snz << SVP64_MODE_BC_SNZ));
+ svp64->srcwid = ((svp64->bc_vsb << 1) | svp64->bc_lru);
+ svp64->destwid = ((svp64->bc_lru << 1) | svp64->bc_all);
+}
+
+static void
+svp64_validate_and_fix_mode_mr (struct svp64_ctx *svp64)
+{
+ svp64->mode |= (1U << SVP64_MODE_REDUCE);
+ svp64_raise_if (svp64->dz,
+ "dest-zero not allowed in mr mode");
+
+ if (svp64->RG)
+ svp64->mode |= (1U << SVP64_MODE_RG);
+
+ if (svp64->crm)
+ {
+ svp64->mode |= (1U << SVP64_MODE_CRM);
+ svp64_raise_if (!svp64->desc->Rc, "CRM only allowed when Rc=1");
+ }
+
+ /*
+ * Bit of weird encoding to jam zero-pred or SVM mode in.
+ * SVM mode can be enabled only when SUBVL=2/3/4 (vec2/3/4)
+ */
+ if (svp64->subvl == 0)
+ svp64->mode |= (svp64->dz << SVP64_MODE_DZ);
+}
+
+static void
+svp64_validate_and_fix_mode_ff(struct svp64_ctx *svp64)
+{
+ svp64_raise_if (svp64->sz,
+ "dest-zero not allowed in ff mode");
+
+ if (svp64->ff & SVP64_RC1_ACTIVE)
+ {
+ svp64->mode |= (1U << SVP64_MODE_RC1);
+ svp64->mode |= (svp64->dz << SVP64_MODE_DZ);
+ svp64_raise_if (svp64->desc->Rc,
+ "ffirst RC1/~RC1 only possible when Rc=0");
+ if (svp64->ff & SVP64_RC1_INVERT)
+ svp64->mode |= (1U << SVP64_MODE_INV);
+ }
+ else
+ {
+ svp64_raise_if (svp64->dz,
+ "dst-zero not allowed in ffirst BO");
+ svp64_raise_if (!svp64->desc->Rc,
+ "ffirst BO only possible when Rc=1");
+ svp64->mode |= (svp64->ff << SVP64_MODE_BO_LSB);
+ }
+}
+
+static void
+svp64_validate_and_fix_mode_sat(struct svp64_ctx *svp64)
+{
+ svp64->mode |= (svp64->sz << SVP64_MODE_SZ);
+ svp64->mode |= (svp64->dz << SVP64_MODE_DZ);
+ svp64->mode |= (svp64->sat << SVP64_MODE_N);
+}
+
+static void
+svp64_validate_and_fix_mode_strided(struct svp64_ctx *svp64)
+{
+ svp64->mode |= (svp64->dz << SVP64_MODE_DZ);
+ svp64->mode |= (svp64->sz << SVP64_MODE_SZ);
+ svp64->mode |= (svp64->sea << SVP64_MODE_SEA);
+}
+
+static void
+svp64_validate_and_fix_mode_explicit(struct svp64_ctx *svp64)
+{
+ static void (*const table[])(struct svp64_ctx *svp64) = {
+ svp64_validate_and_fix_mode_mr,
+ svp64_validate_and_fix_mode_ff,
+ svp64_validate_and_fix_mode_sat,
+ };
+
+ if ((svp64->sv_mode == 0b01) && (svp64->desc->mode == SVP64_MODE_LDST_IDX))
+ return svp64_validate_and_fix_mode_strided (svp64);
+
+ return (*table[svp64->sv_mode]) (svp64);
+}
+
+static void
+svp64_validate_and_fix_mode_normal (struct svp64_ctx *svp64)
+{
+ svp64->mode |= (svp64->sz << SVP64_MODE_SZ);
+ svp64->mode |= (svp64->dz << SVP64_MODE_DZ);
+ if ((svp64->desc->mode == SVP64_MODE_LDST_IMM) ||
+ (svp64->desc->mode == SVP64_MODE_LDST_IDX))
+ {
+ /* TODO: for now, LD/ST-indexed is ignored. */
+ svp64->mode |= (svp64->els << SVP64_MODE_ELS_NORMAL);
+ }
+ else
+ {
+ /*
+ * TODO: reduce and subvector mode.
+ * 00 1 dz CRM reduce mode (mr), SUBVL=1
+ * 00 1 SVM CRM subvector reduce mode, SUBVL>1
+ */
+ }
+ svp64->sv_mode = 0;
+}
+
+/*
+ * There are 4 different modes, here, which will be partly-merged-in:
+ * is_ldst is merged in with "normal", but is_bc is so different it's
+ * done separately. Likewise is_cr (when it is done).
+ *
+ * "normal" arithmetic: https://libre-soc.org/openpower/sv/normal
+ * | 0-1 | 2 | 3 4 | description |
+ * | --- | --- |---------|------------------------------------------ |
+ * | 00 | 0 | dz sz | normal mode |
+ * | 00 | 1 | 0 RG | scalar reduce mode (mr), SUBVL=1 |
+ * | 00 | 1 | 1 / | parallel reduce mode (mr), SUBVL=1 |
+ * | 00 | 1 | SVM RG | subvector reduce mode, SUBVL>1 |
+ * | 01 | inv | CR-bit | Rc=1: ffirst CR sel |
+ * | 01 | inv | VLi RC1 | Rc=0: ffirst z/nonz |
+ * | 10 | N | dz sz | sat mode: N=0/1 u/s |
+ * | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
+ * | 11 | inv | dz RC1 | Rc=0: pred-result z/nonz |
+ *
+ * LD/ST-immediate: https://libre-soc.org/openpower/sv/ldst
+ * | 0-1 | 2 | 3 4 | description |
+ * | --- | --- |---------|------------------------------------------ |
+ * | 00 | 0 | dz els | normal mode |
+ * | 00 | 1 | dz shf | shift mode |
+ * | 01 | inv | CR-bit | Rc=1: ffirst CR sel |
+ * | 01 | inv | els RC1 | Rc=0: ffirst z/nonz |
+ * | 10 | N | dz els | sat mode: N=0/1 u/s |
+ * | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
+ * | 11 | inv | els RC1 | Rc=0: pred-result z/nonz |
+ *
+ * LD/ST-indexed (RA+RB): https://libre-soc.org/openpower/sv/ldst
+ * | 0-1 | 2 | 3 4 | description |
+ * | --- | --- |---------|------------------------------------------ |
+ * | 00 | SEA | dz sz | normal mode |
+ * | 01 | SEA | dz sz | Strided (scalar only source) |
+ * | 10 | N | dz sz | sat mode: N=0/1 u/s |
+ * | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
+ * | 11 | inv | dz RC1 | Rc=0: pred-result z/nonz |
+ *
+ * ...and branches/cr_ops are still in development.
+ */
+static void
+svp64_validate_and_fix_mode (struct svp64_ctx *svp64)
+{
+ if (svp64->desc->mode == SVP64_MODE_BRANCH)
+ svp64_validate_and_fix_mode_bc (svp64);
+ else if (svp64->sv_mode_explicit)
+ svp64_validate_and_fix_mode_explicit (svp64);
+ else
+ svp64_validate_and_fix_mode_normal (svp64);
+
+ svp64->mode |= (((svp64->sv_mode >> 0) & 0x1) << SVP64_MODE_MOD2_LSB);
+ svp64->mode |= (((svp64->sv_mode >> 1) & 0x1) << SVP64_MODE_MOD2_MSB);
+}
+
+static void
+svp64_validate_and_fix (struct svp64_ctx *svp64)
{
if (svp64->desc->ptype == SVP64_PTYPE_P2)
{
svp64_raise_if (!svp64->has_smask && !svp64->mask_m_specified,
"src zeroing requires a source predicate");
}
+
+ svp64_validate_and_fix_mode (svp64);
}
static void
memset (&svp64, 0, sizeof (svp64));
svp64_decode (str, &svp64);
- svp64_validate (&svp64);
+ svp64_validate_and_fix (&svp64);
as_warn (_("opcode ignored (desc=%p)"), svp64.desc);
memcpy (str, "nop", sizeof ("nop"));