mirror of
https://github.com/phabrics/Run-Sun3-SunOS-4.1.1.git
synced 2026-04-29 11:02:59 -04:00
437 lines
14 KiB
C
437 lines
14 KiB
C
/* $Id: sparc-rc-cc.c,v 1.2 2009/08/28 01:41:45 fredette Exp $ */
|
|
|
|
/* ic/sparc/sparc-rc-cc.c - SPARC recode condition code support: */
|
|
|
|
/*
|
|
* Copyright (c) 2008 Matt Fredette
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Matt Fredette.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#if TME_SPARC_RECODE_SIZE(ic) == TME_RECODE_SIZE_32
|
|
|
|
_TME_RCSID("$Id: sparc-rc-cc.c,v 1.2 2009/08/28 01:41:45 fredette Exp $");
|
|
|
|
/* macros: */
|
|
|
|
/* this converts sparc64 icc flags into the current architecture's icc
|
|
flags: */
|
|
#define TME_SPARC_ICC(ccr_icc) \
|
|
((ccr_icc) \
|
|
* (((TME_SPARC_VERSION(ic) < 9) \
|
|
* (TME_SPARC32_PSR_ICC \
|
|
/ TME_SPARC64_CCR_ICC)) \
|
|
+ (TME_SPARC_VERSION(ic) >= 9)))
|
|
|
|
#define TME_SPARC_RECODE_CCR_NEED(insn_class, insn_size, size) \
|
|
((((insn_class == TME_RECODE_INSN_CLASS_ADDITIVE) \
|
|
* ((TME_SPARC64_CCR_ICC_C \
|
|
* (TME_RECODE_FLAG_NEED(insn_class, insn_size, \
|
|
TME_RECODE_COND_C, size) \
|
|
!= 0)) \
|
|
+ (TME_SPARC64_CCR_ICC_V \
|
|
* (TME_RECODE_FLAG_NEED(insn_class, insn_size, \
|
|
TME_RECODE_COND_V, size) \
|
|
!= 0)))) \
|
|
+ (TME_SPARC64_CCR_ICC_Z \
|
|
* (TME_RECODE_FLAG_NEED(insn_class, insn_size, \
|
|
TME_RECODE_COND_Z, size) \
|
|
!= 0)) \
|
|
+ (TME_SPARC64_CCR_ICC_N \
|
|
* (TME_RECODE_FLAG_NEED(insn_class, insn_size, \
|
|
TME_RECODE_COND_N, size) \
|
|
!= 0))) \
|
|
* ((TME_SPARC64_CCR_XCC \
|
|
/ TME_SPARC64_CCR_ICC) \
|
|
* (size > TME_RECODE_SIZE_32)))
|
|
|
|
/* this macro gives the %icc and %xcc N and Z flags: */
|
|
#define TME_SPARC_RECODE_CCR_N_Z(dst, ccr_need) \
|
|
(0 \
|
|
+ ((((tme_uint32_t) (dst)) == 0) \
|
|
* ((ccr_need) & TME_SPARC64_CCR_ICC_Z)) \
|
|
+ ((((tme_int32_t) (dst)) < 0) \
|
|
* ((ccr_need) & TME_SPARC64_CCR_ICC_N)) \
|
|
+ ((((tme_sparc_ireg_t) (dst)) == 0) \
|
|
* ((ccr_need) & TME_SPARC64_CCR_XCC_Z)) \
|
|
+ ((((dst) & TME_SPARC_IREG_MSBIT) != 0) \
|
|
* ((ccr_need) & TME_SPARC64_CCR_XCC_N)))
|
|
|
|
/* this macro updates %icc and %xcc: */
|
|
#define TME_SPARC_RECODE_CCR_UPDATE(ic, ccr, ccr_need) \
|
|
do { \
|
|
if (TME_SPARC_VERSION((struct tme_sparc *) (ic)) >= 9) { \
|
|
((struct tme_sparc *) (ic))->tme_sparc64_ireg_ccr \
|
|
= ((((struct tme_sparc *) (ic))->tme_sparc64_ireg_ccr \
|
|
& ~ccr_need) \
|
|
| ccr); \
|
|
} \
|
|
else { \
|
|
((struct tme_sparc *) (ic))->tme_sparc32_ireg_psr \
|
|
= ((((struct tme_sparc *) (ic))->tme_sparc32_ireg_psr \
|
|
& ~TME_SPARC_ICC(ccr_need)) \
|
|
| TME_SPARC_ICC(ccr_need)); \
|
|
} \
|
|
} while (/* CONSTCOND */ 0)
|
|
|
|
/* rename various things by the architecture size: */
|
|
#define _tme_sparc_flags_additive _TME_SPARC_RECODE_SIZE(_tme_sparc,_flags_additive)
|
|
#define _tme_sparc_flags_logical _TME_SPARC_RECODE_SIZE(_tme_sparc,_flags_logical)
|
|
#define _tme_sparc_flags_func_logical _TME_SPARC_RECODE_SIZE(_tme_sparc,_flags_func_logical)
|
|
#define _tme_sparc_flags_func_add _TME_SPARC_RECODE_SIZE(_tme_sparc,_flags_func_add)
|
|
#define _tme_sparc_flags_func_sub _TME_SPARC_RECODE_SIZE(_tme_sparc,_flags_func_sub)
|
|
#define _tme_sparc_recode_conds_func_icc _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_conds_func_icc)
|
|
#define _tme_sparc_recode_cc_init _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_cc_init)
|
|
|
|
/* the sparc64 recode xcc conditions function: */
|
|
static int
|
|
_tme_sparc64_recode_conds_func_xcc(tme_recode_uguest_t flags, tme_uint32_t cond)
|
|
{
|
|
return (_tme_sparc_conds_icc
|
|
[TME_FIELD_MASK_EXTRACTU(flags, TME_SPARC64_CCR_XCC)]
|
|
& (1 << cond));
|
|
}
|
|
|
|
#endif /* TME_SPARC_RECODE_SIZE(ic) == TME_RECODE_SIZE_32 */
|
|
|
|
/* the additive instruction flags: */
|
|
static const struct tme_recode_flag _tme_sparc_flags_additive[] = {
|
|
#if TME_SPARC_VERSION(ic) >= 9
|
|
{
|
|
TME_RECODE_COND_N,
|
|
TME_RECODE_SIZE_64,
|
|
TME_SPARC64_CCR_XCC_N
|
|
},
|
|
{
|
|
TME_RECODE_COND_Z,
|
|
TME_RECODE_SIZE_64,
|
|
TME_SPARC64_CCR_XCC_Z
|
|
},
|
|
{
|
|
TME_RECODE_COND_V,
|
|
TME_RECODE_SIZE_64,
|
|
TME_SPARC64_CCR_XCC_V
|
|
},
|
|
{
|
|
TME_RECODE_COND_C,
|
|
TME_RECODE_SIZE_64,
|
|
TME_SPARC64_CCR_XCC_C
|
|
},
|
|
#endif /* TME_SPARC_VERSION(ic) >= 9 */
|
|
{
|
|
TME_RECODE_COND_N,
|
|
TME_RECODE_SIZE_32,
|
|
TME_SPARC_ICC(TME_SPARC64_CCR_ICC_N)
|
|
},
|
|
{
|
|
TME_RECODE_COND_Z,
|
|
TME_RECODE_SIZE_32,
|
|
TME_SPARC_ICC(TME_SPARC64_CCR_ICC_Z)
|
|
},
|
|
{
|
|
TME_RECODE_COND_V,
|
|
TME_RECODE_SIZE_32,
|
|
TME_SPARC_ICC(TME_SPARC64_CCR_ICC_V)
|
|
},
|
|
{
|
|
TME_RECODE_COND_C,
|
|
TME_RECODE_SIZE_32,
|
|
TME_SPARC_ICC(TME_SPARC64_CCR_ICC_C)
|
|
},
|
|
{
|
|
0,
|
|
0,
|
|
0
|
|
}
|
|
};
|
|
|
|
/* the logical instruction flags: */
|
|
static const struct tme_recode_flag _tme_sparc_flags_logical[] = {
|
|
#if TME_SPARC_VERSION(ic) >= 9
|
|
{
|
|
TME_RECODE_COND_N,
|
|
TME_RECODE_SIZE_64,
|
|
TME_SPARC64_CCR_XCC_N
|
|
},
|
|
{
|
|
TME_RECODE_COND_Z,
|
|
TME_RECODE_SIZE_64,
|
|
TME_SPARC64_CCR_XCC_Z
|
|
},
|
|
{
|
|
TME_RECODE_COND_FALSE,
|
|
0,
|
|
TME_SPARC64_CCR_XCC_V
|
|
},
|
|
{
|
|
TME_RECODE_COND_FALSE,
|
|
0,
|
|
TME_SPARC64_CCR_XCC_C
|
|
},
|
|
#endif /* TME_SPARC_VERSION(ic) >= 9 */
|
|
{
|
|
TME_RECODE_COND_N,
|
|
TME_RECODE_SIZE_32,
|
|
TME_SPARC_ICC(TME_SPARC64_CCR_ICC_N)
|
|
},
|
|
{
|
|
TME_RECODE_COND_Z,
|
|
TME_RECODE_SIZE_32,
|
|
TME_SPARC_ICC(TME_SPARC64_CCR_ICC_Z)
|
|
},
|
|
{
|
|
TME_RECODE_COND_FALSE,
|
|
0,
|
|
TME_SPARC_ICC(TME_SPARC64_CCR_ICC_V)
|
|
},
|
|
{
|
|
TME_RECODE_COND_FALSE,
|
|
0,
|
|
TME_SPARC_ICC(TME_SPARC64_CCR_ICC_C)
|
|
},
|
|
{
|
|
0,
|
|
0,
|
|
0
|
|
}
|
|
};
|
|
|
|
/* the logical instruction flags function: */
|
|
static void
|
|
_tme_sparc_flags_func_logical(struct tme_ic *ic,
|
|
tme_recode_uguest_t src1,
|
|
tme_recode_uguest_t src2,
|
|
tme_recode_uguest_t dst)
|
|
{
|
|
unsigned int ccr_need;
|
|
|
|
ccr_need
|
|
= (TME_SPARC_RECODE_CCR_NEED(TME_RECODE_INSN_CLASS_LOGICAL,
|
|
TME_SPARC_RECODE_SIZE(ic),
|
|
TME_RECODE_SIZE_32)
|
|
| TME_SPARC_RECODE_CCR_NEED(TME_RECODE_INSN_CLASS_LOGICAL,
|
|
TME_SPARC_RECODE_SIZE(ic),
|
|
TME_SPARC_RECODE_SIZE(ic)));
|
|
|
|
TME_SPARC_RECODE_CCR_UPDATE(ic,
|
|
TME_SPARC_RECODE_CCR_N_Z(dst, ccr_need),
|
|
ccr_need);
|
|
}
|
|
|
|
/* the add instruction flags function: */
|
|
static void
|
|
_tme_sparc_flags_func_add(struct tme_ic *ic,
|
|
tme_recode_uguest_t src1,
|
|
tme_recode_uguest_t src2,
|
|
tme_recode_uguest_t dst)
|
|
{
|
|
unsigned int ccr_need;
|
|
unsigned int ccr;
|
|
|
|
ccr_need
|
|
= (TME_SPARC_RECODE_CCR_NEED(TME_RECODE_INSN_CLASS_ADDITIVE,
|
|
TME_SPARC_RECODE_SIZE(ic),
|
|
TME_RECODE_SIZE_32)
|
|
| TME_SPARC_RECODE_CCR_NEED(TME_RECODE_INSN_CLASS_ADDITIVE,
|
|
TME_SPARC_RECODE_SIZE(ic),
|
|
TME_SPARC_RECODE_SIZE(ic)));
|
|
|
|
/* make the %icc and %xcc N and Z flags: */
|
|
ccr = TME_SPARC_RECODE_CCR_N_Z(dst, ccr_need);
|
|
|
|
/* if src1 and src2 both have bit 31 set, or if dst does not have
|
|
bit 31 set and either src1 or src2 does, set %icc.C: */
|
|
if (((tme_int32_t) ((src1 & src2) | (~dst & (src1 | src2)))) < 0) {
|
|
ccr += (ccr_need & TME_SPARC64_CCR_ICC_C);
|
|
}
|
|
|
|
/* if src1 and src2 have the same bit 31, and dst has a different
|
|
bit 31, set %icc.V: */
|
|
if (((tme_int32_t) ((src2 ^ dst) & (src1 ^ ~src2))) < 0) {
|
|
ccr += (ccr_need & TME_SPARC64_CCR_ICC_V);
|
|
}
|
|
|
|
/* if src1 and src2 both have the most-significant bit set, or if
|
|
dst does not have the most-significant bit set either src1 or
|
|
src2 does, set %xcc.C: */
|
|
if (((src1 & src2) | (~dst & (src1 | src2))) & TME_SPARC_IREG_MSBIT) {
|
|
ccr += (ccr_need & TME_SPARC64_CCR_XCC_C);
|
|
}
|
|
|
|
/* if src1 and src2 have the same most-significant bit, and dst has
|
|
a different most-significant bit, set %xcc.V: */
|
|
if (((src2 ^ dst) & (src1 ^ ~src2)) & TME_SPARC_IREG_MSBIT) {
|
|
ccr += (ccr_need & TME_SPARC64_CCR_XCC_V);
|
|
}
|
|
|
|
TME_SPARC_RECODE_CCR_UPDATE(ic, ccr, ccr_need);
|
|
}
|
|
|
|
/* the sub instruction flags function: */
|
|
static void
|
|
_tme_sparc_flags_func_sub(struct tme_ic *ic,
|
|
tme_recode_uguest_t src1,
|
|
tme_recode_uguest_t src2,
|
|
tme_recode_uguest_t dst)
|
|
{
|
|
unsigned int ccr_need;
|
|
unsigned int ccr;
|
|
|
|
ccr_need
|
|
= (TME_SPARC_RECODE_CCR_NEED(TME_RECODE_INSN_CLASS_ADDITIVE,
|
|
TME_SPARC_RECODE_SIZE(ic),
|
|
TME_RECODE_SIZE_32)
|
|
| TME_SPARC_RECODE_CCR_NEED(TME_RECODE_INSN_CLASS_ADDITIVE,
|
|
TME_SPARC_RECODE_SIZE(ic),
|
|
TME_SPARC_RECODE_SIZE(ic)));
|
|
|
|
/* make the %icc and %xcc N and Z flags: */
|
|
ccr = TME_SPARC_RECODE_CCR_N_Z(dst, ccr_need);
|
|
|
|
/* if src2 is greater than src1 in 32 bits, set %icc.C: */
|
|
if (((tme_uint32_t) src2) > ((tme_uint32_t) src1)) {
|
|
ccr += (ccr_need & TME_SPARC64_CCR_ICC_C);
|
|
}
|
|
|
|
/* if src1 and src2 have different bit 31s, and dst has a different
|
|
bit 31 than src1, set %icc.V: */
|
|
if (((tme_int32_t) ((src1 ^ src2) & (src1 ^ dst))) < 0) {
|
|
ccr += (ccr_need & TME_SPARC64_CCR_ICC_V);
|
|
}
|
|
|
|
/* if src2 is greater than src1, set %xcc.C: */
|
|
if (((tme_sparc_ireg_t) src2) > ((tme_sparc_ireg_t) src1)) {
|
|
ccr += (ccr_need & TME_SPARC64_CCR_XCC_C);
|
|
}
|
|
|
|
/* if src1 and src2 have different most-significant bits, and dst
|
|
has a different most-significant bit than src1, set %xcc.V: */
|
|
if (((src1 ^ src2) & (src1 ^ dst)) & TME_SPARC_IREG_MSBIT) {
|
|
ccr += (ccr_need & TME_SPARC64_CCR_XCC_V);
|
|
}
|
|
|
|
TME_SPARC_RECODE_CCR_UPDATE(ic, ccr, ccr_need);
|
|
}
|
|
|
|
/* the sparc icc conditions function: */
|
|
static int
|
|
_tme_sparc_recode_conds_func_icc(tme_recode_uguest_t flags, tme_uint32_t cond)
|
|
{
|
|
return (_tme_sparc_conds_icc
|
|
[TME_FIELD_MASK_EXTRACTU(flags, TME_SPARC_ICC(TME_SPARC64_CCR_ICC))]
|
|
& (1 << cond));
|
|
}
|
|
|
|
/* this initializes for condition codes: */
|
|
static void
|
|
_tme_sparc_recode_cc_init(struct tme_sparc *ic)
|
|
{
|
|
struct tme_recode_ic *recode_ic;
|
|
struct tme_recode_flags_group flags_group;
|
|
struct tme_recode_conds_group conds_group;
|
|
|
|
/* recover the recode ic: */
|
|
recode_ic = ic->tme_sparc_recode_ic;
|
|
|
|
/* make the common parts of a flags group: */
|
|
memset((char *) &flags_group, 0, sizeof(flags_group));
|
|
flags_group.tme_recode_flags_group_insn_size = TME_SPARC_RECODE_SIZE(ic);
|
|
if (TME_SPARC_VERSION(ic) <= 8) {
|
|
flags_group.tme_recode_flags_group_flags_reg_size = TME_RECODE_SIZE_32;
|
|
flags_group.tme_recode_flags_group_flags_reg = TME_SPARC32_IREG_PSR;
|
|
}
|
|
else {
|
|
flags_group.tme_recode_flags_group_flags_reg_size = TME_RECODE_SIZE_8;
|
|
flags_group.tme_recode_flags_group_flags_reg = TME_SPARC64_IREG_CCR << 3;
|
|
}
|
|
|
|
/* make the flags thunk for addcc and addxcc: */
|
|
flags_group.tme_recode_flags_group_insn_class = TME_RECODE_INSN_CLASS_ADDITIVE;
|
|
flags_group.tme_recode_flags_group_flags = _tme_sparc_flags_additive;
|
|
flags_group.tme_recode_flags_group_guest_func = _tme_sparc_flags_func_add;
|
|
ic->tme_sparc_recode_flags_thunk_add
|
|
= tme_recode_flags_thunk(recode_ic,
|
|
&flags_group);
|
|
|
|
/* make the flags thunk for subcc and subxcc: */
|
|
flags_group.tme_recode_flags_group_insn_class = TME_RECODE_INSN_CLASS_ADDITIVE;
|
|
flags_group.tme_recode_flags_group_flags = _tme_sparc_flags_additive;
|
|
flags_group.tme_recode_flags_group_guest_func = _tme_sparc_flags_func_sub;
|
|
ic->tme_sparc_recode_flags_thunk_sub
|
|
= tme_recode_flags_thunk(recode_ic,
|
|
&flags_group);
|
|
|
|
/* make the flags thunk for the logical instructions: */
|
|
flags_group.tme_recode_flags_group_insn_class = TME_RECODE_INSN_CLASS_LOGICAL;
|
|
flags_group.tme_recode_flags_group_flags = _tme_sparc_flags_logical;
|
|
flags_group.tme_recode_flags_group_guest_func = _tme_sparc_flags_func_logical;
|
|
ic->tme_sparc_recode_flags_thunk_logical
|
|
= tme_recode_flags_thunk(recode_ic,
|
|
&flags_group);
|
|
|
|
/* make the common parts of a conditions group: */
|
|
memset((char *) &conds_group, 0, sizeof(conds_group));
|
|
conds_group.tme_recode_conds_group_flags_reg_size = flags_group.tme_recode_flags_group_flags_reg_size;
|
|
conds_group.tme_recode_conds_group_flags_reg = flags_group.tme_recode_flags_group_flags_reg;
|
|
conds_group.tme_recode_conds_group_cond_count = TME_SPARC_COND_NOT;
|
|
|
|
/* make the conditions thunk for %icc: */
|
|
conds_group.tme_recode_conds_group_flags = TME_SPARC_ICC(TME_SPARC64_CCR_ICC);
|
|
conds_group.tme_recode_conds_group_guest_func = _tme_sparc_recode_conds_func_icc;
|
|
ic->tme_sparc_recode_conds_thunk_icc
|
|
= tme_recode_conds_thunk(recode_ic,
|
|
&conds_group);
|
|
|
|
/* if this is a sparc64: */
|
|
if (TME_SPARC_VERSION(ic) >= 9) {
|
|
|
|
/* make the flags thunk for the sparc64 internal "rcc" flags.
|
|
this is identical to the flags thunk for the logical
|
|
instructions, except it uses the internal "rcc" register: */
|
|
flags_group.tme_recode_flags_group_flags_reg = TME_SPARC64_IREG_RCC << 3;
|
|
ic->tme_sparc_recode_flags_thunk_rcc
|
|
= tme_recode_flags_thunk(recode_ic,
|
|
&flags_group);
|
|
|
|
/* make the conditions thunk for %xcc: */
|
|
conds_group.tme_recode_conds_group_flags = TME_SPARC64_CCR_XCC;
|
|
conds_group.tme_recode_conds_group_guest_func = _tme_sparc64_recode_conds_func_xcc;
|
|
ic->tme_sparc_recode_conds_thunk_xcc
|
|
= tme_recode_conds_thunk(recode_ic,
|
|
&conds_group);
|
|
|
|
/* make the conditions thunk for the internal "rcc" flags. this
|
|
is identical to the conditions thunk for %xcc, except it uses
|
|
the internal "rcc" register: */
|
|
conds_group.tme_recode_conds_group_flags_reg = flags_group.tme_recode_flags_group_flags_reg;
|
|
ic->tme_sparc_recode_conds_thunk_rcc
|
|
= tme_recode_conds_thunk(recode_ic,
|
|
&conds_group);
|
|
}
|
|
}
|