Skip to content

Conversation

@daskey
Copy link

@daskey daskey commented Dec 26, 2025

Add VLE Unsigned Saturating Arithmetic Instructions for e200z4 Core

Summary

This PR adds support for five unsigned saturating arithmetic instructions found in NXP e200z4, commonly used in MPC57xx microcontrollers. These instructions perform addition or subtraction with automatic clamping to prevent overflow/underflow wraparound.

⚠️ UNVERIFIED: These instructions are not documented in any public reference manual that could be located. The encodings and semantics were reverse-engineered from production firmware and validated against IDA Pro disassembly.

Instructions Added

Instruction XOP Description
e_addwus 0x36A Add Word Unsigned Saturate (32-bit)
e_addhus 0x3AA Add Halfword Unsigned Saturate (16-bit)
e_addbus 0x3EA Add Byte Unsigned Saturate (8-bit)
e_subfhus 0x3A8 Subtract Halfword Unsigned Saturate (16-bit)
e_subfbus 0x3E8 Subtract Byte Unsigned Saturate (8-bit)

Semantics

  • Add instructions: If the addition would overflow, the result saturates to the maximum value (0xFF, 0xFFFF, or 0xFFFFFFFF)
  • Subtract instructions: If the subtraction would underflow (result negative), the result saturates to 0
  • Operand order: Following PowerPC subf convention, subtract computes rB - rA (not rA - rB)

Validated Examples from Firmware


e_addwus (Add Word Unsigned Saturate)

Disassembly:

                             FUN_09058c68                                    XREF[1]:     FUN_09058c82:09058d2e(c)  
        09058c68 70 e8 e0 01     e_lis      r7,0x4001
        09058c6c 50 e7 d9 6c     e_lwz      r7,-0x2694(r7)=>DAT_4000d96c
        09058c70 2c 00           se_bmaski  r0,0x0
        09058c72 0c 07           se_cmp     r7,r0
        09058c74 e2 03           se_bne     cr0,LAB_09058c7a
        09058c76 48 03           se_li      r3,0x0
        09058c78 00 04           se_blr
                             LAB_09058c7a                                    XREF[1]:     09058c74(j)  
        09058c7a 48 13           se_li      r3,0x1
        09058c7c 7c 67 1e d4     e_addwus   r3,r7,r3
        09058c80 00 04           se_blr

Decompiled:

int FUN_09058c68(void)
{
  int iVar1;
  
  if (_DAT_4000d96c == -1)
  {
    return 0;
  }
  iVar1 = _DAT_4000d96c + 1;
  if (_DAT_4000d96c == -1)
  {
    iVar1 = -1;
  }
  return iVar1;
}

e_addhus (Add Halfword Unsigned Saturate)

Disassembly:

                             FUN_090d3c7a                                    XREF[2]:     FUN_090d3ca0:090d3cdc(c), 
                                                                                          FUN_090d3ca0:090d3cf8(c)  
        090d3c7a 2a 13           se_cmpi    param_1,0x1
        090d3c7c e2 07           se_bne     cr0,LAB_090d3c8a
        090d3c7e 0d 54           se_cmpl    param_2,param_3
        090d3c80 e2 05           se_bne     cr0,LAB_090d3c8a
        090d3c82 48 10           se_li      r0,0x1
        090d3c84 7c c6 07 54     e_addhus   param_4,param_4,r0
        090d3c88 e8 02           se_b       LAB_090d3c8c
                             LAB_090d3c8a                                    XREF[2]:     090d3c7c(j), 090d3c80(j)  
        090d3c8a 48 06           se_li      param_4,0x0
                             LAB_090d3c8c                                    XREF[1]:     090d3c88(j)  
        090d3c8c 01 63           se_mr      param_1,param_4
        090d3c8e 00 04           se_blr

Decompiled:

short FUN_090d3c7a(int param_1,int param_2,int param_3,short param_4)
{
  short sVar1;
  
  if ((param_1 == 1) && (param_2 == param_3))
  {
    sVar1 = param_4 + 1;
    if (param_4 == -1)
    {
      sVar1 = -1;
    }
  }
  else
  {
    sVar1 = 0;
  }
  return sVar1;
}

e_addbus (Add Byte Unsigned Saturate)

