//------------------------------------------------------------------- // nochain4.cpp // // Shows how to address planar memory in Mode-X configuration. // Allows parallel modifying of up to sixteen adjacent pixels. // // Reference: Michael Abrash, The Zen of Graphics Programming, // Coriolis Group (1995), pp. 516-518. // // NOTE: // This demo worked correctly with SiS 315 Graphics Processor, // but not when tested using an ATI Technologies Rage IIC GPU, // so may not yet work correctly using other non-SiS chipsets, // suggesting that additional VGA registers may need 'tweaks'. // // programmer: ALLAN CRUSE // written on: 03 DEC 2003 //------------------------------------------------------------------- #include // for printf(), perror() #include // for open() #include // for exit() #include // for read(), write(), close() #include // for tcgetattr(), tcsetattr() #include // for mmap() #include // for iopl() #define VRAM_BASE_ADDRESS 0xA0000000 #define VGA_MEMORY_LENGTH ( 4 << 20) unsigned char *vram = (unsigned char*)VRAM_BASE_ADDRESS; const int display_mode = 0x4101, hres = 640, vres = 480; int pitch = hres; // value of display-pitch int planes = 1; // count of memory-planes void put_pixel( int x, int y, int color ) { // restrict writing to visible screen if (( x < 0 )||( x >= hres )) return; if (( y < 0 )||( y >= vres )) return; int vram_plane, vram_index, map_mask; int pixel_offset = y * pitch + x; switch( planes ) { case 1: vram[ pixel_offset ] = color; break; case 4: vram_index = pixel_offset / 4; vram_plane = pixel_offset % 4; map_mask = ( 1 << vram_plane ); outw( ( map_mask << 8 )|0x02, 0x3C4 ); vram[ vram_index ] = color; break; } } void draw_rectangle( int x, int y, int h, int v, int color ) { int minx = x, miny = y, maxx = x+h-1, maxy = y+v-1; do { put_pixel( x, y, color ); ++x; } while ( x < maxx ); do { put_pixel( x, y, color ); ++y; } while ( y < maxy ); do { put_pixel( x, y, color ); --x; } while ( x > minx ); do { put_pixel( x, y, color ); --y; } while ( y > miny ); } int map_system_memory( int base, int size ) { int fd = open( "/dev/vram", O_RDWR ); if ( fd < 0 ) { perror( "/dev/vram" ); return -1; } int prot = PROT_READ | PROT_WRITE; int flag = MAP_FIXED | MAP_SHARED; void *mm = (void*)base; if ( mmap( mm, size, prot, flag, fd, 0 ) == MAP_FAILED ) { perror( "mmap" ); return -1; } close( fd ); } void tweak_the_display_mode( void ) { // VGA Sequencer's Memory-Mode Register (index 4) outw( 0x0604, 0x3C4 ); // Disable Chain-4 mode getchar(); // CRT Controller's Underline Location Register (index 0x14) outw( 0x0014, 0x3D4 ); // Turn off DWORD Mode getchar(); // CRT Controller's Mode Control Register (index 0x17h) outw( 0xE317, 0x3D4 ); // Turn on BYTE Mode getchar(); // adjust software display-variable (for put_pixel switch) planes = 4; } void fullscreen_pattern_fill( unsigned long *pattern ) { // demonstrates "parallel programming" (i.e., one instruction // is used to simultaneously modify sixteen adjacent pixels outw( 0x0F02, 0x3C4 ); // enable writing to all planes unsigned long *dstn = (unsigned long*)vram; for (int v = 0; v < vres; v+=4) for (int i = 0; i < 4; i++) { unsigned long line = pattern[ ( v / 4 ) % 4 ]; for (int h = 0; h < hres/16; h++) dstn[ h ] = line; dstn += hres/16; } } int main( int argc, char **argv ) { if ( iopl( 3 ) ) { perror( "iopl" ); exit(1); } system( "/sbin/insmod vram.o" ); map_system_memory( VRAM_BASE_ADDRESS, VGA_MEMORY_LENGTH ); struct termios otty; tcgetattr( 0, &otty ); struct termios tty = otty; tty.c_lflag &= ~( ICANON | ECHO | ISIG ); tty.c_cc[ VMIN ] = 1; tty.c_cc[ VTIME ] = 0; tcsetattr( 0, TCSAFLUSH, &tty ); // enter graphics mode char command[ 40 ]; sprintf( command, " clear ; mode3 %d ", display_mode ); system( command ); // draw white screen border int white = 15; draw_rectangle( 0, 0, hres, vres, white ); getchar(); // modify VGA registers for Mode-X style memory-addressing tweak_the_display_mode(); getchar(); // draw vertical red line int red = 12; for (int i = 0; i < 480; i++) put_pixel( hres/2, i, red ); getchar(); // draw yellow diagonal line int yellow = 14; for (int i = 0; i < vres; i++) put_pixel( i, i, yellow ); getchar(); // draw purple border int purple = 13; draw_rectangle( 3, 3, hres-6, vres-6, purple ); getchar(); // create random 4x4 pattern unsigned char pattern[ 16 ]; for (int i = 0; i < 16; i++) pattern[ i ] = random(); fullscreen_pattern_fill( (unsigned long*)pattern ); getchar(); // leave graphics mode system( " mode3 3 " ); tcsetattr( 0, TCSAFLUSH, &otty ); }