//------------------------------------------------------------------- // mymode.cpp // // Here we reprogram the CRT controller registers for a custom // 256-color display-mode having screen-resolution 576-by-432. // // compile using: $ g++ mymode.cpp int86.cpp -o mymode // // programmer: ALLAN CRUSE // written on: 01 DEC 2003 // revised on: 11 NOV 2005 -- replace 'svgalib' with 'int86()' //------------------------------------------------------------------- #include // for printf(), perror() #include // for open() #include // for exit() #include // for lseek() #include // for tcgetattr(), tcsetattr() #include // for mmap() #include // for inb(), outb() #include "int86.h" // for init8086(), int86() #define CRTC_PORT 0x3D4 unsigned char *vram = (unsigned char*)0xA0000000; int vesa_mode = 0x4101, hres = 640, vres = 480; struct vm86plus_struct vm; unsigned char crtc_original[ 25 ], crtc_modified[ 25 ]; int pitch = 640; void draw_the_scene( int wide, int high, int fgcolor, int bgcolor ); void capture_crtc_registers( unsigned char *crtc ) { for (int i = 0; i < 25; i++) { outb( i, CRTC_PORT ); crtc[ i ] = inb( CRTC_PORT+1 ); } } void display_crtc_registers( unsigned char *crtc ) { for (int i = 0; i < 25; i++) printf( "%02X ", crtc[ i ] ); printf( "\n" ); } 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 { vram[ y*pitch + x ] = color; ++x; } while ( x < maxx ); do { vram[ y*pitch + x ] = color; ++y; } while ( y < maxy ); do { vram[ y*pitch + x ] = color; --x; } while ( x > minx ); do { vram[ y*pitch + x ] = color; --y; } while ( y > miny ); } void reprogram_crtc_registers( void ) { capture_crtc_registers( crtc_original ); //------------------------------------------------------ // 0. Unlock access to CRTC timing registers (i.e., by // clearing highest bit in Vertl Retrace End register //------------------------------------------------------ outb( 0x11, CRTC_PORT ); // Vertl Retrace End int vrt_end = inw( CRTC_PORT ); vrt_end &= ~0x8000; outw( vrt_end, CRTC_PORT ); //------------------------------------------------------ // 1. Change HORIZONTAL RESOLUTION of displayed image // from 80-characters to 72-characters (640 to 576) // i.e., change register-value from 0x4F to 0x47 //------------------------------------------------------ outw( 0x4701, CRTC_PORT ); // Horiz Display End getchar(); //------------------------------------------------------ // 2. Change VERTICAL RESOLUTION of displayed image // from 480-scanlines to 432-scanlines // i.e., change register-value from 0xDF to 0xAF //------------------------------------------------------ outw( 0xAF12, CRTC_PORT ); // Vertl Display End getchar(); //------------------------------------------------------ // 3. Shift POSITION of displayed image to the right // by starting horizontal retrace 5 characters sooner // i.e., change register-value from 0x55h to 0x50h //------------------------------------------------------ outw( 0x5004, CRTC_PORT ); // Horiz Retrace Start getchar(); //------------------------------------------------------ // 4. Shift POSITION of displayed image downward // by starting vertical retrace 15 scanlines sooner // i.e., change register-value from 0xE9h to 0xDAh //------------------------------------------------------ outw( 0xDA10, CRTC_PORT ); // Vertl Retrace Start getchar(); //------------------------------------------------------ // 5. Reduce PITCH OFFSET of the displayed image // by clipping 8 characters from every scanline // i.e., change register-value from 0x50h to 0x58h //------------------------------------------------------ outw( 0x4813, CRTC_PORT ); // CRTC Offset Register getchar(); capture_crtc_registers( crtc_modified ); } int main( int argc, char **argv ) { // map the video memory to userspace int fd = open( "/dev/vram", O_RDWR ); if ( fd < 0 ) { perror( "/dev/vram" ); return -1; } int size = lseek( fd, 0, SEEK_END ); int prot = PROT_READ | PROT_WRITE; int flag = MAP_FIXED | MAP_SHARED; if ( mmap( (void*)vram, size, prot, flag, fd, 0 ) == MAP_FAILED ) { perror( "mmap" ); return -1; } // reprogram terminal for noncanonical keyboard-input 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 init8086(); vm.regs.eax = 0x4F02; vm.regs.ebx = vesa_mode; int86( 0x10, vm ); // draw a screen border int color = 15; draw_rectangle( 0, 0, hres, vres, color ); getchar(); // draw a solid red circle against a green background int wide = hres, high = vres, red = 4, green = 2; draw_the_scene( wide, high, red, green ); getchar(); // draw a yellow border around new screen dimensions int yellow = 14; draw_rectangle( 0, 0, 576, 432, yellow ); getchar(); // step through reprogramming of five CRTC registers reprogram_crtc_registers(); // redraw earlier scene to conform with new dimensions wide = 576, high = 432, pitch = 576; draw_the_scene( wide, high, red, green ); getchar(); draw_rectangle( 0, 0, wide, high, yellow ); getchar(); // leave graphics mode and restore canonical terminal mode vm.regs.eax = 0x0003; int86( 0x10, vm ); tcsetattr( 0, TCSAFLUSH, &otty ); // show CRTC register-values before and after modifications display_crtc_registers( crtc_original ); display_crtc_registers( crtc_modified ); printf( "\n" ); } void draw_the_scene( int wide, int high, int fgcolor, int bgcolor ) { float r = vres/4; // radius for the circle // main loop iterates through each pixel-location for (int y = 1; y < high-1; y++) for (int x = 1; x < wide-1; x++) { // pixels inside circle are painted with forecolor, // pixels outside circle are painted with backcolor float dx = x - wide/2; float dy = y - high/2; float sq = dx*dx + dy*dy; int color = ( sq < r*r ) ? fgcolor : bgcolor; vram[ y * pitch + x ] = color; } }