-\r
-/*\r
- * Define the port addresses of some VGA registers.\r
- */\r
-#define CRTC_ADDR 0x3d4 /* Base port of the CRT Controller (color) */\r
-\r
-#define SEQU_ADDR 0x3c4 /* Base port of the Sequencer */\r
-#define GRAC_ADDR 0x3ce /* Base port of the Graphics Controller */\r
-#define STATUS_ADDR 0x3DA\r
-\r
-unsigned char *RowsX[600];\r
-unsigned char write_plane, read_plane;\r
-unsigned short text_mask[16] = { 0x0002, 0x0102, 0x0202, 0x0302,\r
- 0x0402, 0x0502, 0x0602, 0x0702,\r
- 0x0802, 0x0902, 0x0A02, 0x0B02,\r
- 0x0C02, 0x0D02, 0x0E02, 0x0F02 };\r
-\r
-\r
-/*\r
- * Make a far pointer to the VGA graphics buffer segment. Your compiler\r
- * might not have the MK_FP macro, but you'll figure something out.\r
- */\r
-byte *vga = (byte *) MK_FP(0xA000, 0);\r
-\r
-\r
-/*\r
- * width and height should specify the mode dimensions. widthBytes\r
- * specify the width of a line in addressable bytes.\r
- */\r
-unsigned width, height, widthBytes;\r
-\r
-/*\r
- * actStart specifies the start of the page being accessed by\r
- * drawing operations. visStart specifies the contents of the Screen\r
- * Start register, i.e. the start of the visible page.\r
- */\r
-unsigned actStart, visStart;\r
-\r
-/*\r
- * set320x200x256_X()\r
- * sets mode 13h, then turns it into an unchained (planar), 4-page\r
- * 320x200x256 mode.\r
- */\r
-void set320x200x256_X(void)\r
- {\r
- union REGS r;\r
-\r
- /* Set VGA BIOS mode 13h: */\r
- r.x.ax = 0x0013;\r
- int86(0x10, &r, &r);\r
-\r
- /* Turn off the Chain-4 bit (bit 3 at index 4, port 0x3c4): */\r
- outpw(SEQU_ADDR, 0x0604);\r
-\r
- /* Turn off word mode, by setting the Mode Control register\r
- of the CRT Controller (index 0x17, port 0x3d4): */\r
- outpw(CRTC_ADDR, 0xE317);\r
-\r
- /* Turn off doubleword mode, by setting the Underline Location\r
- register (index 0x14, port 0x3d4): */\r
- outpw(CRTC_ADDR, 0x0014);\r
-\r
- /* Clear entire video memory, by selecting all four planes, then\r
- writing 0 to entire segment. */\r
- outpw(SEQU_ADDR, 0x0F02);\r
- memset(vga+1, 0, 0xffff); /* stupid size_t exactly 1 too small */\r
- vga[0] = 0;\r
-\r
- /* Update the global variables to reflect dimensions of this\r
- mode. This is needed by most future drawing operations. */\r
- width = 320;\r
- height = 200;\r
-\r
- /* Each byte addresses four pixels, so the width of a scan line\r
- in *bytes* is one fourth of the number of pixels on a line. */\r
- widthBytes = width / 4;\r
-\r
- /* By default we want screen refreshing and drawing operations\r
- to be based at offset 0 in the video segment. */\r
- actStart = visStart = 0;\r
-\r
- /*\r
---------------------\r
-HORIZONTAL SCROLLING\r
---------------------\r
-Horizontal scrolling is essentially the same as vertical scrolling, all\r
-you do is increment or decrement the VGA offset register by 1 instead of\r
-80 as with vertical scrolling.\r
-\r
-However, horizontal scrolling is complicated by two things\r
-\r
- 1. Incrementing the offset register by one actually scrolls by FOUR\r
- pixels (and there are FOUR planes on the VGA, what a coincidence)\r
-\r
- 2. You can't draw the image off the screen and then scroll it on\r
- because of the way the VGA wraps to the next row every 80 bytes\r
- (80 bytes * 4 planes = 320 pixels), if you tried it, you would\r
- actually be drawing to the other side of the screen (which is\r
- entirely visible)\r
-\r
-I'll solve these problems one at a time.\r
-\r
-Firstly, to get the VGA to scroll by only one pixel you use the horizontal\r
-pixel panning (HPP) register. This register resides at\r
-\r
- PORT: 3C0H\r
- INDEX: 13h\r
-\r
-and in real life, you use it like this\r
-\r
------------------ Pixel Panning ---------------\r
-IN PORT 3DAH (this clears an internal\r
- flip-flop of the VGA)\r
-OUT 13H TO PORT 3C0H\r
-OUT value TO PORT 3C0H (where "value" is the\r
- number of pixels to offset)\r
------------------------------------------------\r
-*/\r
-\r
- }\r
-\r
-/*\r
- * setActiveStart() tells our graphics operations which address in video\r
- * memory should be considered the top left corner.\r
- */\r
-void setActiveStart(unsigned offset)\r
- {\r
- actStart = offset;\r
- }\r
-\r
-/*\r
- * setVisibleStart() tells the VGA from which byte to fetch the first\r
- * pixel when starting refresh at the top of the screen. This version\r
- * won't look very well in time critical situations (games for\r
- * instance) as the register outputs are not synchronized with the\r
- * screen refresh. This refresh might start when the high byte is\r
- * set, but before the low byte is set, which produces a bad flicker.\r
- */\r
-void setVisibleStart(unsigned offset)\r
- {\r
- visStart = offset;\r
- outpw(CRTC_ADDR, 0x0C); /* set high byte */\r
- outpw(CRTC_ADDR+1, visStart >> 8);\r
- outpw(CRTC_ADDR, 0x0D); /* set low byte */\r
- outpw(CRTC_ADDR+1, visStart & 0xff);\r
- }\r
-\r
-/*\r
- * setXXXPage() sets the specified page by multiplying the page number\r
- * with the size of one page at the current resolution, then handing the\r
- * resulting offset value over to the corresponding setXXXStart()\r
- * function. The first page is number 0.\r
- */\r
-void setActivePage(int page)\r
- {\r
- setActiveStart(page * widthBytes * height);\r
- }\r
-\r
-void setVisiblePage(int page)\r
- {\r
- setVisibleStart(page * widthBytes * height);\r
- }\r
-\r
-void putPixel_X(int x, int y, byte color)\r
- {\r
- /* Each address accesses four neighboring pixels, so set\r
- Write Plane Enable according to which pixel we want\r
- to modify. The plane is determined by the two least\r
- significant bits of the x-coordinate: */\r
- outp(0x3c4, 0x02);\r
- outp(0x3c5, 0x01 << (x & 3));\r
-\r
- /* The offset of the pixel into the video segment is\r
- offset = (width * y + x) / 4, and write the given\r
- color to the plane we selected above. Heed the active\r
- page start selection. */\r
- vga[(unsigned)(widthBytes * y) + (x / 4) + actStart] = color;\r
-\r
- }\r
-\r
-byte getPixel_X(int x, int y)\r
- {\r
- /* Select the plane from which we must read the pixel color: */\r
- outpw(GRAC_ADDR, 0x04);\r
- outpw(GRAC_ADDR+1, x & 3);\r
-\r
- return vga[(unsigned)(widthBytes * y) + (x / 4) + actStart];\r
-\r
- }\r
-\r
-void set320x240x256_X(void)\r
- {\r
- /* Set the unchained version of mode 13h: */\r
- set320x200x256_X();\r
-\r
- /* Modify the vertical sync polarity bits in the Misc. Output\r
- Register to achieve square aspect ratio: */\r
- outp(0x3C2, 0xE3);\r
-\r
- /* Modify the vertical timing registers to reflect the increased\r
- vertical resolution, and to center the image as good as\r
- possible: */\r
- outpw(0x3D4, 0x2C11); /* turn off write protect */\r
- outpw(0x3D4, 0x0D06); /* vertical total */\r
- outpw(0x3D4, 0x3E07); /* overflow register */\r
- outpw(0x3D4, 0xEA10); /* vertical retrace start */\r
- outpw(0x3D4, 0xAC11); /* vertical retrace end AND wr.prot */\r
- outpw(0x3D4, 0xDF12); /* vertical display enable end */\r
- outpw(0x3D4, 0xE715); /* start vertical blanking */\r
- outpw(0x3D4, 0x0616); /* end vertical blanking */\r
-\r
- /* Update mode info, so future operations are aware of the\r
- resolution */\r
- height = 240;\r
-\r
-//#pragma aux mxSetVirtualScreen "_"\r
-//void mxSetVirtualScreen(unsigned short int width, unsigned short int height);\r
-mxSetVirtualScreen(480,360);\r
- }\r
-\r
-\r
-/*-----------XXXX-------------*/\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// //\r
-// WaitRetrace() - This waits until you are in a Verticle Retrace. //\r
-// //\r
-/////////////////////////////////////////////////////////////////////////////\r
-void wait_for_retrace(void)\r
-{\r
- while (!(inp(STATUS_ADDR) & 0x08));\r
-}\r