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 }