Disassembly:

                             FUN_090d1eae                                    XREF[1]:     FUN_090d1ecc:090d1edc(c)  
        090d1eae 70 e8 e0 01     e_lis      r7,0x4001
        090d1eb2 1c e7 0d 78     e_add16i   r7,r7,0xd78
        090d1eb6 80 67           se_lbz     r6,0x0(r7)=>DAT_40010d78
        090d1eb8 48 10           se_li      r0,0x1
        090d1eba 7c 06 07 d4     e_addbus   r0,r6,r0
        090d1ebe 90 07           se_stb     r0,0x0(r7)=>DAT_40010d78
        090d1ec0 70 e8 e0 01     e_lis      r7,0x4001
        090d1ec4 00 20           se_not     r0
        090d1ec6 34 07 0d 7f     e_stb      r0,offset DAT_40010d7f(r7)
        090d1eca 00 04           se_blr

Decompiled:

void FUN_090d1eae(void)
{
  byte bVar1;
  
  bVar1 = DAT_40010d78 + 1;
  if (DAT_40010d78 == -1)
  {
    bVar1 = 0xff;
  }
  DAT_40010d78 = bVar1;
  DAT_40010d7f = ~bVar1;
  return;
}

e_subfhus (Subtract Halfword Unsigned Saturate)

Disassembly:

                             FUN_09019b36                                    XREF[1]:     FUN_08fdeb70:08fded54(c)  
        09019b36 70 e1 e1 26     e_lis      r7,0x926
        09019b3a 70 c1 e1 26     e_lis      r6,0x926
        09019b3e 58 e7 8e ee     e_lhz      r7,-0x7112(r7)=>DAT_09258eee                     = 0028h
        09019b42 58 c6 8e e4     e_lhz      r6,-0x711c(r6)=>DAT_09258ee4                     = 002Dh
        09019b46 7c 07 37 50     e_subfhus  r0,r7,r6
        09019b4a 70 ea e0 80     e_lis      r7,0x5080
        09019b4e 5c 07 1f 0a     e_sth      r0,offset DAT_50801f0a(r7)
        09019b52 00 04           se_blr

Decompiled:

void FUN_09019b36(void)
{
  _DAT_50801f0a = DAT_09258ee4 - DAT_09258eee;
  if (DAT_09258ee4 < DAT_09258eee)
  {
    _DAT_50801f0a = 0;
  }
  return;
}

e_subfbus (Subtract Byte Unsigned Saturate)

Disassembly:

                             FUN_0901a458                                    XREF[1]:     FUN_0901a568:0901a57c(c)  
        0901a458 70 ea e0 80     e_lis      r7,0x5080
        0901a45c 1c e7 1f 48     e_add16i   r7,r7,0x1f48
        0901a460 80 07           se_lbz     r0,0x0(r7)=>DAT_50801f48
        0901a462 22 30           se_cmpli   r0,0x4
        0901a464 e1 05           se_ble     cr0,LAB_0901a46e
        0901a466 80 77           se_lbz     r7,0x0(r7)=>DAT_50801f48
        0901a468 48 40           se_li      r0,0x4
        0901a46a 7c 00 3f d0     e_subfbus  r0,r0,r7
                             LAB_0901a46e                                    XREF[1]:     0901a464(j)  
        0901a46e 22 30           se_cmpli   r0,0x4
        0901a470 48 47           se_li      r7,0x4
        0901a472 7c 07 00 5e     iselgt     r0,r7,r0,cr0
        0901a476 70 ea e0 80     e_lis      r7,0x5080
        0901a47a 34 07 1f 49     e_stb      r0,offset DAT_50801f49(r7)
        0901a47e 00 04           se_blr

Decompiled:

void FUN_0901a458(void)
{
  DAT_50801f49 = DAT_50801f48;
  if ((4 < DAT_50801f48) && (DAT_50801f49 = DAT_50801f48 - 4, DAT_50801f48 < 4))
  {
    DAT_50801f49 = 0;
  }
  if (4 < DAT_50801f49)
  {
    DAT_50801f49 = 4;
  }
  return;
}

Testing

  • Instruction encodings verified against IDA Pro disassembly of production firmware
  • Target hardware: NXP MPC5746R processor with e200z4 core
  • Decompiler output verified to match expected saturating semantics
  • No official NXP/Freescale documentation located for these specific instructions

Copilot AI review requested due to automatic review settings December 26, 2025 10:21
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for five unsigned saturating arithmetic instructions for the PowerPC VLE (Variable Length Encoding) instruction set, specifically targeting the NXP e200z4 core used in MPC57xx microcontrollers. These reverse-engineered instructions perform addition or subtraction with automatic saturation to prevent wraparound on overflow/underflow.

Key Changes:

  • Implemented three unsigned saturating addition instructions (word, halfword, and byte variants)
  • Implemented two unsigned saturating subtraction instructions (halfword and byte variants)
  • All implementations validated against production firmware disassembly and decompilation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants