2020-12-31 03:55:59 +00:00
|
|
|
|
//
|
2021-01-15 23:16:01 +00:00
|
|
|
|
// Instruction.hpp
|
2020-12-31 03:55:59 +00:00
|
|
|
|
// Clock Signal
|
|
|
|
|
//
|
2021-01-17 03:09:19 +00:00
|
|
|
|
// Created by Thomas Harte on 15/01/21.
|
2021-01-15 23:16:01 +00:00
|
|
|
|
// Copyright © 2021 Thomas Harte. All rights reserved.
|
2020-12-31 03:55:59 +00:00
|
|
|
|
//
|
|
|
|
|
|
2021-01-15 23:16:01 +00:00
|
|
|
|
#ifndef InstructionSets_PowerPC_Instruction_h
|
|
|
|
|
#define InstructionSets_PowerPC_Instruction_h
|
2020-12-31 03:55:59 +00:00
|
|
|
|
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
|
2021-01-16 02:30:30 +00:00
|
|
|
|
namespace InstructionSet {
|
2020-12-31 03:55:59 +00:00
|
|
|
|
namespace PowerPC {
|
|
|
|
|
|
2022-03-21 14:17:55 +00:00
|
|
|
|
enum class CacheLine: uint32_t {
|
|
|
|
|
Instruction = 0b01100,
|
|
|
|
|
Data = 0b1101,
|
|
|
|
|
Minimum = 0b01110,
|
|
|
|
|
Maximum = 0b01111,
|
|
|
|
|
};
|
|
|
|
|
|
2022-03-25 00:44:03 +00:00
|
|
|
|
enum class Condition: uint32_t {
|
|
|
|
|
// CR0
|
|
|
|
|
Negative = 0, // LT
|
|
|
|
|
Positive = 1, // GT
|
|
|
|
|
Zero = 2, // EQ
|
|
|
|
|
SummaryOverflow = 3, // SO
|
|
|
|
|
|
|
|
|
|
// CR1
|
|
|
|
|
FPException = 4, // FX
|
|
|
|
|
FPEnabledException = 5, // FEX
|
|
|
|
|
FPInvalidException = 6, // VX
|
|
|
|
|
FPOverflowException = 7, // OX
|
|
|
|
|
|
|
|
|
|
// CRs2–7 fill out the condition register.
|
|
|
|
|
};
|
|
|
|
|
|
2022-03-25 12:41:57 +00:00
|
|
|
|
enum class BranchOption: uint32_t {
|
2022-03-21 14:19:30 +00:00
|
|
|
|
// Naming convention:
|
|
|
|
|
//
|
|
|
|
|
// Dec_ prefix => decrement the CTR;
|
|
|
|
|
// condition starting NotZero or Zero => test CTR;
|
|
|
|
|
// condition ending Set or Clear => test for condition bit.
|
|
|
|
|
//
|
|
|
|
|
// Numerical suffixes are present because there's some redundancy
|
|
|
|
|
// in encodings.
|
|
|
|
|
//
|
|
|
|
|
// Note that the encodings themselves may suggest alternative means
|
|
|
|
|
// of interpretation than mapping via this enum.
|
2022-03-25 00:44:03 +00:00
|
|
|
|
Dec_NotZeroAndClear = 0b0000,
|
|
|
|
|
Dec_ZeroAndClear = 0b0001,
|
|
|
|
|
Clear = 0b0010,
|
|
|
|
|
Dec_NotZeroAndSet = 0b0100,
|
|
|
|
|
Dec_ZeroAndSet = 0b0101,
|
|
|
|
|
Set = 0b0110,
|
|
|
|
|
Dec_NotZero = 0b1000,
|
|
|
|
|
Dec_Zero = 0b1001,
|
|
|
|
|
Always = 0b1010,
|
2022-03-21 14:19:30 +00:00
|
|
|
|
};
|
|
|
|
|
|
2020-12-31 03:55:59 +00:00
|
|
|
|
enum class Operation: uint8_t {
|
|
|
|
|
Undefined,
|
|
|
|
|
|
2022-03-27 12:47:01 +00:00
|
|
|
|
//
|
2020-12-31 03:55:59 +00:00
|
|
|
|
// These 601-exclusive instructions; a lot of them are carry-overs
|
2022-03-21 14:17:55 +00:00
|
|
|
|
// from POWER. These are not part of the PowerPC architecture.
|
2022-03-27 12:47:01 +00:00
|
|
|
|
//
|
2022-03-21 14:17:55 +00:00
|
|
|
|
|
|
|
|
|
/// |rA| is placed into rD. If rA = 0x8000'0000 then 0x8000'0000 is placed into rD
|
|
|
|
|
/// and XER[OV] is set if oe() indicates that overflow is enabled.
|
|
|
|
|
absx,
|
|
|
|
|
|
|
|
|
|
/// The size of the cache line specified by rA is placed into rD. Cf. the CacheLine enum.
|
|
|
|
|
/// As an aside: all cache lines are 64 bytes on the MPC601.
|
|
|
|
|
clcs,
|
|
|
|
|
|
|
|
|
|
/// div, div., divo, div.; unsigned 64-bit divide. rA|MQ / rB is placed into rD and the
|
|
|
|
|
/// remainder is placed into MQ. The ermainder has the same sign as the dividend
|
|
|
|
|
/// such that remainder + divisor * quotient = dividend.
|
|
|
|
|
///
|
|
|
|
|
/// rc() != 0 => the LT, GT and EQ bits in CR are set as per the remainder.
|
|
|
|
|
/// oe() != 0 => SO and OV are set if the quotient exceeds 32 bits.
|
|
|
|
|
divx,
|
|
|
|
|
|
|
|
|
|
/// divs, divs., divso, divso.; signed 32-bit divide. rD = rA/rB; remainder is
|
|
|
|
|
/// placed into MQ. The ermainder has the same sign as the dividend
|
|
|
|
|
/// such that remainder + divisor * quotient = dividend.
|
|
|
|
|
///
|
|
|
|
|
/// rc() != 0 => the LT, GT and EQ bits in CR are set as per the remainder.
|
|
|
|
|
/// oe() != 0 => SO and OV are set if the quotient exceeds 32 bits.
|
2022-03-21 14:49:01 +00:00
|
|
|
|
divsx,
|
|
|
|
|
|
|
|
|
|
/// if rA > rB then rD = 0; else rD = NOT(rA) + rB + 1.
|
|
|
|
|
dozx,
|
|
|
|
|
|
|
|
|
|
/// if rA > simm() then rD = 0; else rD = NOT(rA) + simm() + 1.
|
|
|
|
|
dozi,
|
|
|
|
|
|
|
|
|
|
lscbxx, maskgx, maskirx, mulx,
|
2020-12-31 03:55:59 +00:00
|
|
|
|
nabsx, rlmix, rribx, slex, sleqx, sliqx, slliqx, sllqx, slqx,
|
|
|
|
|
sraiqx, sraqx, srex, sreax, sreqx, sriqx, srliqx, srlqx, srqx,
|
2021-01-15 23:16:01 +00:00
|
|
|
|
|
2022-03-27 12:47:01 +00:00
|
|
|
|
//
|
2020-12-31 03:55:59 +00:00
|
|
|
|
// 32- and 64-bit PowerPC instructions.
|
2022-03-27 12:47:01 +00:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
addx, addcx, addex,
|
|
|
|
|
|
|
|
|
|
/// Add immediate.
|
|
|
|
|
///
|
|
|
|
|
/// rD() = (rA() | 0) + simm()
|
|
|
|
|
addi,
|
|
|
|
|
|
|
|
|
|
/// Add immediate carrying.
|
|
|
|
|
///
|
|
|
|
|
/// rD() = (rA() | 0) + simm()
|
|
|
|
|
/// XER[CA] = carry.
|
|
|
|
|
addic,
|
|
|
|
|
|
|
|
|
|
/// Add immediate carrying.
|
|
|
|
|
///
|
|
|
|
|
/// rD() = (rA() | 0) + simm()
|
|
|
|
|
/// XER[CA] = carry, and the condition register is updated.
|
|
|
|
|
addic_,
|
|
|
|
|
|
|
|
|
|
/// Add immediate shifter.
|
|
|
|
|
///
|
|
|
|
|
/// rD() = (rA() | 0) + (simm() << 16)
|
|
|
|
|
addis,
|
|
|
|
|
|
|
|
|
|
addmex, addzex, andx,
|
2022-03-18 23:55:26 +00:00
|
|
|
|
andcx, andi_, andis_,
|
|
|
|
|
|
|
|
|
|
/// Branch unconditional.
|
|
|
|
|
///
|
|
|
|
|
/// Use li() to get the included immediate value.
|
|
|
|
|
///
|
|
|
|
|
/// Use aa() to determine whether it's a relative (aa() = 0) or absolute (aa() != 0) address.
|
|
|
|
|
/// Also check lk() to determine whether to update the link register.
|
|
|
|
|
///
|
|
|
|
|
/// Synonyms include:
|
|
|
|
|
/// * b (relative, no link) [though assemblers might encode as a bcx];
|
|
|
|
|
/// * bl (relative, link);
|
|
|
|
|
/// * ba (absolute, no link);
|
|
|
|
|
/// * bla (absolute, link).
|
|
|
|
|
bx,
|
|
|
|
|
|
|
|
|
|
/// Branch conditional.
|
|
|
|
|
///
|
2022-03-26 00:10:08 +00:00
|
|
|
|
/// aa() determines whether the branch has a relative or absolute target.
|
2022-03-18 23:55:26 +00:00
|
|
|
|
/// lk() determines whether to update the link register.
|
2022-03-26 00:10:08 +00:00
|
|
|
|
/// bd() supplies a relative displacment or absolute address.
|
2022-03-25 00:44:03 +00:00
|
|
|
|
/// bi() specifies which CR bit to use as a condition; cf. the Condition enum.
|
|
|
|
|
/// bo() provides other branch options and a branch prediction hint as per (BranchOptions enum << 1) | hint.
|
2022-03-18 23:55:26 +00:00
|
|
|
|
///
|
|
|
|
|
/// Synonyms incude:
|
|
|
|
|
/// * b (relative, no link) [though assemblers might encode as a bx].
|
|
|
|
|
bcx,
|
|
|
|
|
|
|
|
|
|
/// Branch conditional to count register.
|
|
|
|
|
///
|
2022-03-26 00:10:08 +00:00
|
|
|
|
/// aa(), bi(), bo() and lk() are as per bcx.
|
2022-03-18 23:55:26 +00:00
|
|
|
|
///
|
|
|
|
|
/// On the MPC601, anything that decrements the count register will use the non-decremented
|
|
|
|
|
/// version as the branch target. Other processors will use the decremented version.
|
|
|
|
|
bcctrx,
|
|
|
|
|
|
2022-03-25 10:25:06 +00:00
|
|
|
|
/// Branch conditional to link register.
|
|
|
|
|
///
|
2022-03-26 00:10:08 +00:00
|
|
|
|
/// aa(), bi(), bo() and lk() are as per bcx.
|
2022-03-25 10:25:06 +00:00
|
|
|
|
bclrx,
|
|
|
|
|
|
|
|
|
|
cmp, cmpi, cmpl, cmpli,
|
2020-12-31 03:55:59 +00:00
|
|
|
|
cntlzwx, crand, crandc, creqv, crnand, crnor, cror, crorc, crxor, dcbf,
|
|
|
|
|
dcbst, dcbt, dcbtst, dcbz, divwx, divwux, eciwx, ecowx, eieio, eqvx,
|
|
|
|
|
extsbx, extshx, fabsx, faddx, faddsx, fcmpo, fcmpu, fctiwx, fctiwzx,
|
|
|
|
|
fdivx, fdivsx, fmaddx, fmaddsx, fmrx, fmsubx, fmsubsx, fmulx, fmulsx,
|
|
|
|
|
fnabsx, fnegx, fnmaddx, fnmaddsx, fnmsubx, fnmsubsx, frspx, fsubx, fsubsx,
|
2022-03-26 12:45:07 +00:00
|
|
|
|
icbi, isync, lbz, lbzu,
|
|
|
|
|
|
|
|
|
|
/// Load byte and zero with update indexed.
|
|
|
|
|
///
|
|
|
|
|
/// rD()[24, 31] = [ rA()|0 + rB() ]; and rA() is set to the calculated address
|
|
|
|
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
|
|
|
|
/// The rest of rD is set to 0.
|
|
|
|
|
///
|
|
|
|
|
/// PowerPC defines rA=0 and rA=rD to be invalid forms; the MPC601
|
|
|
|
|
/// will suppress the update if rA=0 or rA=rD.
|
|
|
|
|
lbzux,
|
|
|
|
|
|
|
|
|
|
/// Load byte and zero indexed.
|
|
|
|
|
///
|
|
|
|
|
/// rD[24, 31] = [ (rA()|0) + rB() ]
|
|
|
|
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
|
|
|
|
/// The rest of rD is set to 0.
|
|
|
|
|
lbzx,
|
|
|
|
|
|
|
|
|
|
lfd, lfdu, lfdux, lfdx, lfs, lfsu,
|
2022-03-27 12:47:01 +00:00
|
|
|
|
lfsux, lfsx, lha, lhau,
|
|
|
|
|
|
|
|
|
|
/// Load half-word algebraic with update indexed.
|
|
|
|
|
///
|
|
|
|
|
/// rD()[16, 31] = [ rA()|0 + rB() ]; and rA() is set to the calculated address
|
|
|
|
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
|
|
|
|
/// The result in rD is sign extended.
|
|
|
|
|
///
|
|
|
|
|
/// PowerPC defines rA=0 and rA=rD to be invalid forms; the MPC601
|
|
|
|
|
/// will suppress the update if rA=0 or rA=rD.
|
|
|
|
|
lhaux,
|
|
|
|
|
|
|
|
|
|
/// Load half-word algebraic indexed.
|
|
|
|
|
///
|
|
|
|
|
/// rD[16, 31] = [ (rA()|0) + rB() ]
|
|
|
|
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
|
|
|
|
/// The result in rD is sign extended.
|
|
|
|
|
lhax,
|
|
|
|
|
|
|
|
|
|
lhbrx, lhz, lhzu,
|
|
|
|
|
|
|
|
|
|
/// Load half-word and zero with update indexed.
|
|
|
|
|
///
|
|
|
|
|
/// rD()[16, 31] = [ rA()|0 + rB() ]; and rA() is set to the calculated address
|
|
|
|
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
|
|
|
|
/// The rest of rD is set to 0.
|
|
|
|
|
///
|
|
|
|
|
/// PowerPC defines rA=0 and rA=rD to be invalid forms; the MPC601
|
|
|
|
|
/// will suppress the update if rA=0 or rA=rD.
|
|
|
|
|
lhzux,
|
|
|
|
|
|
|
|
|
|
/// Load half-word and zero indexed.
|
|
|
|
|
///
|
|
|
|
|
/// rD[16, 31] = [ (rA()|0) + rB() ]
|
|
|
|
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
|
|
|
|
/// The rest of rD is set to 0.
|
|
|
|
|
lhzx,
|
|
|
|
|
|
|
|
|
|
lmw,
|
2022-03-26 00:31:47 +00:00
|
|
|
|
lswi, lswx, lwarx, lwbrx, lwz, lwzu,
|
|
|
|
|
|
2022-03-26 12:45:07 +00:00
|
|
|
|
/// Load word and zero with update indexed.
|
2022-03-26 00:31:47 +00:00
|
|
|
|
///
|
2022-03-26 12:45:07 +00:00
|
|
|
|
/// rD() = [ rA()|0 + rB() ]; and rA() is set to the calculated address
|
|
|
|
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
2022-03-26 00:31:47 +00:00
|
|
|
|
///
|
|
|
|
|
/// PowerPC defines rA=0 and rA=rD to be invalid forms; the MPC601
|
|
|
|
|
/// will suppress the update if rA=0 or rA=rD.
|
|
|
|
|
lwzux,
|
2022-03-26 00:23:21 +00:00
|
|
|
|
|
|
|
|
|
/// Load word and zero indexed.
|
|
|
|
|
///
|
2022-03-26 12:45:07 +00:00
|
|
|
|
/// rD() = [ (rA()|0) + rB() ]
|
|
|
|
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
2022-03-26 00:23:21 +00:00
|
|
|
|
lwzx,
|
|
|
|
|
|
|
|
|
|
mcrf, mcrfs, mcrxr,
|
2020-12-31 03:55:59 +00:00
|
|
|
|
mfcr, mffsx, mfmsr, mfspr, mfsr, mfsrin, mtcrf, mtfsb0x, mtfsb1x, mtfsfx,
|
2022-03-27 12:47:01 +00:00
|
|
|
|
mtfsfix, mtmsr, mtspr, mtsr, mtsrin, mulhwx, mulhwux,
|
|
|
|
|
|
|
|
|
|
/// Multiply low immediate.
|
|
|
|
|
///
|
|
|
|
|
/// rD() = [low 32 bits of] rA() * simm()
|
|
|
|
|
/// XER[OV] is set if, were the operands treated as signed, overflow occurred.
|
|
|
|
|
mulli,
|
|
|
|
|
|
|
|
|
|
mullwx,
|
2020-12-31 03:55:59 +00:00
|
|
|
|
nandx, negx, norx, orx, orcx, ori, oris, rfi, rlwimix, rlwinmx, rlwnmx,
|
2022-03-27 12:47:01 +00:00
|
|
|
|
sc, slwx, srawx, srawix, srwx, stb, stbu,
|
|
|
|
|
|
|
|
|
|
/// Store byte with update indexed.
|
|
|
|
|
///
|
|
|
|
|
/// [ (ra()|0) + rB() ] = rS()[24, 31]; and rA() is updated with the calculated address.
|
|
|
|
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
|
|
|
|
///
|
|
|
|
|
/// PowerPC defines rA=0 to an invalid form; the MPC601 will store to r0.
|
|
|
|
|
stbux,
|
|
|
|
|
|
|
|
|
|
/// Store byte indexed.
|
|
|
|
|
///
|
|
|
|
|
/// [ (ra()|0) + rB() ] = rS()[24, 31]
|
|
|
|
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
|
|
|
|
stbx,
|
|
|
|
|
|
|
|
|
|
stfd, stfdu,
|
|
|
|
|
stfdux, stfdx, stfs, stfsu, stfsux, stfsx, sth, sthbrx, sthu,
|
|
|
|
|
|
|
|
|
|
/// Store half-word with update indexed.
|
|
|
|
|
///
|
|
|
|
|
/// [ (ra()|0) + rB() ] = rS()[16, 31]; and rA() is updated with the calculated address.
|
|
|
|
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
|
|
|
|
///
|
|
|
|
|
/// PowerPC defines rA=0 to an invalid form; the MPC601 will store to r0.
|
|
|
|
|
sthux,
|
|
|
|
|
|
|
|
|
|
/// Store half-word indexed.
|
|
|
|
|
///
|
|
|
|
|
/// [ (ra()|0) + rB() ] = rS()[16, 31]
|
|
|
|
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
|
|
|
|
sthx,
|
|
|
|
|
|
|
|
|
|
stmw, stswi, stswx, stw, stwbrx, stwcx_, stwu,
|
|
|
|
|
|
|
|
|
|
/// Store word with update indexed.
|
|
|
|
|
///
|
|
|
|
|
/// [ (ra()|0) + rB() ] = rS(); and rA() is updated with the calculated address.
|
|
|
|
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
|
|
|
|
///
|
|
|
|
|
/// PowerPC defines rA=0 to an invalid form; the MPC601 will store to r0.
|
|
|
|
|
stwux,
|
|
|
|
|
|
|
|
|
|
/// Store word indexed.
|
|
|
|
|
///
|
|
|
|
|
/// [ (ra()|0) + rB() ] = rS()
|
|
|
|
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
|
|
|
|
stwx,
|
|
|
|
|
|
2022-03-29 00:18:41 +00:00
|
|
|
|
subfx,
|
|
|
|
|
|
|
|
|
|
/// Subtract from carrying.
|
|
|
|
|
/// subfc, subfc., subfco, subfco.
|
|
|
|
|
///
|
|
|
|
|
/// rD() = -rA() +rB() + 1
|
|
|
|
|
///
|
|
|
|
|
/// oe(), rc() apply.
|
|
|
|
|
subfcx,
|
2022-03-27 12:47:01 +00:00
|
|
|
|
subfex,
|
|
|
|
|
|
|
|
|
|
/// Subtract from immediate carrying
|
|
|
|
|
///
|
|
|
|
|
/// rD() = ~rA() + simm() + 1
|
|
|
|
|
subfic,
|
|
|
|
|
|
|
|
|
|
subfmex, subfzex, sync, tw, twi, xorx, xori, xoris, mftb,
|
2021-01-01 02:12:36 +00:00
|
|
|
|
|
2020-12-31 03:55:59 +00:00
|
|
|
|
// 32-bit, supervisor level.
|
|
|
|
|
dcbi,
|
2021-01-01 02:12:36 +00:00
|
|
|
|
|
2020-12-31 23:14:38 +00:00
|
|
|
|
// Supervisor, optional.
|
2021-01-01 02:12:36 +00:00
|
|
|
|
tlbia, tlbie, tlbsync,
|
|
|
|
|
|
2020-12-31 03:55:59 +00:00
|
|
|
|
// Optional.
|
2021-01-01 16:46:26 +00:00
|
|
|
|
fresx, frsqrtex, fselx, fsqrtx, slbia, slbie, stfiwx,
|
2020-12-31 03:55:59 +00:00
|
|
|
|
|
2022-03-27 12:47:01 +00:00
|
|
|
|
//
|
2020-12-31 03:55:59 +00:00
|
|
|
|
// 64-bit only PowerPC instructions.
|
2022-03-27 12:47:01 +00:00
|
|
|
|
//
|
2021-01-01 02:12:36 +00:00
|
|
|
|
cntlzdx, divdx, divdux, extswx, fcfidx, fctidx, fctidzx, tdi, mulhdux,
|
|
|
|
|
ldx, sldx, ldux, td, mulhdx, ldarx, stdx, stdux, mulld, lwax, lwaux,
|
2021-01-01 16:46:26 +00:00
|
|
|
|
sradix, srdx, sradx, extsw, fsqrtsx, std, stdu, stdcx_,
|
2020-12-31 03:55:59 +00:00
|
|
|
|
};
|
|
|
|
|
|
2020-12-31 21:51:31 +00:00
|
|
|
|
/*!
|
|
|
|
|
Holds a decoded PowerPC instruction.
|
|
|
|
|
|
|
|
|
|
Implementation note: because the PowerPC encoding is particularly straightforward,
|
|
|
|
|
only the operation has been decoded ahead of time; all other fields are decoded on-demand.
|
2021-01-09 03:22:07 +00:00
|
|
|
|
|
|
|
|
|
It would be possible to partition the ordering of Operations into user followed by supervisor,
|
|
|
|
|
eliminating the storage necessary for a flag, but it wouldn't save anything due to alignment.
|
2020-12-31 21:51:31 +00:00
|
|
|
|
*/
|
2020-12-31 03:55:59 +00:00
|
|
|
|
struct Instruction {
|
2021-01-03 03:47:42 +00:00
|
|
|
|
Operation operation = Operation::Undefined;
|
|
|
|
|
bool is_supervisor = false;
|
|
|
|
|
uint32_t opcode = 0;
|
2020-12-31 03:55:59 +00:00
|
|
|
|
|
2021-01-09 03:38:56 +00:00
|
|
|
|
Instruction() noexcept {}
|
|
|
|
|
Instruction(uint32_t opcode) noexcept : opcode(opcode) {}
|
|
|
|
|
Instruction(Operation operation, uint32_t opcode, bool is_supervisor = false) noexcept : operation(operation), is_supervisor(is_supervisor), opcode(opcode) {}
|
2020-12-31 03:55:59 +00:00
|
|
|
|
|
2021-01-01 16:46:26 +00:00
|
|
|
|
// Instruction fields are decoded below; naming is a compromise between
|
|
|
|
|
// Motorola's documentation and IBM's.
|
|
|
|
|
//
|
|
|
|
|
// I've dutifully implemented various synonyms with unique entry points,
|
|
|
|
|
// in order to capture that information here rather than thrusting it upon
|
|
|
|
|
// the reader of whatever implementation may follow.
|
2020-12-31 21:51:31 +00:00
|
|
|
|
|
2021-01-01 21:38:40 +00:00
|
|
|
|
// Currently omitted: OPCD and XO, which I think are unnecessary given that
|
|
|
|
|
// full decoding has already occurred.
|
2021-01-01 02:12:36 +00:00
|
|
|
|
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Immediate field used to specify an unsigned 16-bit integer.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint16_t uimm() const { return uint16_t(opcode & 0xffff); }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Immediate field used to specify a signed 16-bit integer.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
int16_t simm() const { return int16_t(opcode & 0xffff); }
|
2021-01-01 21:38:40 +00:00
|
|
|
|
/// Immediate field used to specify a signed 16-bit integer.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
int16_t d() const { return int16_t(opcode & 0xffff); }
|
2021-01-01 21:38:40 +00:00
|
|
|
|
/// Immediate field used to specify a signed 14-bit integer [64-bit only].
|
2021-01-05 03:36:39 +00:00
|
|
|
|
int16_t ds() const { return int16_t(opcode & 0xfffc); }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Immediate field used as data to be placed into a field in the floating point status and condition register.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
int32_t imm() const { return (opcode >> 12) & 0xf; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
|
|
|
|
|
/// Specifies the conditions on which to trap.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
int32_t to() const { return (opcode >> 21) & 0x1f; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
|
|
|
|
|
/// Register source A or destination.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t rA() const { return (opcode >> 16) & 0x1f; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Register source B.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t rB() const { return (opcode >> 11) & 0x1f; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Register destination.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t rD() const { return (opcode >> 21) & 0x1f; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Register source.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t rS() const { return (opcode >> 21) & 0x1f; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
|
|
|
|
|
/// Floating point register source A.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t frA() const { return (opcode >> 16) & 0x1f; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Floating point register source B.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t frB() const { return (opcode >> 11) & 0x1f; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Floating point register source C.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t frC() const { return (opcode >> 6) & 0x1f; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Floating point register source.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t frS() const { return (opcode >> 21) & 0x1f; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Floating point register destination.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t frD() const { return (opcode >> 21) & 0x1f; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
|
2022-03-25 00:44:03 +00:00
|
|
|
|
/// Branch conditional options as per PowerPC spec, i.e. options + branch-prediction flag.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t bo() const { return (opcode >> 21) & 0x1f; }
|
2022-03-25 00:44:03 +00:00
|
|
|
|
/// Just the branch options, with the branch prediction flag severed.
|
2022-03-25 12:41:57 +00:00
|
|
|
|
BranchOption branch_options() const {
|
|
|
|
|
return BranchOption((opcode >> 22) & 0xf);
|
2022-03-25 00:44:03 +00:00
|
|
|
|
}
|
|
|
|
|
/// Just the branch-prediction hint; @c 0 => expect untaken; @c non-0 => expect take.
|
|
|
|
|
uint32_t branch_prediction_hint() const {
|
|
|
|
|
return opcode & 0x200000;
|
|
|
|
|
}
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Source condition register bit for branch conditionals.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t bi() const { return (opcode >> 16) & 0x1f; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Branch displacement; provided as already sign extended.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
int16_t bd() const { return int16_t(opcode & 0xfffc); }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
|
2021-01-01 21:38:40 +00:00
|
|
|
|
/// Specifies the first 1 bit of a 32/64-bit mask for rotate operations.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t mb() const { return (opcode >> 6) & 0x1f; }
|
2021-01-01 21:38:40 +00:00
|
|
|
|
/// Specifies the first 1 bit of a 32/64-bit mask for rotate operations.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t me() const { return (opcode >> 1) & 0x1f; }
|
2021-01-01 21:38:40 +00:00
|
|
|
|
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Condition register source bit A.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t crbA() const { return (opcode >> 16) & 0x1f; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Condition register source bit B.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t crbB() const { return (opcode >> 11) & 0x1f; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Condition register (or floating point status & condition register) destination bit.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t crbD() const { return (opcode >> 21) & 0x1f; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
|
|
|
|
|
/// Condition register (or floating point status & condition register) destination field.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t crfD() const { return (opcode >> 23) & 0x07; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Condition register (or floating point status & condition register) source field.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t crfS() const { return (opcode >> 18) & 0x07; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
|
|
|
|
|
/// Mask identifying fields to be updated by mtcrf.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t crm() const { return (opcode >> 12) & 0xff; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
|
|
|
|
|
/// Mask identifying fields to be updated by mtfsf.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t fm() const { return (opcode >> 17) & 0xff; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
|
2021-01-01 21:38:40 +00:00
|
|
|
|
/// Specifies the number of bytes to move in an immediate string load or store.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t nb() const { return (opcode >> 11) & 0x1f; }
|
2021-01-01 21:38:40 +00:00
|
|
|
|
|
|
|
|
|
/// Specifies a shift amount.
|
|
|
|
|
/// TODO: possibly bit 30 is also used in 64-bit mode, find out.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t sh() const { return (opcode >> 11) & 0x1f; }
|
2021-01-01 21:38:40 +00:00
|
|
|
|
|
|
|
|
|
/// Specifies one of the 16 segment registers [32-bit only].
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t sr() const { return (opcode >> 16) & 0xf; }
|
2021-01-01 21:38:40 +00:00
|
|
|
|
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// A 24-bit signed number; provided as already sign extended.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
int32_t li() const {
|
2021-01-01 16:46:26 +00:00
|
|
|
|
constexpr uint32_t extensions[2] = {
|
|
|
|
|
0x0000'0000,
|
|
|
|
|
0xfc00'0000
|
|
|
|
|
};
|
2021-01-03 16:14:43 +00:00
|
|
|
|
const uint32_t value = (opcode & 0x03ff'fffc) | extensions[(opcode >> 25) & 1];
|
2021-01-01 16:46:26 +00:00
|
|
|
|
return int32_t(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Absolute address bit; @c 0 or @c non-0.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t aa() const { return opcode & 0x02; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Link bit; @c 0 or @c non-0.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t lk() const { return opcode & 0x01; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Record bit; @c 0 or @c non-0.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t rc() const { return opcode & 0x01; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Whether to compare 32-bit or 64-bit numbers [for 64-bit implementations only]; @c 0 or @c non-0.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t l() const { return opcode & 0x200000; }
|
2021-01-01 16:46:26 +00:00
|
|
|
|
/// Enables setting of OV and SO in the XER; @c 0 or @c non-0.
|
2021-01-05 03:36:39 +00:00
|
|
|
|
uint32_t oe() const { return opcode & 0x800; }
|
2020-12-31 03:55:59 +00:00
|
|
|
|
};
|
|
|
|
|
|
2021-01-15 23:16:01 +00:00
|
|
|
|
// Sanity check on Instruction size.
|
2021-01-09 03:38:56 +00:00
|
|
|
|
static_assert(sizeof(Instruction) <= 8);
|
|
|
|
|
|
2020-12-31 03:55:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-15 23:16:01 +00:00
|
|
|
|
#endif /* InstructionSets_PowerPC_Instruction_h */
|