Table of contents

Microoperations

For more information on p6as syntax, see p6as page.

The general instruction format is:

[flow_modifier] destination =  operation[.modifier1[.modifier2[...]]](source1, source2 [, segment] [, ubits/OA/IA values])

Components

Binary represenation

On Pentium Pro (first P6 microprocessor) microcode word in triplet is 72 bits wide and has the following format:

|  7    |              6        |          5      |            4  |               |3              | |  2    |         |    1            |      0|
|1 0 9 8|7 6 5 4 3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8 7|6 5 4 3 2 1 0 9|8 7 6 5 4 3 2 1|0 9 8 7 6 5 4 3|2|1 0 9 8|7 6 5 4 3|2 1 0 9 8 7 6 5 4|3 2 1 0|
|opalias|         opcode        |                 |     LSrc2     |     LSrc1     |     LDest     | |  LSeg | ImmAlias|    Immediate    | FlowM |

There are also additional bits 72-79 on Pentium 2, total 80 bits (see notes on Peter Bosch work below). Each MSROM/MSRAM line has 231 bits, so some bits are shared across all opcodes in triplet.

Pentium 3 has slightly different format compared to Pentium 2.

Pentium M introduced new 8th bit for register addressing (LDest,LSrc1,LSrc2), we call this EXLDEST, EXLSRC1, EXLSRC2 respectively. This is used mainly for SSE2 XMMn registers.

Core CPUs (Yonah) are using very similar encoding as Pentium M.

Core2 seems to have introduced new opcode bit - which is called EXOPCODE in our represenatation (work in progress, to be further analyzed).

Register Specifications

Branch Targets

For branch operations, source2 is a branch target:

Operation Modifiers

Operations can have up to 3 modifiers separated by dots: operation.modifier1.modifier2.modifier3

The number and type of modifiers depends on the specific operation.

Direct Opcode Specification

For unknown or special opcodes: UOP.XXX where XXX is the hexadecimal opcode value.

Flow markers

Flow markers define where each original instruction (macroinstruction) begins and ends in terms of its translated logical micro-operations (micro-ops).

Opcode

opalias probably changes opcode meaning. To be further analyzed.

Many opcodes have modifiers which further specify operation (e.g. data size, DSZ32/DSZ16/DSZ8/etc.)

AP-526 on pp. 66 brings some light to this.

Core2

Core2 seems to have additional opcode bit (that is present in approx. 25% of the MSROM code). Verified on this - result is rax=000000000000AA51 ([[BTR]] 0xaa55,2) rbx=00000000C6D6C5D5 (WUCONCAT.dsz16 0xE5F555AAA5B5C5D5, 0xE6F655AAA6B6C6D6), rcx=9BD956AA9ADB1B5B (ROL E6F655AAA6B6C6D6,2):

.org 0x7f80
RBX =         UOP.506      (RSI          , RBP          , U4.00400000)    # this is in fact WUCONCAT!
RAX =         UOP.506      (RAX          , RCX          , U4.00000000)    # this is BTR.DSZ16 (506)
RCX =         MOVE.DSZ64   (RSI          , RCX          , U4.00400000)    # this becomes ROL !



EOM MOVE.DSZ32     (CONST  , CONST_0       , U4.00040000)
EOM MOVE.DSZ32     (CONST  , CONST_0       , U4.00040000)
EOM  MOVE.DSZ32     (CONST  , CONST_0       , U4.00040000)
.end
b855aa0000b9020000000f33c3c3c3c3c3

FF00: 0FC2D3F0 04253F00 07047E82 00000000 05404400 04801803 00000000 00000000
FF08: 00020000 00200008 00000000 40000000 00000000 04809012 00040000 20000100

WUCONCAT can also be encoded as "UOP.502 (RSI , RBP , U4.00400000)" - seems that not all opcode bits are decoded.

Opcode alias

Looks like these are bit values (OA.C = OA.4|OA.8)

DEST, SRC1, SRC2

Fields dest, src1, src2 contain register ID (e.g. AL=0x08, AH=0x0C, AX=0x28, EAX=0x38, ST0=0x10, 0x18=TMP6,). Register indexes have variable bit width. For more information see registers page.

SINK register (ID 0x01) has special meaning, it is in LDEST and is used to discard the uop result. p6dis simply omits uop assignment for SING register, p6as emits SINK when there is no uop result assignment.

If uop is taking only 1 argument, such as MOVE/BSF/BSR/MOVEFROMCREG/etc, usually lsrc2 is used (lsrc1 is ignored, but used by execution unit for dependency handling)

List of const usage in CPUID 6D8 MSROM:

Real CPU smaples of various CONST_qq on Yonah CPUID 6E8 plat 20:

EAX =          MOVE.DSZ32     (CONST         , CONST_QQ+001  )
EBX =          MOVE.DSZ32     (CONST         , CONST_QQ+012  )
ECX =          MOVE.DSZ32     (CONST         , CONST_QQ+123  )
EDX =          MOVE.DSZ32     (CONST         , CONST_QQ+1FF  )
Result:

CONST_00: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_01: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_02: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_03: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_04: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_05: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_06: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_07: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_08: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_09: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_0A: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_0B: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_0C: EAX=000006d0 EBX=ffdbb22a ECX=e03f003f EDX=fffefbff
CONST_0D: EAX=80040e14 EBX=803f4fd7 ECX=803e0006 EDX=bfffffff
CONST_0E: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_0F: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_10: EAX=00000001 EBX=00000012 ECX=ffffff23 EDX=ffffffff
CONST_11: EAX=080483e4 EBX=08048547 ECX=080487e7 EDX=1a0c8164
CONST_12: EAX=00000001 EBX=00000012 ECX=ffffff23 EDX=ffffffff
CONST_13: EAX=080483e4 EBX=08048547 ECX=080487e7 EDX=1a0c8164
CONST_14: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_15: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_16: EAX=00000001 EBX=00000012 ECX=ffffff23 EDX=ffffffff
CONST_17: EAX=080483e4 EBX=08048547 ECX=080487e7 EDX=3a0c8164
CONST_18: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_19: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_1A: EAX=00000001 EBX=00000012 ECX=ffffff23 EDX=ffffffff
CONST_1B: EAX=080483e4 EBX=08048547 ECX=080487e7 EDX=1a0c8164
CONST_1C: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_1D: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_1E: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
CONST_1F: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000

Real CPU smaples of ALIAS.xx values on Yonah CPUID 6E8 plat 20:

000: a2000000  (this is from opcode "0F A2"; not exactly an immediate, but ...?)
001: 080483e4
002: 08048547
003: 080487e7
004: 3f083118
005: 3f0cb3fc
006: 3f0cb55f
007: 3a0c8164
008: 7d89d875
009: 080483e4
00A: 08048547
00B: 080487e7
00C: 3f083118
00D: 3f0cb3fc
00E: 3f0cb55f
00F: 3a0c8164 (sometimes 3a0c8164)
010: 00000004 - DSZOP ?
011: 080483e4 - last called routine (cpuid asm in this case)
012: 08048547 - address after last called routine
013: 080487e7 - ???
014: 3f083118
015: 3f0cb3fc
016: 3f0cb55f
017: 3a0c8164
018: 01a20000
019: 080483e4 -  same as 11
01A: 08048547 - same as 1A
01B: 080487e7
01C: 3f083118
01D: 3f0cb3fc - same as 0D ?
01E: 3f0cb55f - same as 0E ?
01F: 1a0c8164 - same as 0F ?

Constant immediate value

Any of operands can contain immediate value, that is added to source. Typically used with constants. Meaning of alias item is unknown, likely it is used to select expansion from 9bit imm field to deisred length.

Constant ROM

Is 512-dword memory specific to each CPU that holds various constants. For example you can find there CPUID "GenuineIntel" doublewords. It is different from FPROM.

Branch target

Branch target has 17 bits and is encoded to src2 register and immediate value:

LSrc2  = (btarg >> 9) & 0xff;   (39)
Immmediate = btarg & 0x1ff;    (4)

SEG

Segment specification for memory/IO operations

Possible values:

{0x00, "SEG_SINK"},
{0x01, "LINSEG"},
{0x02, "SEG_02"},
{0x03, "SEG_03"},
{0x04, "SEG_04"},
{0x05, "SEG_05"},
{0x06, "GDTR"},
{0x07, "LDTR"},
{0x08, "ES"},
{0x09, "CS"},
{0x0A, "SS"},
{0x0B, "DS"},
{0x0C, "FS"},
{0x0D, "GS"},
{0x0E, "IDTR"},
{0x0F, "TR"},

Flags/Unknown bits

These are typically unknown values U1,U2,U3,U4 that belong to the uop. Values U1..U3 have same meaning across all CPUs, U4 is microarchitecture-dependent, used only starting Pentium III.

There are also unknown bits per uop:

Name Position Size CPUs Notice
U1 22 1 bit all
U2 47-55 9 bits all
U3 72-79 (not shown in the format above) 8 bits all These bits were taken from Peter Bosch's Python code, their meaning/structure is not known
U4 80-...(not shown in the format above) ? Pentium 3,Pentium M, Yonah, Core2 The U4 range is temporary, used for bits with unknown meaning (possibly some other Ux bits)

U1

bit 22 - U1.1 seems to be negated implicit supervisor access (0=implicit supervisor access, no perms checked), use with STA/LDA

U2

U3

U3.01 seems to be paired with these opcodes: TRANSPORTUIP, U_JCC_N.xxx U_JCC_T.xxx, U_JMP_NT UOP.010 (From Pentium II to Core2)

U3 bits 3-4 - Weird P-II Peter Bosch's code

U3 bits 3-4 for triad slot 2 are NEVER assigned!

