9c20eb0135
Changed u64v handshake reads to u32v with an inline zero-extending upcast. Clang -Oz now emits 104 bytes, exactly matching vendor's 104 bytes, with 26 instructions on both sides. Three semantic-equivalent byte differences remain (register allocation, tst-form, test width) that aren't closable from C alone — need armclang or inline asm. Matching-decomp verdict for this function: semantic equivalence + size identity + instruction-count identity = the practical ceiling. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
25 lines
990 B
C
25 lines
990 B
C
/* Iteration 3: match vendor's "32-bit load, 64-bit test" pattern.
|
|
* The u64v volatile forced clang to 64-bit loads and hoist the base
|
|
* address out of the loop. Use u32v loads but upcast for the test. */
|
|
typedef volatile unsigned int u32v;
|
|
|
|
static inline unsigned long xld(u32v *p) {
|
|
/* Zero-extend 32-bit load to 64-bit implicit via ldr w; tst x. */
|
|
return (unsigned long)*p;
|
|
}
|
|
|
|
void train_phy_block(unsigned long ctx)
|
|
{
|
|
unsigned char *phy = (unsigned char *)(*(unsigned long *)(ctx + 0xb8) + 0x8000);
|
|
*(u32v *)(phy + 0x110) = 0xf000f000u;
|
|
while ((*(u32v *)(phy + 0x118) & 0xf0000000u) == 0u) ;
|
|
while ((*(u32v *)(phy + 0x120) & 0xf0000000u) == 0u) ;
|
|
*(u32v *)(phy + 0x160) = 0x30003u;
|
|
*(u32v *)(phy + 0x154) = 0x30003u;
|
|
while ((xld((u32v *)(phy + 0x184)) & 3ul) == 0ul) ;
|
|
*(u32v *)(phy + 0x154) = 0x30000u;
|
|
while ((xld((u32v *)(phy + 0x184)) & 3ul) != 0ul) ;
|
|
*(u32v *)(phy + 0x160) = 0x30000u;
|
|
*(u32v *)(phy + 0x110) = 0xf0000000u;
|
|
}
|