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 Sat Jun 14 11:54:15 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change Change colour params to float
Convert background processing over to scene structure (fixes some depth issues as well)
Add color unclamp when supported
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
}
.