uop[2][73] = right_1[2];    // U3 bit1
uop[2][74] = right_1[5];    // U3 bit2
// uop[75] never set?       // U3 bit3
// uop[76] never set?       // U3 bit4

U3 bits 5,6 - Shared bits - P-II Peter Bosch's code

These bits U3 bits 5-6 (values 0x20 and 0x40) are shared between all slots in triad.

uop[0][77] = left_1[0]; // U3 bit 5
uop[0][78] = left_1[1]; // U3 bit 6
uop[1][77] = left_1[0];
uop[1][78] = left_1[1];
uop[2][77] = left_1[0];
uop[2][78] = left_1[1];

U4

These bits/flags do not have same function across platforms. Used only in Pentium 3, Pentium M, Core, Core2.

.utripletbits

Core2

Single unknown bit, seems to go along with UOP.051

.utripletbits 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
UROM_237C                                 UOP.051        (ALIAS.199     , ST5           , U3.01, U4.00440000 /* U4:0000 0000 0100 0100 0000 0000 0000 0000 */)
UROM_237D       Fl3        REG.47 =       MOVE.DSZ32     (CONST         , CONST_16+0FF  , U4.00240000 /* U4:0000 0000 0010 0100 0000 0000 0000 0000 */)

UROM_237E  loc_237E:                    ;  xref: 102E
--
.utripletbits 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
UROM_259C                                 UOP.051        (ALIAS.1F0     , R11B_4x       , U3.01, U4.00440000 /* U4:0000 0000 0100 0100 0000 0000 0000 0000 */)
UROM_259D       Fl3        REG.47 =       MOVE.DSZ32     (CONST         , CONST_16+0FF  , U4.00240000 /* U4:0000 0000 0010 0100 0000 0000 0000 0000 */)

UROM_259E  loc_259E:                    ;  xref: 2F6C
--
.utripletbits 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
UROM_25A0                                 UOP.051        (ALIAS.1F0     , R11B_4x       , U3.01, U4.00440000 /* U4:0000 0000 0100 0100 0000 0000 0000 0000 */)
UROM_25A1       Fl3        REG.47 =       MOVE.DSZ32     (CONST         , CONST_16+0FF  , U4.00240000 /* U4:0000 0000 0010 0100 0000 0000 0000 0000 */)

UROM_25A2  loc_25A2:                    ;  xref: 2558
--
.utripletbits 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
UROM_4B94                                 UOP.051        (ALIAS.199     , ST5           , U3.01, U4.00440000 /* U4:0000 0000 0100 0100 0000 0000 0000 0000 */)
UROM_4B95                                 MOVE.DSZ8      (CONST         , CONST_0       )
UROM_4B96                                 MOVE.DSZ8      (CONST         , CONST_0       )
UROM_4B98                                 U_JMP.NT       (CONST         , UROM_4BA4     , IA.11, U3.01, U4.00440028 /* U4:0000 0000 0100 0100 0000 0000 0010 1000 */)
--
.utripletbits 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
UROM_550C                                 UOP.051        (ALIAS.11D     , CL            , U3.01, U4.00440000 /* U4:0000 0000 0100 0100 0000 0000 0000 0000 */)
UROM_550D                                 MOVE.DSZ8      (CONST         , CONST_0       )
UROM_550E                                 MOVE.DSZ8      (CONST         , CONST_0       )
UROM_5510                                 U_JMP.NT       (CONST         , UROM_2249     , IA.11, U3.01, U4.00440028 /* U4:0000 0000 0100 0100 0000 0000 0010 1000 */)

References


The author is not affiliated with, endorsed by, or sponsored by Intel Corporation or its affiliates. All trademarks, including but not limited to Intel, Pentium, and any other registered or unregistered marks mentioned herein, are the property of their respective owners. Their use in this context is solely for descriptive and informational purposes and constitutes nominative fair use under applicable trademark laws.
  • index page
  • uop description
  • ADC
  • ADD
  • AND
  • BSF
  • BSR
  • BSWAP
  • BTEST
  • DIV
  • FANDNOT
  • FCALCTW
  • FCMOV
  • FCOM
  • FMERGE
  • FMOV
  • FPEXTRACT
  • FPORDATATYPE
  • FPSIGNEXT
  • FREADROM
  • FXORS
  • IDIV
  • IMUL
  • INTEXTRACT
  • LEA
  • LOAD
  • MOVE
  • MOVEFROMCREG
  • MOVETOCREG
  • MUL
  • OR
  • PORTIN
  • PORTOUT
  • RCL
  • RCR
  • RDSEGFLD
  • ROL
  • ROR
  • SAL
  • SAR
  • SBC
  • SHL
  • SHR
  • SIGEVENT
  • STA
  • STRD
  • SUB
  • SUBR
  • TRANSPORTUIP
  • UOP
  • U_JCC
  • U_JMP
  • U_JMP_INDIR
  • WRSEGFLD
  • WUCONCAT
  • WUEXTRBK
  • WUINSERT
  • WUMERGE
  • XOR