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