mirror of
https://github.com/elliotnunn/NetBoot.git
synced 2024-11-03 02:05:44 +00:00
588 lines
12 KiB
C
588 lines
12 KiB
C
/* Operand description structure */
|
|
struct powerpc_operand
|
|
{
|
|
int bits;
|
|
int shift;
|
|
uint32_t (*insert)(uint32_t,int32_t,const char **);
|
|
uint32_t flags;
|
|
};
|
|
|
|
/* powerpc_operand flags */
|
|
#define OPER_SIGNED (1) /* signed values */
|
|
#define OPER_SIGNOPT (2) /* signed values up to 0xffff */
|
|
#define OPER_FAKE (4) /* just reuse last read operand */
|
|
#define OPER_PARENS (8) /* operand is in parentheses */
|
|
#define OPER_CR (0x10) /* CR field */
|
|
#define OPER_GPR (0x20) /* GPR field */
|
|
#define OPER_FPR (0x40) /* FPR field */
|
|
#define OPER_RELATIVE (0x80) /* relative branch displacement */
|
|
#define OPER_ABSOLUTE (0x100) /* absolute branch address */
|
|
#define OPER_OPTIONAL (0x200) /* optional, zero if omitted */
|
|
#define OPER_NEXT (0x400) /* hack for rotate instructions */
|
|
#define OPER_NEGATIVE (0x800) /* range check on negative value */
|
|
#define OPER_VR (0x1000) /* Altivec register field */
|
|
|
|
/* Operand types. */
|
|
enum {
|
|
UNUSED,BA,BAT,BB,BBA,BD,BDA,BDM,BDMA,BDP,BDPA,BF,OBF,BFA,BI,BO,BOE,
|
|
BT,CR,D,DS,E,FL1,FL2,FLM,FRA,FRB,FRC,FRS,FXM,L,LEV,LI,LIA,MB,ME,
|
|
MBE,MBE_,MB6,NB,NSI,RA,RAL,RAM,RAS,RB,RBS,RS,SH,SH6,SI,SISIGNOPT,
|
|
SPR,SPRBAT,SPRG,SR,SV,TBR,TO,U,UI,VA,VB,VC,VD,SIMM,UIMM,SHB,
|
|
SLWI,SRWI,EXTLWI,EXTRWI,EXTWIB,INSLWI,INSRWI,ROTRWI,CLRRWI,CLRLSL,
|
|
STRM,AT,LS,RSOPT,RAOPT,RBOPT,CT,SHO,CRFS,EVUIMM_2,EVUIMM_4,EVUIMM_8
|
|
};
|
|
|
|
#define FRT FRS
|
|
#define ME6 MB6
|
|
#define RT RS
|
|
#define RTOPT RSOPT
|
|
#define VS VD
|
|
#define CRB MB
|
|
#define PMR SPR
|
|
#define TMR SPR
|
|
#define CRFD BF
|
|
#define EVUIMM SH
|
|
|
|
#define NEXT (-1) /* use operand_type+1 for next operand */
|
|
|
|
|
|
/* The functions used to insert complex operands. */
|
|
|
|
static uint32_t insert_bat(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
return insn | (((insn >> 21) & 0x1f) << 16);
|
|
}
|
|
|
|
static uint32_t insert_bba(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
return insn | (((insn >> 16) & 0x1f) << 11);
|
|
}
|
|
|
|
static uint32_t insert_bd(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
return insn | (value & 0xfffc);
|
|
}
|
|
|
|
static uint32_t insert_bdm(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
if ((value & 0x8000) != 0)
|
|
insn |= 1 << 21;
|
|
return insn | (value & 0xfffc);
|
|
}
|
|
|
|
static uint32_t insert_bdp(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
if ((value & 0x8000) == 0)
|
|
insn |= 1 << 21;
|
|
return insn | (value & 0xfffc);
|
|
}
|
|
|
|
static int valid_bo(int32_t value)
|
|
{
|
|
switch (value & 0x14) {
|
|
default:
|
|
case 0:
|
|
return 1;
|
|
case 0x4:
|
|
return (value & 0x2) == 0;
|
|
case 0x10:
|
|
return (value & 0x8) == 0;
|
|
case 0x14:
|
|
return value == 0x14;
|
|
}
|
|
}
|
|
|
|
static uint32_t insert_bo(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
if (!valid_bo (value))
|
|
*errmsg = "invalid conditional option";
|
|
return insn | ((value & 0x1f) << 21);
|
|
}
|
|
|
|
static uint32_t insert_boe(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
if (!valid_bo (value))
|
|
*errmsg = "invalid conditional option";
|
|
else if ((value & 1) != 0)
|
|
*errmsg = "attempt to set y bit when using + or - modifier";
|
|
return insn | ((value & 0x1f) << 21);
|
|
}
|
|
|
|
static uint32_t insert_ds(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
return insn | (value & 0xfffc);
|
|
}
|
|
|
|
static uint32_t insert_li(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
if ((value & 3) != 0)
|
|
*errmsg = "ignoring least significant bits in branch offset";
|
|
return insn | (value & 0x3fffffc);
|
|
}
|
|
|
|
static uint32_t insert_mbe(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
uint32_t uval, mask;
|
|
int mb, me, mx, count, last;
|
|
|
|
uval = value;
|
|
|
|
if (uval == 0) {
|
|
*errmsg = "illegal bitmask";
|
|
return insn;
|
|
}
|
|
|
|
mb = 0;
|
|
me = 32;
|
|
if ((uval & 1) != 0)
|
|
last = 1;
|
|
else
|
|
last = 0;
|
|
count = 0;
|
|
|
|
for (mx = 0, mask = (int32_t) 1 << 31; mx < 32; ++mx, mask >>= 1) {
|
|
if ((uval & mask) && !last) {
|
|
++count;
|
|
mb = mx;
|
|
last = 1;
|
|
}
|
|
else if (!(uval & mask) && last) {
|
|
++count;
|
|
me = mx;
|
|
last = 0;
|
|
}
|
|
}
|
|
if (me == 0)
|
|
me = 32;
|
|
|
|
if (count != 2 && (count != 0 || ! last)) {
|
|
*errmsg = "illegal bitmask";
|
|
}
|
|
|
|
return insn | (mb << 6) | ((me - 1) << 1);
|
|
}
|
|
|
|
static uint32_t insert_mb6(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
return insn | ((value & 0x1f) << 6) | (value & 0x20);
|
|
}
|
|
|
|
static uint32_t insert_nb(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
if (value < 0 || value > 32)
|
|
*errmsg = "value out of range";
|
|
if (value == 32)
|
|
value = 0;
|
|
return insn | ((value & 0x1f) << 11);
|
|
}
|
|
|
|
static uint32_t insert_nsi(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
return insn | ((- value) & 0xffff);
|
|
}
|
|
|
|
static uint32_t insert_ral(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
if (value == 0
|
|
|| (uint32_t) value == ((insn >> 21) & 0x1f))
|
|
*errmsg = "invalid register operand when updating";
|
|
return insn | ((value & 0x1f) << 16);
|
|
}
|
|
|
|
static uint32_t insert_ram(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
if ((uint32_t) value >= ((insn >> 21) & 0x1f))
|
|
*errmsg = "index register in load range";
|
|
return insn | ((value & 0x1f) << 16);
|
|
}
|
|
|
|
static uint32_t insert_ras(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
if (value == 0)
|
|
*errmsg = "invalid register operand when updating";
|
|
return insn | ((value & 0x1f) << 16);
|
|
}
|
|
|
|
static uint32_t insert_rbs(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
return insn | (((insn >> 21) & 0x1f) << 11);
|
|
}
|
|
|
|
static uint32_t insert_sh6(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
return insn | ((value & 0x1f) << 11) | ((value & 0x20) >> 4);
|
|
}
|
|
|
|
static uint32_t insert_spr(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6);
|
|
}
|
|
|
|
static uint32_t insert_sprg(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
/* @@@ only BOOKE, VLE and 405 have 8 SPRGs */
|
|
if (value & ~7)
|
|
*errmsg = "illegal SPRG number";
|
|
if ((insn & 0x100)!=0 || value<=3)
|
|
value |= 0x10; /* mfsprg 4..7 use SPR260..263 */
|
|
return insn | ((value & 17) << 16);
|
|
}
|
|
|
|
static uint32_t insert_tbr(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
if (value == 0)
|
|
value = 268;
|
|
return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6);
|
|
}
|
|
|
|
static uint32_t insert_slwi(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
return insn | ((value&0x1f)<<11) | ((31-(value&0x1f))<<1);
|
|
}
|
|
|
|
static uint32_t insert_srwi(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
return insn | (((32-value)&0x1f)<<11) | ((value&0x1f)<<6) | (31<<1);
|
|
}
|
|
|
|
static uint32_t insert_extlwi(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
if (value<1 || value>32)
|
|
*errmsg = "value out of range (1-32)";
|
|
return insn | (((value-1)&0x1f)<<1);
|
|
}
|
|
|
|
static uint32_t insert_extrwi(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
if (value<1 || value>32)
|
|
*errmsg = "value out of range (1-32)";
|
|
return insn | ((value&0x1f)<<11) | (((32-value)&0x1f)<<6) | (31<<1);
|
|
}
|
|
|
|
static uint32_t insert_extwib(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
value += (insn>>11) & 0x1f;
|
|
if (value > 32)
|
|
*errmsg = "sum of last two operands out of range (0-32)";
|
|
return (insn&~0xf800) | ((value&0x1f)<<11);
|
|
}
|
|
|
|
static uint32_t insert_inslwi(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
int32_t n = ((insn>>1) & 0x1f) + 1;
|
|
if (value+n > 32)
|
|
*errmsg = "sum of last two operands out of range (1-32)";
|
|
return (insn&~0xfffe) | (((32-value)&0x1f)<<11) | ((value&0x1f)<<6)
|
|
| ((((value+n)-1)&0x1f)<<1);
|
|
}
|
|
|
|
static uint32_t insert_insrwi(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
int32_t n = ((insn>>1) & 0x1f) + 1;
|
|
if (value+n > 32)
|
|
*errmsg = "sum of last two operands out of range (1-32)";
|
|
return (insn&~0xfffe) | (((32-(value+n))&0x1f)<<11) | ((value&0x1f)<<6)
|
|
| ((((value+n)-1)&0x1f)<<1);
|
|
}
|
|
|
|
static uint32_t insert_rotrwi(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
return insn | (((32-value)&0x1f)<<11);
|
|
}
|
|
|
|
static uint32_t insert_clrrwi(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
return insn | (((31-value)&0x1f)<<1);
|
|
}
|
|
|
|
static uint32_t insert_clrlslwi(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
int32_t b = (insn>>6) & 0x1f;
|
|
if (value > b)
|
|
*errmsg = "n (4th oper) must be less or equal to b (3rd oper)";
|
|
return (insn&~0x7c0) | ((value&0x1f)<<11) | (((b-value)&0x1f)<<6)
|
|
| (((31-value)&0x1f)<<1);
|
|
}
|
|
|
|
static uint32_t insert_ls(uint32_t insn,int32_t value,const char **errmsg)
|
|
{
|
|
/* @@@ check for POWER4 */
|
|
return insn | ((value&3)<<21);
|
|
}
|
|
|
|
|
|
/* The operands table.
|
|
The fields are: bits, shift, insert, flags. */
|
|
|
|
const struct powerpc_operand powerpc_operands[] =
|
|
{
|
|
/* UNUSED */
|
|
{ 0, 0, 0, 0 },
|
|
|
|
/* BA */
|
|
{ 5, 16, 0, OPER_CR },
|
|
|
|
/* BAT */
|
|
{ 5, 16, insert_bat, OPER_FAKE },
|
|
|
|
/* BB */
|
|
{ 5, 11, 0, OPER_CR },
|
|
|
|
/* BBA */
|
|
{ 5, 11, insert_bba, OPER_FAKE },
|
|
|
|
/* BD */
|
|
{ 16, 0, insert_bd, OPER_RELATIVE | OPER_SIGNED },
|
|
|
|
/* BDA */
|
|
{ 16, 0, insert_bd, OPER_ABSOLUTE | OPER_SIGNED },
|
|
|
|
/* BDM */
|
|
{ 16, 0, insert_bdm, OPER_RELATIVE | OPER_SIGNED },
|
|
|
|
/* BDMA */
|
|
{ 16, 0, insert_bdm, OPER_ABSOLUTE | OPER_SIGNED },
|
|
|
|
/* BDP */
|
|
{ 16, 0, insert_bdp, OPER_RELATIVE | OPER_SIGNED },
|
|
|
|
/* BDPA */
|
|
{ 16, 0, insert_bdp, OPER_ABSOLUTE | OPER_SIGNED },
|
|
|
|
/* BF */
|
|
{ 3, 23, 0, OPER_CR },
|
|
|
|
/* OBF */
|
|
{ 3, 23, 0, OPER_CR | OPER_OPTIONAL },
|
|
|
|
/* BFA */
|
|
{ 3, 18, 0, OPER_CR },
|
|
|
|
/* BI */
|
|
{ 5, 16, 0, OPER_CR },
|
|
|
|
/* BO */
|
|
{ 5, 21, insert_bo, 0 },
|
|
|
|
/* BOE */
|
|
{ 5, 21, insert_boe, 0 },
|
|
|
|
/* BT */
|
|
{ 5, 21, 0, OPER_CR },
|
|
|
|
/* CR */
|
|
{ 3, 18, 0, OPER_CR | OPER_OPTIONAL },
|
|
|
|
/* D */
|
|
{ 16, 0, 0, OPER_PARENS | OPER_SIGNED },
|
|
|
|
/* DS */
|
|
{ 16, 0, insert_ds, OPER_PARENS | OPER_SIGNED },
|
|
|
|
/* E */
|
|
{ 1, 15, 0, 0 },
|
|
|
|
/* FL1 */
|
|
{ 4, 12, 0, 0 },
|
|
|
|
/* FL2 */
|
|
{ 3, 2, 0, 0 },
|
|
|
|
/* FLM */
|
|
{ 8, 17, 0, 0 },
|
|
|
|
/* FRA */
|
|
{ 5, 16, 0, OPER_FPR },
|
|
|
|
/* FRB */
|
|
{ 5, 11, 0, OPER_FPR },
|
|
|
|
/* FRC */
|
|
{ 5, 6, 0, OPER_FPR },
|
|
|
|
/* FRS */
|
|
{ 5, 21, 0, OPER_FPR },
|
|
|
|
/* FXM */
|
|
{ 8, 12, 0, 0 },
|
|
|
|
/* L */
|
|
{ 1, 21, 0, OPER_OPTIONAL },
|
|
|
|
/* LEV */
|
|
{ 7, 5, 0, 0 },
|
|
|
|
/* LI */
|
|
{ 26, 0, insert_li, OPER_RELATIVE | OPER_SIGNED },
|
|
|
|
/* LIA */
|
|
{ 26, 0, insert_li, OPER_ABSOLUTE | OPER_SIGNED },
|
|
|
|
/* MB */
|
|
{ 5, 6, 0, 0 },
|
|
|
|
/* ME */
|
|
{ 5, 1, 0, 0 },
|
|
|
|
/* MBE */
|
|
{ 5, 6, 0, OPER_OPTIONAL | OPER_NEXT },
|
|
/* MBE_ (NEXT) */
|
|
{ 31, 1, insert_mbe, 0 },
|
|
|
|
/* MB6 */
|
|
{ 6, 5, insert_mb6, 0 },
|
|
|
|
/* NB */
|
|
{ 6, 11, insert_nb, 0 },
|
|
|
|
/* NSI */
|
|
{ 16, 0, insert_nsi, OPER_NEGATIVE | OPER_SIGNED },
|
|
|
|
/* RA */
|
|
{ 5, 16, 0, OPER_GPR },
|
|
|
|
/* RAL */
|
|
{ 5, 16, insert_ral, OPER_GPR },
|
|
|
|
/* RAM */
|
|
{ 5, 16, insert_ram, OPER_GPR },
|
|
|
|
/* RAS */
|
|
{ 5, 16, insert_ras, OPER_GPR },
|
|
|
|
/* RB */
|
|
{ 5, 11, 0, OPER_GPR },
|
|
|
|
/* RBS */
|
|
{ 5, 1, insert_rbs, OPER_FAKE },
|
|
|
|
/* RS */
|
|
{ 5, 21, 0, OPER_GPR },
|
|
|
|
/* SH */
|
|
{ 5, 11, 0, 0 },
|
|
|
|
/* SH6 */
|
|
{ 6, 1, insert_sh6, 0 },
|
|
|
|
/* SI */
|
|
{ 16, 0, 0, OPER_SIGNED },
|
|
|
|
/* SISIGNOPT */
|
|
{ 16, 0, 0, OPER_SIGNED | OPER_SIGNOPT },
|
|
|
|
/* SPR */
|
|
{ 10, 11, insert_spr, 0 },
|
|
|
|
/* SPRBAT */
|
|
{ 2, 17, 0, 0 },
|
|
|
|
/* SPRG */
|
|
{ 3, 16, insert_sprg, 0 },
|
|
|
|
/* SR */
|
|
{ 4, 16, 0, 0 },
|
|
|
|
/* SV */
|
|
{ 14, 2, 0, 0 },
|
|
|
|
/* TBR */
|
|
{ 10, 11, insert_tbr, OPER_OPTIONAL },
|
|
|
|
/* TO */
|
|
{ 5, 21, 0, 0 },
|
|
|
|
/* U */
|
|
{ 4, 12, 0, 0 },
|
|
|
|
/* UI */
|
|
{ 16, 0, 0, 0 },
|
|
|
|
/* VA */
|
|
{ 5, 16, 0, OPER_VR },
|
|
|
|
/* VB */
|
|
{ 5, 11, 0, OPER_VR },
|
|
|
|
/* VC */
|
|
{ 5, 6, 0, OPER_VR },
|
|
|
|
/* VD */
|
|
{ 5, 21, 0, OPER_VR },
|
|
|
|
/* SIMM */
|
|
{ 5, 16, 0, OPER_SIGNED},
|
|
|
|
/* UIMM */
|
|
{ 5, 16, 0, 0 },
|
|
|
|
/* SHB */
|
|
{ 4, 6, 0, 0 },
|
|
|
|
/* SLWI */
|
|
{ 5, 11, insert_slwi, 0 },
|
|
|
|
/* SRWI */
|
|
{ 5, 11, insert_srwi, 0 },
|
|
|
|
/* EXTLWI */
|
|
{ 31, 1, insert_extlwi, 0 },
|
|
|
|
/* EXTRWI */
|
|
{ 31, 1, insert_extrwi, 0 },
|
|
|
|
/* EXTWIB */
|
|
{ 5, 11, insert_extwib, 0 },
|
|
|
|
/* INSLWI */
|
|
{ 5, 11, insert_inslwi, 0 },
|
|
|
|
/* INSRWI */
|
|
{ 5, 11, insert_insrwi, 0 },
|
|
|
|
/* ROTRWI */
|
|
{ 5, 11, insert_rotrwi, 0 },
|
|
|
|
/* CLRRWI */
|
|
{ 5, 1, insert_clrrwi, 0 },
|
|
|
|
/* CLRLSL */
|
|
{ 5, 11, insert_clrlslwi, 0 },
|
|
|
|
/* STRM */
|
|
{ 2, 21, 0, 0 },
|
|
|
|
/* AT */
|
|
{ 1, 25, 0, OPER_OPTIONAL },
|
|
|
|
/* LS */
|
|
{ 2, 21, insert_ls, OPER_OPTIONAL },
|
|
|
|
/* RSOPT */
|
|
{ 5, 21, 0, OPER_GPR | OPER_OPTIONAL },
|
|
|
|
/* RAOPT */
|
|
{ 5, 16, 0, OPER_GPR | OPER_OPTIONAL },
|
|
|
|
/* RBOPT */
|
|
{ 5, 11, 0, OPER_GPR | OPER_OPTIONAL },
|
|
|
|
/* CT */
|
|
{ 5, 21, 0, OPER_OPTIONAL },
|
|
|
|
/* SHO */
|
|
{ 5, 11, 0, OPER_OPTIONAL },
|
|
|
|
/* CRFS */
|
|
{ 3, 0, 0, OPER_CR },
|
|
|
|
/* EVUIMM_2 */
|
|
{ 5, 10, 0, OPER_PARENS },
|
|
|
|
/* EVUIMM_4 */
|
|
{ 5, 9, 0, OPER_PARENS },
|
|
|
|
/* EVUIMM_8 */
|
|
{ 5, 8, 0, OPER_PARENS },
|
|
};
|