1 /* Copyright 2013 Theo Berkau
2
3 This file is part of YabauseUT
4
5 YabauseUT is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 YabauseUT is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with YabauseUT; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include <iapetus.h>
21 #include "tests.h"
22
23 #define SH2REG_CCR (*(volatile u8 *)0xFFFFFE92)
24 #define SH2REG_IPRA (*(volatile u16 *)0xFFFFFEE2)
25 #define SH2REG_DVSR (*(volatile u32 *)0xFFFFFF00)
26 #define SH2REG_DVDNT (*(volatile u32 *)0xFFFFFF04)
27 #define SH2REG_DVCR (*(volatile u32 *)0xFFFFFF08)
28 #define SH2REG_VCRDIV (*(volatile u32 *)0xFFFFFF0C)
29 #define SH2REG_DVDNTH (*(volatile u32 *)0xFFFFFF10)
30 #define SH2REG_DVDNTL (*(volatile u32 *)0xFFFFFF14)
31 #define SH2REG_DVDNTUH (*(volatile u32 *)0xFFFFFF18)
32 #define SH2REG_DVDNTUL (*(volatile u32 *)0xFFFFFF1C)
33 #define SH2REG_DVSR2 (*(volatile u32 *)0xFFFFFF20)
34 #define SH2REG_DVDNT2 (*(volatile u32 *)0xFFFFFF24)
35 #define SH2REG_DVCR2 (*(volatile u32 *)0xFFFFFF28)
36 #define SH2REG_VCRDIV2 (*(volatile u32 *)0xFFFFFF2C)
37 #define SH2REG_DVDNTH2 (*(volatile u32 *)0xFFFFFF30)
38 #define SH2REG_DVDNTL2 (*(volatile u32 *)0xFFFFFF34)
39 #define SH2REG_DVDNTUH2 (*(volatile u32 *)0xFFFFFF38)
40 #define SH2REG_DVDNTUL2 (*(volatile u32 *)0xFFFFFF3C)
41
42 #define SH2REG_SAR0 (*(volatile u32 *)0xFFFFFF80)
43 #define SH2REG_DAR0 (*(volatile u32 *)0xFFFFFF84)
44 #define SH2REG_TCR0 (*(volatile u32 *)0xFFFFFF88)
45 #define SH2REG_CHCR0 (*(volatile u32 *)0xFFFFFF8C)
46 #define SH2REG_VCRMDA0 (*(volatile u32 *)0xFFFFFFA0)
47 #define SH2REG_DRCR0 (*(volatile u8 *)0xFFFFFE71)
48
49 #define SH2REG_SAR1 (*(volatile u32 *)0xFFFFFF90)
50 #define SH2REG_DAR1 (*(volatile u32 *)0xFFFFFF94)
51 #define SH2REG_TCR1 (*(volatile u32 *)0xFFFFFF98)
52 #define SH2REG_CHCR1 (*(volatile u32 *)0xFFFFFF9C)
53 #define SH2REG_VCRMDA1 (*(volatile u32 *)0xFFFFFFA8)
54 #define SH2REG_DRCR1 (*(volatile u8 *)0xFFFFFE72)
55
56 #define SH2REG_DMAOR (*(volatile u32 *)0xFFFFFFB0)
57
58 #define RSTCSR_W (*(volatile u16 *)0XFFFFFE82)
59
60 void div_mirror_test(void);
61 void div_operation_test(void);
62 void div_interrupt_test(void);
63
64 //////////////////////////////////////////////////////////////////////////////
65
sh2_test()66 void sh2_test()
67 {
68 interrupt_set_level_mask(0xF);
69
70 init_iapetus(RES_320x224);
71
72 // Setup a screen for us draw on
73 vdp_rbg0_init(&test_disp_settings);
74 vdp_set_default_palette();
75
76 // Display On
77 vdp_disp_on();
78
79 unregister_all_tests();
80 register_test(&div_mirror_test, "DIV register access");
81 register_test(&div_operation_test, "DIV operations");
82 register_test(&div_interrupt_test, "DIV overflow interrupt");
83 do_tests("SH2 tests", 0, 0);
84
85 // Other tests to do: instruction tests, check all register accesses,
86 // onchip functions
87 }
88
89 //////////////////////////////////////////////////////////////////////////////
90
91 #define test_access_b(r) \
92 r = 0x01; \
93 if (r != 0x01) \
94 { \
95 stage_status = STAGESTAT_BADDATA; \
96 return; \
97 }
98
99 #define test_access_w(r) \
100 r = 0x0102; \
101 if (r != 0x0102) \
102 { \
103 stage_status = STAGESTAT_BADDATA; \
104 return; \
105 }
106
107 #define test_access_l(r) \
108 r = 0x01020304; \
109 if (r != 0x01020304) \
110 { \
111 stage_status = STAGESTAT_BADDATA; \
112 return; \
113 }
114
div_mirror_test(void)115 void div_mirror_test(void)
116 {
117 // This tests DIV register reads/writes and checks mirroring
118 test_access_w(SH2REG_VCRDIV)
119 test_access_w(SH2REG_VCRDIV2)
120 SH2REG_VCRDIV = 0;
121
122 test_access_b(SH2REG_DVCR)
123 test_access_b(SH2REG_DVCR2)
124 SH2REG_DVCR = 0;
125
126 test_access_l(SH2REG_DVDNTH)
127 test_access_l(SH2REG_DVDNTH2)
128 test_access_l(SH2REG_DVSR)
129 test_access_l(SH2REG_DVSR2)
130 test_access_l(SH2REG_DVDNTUH)
131 test_access_l(SH2REG_DVDNTUH2)
132 test_access_l(SH2REG_DVDNTUL)
133 test_access_l(SH2REG_DVDNTUL2)
134
135 stage_status = STAGESTAT_DONE;
136 }
137
138 //////////////////////////////////////////////////////////////////////////////
139
div_operation_test(void)140 void div_operation_test(void)
141 {
142 // This tests to make sure the dividing operation is correct
143 int i;
144
145 // Test 64-bit/32-bit operation
146 SH2REG_DVSR = 0x10;
147 SH2REG_DVDNTH = 0x1;
148 SH2REG_DVDNTL = 0x9;
149
150 // Wait a bit
151 for (i = 0; i < 20; i++) {}
152
153 if (SH2REG_DVDNTL != 0x10000000 ||
154 SH2REG_DVDNTL2 != 0x10000000 ||
155 SH2REG_DVDNT != 0x10000000 ||
156 SH2REG_DVDNT2 != 0x10000000 ||
157 SH2REG_DVDNTUL != 0x10000000 ||
158 SH2REG_DVDNTUL2 != 0x10000000 ||
159 SH2REG_DVDNTH != 9 ||
160 SH2REG_DVDNTH2 != 9 ||
161 SH2REG_DVDNTUH != 9 ||
162 SH2REG_DVDNTUH2 != 9)
163 {
164 stage_status = STAGESTAT_BADDATA;
165 return;
166 }
167
168 // Ok, mirrors are working alright, and 64-bit/32-bit operation is correct
169
170 // Test 32-bit/32-bit operation
171 SH2REG_DVSR = 0x10;
172 SH2REG_DVDNT = 0x10000009;
173
174 // Wait a bit
175 for (i = 0; i < 20; i++) {}
176
177 if (SH2REG_DVDNTL != 0x1000000 ||
178 SH2REG_DVDNTL2 != 0x1000000 ||
179 SH2REG_DVDNT != 0x1000000 ||
180 SH2REG_DVDNT2 != 0x1000000 ||
181 SH2REG_DVDNTUL != 0x1000000 ||
182 SH2REG_DVDNTUL2 != 0x1000000 ||
183 SH2REG_DVDNTH != 9 ||
184 SH2REG_DVDNTH2 != 9 ||
185 SH2REG_DVDNTUH != 9 ||
186 SH2REG_DVDNTUH2 != 9)
187 {
188 stage_status = STAGESTAT_BADDATA;
189 return;
190 }
191
192 // Ok, mirrors are working alright, and 32-bit/32-bit operation is correct
193
194 // Now let's do an overflow test(It seems you can only trigger it using 64-bit/32-bit operation)
195 SH2REG_DVSR = 0x1;
196 SH2REG_DVCR = 0;
197 SH2REG_DVDNTH = 0x1;
198 SH2REG_DVDNTL = 0x0;
199
200 // Wait a bit
201 for (i = 0; i < 20; i++) {}
202
203 if (SH2REG_DVDNTL != 0x7FFFFFFF ||
204 SH2REG_DVDNTH != 0xFFFFFFFE ||
205 SH2REG_DVCR != 0x1)
206 {
207 stage_status = STAGESTAT_BADDATA;
208 return;
209 }
210
211 // Lastly, do two divide by zero tests
212 SH2REG_DVSR = 0;
213 SH2REG_DVCR = 0;
214 SH2REG_DVDNT = 0;
215
216 // Wait a bit
217 for (i = 0; i < 20; i++) {}
218
219 if (SH2REG_DVDNT != 0x7FFFFFFF ||
220 SH2REG_DVDNTH != 0 ||
221 SH2REG_DVCR != 0x1)
222 {
223 stage_status = STAGESTAT_BADDATA;
224 return;
225 }
226
227 SH2REG_DVSR = 0;
228 SH2REG_DVCR = 0;
229 SH2REG_DVDNT = 0xD0000000;
230
231 // Wait a bit
232 for (i = 0; i < 20; i++) {}
233
234 if (SH2REG_DVDNT != 0x80000000 ||
235 SH2REG_DVDNTH != 0xFFFFFFFE ||
236 SH2REG_DVCR != 0x1)
237 {
238 stage_status = STAGESTAT_BADDATA;
239 return;
240 }
241
242 stage_status = STAGESTAT_DONE;
243 }
244
245 //////////////////////////////////////////////////////////////////////////////
246
247 void sh2_int_test_func(void) __attribute__ ((interrupt_handler));
248
sh2_int_test_func(void)249 void sh2_int_test_func(void)
250 {
251 bios_set_sh2_interrupt(0x6E, 0);
252 SH2REG_DVCR = 0;
253 stage_status = STAGESTAT_DONE;
254 }
255
256 //////////////////////////////////////////////////////////////////////////////
257
div_interrupt_test(void)258 void div_interrupt_test(void)
259 {
260 // This tests to make sure an interrupt is generated when the registers are setup
261 // for it, and an overflow occurs
262
263 stage_status = STAGESTAT_WAITINGFORINT;
264 bios_set_sh2_interrupt(0x6E, sh2_int_test_func);
265 SH2REG_VCRDIV = 0x6E;
266 SH2REG_IPRA = 0xF << 12;
267 interrupt_set_level_mask(0xE);
268
269 SH2REG_DVSR = 0;
270 SH2REG_DVCR = 0x2;
271 SH2REG_DVDNT = 0xD0000000;
272
273 // Alright, test is all setup, now when the interrupt is done, the test
274 // will successfully complete
275 }
276
277 //////////////////////////////////////////////////////////////////////////////
278
clear_framebuffer()279 void clear_framebuffer()
280 {
281 u32* dest = (u32 *)VDP2_RAM;
282
283 int q;
284
285 for (q = 0; q < 0x10000; q++)
286 {
287 dest[q] = 0;
288 }
289 }
290
291 //////////////////////////////////////////////////////////////////////////////
292
293 //assuming the 28th bit is 0
294 //0b0000 0x0 cache area
295 //0b0010 0x2 cache through
296 //0b0100 0x4 purge
297 //0b0110 0x6 address array
298 //0b1100 0xC data array
299 //0x1110 0xE I/O area
300
301 volatile u32 *wram_cache = (volatile u32 *)(0x06000000);
302 volatile u32 *wram_cache_through = (volatile u32 *)(0x26000000);
303 volatile u32 *address_array = (volatile u32 *)(0x60000000);
304 volatile u32 *data_array = (volatile u32 *)(0xC0000000);
305
306 //////////////////////////////////////////////////////////////////////////////
307
print_addr_data(int x_start,int y_start,u32 addr_val)308 void print_addr_data(int x_start, int y_start, u32 addr_val)
309 {
310 int x_pos = x_start;
311 int y_pos = y_start;
312
313 u32 tag = addr_val & 0x1FFFFC00;
314 u32 lru = (addr_val >> 4) & 0x3f;
315 u32 v = (addr_val >> 2) & 1;
316
317 y_pos += 2;
318
319 vdp_printf(&test_disp_font, x_pos * 8, y_pos * 8, 0xC, "tag: 0x%08x lru: 0x%02x v: 0x%01x", tag, lru, v);
320 }
321
322 //////////////////////////////////////////////////////////////////////////////
323
print_cache_for_way(int x_start,int y_start,int way,int index)324 void print_cache_for_way(int x_start, int y_start, int way, int index)
325 {
326 int x_pos = x_start;
327 int y_pos = y_start;
328
329 vdp_printf(&test_disp_font, x_pos * 8, y_pos * 8, 0xC, "0x%02x", way);
330
331 x_pos += 5;
332
333 SH2REG_CCR = way << 6;
334
335 u32 addr = 0x60000000 | (index << 4);
336 u32 addr_val = (*(volatile u32 *)addr);
337
338 vdp_printf(&test_disp_font, x_pos * 8, y_pos * 8, 0xC, "0x%08x", addr_val);
339
340 x_pos += 11;
341
342 u32 data = data_array[(index * 4) + 0 + (way * 0x100)];
343 vdp_printf(&test_disp_font, x_pos * 8, y_pos * 8, 0xC, "0x%08x", data);
344
345 x_pos += 11;
346
347 data = data_array[(index * 4) + 1 + (way * 0x100)];
348 vdp_printf(&test_disp_font, x_pos * 8, y_pos * 8, 0xC, "0x%08x", data);
349
350 x_pos -= 11;
351 y_pos += 1;
352
353 data = data_array[(index * 4) + 2 + (way * 0x100)];
354 vdp_printf(&test_disp_font, x_pos * 8, y_pos * 8, 0xC, "0x%08x", data);
355
356 x_pos += 11;
357
358 data = data_array[(index * 4) + 3 + (way * 0x100)];
359 vdp_printf(&test_disp_font, x_pos * 8, y_pos * 8, 0xC, "0x%08x", data);
360
361 x_pos = 0;
362
363 print_addr_data(x_pos, y_pos, addr_val);
364 }
365
366 //////////////////////////////////////////////////////////////////////////////
367
print_cache_all_ways(int y_start,int index)368 void print_cache_all_ways(int y_start, int index)
369 {
370 int y = y_start;
371
372 vdp_printf(&test_disp_font, 0 * 8, y * 8, 0xC, "index: 0x%02x", index);
373 y += 2;
374
375 int way;
376
377 for (way = 0; way < 4; way++)
378 {
379 print_cache_for_way(0, y, way, index);
380 y += 6;
381 }
382 }
383
384 //////////////////////////////////////////////////////////////////////////////
385
print_cache_at_index(int index)386 void print_cache_at_index(int index)
387 {
388 clear_framebuffer();
389
390 vdp_printf(&test_disp_font, 0 * 8, 0 * 8, 0xC, "way address data");
391
392 print_cache_all_ways(2, index);
393 }
394
395 //////////////////////////////////////////////////////////////////////////////
396
cache_print_and_wait()397 void cache_print_and_wait()
398 {
399 int index = 0;
400
401 print_cache_at_index(0);
402
403 for (;;)
404 {
405 vdp_vsync();
406
407 if (per[0].but_push_once & PAD_A)
408 {
409 break;
410 }
411
412 if (per[0].but_push_once & PAD_Y)
413 {
414 reset_system();
415 }
416
417 if (per[0].but_push_once & PAD_UP)
418 {
419 index--;
420 if (index < 0)
421 index = 0;
422 print_cache_at_index(index);
423 }
424
425 if (per[0].but_push_once & PAD_DOWN)
426 {
427 index++;
428 print_cache_at_index(index);
429 }
430 }
431 }
432
433 //////////////////////////////////////////////////////////////////////////////
434
cache_test()435 void cache_test()
436 {
437 int i = 0;
438 int way = 0;
439
440 SH2REG_CCR = 0;//disable cache
441
442 //clear address arrays
443 for (way = 0; way < 4; way++)
444 {
445 //bank switch
446 SH2REG_CCR = way << 6;
447
448 for (i = 0; i < 64; i++)
449 {
450 address_array[i] = 0;
451 }
452 }
453
454 //clear data array
455 for (i = 0; i < 0x400; i++)
456 data_array[i] = 0;
457
458 wram_cache_through[0x11000] = 0xdeadbeef;
459 wram_cache_through[0x11001] = 0xcafef00d;
460 wram_cache_through[0x11002] = 0xb01dface;
461 wram_cache_through[0x11003] = 0xba5eba11;
462
463 for (i = 0; i < 64; i++)
464 {
465 wram_cache_through[0x12000 + i] = i;
466 }
467
468 SH2REG_CCR = (1 << 4); //purge
469 SH2REG_CCR = 1; //enable
470
471 //test write
472 wram_cache[0x10000] = wram_cache[0x11000];
473
474 SH2REG_CCR = 0;//disable cache
475
476 way = 0;
477
478 cache_print_and_wait();
479
480 //part 2
481
482 for (i = 0; i < 64; i+=4)
483 {
484 SH2REG_CCR = 1; //enable
485
486 wram_cache[0x13000 + i] = wram_cache[0x12000 + i];
487
488 SH2REG_CCR = 0;//disable
489
490 cache_print_and_wait();
491 }
492 }
493
test_sh2_dma_impl(u32 src_addr,u32 dst_addr,u32 count,u8 transfer_size)494 void test_sh2_dma_impl(
495 u32 src_addr,
496 u32 dst_addr,
497 u32 count,
498 u8 transfer_size
499 )
500 {
501 volatile u32 *source = (volatile u32 *)(src_addr);
502 volatile u32 *dest = (volatile u32 *)(dst_addr);
503 int i;
504
505 clear_framebuffer();
506
507 //read te
508 volatile u32 dummy = SH2REG_CHCR0;
509
510 //and clear it
511 SH2REG_CHCR0 = 0;
512
513 //read nmif
514 dummy = SH2REG_DMAOR;
515
516 //and clear it
517 SH2REG_DMAOR = 0;
518
519 for (i = 0; i < count; i+=2)
520 {
521 source[i] = 0xdeadbeef;
522 source[i+2] = 0xcafef00d;
523 }
524
525 for (i = 0; i < count; i++)
526 {
527 dest[i] = 0;
528 }
529
530 u8 round_robin = 0;
531 u8 all_dma_enabled = 1;
532
533 SH2REG_DMAOR =
534 (round_robin << 3) |
535 all_dma_enabled;
536
537 SH2REG_SAR0 = src_addr;
538 SH2REG_DAR0 = dst_addr;
539 SH2REG_TCR0 = count;
540
541 u8 destination_address_mode = 1;
542 u8 source_address_mode = 1;
543 u8 transfer_enabled = 1;
544 u8 auto_request_mode = 1;//must be set
545
546 SH2REG_CHCR0 =
547 (destination_address_mode << 14) |
548 (source_address_mode << 12) |
549 (transfer_size << 10) |
550 (auto_request_mode << 9) |
551 transfer_enabled;
552
553 while (!(SH2REG_CHCR0 & 2)) {}//wait for TE to be set
554
555 for (;;)
556 {
557 vdp_vsync();
558
559 vdp_printf(&test_disp_font, 0 * 8, 4 * 8, 0xC, "SAR0 0x%08x DAR0 0x%08x",
560 SH2REG_SAR0,
561 SH2REG_DAR0);
562
563 vdp_printf(&test_disp_font, 0 * 8, 5 * 8, 0xC, "TCR0 0x%08x CHR0 0x%08x",
564 SH2REG_TCR0,
565 SH2REG_CHCR0);
566
567 vdp_printf(&test_disp_font, 0 * 8, 6 * 8, 0xC, "DMAOR 0x%08x",
568 SH2REG_DMAOR);
569
570 volatile u8 de = SH2REG_CHCR0 & 1;
571 volatile u8 dme = SH2REG_DMAOR & 1;
572 volatile u8 te = (SH2REG_CHCR0 >> 1) & 1;
573 volatile u8 nmif = (SH2REG_DMAOR >> 1) & 1;
574 volatile u8 ae = (SH2REG_DMAOR >> 2) & 1;
575
576 vdp_printf(&test_disp_font, 0 * 8, 7 * 8, 0xC, "DE %01x DME %01x TE %01x NMIF %01x AE %01x",
577 de,dme,te,nmif,ae);
578
579 if (per[0].but_push_once & PAD_Y)
580 {
581 reset_system();
582 }
583
584 if (per[0].but_push_once & PAD_A)
585 {
586 break;
587 }
588 }
589 }
590
test_sh2_dma()591 void test_sh2_dma()
592 {
593 test_sh2_dma_impl(0x260ED000, 0x25E00000, 0x1000, 2);
594 test_sh2_dma_impl(0x260ED000, 0x25E00000, 0x800, 3);
595 }
596
do_test_asm(u32 value,u32 addr,int is_write,int size,u32 * b2,int num_times)597 u32 do_test_asm(u32 value, u32 addr, int is_write, int size, u32 * b2, int num_times)
598 {
599 u32 a = value;
600 u32 b = addr;
601 u32 c = num_times;
602 u32 a_out, b_out, sr;
603
604 if (is_write)
605 {
606 if (size == 0)
607 {
608 asm(
609 "mov %[a],r0\n\t"
610 "mov %[b],r1\n\t"
611 "mov %[c],r2\n\t"
612 "mov #0, r3\n\t"//loop counter
613 "loop%=: \n\t"
614 "cmp/ge r2,r3 \n\t"
615 "bt end%= \n\t"
616 "add #1, r3 \n\t"
617 "mov.b r0, @r1\n\t"
618 "bra loop%= \n\t"
619 "nop \n\t"
620 "end%=: \n\t"
621 "mov r0,%[a_out]\n\t"
622 "mov r1,%[b_out]\n\t"
623 : [a_out] "=r" (a_out), [b_out] "=r" (b_out), [sr] "=r" (sr)//output
624 : [a] "r" (a), [b] "r" (b), [c] "r" (c)//input
625 : "r0", "r1", "r2", "r3");//clobbers
626 }
627 else if (size == 1)
628 {
629 asm(
630 "mov %[a],r0\n\t"
631 "mov %[b],r1\n\t"
632 "mov %[c],r2\n\t"
633 "mov #0, r3\n\t"//loop counter
634 "loop%=: \n\t"
635 "cmp/ge r2,r3 \n\t"
636 "bt end%= \n\t"
637 "add #1, r3 \n\t"
638 "mov.w r0, @r1\n\t"
639 "bra loop%= \n\t"
640 "nop \n\t"
641 "end%=: \n\t"
642 "mov r0,%[a_out]\n\t"
643 "mov r1,%[b_out]\n\t"
644 : [a_out] "=r" (a_out), [b_out] "=r" (b_out), [sr] "=r" (sr)//output
645 : [a] "r" (a), [b] "r" (b), [c] "r" (c)//input
646 : "r0", "r1", "r2", "r3");//clobbers
647 }
648 else
649 {
650 asm(
651 "mov %[a],r0\n\t"
652 "mov %[b],r1\n\t"
653 "mov %[c],r2\n\t"
654 "mov #0, r3\n\t"//loop counter
655 "loop%=: \n\t"
656 "cmp/ge r2,r3 \n\t"
657 "bt end%= \n\t"
658 "add #1, r3 \n\t"
659 "mov.l r0, @r1\n\t"
660 "bra loop%= \n\t"
661 "nop \n\t"
662 "end%=: \n\t"
663 "mov r0,%[a_out]\n\t"
664 "mov r1,%[b_out]\n\t"
665 : [a_out] "=r" (a_out), [b_out] "=r" (b_out), [sr] "=r" (sr)//output
666 : [a] "r" (a), [b] "r" (b), [c] "r" (c)//input
667 : "r0", "r1", "r2", "r3");//clobbers
668 }
669
670
671 }
672 else
673 {
674 if (size == 0)
675 {
676 asm(
677 "mov %[a],r0\n\t"
678 "mov %[b],r1\n\t"
679 "mov %[c],r2\n\t"
680 "mov #0, r3\n\t"//loop counter
681 "loop%=: \n\t"
682 "cmp/ge r2,r3 \n\t"
683 "bt end%= \n\t"
684 "add #1, r3 \n\t"
685 "mov.b @r1, r0\n\t"
686 "bra loop%= \n\t"
687 "nop \n\t"
688 "end%=: \n\t"
689 "mov r0,%[a_out]\n\t"
690 "mov r1,%[b_out]\n\t"
691 : [a_out] "=r" (a_out), [b_out] "=r" (b_out), [sr] "=r" (sr)//output
692 : [a] "r" (a), [b] "r" (b), [c] "r" (c)//input
693 : "r0", "r1", "r2", "r3");//clobbers
694 }
695 else if (size == 1)
696 {
697 asm(
698 "mov %[a],r0\n\t"
699 "mov %[b],r1\n\t"
700 "mov %[c],r2\n\t"
701 "mov #0, r3\n\t"//loop counter
702 "loop%=: \n\t"
703 "cmp/ge r2,r3 \n\t"
704 "bt end%= \n\t"
705 "add #1, r3 \n\t"
706 "mov.w @r1, r0\n\t"
707 "bra loop%= \n\t"
708 "nop \n\t"
709 "end%=: \n\t"
710 "mov r0,%[a_out]\n\t"
711 "mov r1,%[b_out]\n\t"
712 : [a_out] "=r" (a_out), [b_out] "=r" (b_out), [sr] "=r" (sr)//output
713 : [a] "r" (a), [b] "r" (b), [c] "r" (c)//input
714 : "r0", "r1", "r2", "r3");//clobbers
715 }
716 else
717 {
718 asm(
719 "mov %[a],r0\n\t"
720 "mov %[b],r1\n\t"
721 "mov %[c],r2\n\t"
722 "mov #0, r3\n\t"//loop counter
723 "loop%=: \n\t"
724 "cmp/ge r2,r3 \n\t"
725 "bt end%= \n\t"
726 "add #1, r3 \n\t"
727 "mov.l @r1, r0\n\t"
728 "bra loop%= \n\t"
729 "nop \n\t"
730 "end%=: \n\t"
731 "mov r0,%[a_out]\n\t"
732 "mov r1,%[b_out]\n\t"
733 : [a_out] "=r" (a_out), [b_out] "=r" (b_out), [sr] "=r" (sr)//output
734 : [a] "r" (a), [b] "r" (b), [c] "r" (c)//input
735 : "r0", "r1", "r2", "r3");//clobbers
736 }
737
738 }
739
740 *b2 = b_out;
741
742 return a_out;
743 }
744
745 void clear_framebuffer();
746
sh2_write_timing(u32 destination,char * test_name,int is_write,int size)747 void sh2_write_timing(u32 destination, char*test_name, int is_write, int size)
748 {
749 clear_framebuffer();
750
751 int print_pos = 10;
752
753 int i;
754
755 if (is_write)
756 vdp_printf(&test_disp_font, 0 * 8, 1 * 8, 0xF, "write to %s", test_name);
757 else
758 vdp_printf(&test_disp_font, 0 * 8, 1 * 8, 0xF, "read from %s", test_name);
759
760 if (size == 0)
761 vdp_printf(&test_disp_font, 0 * 8, 2 * 8, 0xF, "byte");
762 else if (size == 1)
763 vdp_printf(&test_disp_font, 0 * 8, 2 * 8, 0xF, "word");
764 else
765 vdp_printf(&test_disp_font, 0 * 8, 2 * 8, 0xF, "long");
766
767 for (i = 0; i < 5; i++)
768 {
769 vdp_wait_vblankin();
770
771 int num_writes = 2048;
772
773 //zero watchdog timer
774 SH2_REG_WTCNT_W(0);
775 RSTCSR_W = 0;
776
777 //enable timer
778 SH2_REG_WTCSR_W(1 << 5);
779
780 u8 wdt_end_time = SH2_REG_WTCNT_R;
781
782 //disable timer
783 SH2_REG_WTCSR_W(0);
784
785 frc_clear();
786 u32 b2 = 0;
787
788 u32 output = do_test_asm(0xdeadbeef, destination, is_write, size, &b2, num_writes);
789
790 u32 frc_end_time = frc_get();
791
792 vdp_printf(&test_disp_font, 0 * 8, print_pos * 8, 0xF, "frc: %d (~%d cycles), ~%d cycles", frc_end_time, frc_end_time * 8, (frc_end_time * 8) / num_writes);
793 vdp_printf(&test_disp_font, 0 * 8, (print_pos + 6) * 8, 0xF, "%08X %08X", output, b2);
794 print_pos++;
795 }
796
797 for (;;)
798 {
799 vdp_wait_vblankin();
800
801 if (per[0].but_push_once & PAD_A)
802 {
803 break;
804 }
805
806 if (per[0].but_push_once & PAD_Y)
807 {
808 reset_system();
809 }
810 }
811 }
812
do_timing(int is_write,int size)813 void do_timing(int is_write, int size)
814 {
815
816 int i = is_write;
817 int j = size;
818
819 sh2_write_timing(0x20000000, "bios", i, j);
820
821 sh2_write_timing(0x20100000, "smpc", i, j);
822
823 sh2_write_timing(0x25E00000, "vdp2 vram", i, j);
824
825 sh2_write_timing(0x25f00000, "vdp2 color ram", i, j);
826
827 if ((i != 1) && (j != 2))//crashes
828 sh2_write_timing(0x25f80026, "vdp2 regs", i, j);
829
830 sh2_write_timing(0x25a00000, "scsp ram", i, j);
831
832 sh2_write_timing(0x25b00000, "scsp regs", i, j);
833
834 sh2_write_timing(0x25C00000, "vdp1 ram", i, j);
835
836 sh2_write_timing(0x25C80000, "vdp1 framebuffer", i, j);
837
838 sh2_write_timing(0x25d00000, "vdp1 regs", i, j);
839
840 sh2_write_timing(0x20200000, "low work ram", i, j);
841
842 sh2_write_timing(0x260FF000, "high work ram", i, j);
843
844 sh2_write_timing(0x25890008, "ygr", i, j);
845
846 sh2_write_timing(0x25fe0000, "scu regs", i, j);
847 }
848
sh2_write_timing_test()849 void sh2_write_timing_test()
850 {
851 (*(volatile u8 *)0xFFFFFE92) = 1;//enable cache
852
853 int i = 1;
854
855 for (i = 0; i < 2; i++)
856 {
857 int j;
858 for (j = 0; j < 3; j++)
859 {
860 do_timing(i, j);
861 }
862 }
863 }