blob: a7f1a866fdcc917dd9b64f31c49d31e3c64650c0 [file] [log] [blame]
Wolfgang Denkb38e0df2007-03-06 18:08:43 +01001/*
2 * (C) Copyright 2002
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24#include <common.h>
25
26/*
27 * CPU test
28 * Ternary instructions instr rD,rA,rB
29 *
30 * Arithmetic instructions: add, addc, adde, subf, subfc, subfe,
31 * mullw, mulhw, mulhwu, divw, divwu
32 *
33 * The test contains a pre-built table of instructions, operands and
34 * expected results. For each table entry, the test will cyclically use
35 * different sets of operand registers and result registers.
36 */
37
Wolfgang Denkb38e0df2007-03-06 18:08:43 +010038#include <post.h>
39#include "cpu_asm.h"
40
41#if CONFIG_POST & CFG_POST_CPU
42
43extern void cpu_post_exec_22 (ulong *code, ulong *cr, ulong *res, ulong op1,
44 ulong op2);
45extern ulong cpu_post_makecr (long v);
46
47static struct cpu_post_three_s
48{
49 ulong cmd;
50 ulong op1;
51 ulong op2;
52 ulong res;
53} cpu_post_three_table[] =
54{
55 {
56 OP_ADD,
57 100,
58 200,
59 300
60 },
61 {
62 OP_ADD,
63 100,
64 -200,
65 -100
66 },
67 {
68 OP_ADDC,
69 100,
70 200,
71 300
72 },
73 {
74 OP_ADDC,
75 100,
76 -200,
77 -100
78 },
79 {
80 OP_ADDE,
81 100,
82 200,
83 300
84 },
85 {
86 OP_ADDE,
87 100,
88 -200,
89 -100
90 },
91 {
92 OP_SUBF,
93 100,
94 200,
95 100
96 },
97 {
98 OP_SUBF,
99 300,
100 200,
101 -100
102 },
103 {
104 OP_SUBFC,
105 100,
106 200,
107 100
108 },
109 {
110 OP_SUBFC,
111 300,
112 200,
113 -100
114 },
115 {
116 OP_SUBFE,
117 100,
118 200,
119 200 + ~100
120 },
121 {
122 OP_SUBFE,
123 300,
124 200,
125 200 + ~300
126 },
127 {
128 OP_MULLW,
129 200,
130 300,
131 200 * 300
132 },
133 {
134 OP_MULHW,
135 0x10000000,
136 0x10000000,
137 0x1000000
138 },
139 {
140 OP_MULHWU,
141 0x80000000,
142 0x80000000,
143 0x40000000
144 },
145 {
146 OP_DIVW,
147 -20,
148 5,
149 -4
150 },
151 {
152 OP_DIVWU,
153 0x8000,
154 0x200,
155 0x40
156 },
157};
158static unsigned int cpu_post_three_size =
159 sizeof (cpu_post_three_table) / sizeof (struct cpu_post_three_s);
160
161int cpu_post_test_three (void)
162{
163 int ret = 0;
164 unsigned int i, reg;
165 int flag = disable_interrupts();
166
167 for (i = 0; i < cpu_post_three_size && ret == 0; i++)
168 {
169 struct cpu_post_three_s *test = cpu_post_three_table + i;
170
171 for (reg = 0; reg < 32 && ret == 0; reg++)
172 {
173 unsigned int reg0 = (reg + 0) % 32;
174 unsigned int reg1 = (reg + 1) % 32;
175 unsigned int reg2 = (reg + 2) % 32;
176 unsigned int stk = reg < 16 ? 31 : 15;
177 unsigned long code[] =
178 {
179 ASM_STW(stk, 1, -4),
180 ASM_ADDI(stk, 1, -24),
181 ASM_STW(3, stk, 12),
182 ASM_STW(4, stk, 16),
183 ASM_STW(reg0, stk, 8),
184 ASM_STW(reg1, stk, 4),
185 ASM_STW(reg2, stk, 0),
186 ASM_LWZ(reg1, stk, 12),
187 ASM_LWZ(reg0, stk, 16),
188 ASM_12(test->cmd, reg2, reg1, reg0),
189 ASM_STW(reg2, stk, 12),
190 ASM_LWZ(reg2, stk, 0),
191 ASM_LWZ(reg1, stk, 4),
192 ASM_LWZ(reg0, stk, 8),
193 ASM_LWZ(3, stk, 12),
194 ASM_ADDI(1, stk, 24),
195 ASM_LWZ(stk, 1, -4),
196 ASM_BLR,
197 };
198 unsigned long codecr[] =
199 {
200 ASM_STW(stk, 1, -4),
201 ASM_ADDI(stk, 1, -24),
202 ASM_STW(3, stk, 12),
203 ASM_STW(4, stk, 16),
204 ASM_STW(reg0, stk, 8),
205 ASM_STW(reg1, stk, 4),
206 ASM_STW(reg2, stk, 0),
207 ASM_LWZ(reg1, stk, 12),
208 ASM_LWZ(reg0, stk, 16),
209 ASM_12(test->cmd, reg2, reg1, reg0) | BIT_C,
210 ASM_STW(reg2, stk, 12),
211 ASM_LWZ(reg2, stk, 0),
212 ASM_LWZ(reg1, stk, 4),
213 ASM_LWZ(reg0, stk, 8),
214 ASM_LWZ(3, stk, 12),
215 ASM_ADDI(1, stk, 24),
216 ASM_LWZ(stk, 1, -4),
217 ASM_BLR,
218 };
219 ulong res;
220 ulong cr;
221
222 if (ret == 0)
223 {
224 cr = 0;
225 cpu_post_exec_22 (code, & cr, & res, test->op1, test->op2);
226
227 ret = res == test->res && cr == 0 ? 0 : -1;
228
229 if (ret != 0)
230 {
231 post_log ("Error at three test %d !\n", i);
232 }
233 }
234
235 if (ret == 0)
236 {
237 cpu_post_exec_22 (codecr, & cr, & res, test->op1, test->op2);
238
239 ret = res == test->res &&
240 (cr & 0xe0000000) == cpu_post_makecr (res) ? 0 : -1;
241
242 if (ret != 0)
243 {
244 post_log ("Error at three test %d !\n", i);
245 }
246 }
247 }
248 }
249
250 if (flag)
251 enable_interrupts();
252
253 return ret;
254}
255
256#endif