1 /* 2 * (C) Copyright 2002 3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 10 /* 11 * CPU test 12 * Ternary instructions instr rD,rA,rB 13 * 14 * Arithmetic instructions: add, addc, adde, subf, subfc, subfe, 15 * mullw, mulhw, mulhwu, divw, divwu 16 * 17 * The test contains a pre-built table of instructions, operands and 18 * expected results. For each table entry, the test will cyclically use 19 * different sets of operand registers and result registers. 20 */ 21 22 #include <post.h> 23 #include "cpu_asm.h" 24 25 #if CONFIG_POST & CONFIG_SYS_POST_CPU 26 27 extern void cpu_post_exec_22 (ulong *code, ulong *cr, ulong *res, ulong op1, 28 ulong op2); 29 extern ulong cpu_post_makecr (long v); 30 31 static struct cpu_post_three_s 32 { 33 ulong cmd; 34 ulong op1; 35 ulong op2; 36 ulong res; 37 } cpu_post_three_table[] = 38 { 39 { 40 OP_ADD, 41 100, 42 200, 43 300 44 }, 45 { 46 OP_ADD, 47 100, 48 -200, 49 -100 50 }, 51 { 52 OP_ADDC, 53 100, 54 200, 55 300 56 }, 57 { 58 OP_ADDC, 59 100, 60 -200, 61 -100 62 }, 63 { 64 OP_ADDE, 65 100, 66 200, 67 300 68 }, 69 { 70 OP_ADDE, 71 100, 72 -200, 73 -100 74 }, 75 { 76 OP_SUBF, 77 100, 78 200, 79 100 80 }, 81 { 82 OP_SUBF, 83 300, 84 200, 85 -100 86 }, 87 { 88 OP_SUBFC, 89 100, 90 200, 91 100 92 }, 93 { 94 OP_SUBFC, 95 300, 96 200, 97 -100 98 }, 99 { 100 OP_SUBFE, 101 100, 102 200, 103 200 + ~100 104 }, 105 { 106 OP_SUBFE, 107 300, 108 200, 109 200 + ~300 110 }, 111 { 112 OP_MULLW, 113 200, 114 300, 115 200 * 300 116 }, 117 { 118 OP_MULHW, 119 0x10000000, 120 0x10000000, 121 0x1000000 122 }, 123 { 124 OP_MULHWU, 125 0x80000000, 126 0x80000000, 127 0x40000000 128 }, 129 { 130 OP_DIVW, 131 -20, 132 5, 133 -4 134 }, 135 { 136 OP_DIVWU, 137 0x8000, 138 0x200, 139 0x40 140 }, 141 }; 142 static unsigned int cpu_post_three_size = ARRAY_SIZE(cpu_post_three_table); 143 144 int cpu_post_test_three (void) 145 { 146 int ret = 0; 147 unsigned int i, reg; 148 int flag = disable_interrupts(); 149 150 for (i = 0; i < cpu_post_three_size && ret == 0; i++) 151 { 152 struct cpu_post_three_s *test = cpu_post_three_table + i; 153 154 for (reg = 0; reg < 32 && ret == 0; reg++) 155 { 156 unsigned int reg0 = (reg + 0) % 32; 157 unsigned int reg1 = (reg + 1) % 32; 158 unsigned int reg2 = (reg + 2) % 32; 159 unsigned int stk = reg < 16 ? 31 : 15; 160 unsigned long code[] = 161 { 162 ASM_STW(stk, 1, -4), 163 ASM_ADDI(stk, 1, -24), 164 ASM_STW(3, stk, 12), 165 ASM_STW(4, stk, 16), 166 ASM_STW(reg0, stk, 8), 167 ASM_STW(reg1, stk, 4), 168 ASM_STW(reg2, stk, 0), 169 ASM_LWZ(reg1, stk, 12), 170 ASM_LWZ(reg0, stk, 16), 171 ASM_12(test->cmd, reg2, reg1, reg0), 172 ASM_STW(reg2, stk, 12), 173 ASM_LWZ(reg2, stk, 0), 174 ASM_LWZ(reg1, stk, 4), 175 ASM_LWZ(reg0, stk, 8), 176 ASM_LWZ(3, stk, 12), 177 ASM_ADDI(1, stk, 24), 178 ASM_LWZ(stk, 1, -4), 179 ASM_BLR, 180 }; 181 unsigned long codecr[] = 182 { 183 ASM_STW(stk, 1, -4), 184 ASM_ADDI(stk, 1, -24), 185 ASM_STW(3, stk, 12), 186 ASM_STW(4, stk, 16), 187 ASM_STW(reg0, stk, 8), 188 ASM_STW(reg1, stk, 4), 189 ASM_STW(reg2, stk, 0), 190 ASM_LWZ(reg1, stk, 12), 191 ASM_LWZ(reg0, stk, 16), 192 ASM_12(test->cmd, reg2, reg1, reg0) | BIT_C, 193 ASM_STW(reg2, stk, 12), 194 ASM_LWZ(reg2, stk, 0), 195 ASM_LWZ(reg1, stk, 4), 196 ASM_LWZ(reg0, stk, 8), 197 ASM_LWZ(3, stk, 12), 198 ASM_ADDI(1, stk, 24), 199 ASM_LWZ(stk, 1, -4), 200 ASM_BLR, 201 }; 202 ulong res; 203 ulong cr; 204 205 if (ret == 0) 206 { 207 cr = 0; 208 cpu_post_exec_22 (code, & cr, & res, test->op1, test->op2); 209 210 ret = res == test->res && cr == 0 ? 0 : -1; 211 212 if (ret != 0) 213 { 214 post_log ("Error at three test %d !\n", i); 215 } 216 } 217 218 if (ret == 0) 219 { 220 cpu_post_exec_22 (codecr, & cr, & res, test->op1, test->op2); 221 222 ret = res == test->res && 223 (cr & 0xe0000000) == cpu_post_makecr (res) ? 0 : -1; 224 225 if (ret != 0) 226 { 227 post_log ("Error at three test %d !\n", i); 228 } 229 } 230 } 231 } 232 233 if (flag) 234 enable_interrupts(); 235 236 return ret; 237 } 238 239 #endif 240