filename | test/testdisp.c |
changeset | 272:fb6be85235e8 |
prev | 267:e59e36950761 |
next | 561:533f6b478071 |
author | nkeynes |
date | Thu Aug 23 12:31:31 2007 +0000 (16 years ago) |
permissions | -rw-r--r-- |
last change | Add tests for mac.l and mac.w Start test cases for fmov Update exception tests |
file | annotate | diff | log | raw |
nkeynes@263 | 1 | /** |
nkeynes@272 | 2 | * $Id: testdisp.c,v 1.3 2007-01-11 06:53:31 nkeynes Exp $ |
nkeynes@263 | 3 | * |
nkeynes@263 | 4 | * Display (2D) tests. Mainly tests video timing / sync (obviously |
nkeynes@263 | 5 | * it can't actually test display output since there's no way of |
nkeynes@263 | 6 | * reading the results) |
nkeynes@263 | 7 | * |
nkeynes@263 | 8 | * These tests use TMU2 to determine absolute time |
nkeynes@263 | 9 | * Copyright (c) 2006 Nathan Keynes. |
nkeynes@263 | 10 | * |
nkeynes@263 | 11 | * This program is free software; you can redistribute it and/or modify |
nkeynes@263 | 12 | * it under the terms of the GNU General Public License as published by |
nkeynes@263 | 13 | * the Free Software Foundation; either version 2 of the License, or |
nkeynes@263 | 14 | * (at your option) any later version. |
nkeynes@263 | 15 | * |
nkeynes@263 | 16 | * This program is distributed in the hope that it will be useful, |
nkeynes@263 | 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
nkeynes@263 | 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
nkeynes@263 | 19 | * GNU General Public License for more details. |
nkeynes@263 | 20 | */ |
nkeynes@263 | 21 | #include <stdlib.h> |
nkeynes@263 | 22 | #include <stdio.h> |
nkeynes@263 | 23 | #include "lib.h" |
nkeynes@263 | 24 | #include "asic.h" |
nkeynes@263 | 25 | |
nkeynes@263 | 26 | #define PVR_BASE 0xA05F8000 |
nkeynes@263 | 27 | |
nkeynes@263 | 28 | #define BORDERCOL (PVR_BASE+0x040) |
nkeynes@263 | 29 | #define DISPCFG1 (PVR_BASE+0x044) |
nkeynes@263 | 30 | #define DISPADDR1 (PVR_BASE+0x050) |
nkeynes@263 | 31 | #define DISPADDR2 (PVR_BASE+0x054) |
nkeynes@263 | 32 | #define DISPSIZE (PVR_BASE+0x05C) |
nkeynes@263 | 33 | #define HPOSEVENT (PVR_BASE+0x0C8) |
nkeynes@263 | 34 | #define VPOSEVENT (PVR_BASE+0x0CC) |
nkeynes@263 | 35 | #define DISPCFG2 (PVR_BASE+0x0D0) |
nkeynes@263 | 36 | #define HBORDER (PVR_BASE+0x0D4) |
nkeynes@267 | 37 | #define DISPTOTAL (PVR_BASE+0x0D8) |
nkeynes@263 | 38 | #define VBORDER (PVR_BASE+0x0DC) |
nkeynes@267 | 39 | #define SYNCTIME (PVR_BASE+0x0E0) |
nkeynes@263 | 40 | #define DISPCFG3 (PVR_BASE+0x0E8) |
nkeynes@263 | 41 | #define HPOS (PVR_BASE+0x0EC) |
nkeynes@263 | 42 | #define VPOS (PVR_BASE+0x0F0) |
nkeynes@263 | 43 | #define SYNCSTAT (PVR_BASE+0x10C) |
nkeynes@263 | 44 | |
nkeynes@267 | 45 | #define MAX_FRAME_WAIT 0x50000 |
nkeynes@267 | 46 | |
nkeynes@267 | 47 | #define EVENT_RETRACE 5 |
nkeynes@263 | 48 | |
nkeynes@263 | 49 | #define WAIT_LINE( a ) if( wait_line(a) != 0 ) { fprintf(stderr, "Timeout at %s:%d:%s() waiting for line %d\n", __FILE__, __LINE__, __func__, a ); return -1; } |
nkeynes@263 | 50 | #define WAIT_LASTLINE( a ) if( wait_lastline(a) != 0 ) { fprintf(stderr, "Last line check failed at %s:%d:%s() waiting for line %d\n", __FILE__, __LINE__, __func__, a ); return -1; } |
nkeynes@263 | 51 | |
nkeynes@263 | 52 | void dump_display_regs( FILE *out ) |
nkeynes@263 | 53 | { |
nkeynes@263 | 54 | fprintf( out, "%08X DISPCFG1: %08X\n", DISPCFG1, long_read(DISPCFG1) ); |
nkeynes@263 | 55 | fprintf( out, "%08X DISPCFG2: %08X\n", DISPCFG2, long_read(DISPCFG2) ); |
nkeynes@263 | 56 | fprintf( out, "%08X DISPCFG3: %08X\n", DISPCFG3, long_read(DISPCFG3) ); |
nkeynes@263 | 57 | fprintf( out, "%08X DISPSIZE: %08X\n", DISPSIZE, long_read(DISPSIZE) ); |
nkeynes@263 | 58 | fprintf( out, "%08X HBORDER: %08X\n", HBORDER, long_read(HBORDER) ); |
nkeynes@263 | 59 | fprintf( out, "%08X VBORDER: %08X\n", VBORDER, long_read(VBORDER) ); |
nkeynes@267 | 60 | fprintf( out, "%08X SYNCTIME: %08X\n", SYNCTIME, long_read(SYNCTIME) ); |
nkeynes@267 | 61 | fprintf( out, "%08X DISPTOTAL: %08X\n", DISPTOTAL, long_read(DISPTOTAL) ); |
nkeynes@263 | 62 | fprintf( out, "%08X DISPADDR1: %08X\n", DISPADDR1, long_read(DISPADDR1) ); |
nkeynes@263 | 63 | fprintf( out, "%08X DISPADDR2: %08X\n", DISPADDR2, long_read(DISPADDR2) ); |
nkeynes@263 | 64 | fprintf( out, "%08X HPOSEVENT: %08X\n", HPOSEVENT, long_read(HPOSEVENT) ); |
nkeynes@263 | 65 | fprintf( out, "%08X VPOSEVENT: %08X\n", VPOSEVENT, long_read(VPOSEVENT) ); |
nkeynes@263 | 66 | fprintf( out, "%08X HPOS: %08X\n", HPOS, long_read(HPOS) ); |
nkeynes@263 | 67 | fprintf( out, "%08X VPOS: %08X\n", VPOS, long_read(VPOS) ); |
nkeynes@263 | 68 | fprintf( out, "%08X SYNCSTAT: %08X\n", SYNCSTAT, long_read(SYNCSTAT) ); |
nkeynes@263 | 69 | } |
nkeynes@263 | 70 | |
nkeynes@263 | 71 | uint32_t pal_settings[] = { |
nkeynes@263 | 72 | DISPCFG1, 0x00000001, |
nkeynes@263 | 73 | DISPCFG2, 0x00000150, |
nkeynes@263 | 74 | DISPCFG3, 0x00160000, |
nkeynes@263 | 75 | DISPSIZE, 0x1413BD3F, |
nkeynes@263 | 76 | HBORDER, 0x008D034B, |
nkeynes@263 | 77 | VBORDER, 0x00120102, |
nkeynes@267 | 78 | DISPTOTAL, 0x0270035F, |
nkeynes@267 | 79 | SYNCTIME, 0x07D6A53F, |
nkeynes@263 | 80 | HPOS, 0x000000A4, |
nkeynes@263 | 81 | VPOS, 0x00120012, |
nkeynes@267 | 82 | VPOSEVENT, 0x00150136, |
nkeynes@263 | 83 | 0, 0 }; |
nkeynes@263 | 84 | |
nkeynes@267 | 85 | uint32_t ntsc_settings[] = { |
nkeynes@267 | 86 | DISPCFG1, 0x00000001, |
nkeynes@267 | 87 | DISPCFG2, 0x00000150, |
nkeynes@267 | 88 | DISPCFG3, 0x00160000, |
nkeynes@267 | 89 | DISPSIZE, 0x1413BD3F, |
nkeynes@267 | 90 | HBORDER, 0x007e0345, |
nkeynes@267 | 91 | VBORDER, 0x00120102, |
nkeynes@267 | 92 | DISPTOTAL, 0x020C0359, |
nkeynes@267 | 93 | SYNCTIME, 0x07d6c63f, |
nkeynes@267 | 94 | HPOS, 0x000000A4, |
nkeynes@267 | 95 | VPOS, 0x00120012, |
nkeynes@267 | 96 | VPOSEVENT, 0x001501FE, |
nkeynes@267 | 97 | 0, 0 }; |
nkeynes@267 | 98 | |
nkeynes@267 | 99 | |
nkeynes@267 | 100 | struct timing { |
nkeynes@267 | 101 | uint32_t interlaced; |
nkeynes@267 | 102 | uint32_t total_lines; |
nkeynes@267 | 103 | uint32_t vsync_lines; |
nkeynes@267 | 104 | uint32_t line_time_us; |
nkeynes@267 | 105 | uint32_t field_time_us; |
nkeynes@267 | 106 | uint32_t hsync_width_us; |
nkeynes@267 | 107 | uint32_t front_porch_us; |
nkeynes@267 | 108 | uint32_t back_porch_us; |
nkeynes@267 | 109 | }; |
nkeynes@267 | 110 | |
nkeynes@267 | 111 | struct timing ntsc_timing = { 1, 525, 6, 31, 16641, 4, 12, 4 }; |
nkeynes@267 | 112 | struct timing pal_timing = { 1, 625, 5, 31, 19949, 4, 12, 4 }; |
nkeynes@267 | 113 | |
nkeynes@263 | 114 | void apply_display_settings( uint32_t *regs ) { |
nkeynes@263 | 115 | int i; |
nkeynes@263 | 116 | for( i=0; regs[i] != 0; i+=2 ) { |
nkeynes@263 | 117 | long_write( regs[i], regs[i+1] ); |
nkeynes@263 | 118 | } |
nkeynes@263 | 119 | } |
nkeynes@263 | 120 | |
nkeynes@263 | 121 | /** |
nkeynes@263 | 122 | * Wait until the given line is being displayed (ie is set in the syncstat |
nkeynes@263 | 123 | * register). |
nkeynes@263 | 124 | * @return 0 if the line is reached before timeout, otherwise -1. |
nkeynes@263 | 125 | */ |
nkeynes@263 | 126 | int wait_line( int line ) |
nkeynes@263 | 127 | { |
nkeynes@263 | 128 | int i; |
nkeynes@263 | 129 | for( i=0; i< MAX_FRAME_WAIT; i++ ) { |
nkeynes@263 | 130 | uint32_t sync = long_read(SYNCSTAT) & 0x03FF; |
nkeynes@263 | 131 | if( sync == line ) { |
nkeynes@263 | 132 | return 0; |
nkeynes@263 | 133 | } |
nkeynes@263 | 134 | } |
nkeynes@263 | 135 | return -1; |
nkeynes@263 | 136 | } |
nkeynes@263 | 137 | |
nkeynes@263 | 138 | /** |
nkeynes@263 | 139 | * Wait until just after the last line of the frame is being displayed (according |
nkeynes@263 | 140 | * to the syncstat register). After this function the current line will be 0. |
nkeynes@263 | 141 | * @return 0 if the last line is the given line, otherwise -1. |
nkeynes@263 | 142 | */ |
nkeynes@263 | 143 | int wait_lastline( int line ) |
nkeynes@263 | 144 | { |
nkeynes@267 | 145 | int lastline = 0, i; |
nkeynes@263 | 146 | for( i=0; i< MAX_FRAME_WAIT; i++ ) { |
nkeynes@263 | 147 | uint32_t sync = long_read(SYNCSTAT) & 0x03FF; |
nkeynes@267 | 148 | if( sync == 0 && lastline != 0 ) { |
nkeynes@263 | 149 | CHECK_IEQUALS( line, lastline ); |
nkeynes@263 | 150 | return 0; |
nkeynes@263 | 151 | } |
nkeynes@263 | 152 | lastline = sync; |
nkeynes@263 | 153 | } |
nkeynes@263 | 154 | fprintf( stderr, "Timeout waiting for line %d\n", line ); |
nkeynes@263 | 155 | return -1; |
nkeynes@263 | 156 | } |
nkeynes@263 | 157 | |
nkeynes@267 | 158 | int check_events_interlaced( ) |
nkeynes@267 | 159 | { |
nkeynes@267 | 160 | uint32_t status1, status2, status3; |
nkeynes@267 | 161 | int i; |
nkeynes@267 | 162 | for( i=0; i< MAX_FRAME_WAIT; i++ ) { |
nkeynes@267 | 163 | status1 = long_read(SYNCSTAT) & 0x07FF; |
nkeynes@267 | 164 | if( status1 == 0x04FF ) { |
nkeynes@267 | 165 | break; |
nkeynes@267 | 166 | } |
nkeynes@267 | 167 | } |
nkeynes@267 | 168 | asic_clear(); |
nkeynes@267 | 169 | asic_wait(EVENT_RETRACE); |
nkeynes@267 | 170 | status1 = long_read(SYNCSTAT); |
nkeynes@267 | 171 | asic_clear(); |
nkeynes@267 | 172 | asic_wait(EVENT_SCANLINE2); |
nkeynes@267 | 173 | status2 = long_read(SYNCSTAT); |
nkeynes@267 | 174 | asic_clear(); |
nkeynes@267 | 175 | asic_wait(EVENT_SCANLINE1); |
nkeynes@267 | 176 | status3 = long_read(SYNCSTAT); |
nkeynes@267 | 177 | CHECK_IEQUALS( 0x0000, status1 ); |
nkeynes@267 | 178 | CHECK_IEQUALS( 0x202A, status2 ); |
nkeynes@267 | 179 | CHECK_IEQUALS( 0x226C, status3 ); |
nkeynes@267 | 180 | |
nkeynes@267 | 181 | for( i=0; i< MAX_FRAME_WAIT; i++ ) { |
nkeynes@267 | 182 | status1 = long_read(SYNCSTAT) & 0x07FF; |
nkeynes@267 | 183 | if( status1 == 0x00FF ) { |
nkeynes@267 | 184 | break; |
nkeynes@267 | 185 | } |
nkeynes@267 | 186 | } |
nkeynes@267 | 187 | asic_clear(); |
nkeynes@267 | 188 | asic_wait(EVENT_RETRACE); |
nkeynes@267 | 189 | status1 = long_read(SYNCSTAT); |
nkeynes@267 | 190 | asic_clear(); |
nkeynes@267 | 191 | asic_wait(EVENT_SCANLINE2); |
nkeynes@267 | 192 | status2 = long_read(SYNCSTAT); |
nkeynes@267 | 193 | asic_clear(); |
nkeynes@267 | 194 | asic_wait(EVENT_SCANLINE1); |
nkeynes@267 | 195 | status3 = long_read(SYNCSTAT); |
nkeynes@267 | 196 | fprintf( stderr, "%08X, %08X, %08X\n", status1, status2, status3 ); |
nkeynes@267 | 197 | CHECK_IEQUALS( 0x1400, status1 ); |
nkeynes@267 | 198 | CHECK_IEQUALS( 0x242B, status2 ); |
nkeynes@267 | 199 | CHECK_IEQUALS( 0x266D, status3 ); |
nkeynes@263 | 200 | |
nkeynes@263 | 201 | return 0; |
nkeynes@263 | 202 | } |
nkeynes@263 | 203 | |
nkeynes@267 | 204 | int check_timing( struct timing *t ) { |
nkeynes@267 | 205 | uint32_t line_time, field_time; |
nkeynes@267 | 206 | uint32_t stat; |
nkeynes@267 | 207 | uint32_t last_line = t->total_lines - 1; |
nkeynes@267 | 208 | int i; |
nkeynes@267 | 209 | |
nkeynes@272 | 210 | timer_init(); |
nkeynes@267 | 211 | WAIT_LINE( t->total_lines - 1 ); |
nkeynes@267 | 212 | for( i=0; i< MAX_FRAME_WAIT; i++ ) { |
nkeynes@267 | 213 | stat = long_read(SYNCSTAT) & 0x07FF; |
nkeynes@267 | 214 | if( stat == 0 ) { |
nkeynes@267 | 215 | break; |
nkeynes@267 | 216 | } else if( (stat & 0x03FF) != last_line ) { |
nkeynes@267 | 217 | last_line = stat & 0x03FF; |
nkeynes@267 | 218 | } |
nkeynes@267 | 219 | } |
nkeynes@267 | 220 | if( stat != 0 ) { |
nkeynes@267 | 221 | fprintf( stderr, "Timeout waiting for line 0 field 0\n" ); |
nkeynes@267 | 222 | return -1; |
nkeynes@267 | 223 | } |
nkeynes@272 | 224 | timer_run(); |
nkeynes@272 | 225 | CHECK_IEQUALS( stat, 0 ); /* VSYNC, HSYNC, no display */ |
nkeynes@272 | 226 | |
nkeynes@272 | 227 | uint32_t start_of_line = 0; |
nkeynes@272 | 228 | uint32_t laststat = stat; |
nkeynes@272 | 229 | uint32_t lastline = 0; |
nkeynes@272 | 230 | int hsync_count = 0; |
nkeynes@272 | 231 | while(1) { /* for each line */ |
nkeynes@272 | 232 | stat = long_read(SYNCSTAT); |
nkeynes@272 | 233 | if( stat != laststat ) { |
nkeynes@272 | 234 | uint32_t cur_time = timer_gettime_us(); |
nkeynes@272 | 235 | uint32_t time = cur_time - start_of_line; |
nkeynes@272 | 236 | uint32_t line = stat & 0x03FF; |
nkeynes@272 | 237 | if( line != lastline ) { |
nkeynes@272 | 238 | if( time != t->line_time_us && /* Allow variance of +1 us */ |
nkeynes@272 | 239 | time-1 != t->line_time_us ) { |
nkeynes@272 | 240 | fprintf( stderr, "Assertion failed: Expected line time %dus on line %d but was %dus: %d, %d, %d\n", |
nkeynes@272 | 241 | t->line_time_us, lastline, time, start_of_line, cur_time, line ); |
nkeynes@272 | 242 | return -1; |
nkeynes@272 | 243 | } |
nkeynes@272 | 244 | if( line == 0 ) { |
nkeynes@272 | 245 | CHECK_IEQUALS( t->total_lines-1, lastline ); |
nkeynes@272 | 246 | break; |
nkeynes@272 | 247 | } |
nkeynes@272 | 248 | start_of_line = cur_time; |
nkeynes@272 | 249 | lastline = line; |
nkeynes@272 | 250 | } else if( (stat ^ laststat) == 0x1000 && (stat&0x1000) ) { |
nkeynes@272 | 251 | hsync_count++; |
nkeynes@272 | 252 | if( time != t->hsync_width_us && |
nkeynes@272 | 253 | time-1 != t->hsync_width_us ) { |
nkeynes@272 | 254 | fprintf( stderr, "Assertion failed: Expected hsync width %dus on line %d but was %dus, stat = %08X, count=%d\n", |
nkeynes@272 | 255 | t->hsync_width_us, lastline, time, stat, hsync_count ); |
nkeynes@272 | 256 | return -1; |
nkeynes@272 | 257 | } |
nkeynes@272 | 258 | } else { |
nkeynes@272 | 259 | // fprintf( stderr, "Change %08X to %08X\n", laststat, stat ); |
nkeynes@272 | 260 | } |
nkeynes@272 | 261 | laststat = stat; |
nkeynes@272 | 262 | } |
nkeynes@267 | 263 | } |
nkeynes@272 | 264 | |
nkeynes@267 | 265 | field_time = timer_gettime_us(); |
nkeynes@267 | 266 | |
nkeynes@272 | 267 | if( field_time != t->field_time_us ) { |
nkeynes@272 | 268 | fprintf( stderr, "Assertion failed: Expected field time %dus but was %dus\n", |
nkeynes@272 | 269 | t->field_time_us, field_time ); |
nkeynes@267 | 270 | return -1; |
nkeynes@267 | 271 | } |
nkeynes@267 | 272 | return 0; |
nkeynes@267 | 273 | } |
nkeynes@267 | 274 | |
nkeynes@267 | 275 | int test_ntsc_timing() { |
nkeynes@267 | 276 | apply_display_settings( ntsc_settings ); |
nkeynes@267 | 277 | // check_events_interlaced(); |
nkeynes@267 | 278 | asic_clear(); |
nkeynes@267 | 279 | uint32_t result = check_timing( &ntsc_timing ); |
nkeynes@267 | 280 | dump_display_regs( stdout ); |
nkeynes@267 | 281 | return result; |
nkeynes@267 | 282 | } |
nkeynes@267 | 283 | |
nkeynes@263 | 284 | |
nkeynes@263 | 285 | int test_pal_timing() |
nkeynes@263 | 286 | { |
nkeynes@263 | 287 | uint32_t line_time, field_time; |
nkeynes@263 | 288 | /* Set PAL display mode */ |
nkeynes@263 | 289 | apply_display_settings( pal_settings ); |
nkeynes@263 | 290 | |
nkeynes@267 | 291 | check_events_interlaced(); |
nkeynes@263 | 292 | asic_clear(); |
nkeynes@267 | 293 | uint32_t result = check_timing( &pal_timing ); |
nkeynes@263 | 294 | dump_display_regs( stdout ); |
nkeynes@267 | 295 | return result; |
nkeynes@263 | 296 | } |
nkeynes@263 | 297 | |
nkeynes@263 | 298 | |
nkeynes@263 | 299 | /********************************* Main **************************************/ |
nkeynes@263 | 300 | |
nkeynes@263 | 301 | typedef int (*test_func_t)(); |
nkeynes@263 | 302 | |
nkeynes@263 | 303 | test_func_t test_fns[] = { test_ntsc_timing, test_pal_timing, |
nkeynes@263 | 304 | NULL }; |
nkeynes@263 | 305 | |
nkeynes@263 | 306 | int main() |
nkeynes@263 | 307 | { |
nkeynes@263 | 308 | return run_tests( test_fns ); |
nkeynes@263 | 309 | } |
.