Search
lxdream.org :: lxdream/test/testdisp.c
lxdream 0.9.1
released Jun 29
Download Now
filename test/testdisp.c
changeset 561:533f6b478071
prev272:fb6be85235e8
author nkeynes
date Tue Jan 01 05:08:38 2008 +0000 (12 years ago)
branchlxdream-mmu
permissions -rw-r--r--
last change Enable Id keyword on all source files
file annotate diff log raw
nkeynes@263
     1
/**
nkeynes@561
     2
 * $Id$
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
}
.