sdk-core v2026.11.05
PS2 SDK - core tier (build-critical EE/IOP modules)
Loading...
Searching...
No Matches
main.c
1#include <stdio.h>
2#include <kernel.h>
3#include <tamtypes.h>
4
5extern int kputs(char *s);
6
7typedef unsigned long long u64;
8typedef unsigned int u32;
9
10static int g_pass, g_fail;
11
12static void check(const char *name, u64 got, u64 want)
13{
14 char buf[128];
15
16 if (got == want) {
17 g_pass++;
18 return;
19 }
20 g_fail++;
21 snprintf(buf, sizeof(buf), "ee-mmi: %s got=%08x%08x want=%08x%08x\n", name,
22 (u32)(got >> 32), (u32)got, (u32)(want >> 32), (u32)want);
23 kputs(buf);
24}
25
26#define EXP_PCPYLD_LO 0x2222222222222222ULL
27#define EXP_PCPYLD_HI 0x1111111111111111ULL
28#define EXP_PCPYUD_LO 0xaaaaaaaaaaaaaaaaULL
29#define EXP_PCPYUD_HI 0xbbbbbbbbbbbbbbbbULL
30#define EXP_PLZCW 26u
31
32extern void test_pcpyld(void *dst, const void *rs, const void *rt);
33extern void test_pcpyud(void *dst, const void *rs, const void *rt);
34extern void test_qfsrv0(void *dst, const void *rs, const void *rt);
35extern void test_plzcw(void *dst, const void *src);
36
37int main(void)
38{
39 /* pand/por/pnor/pxor - plain 64-bit bitwise ops, uniform across the
40 register (no per-lane packing), safe to hand-compute. */
41 {
42 u64 a = 0xff00ff00ff00ff00ULL, b = 0x0f0f0f0f0f0f0f0fULL, r;
43 __asm__ __volatile__("pand %0, %1, %2" : "=r"(r) : "r"(a), "r"(b));
44 check("pand", r, 0x0f000f000f000f00ULL);
45 }
46 {
47 u64 a = 0xf0f0f0f0f0f0f0f0ULL, b = 0x0f0f0f0f0f0f0f0fULL, r;
48 __asm__ __volatile__("por %0, %1, %2" : "=r"(r) : "r"(a), "r"(b));
49 check("por", r, 0xffffffffffffffffULL);
50 }
51 {
52 u64 a = 0ULL, b = 0ULL, r;
53 __asm__ __volatile__("pnor %0, %1, %2" : "=r"(r) : "r"(a), "r"(b));
54 check("pnor", r, 0xffffffffffffffffULL);
55 }
56 {
57 u64 a = 0xaaaaaaaaaaaaaaaaULL, b = 0x5555555555555555ULL, r;
58 __asm__ __volatile__("pxor %0, %1, %2" : "=r"(r) : "r"(a), "r"(b));
59 check("pxor", r, 0xffffffffffffffffULL);
60 }
61
62 /* paddb/psubb - byte-lane add/sub, wraparound (no saturation). */
63 {
64 u64 a = 0x0101010101010101ULL, b = 0xffffffffffffffffULL, r;
65 __asm__ __volatile__("paddb %0, %1, %2" : "=r"(r) : "r"(a), "r"(b));
66 check("paddb (wrap)", r, 0x0000000000000000ULL);
67 }
68 {
69 u64 a = 0x1010101010101010ULL, b = 0x0101010101010101ULL, r;
70 __asm__ __volatile__("psubb %0, %1, %2" : "=r"(r) : "r"(a), "r"(b));
71 check("psubb", r, 0x0f0f0f0f0f0f0f0fULL);
72 }
73
74 /* paddsb - signed-saturating byte add: 127 + 1 clamps at 127. */
75 {
76 u64 a = 0x7f7f7f7f7f7f7f7fULL, b = 0x0101010101010101ULL, r;
77 __asm__ __volatile__("paddsb %0, %1, %2" : "=r"(r) : "r"(a), "r"(b));
78 check("paddsb (saturate)", r, 0x7f7f7f7f7f7f7f7fULL);
79 }
80
81 /* movn/movz - conditional move, both the move and no-move branch. */
82 {
83 u32 rd = 0xdeadbeef, rs = 0x12345678, rt_nz = 5;
84 __asm__ __volatile__("movn %0, %1, %2" : "+r"(rd) : "r"(rs), "r"(rt_nz));
85 check("movn (rt!=0, moves)", rd, 0x12345678u);
86 }
87 {
88 u32 rd = 0xdeadbeef, rs = 0x12345678, rt_z = 0;
89 __asm__ __volatile__("movn %0, %1, %2" : "+r"(rd) : "r"(rs), "r"(rt_z));
90 check("movn (rt==0, no move)", rd, 0xdeadbeefu);
91 }
92 {
93 u32 rd = 0xdeadbeef, rs = 0x12345678, rt_z = 0;
94 __asm__ __volatile__("movz %0, %1, %2" : "+r"(rd) : "r"(rs), "r"(rt_z));
95 check("movz (rt==0, moves)", rd, 0x12345678u);
96 }
97 {
98 u32 rd = 0xdeadbeef, rs = 0x12345678, rt_nz = 5;
99 __asm__ __volatile__("movz %0, %1, %2" : "+r"(rd) : "r"(rs), "r"(rt_nz));
100 check("movz (rt!=0, no move)", rd, 0xdeadbeefu);
101 }
102
103 /* mult1/mfhi1/mflo1 - pipeline-1 32x32->64 signed multiply. */
104 {
105 u32 a = 1000, b = 2000, hi, lo;
106 __asm__ __volatile__("mult1 %2, %3\n\tmfhi1 %0\n\tmflo1 %1"
107 : "=r"(hi), "=r"(lo) : "r"(a), "r"(b));
108 check("mult1/mfhi1", hi, 0u);
109 check("mult1/mflo1", lo, 2000000u);
110 }
111
112 /* mfsa/mtsa - direct SA register round-trip. */
113 {
114 u32 v = 5, out;
115 __asm__ __volatile__("mtsa %1\n\tmfsa %0" : "=r"(out) : "r"(v));
116 check("mtsa/mfsa round-trip", out, 5u);
117 }
118
119 /* psllh - halfword-lane shift-left by immediate. */
120 {
121 u64 a = 0x0001000200030004ULL, r;
122 __asm__ __volatile__("psllh %0, %1, 4" : "=r"(r) : "r"(a));
123 check("psllh", r, 0x0010002000300040ULL);
124 }
125
126 /* pcpyld/pcpyud - real 128-bit half select/copy, via lq/sq helpers. */
127 {
128 __attribute__((aligned(16))) u64 rs_buf[2] = {0x1111111111111111ULL, 0xaaaaaaaaaaaaaaaaULL};
129 __attribute__((aligned(16))) u64 rt_buf[2] = {0x2222222222222222ULL, 0xbbbbbbbbbbbbbbbbULL};
130 __attribute__((aligned(16))) u64 dst[2] = {0, 0};
131
132 test_pcpyld(dst, rs_buf, rt_buf);
133 check("pcpyld lo", dst[0], EXP_PCPYLD_LO);
134 check("pcpyld hi", dst[1], EXP_PCPYLD_HI);
135
136 test_pcpyud(dst, rs_buf, rt_buf);
137 check("pcpyud lo", dst[0], EXP_PCPYUD_LO);
138 check("pcpyud hi", dst[1], EXP_PCPYUD_HI);
139 }
140
141 /* qfsrv shift=0 identity - definitionally equals rt regardless of the
142 general funnel-shift formula, so this one's safe to hardcode too. */
143 {
144 __attribute__((aligned(16))) u64 rs_buf[2] = {0x1111111111111111ULL, 0xaaaaaaaaaaaaaaaaULL};
145 __attribute__((aligned(16))) u64 rt_buf[2] = {0x2222222222222222ULL, 0xbbbbbbbbbbbbbbbbULL};
146 __attribute__((aligned(16))) u64 dst[2] = {0, 0};
147
148 test_qfsrv0(dst, rs_buf, rt_buf);
149 check("qfsrv shift=0 lo", dst[0], rt_buf[0]);
150 check("qfsrv shift=0 hi", dst[1], rt_buf[1]);
151 }
152
153 /* plzcw - leading zero/one count per 32-bit half. */
154 {
155 u32 src = 0x00000010u, out;
156 test_plzcw(&out, &src);
157 check("plzcw", out, EXP_PLZCW);
158 }
159
160
161 kputs(g_fail ? "ee-mmi: FAIL\n" : "ee-mmi: PASS\n");
162 printf("[ps2rig] exit=%d\n", g_fail ? 1 : 0);
163 SleepThread();
164 return 0;
165}