/* * scr_gfx.hgc: * IBM PC screen handling, Hercules adapter * (translated and adapted from Gnuplot's hrcgraph.asm) */ static char GFXid[] = "$Header: scr_gfx.hgc,v 1.1 89/04/13 16:11:40 pkern Exp $"; /* video mode parameters */ unsigned int txt_mode=0x07, txt_addr=0xb000; unsigned int avm_mode=0, avm_addr=0; unsigned int gfx_mode=0x07, gfx_addr=0xb800; unsigned int gfx_xres=720, gfx_yres=348, gfx_numclr=2; /* Hercules graphics nitty-gritty */ static uchar msk; static unsigned int ofs; #define GB(a) *((uchar far *)0xb8000000+a) #define GMASK(a) (0x80 >> ((a) & 7)) #define GBOFS(a,b) (90*((b)>>2) + ((a)>>3) + ((b)<<13)) #define BOINK(a) if (a) GB(ofs) |= msk; else GB(ofs) &= ~msk; #define GPEEK ((GB(ofs) & msk) == msk) /* * HCtrl_Port equ 03B8H ; Hercules 6845 control port IO addr * HIndx_Port equ 03B4H ; Hercules 6845 index port IO addr * HScrn_Enable equ 008h ; Control port bit to enable video * HCh_Mode equ 020h ; Character output mode * HGr_Mode equ 082h ; Graphics output mode page 1 */ #define HCtrl_Port 0x03B8 #define HIndx_Port 0x03B4 #define HScrn_Enable 0x08 #define HCh_Mode 0x20 #define HGr_Mode 0x82 #define nPARMS 12 static uchar HCh_Parms[nPARMS] = { 0x61, 0x50, 0x52, 0x0F, 0x19, 0x06, 0x19, 0x19, 0x02, 0x0D, 0x0B, 0x0C }; static uchar HGr_Parms[nPARMS] = { 0x35, 0x2D, 0x2E, 0x07, 0x5B, 0x02, 0x57, 0x57, 0x02, 0x03, 0x00, 0x00 }; static setParms(initParms, pcnt) uchar initParms[], pcnt; { uchar i; for (i = 0; i < pcnt; i++) { outportb(HIndx_Port, i); outportb(HIndx_Port+1, initParms[i]); } } static HVmode(grafix) int grafix; { uchar mode, *parms; if (grafix) { gfx_erase(); mode = HGr_Mode; parms = HGr_Parms; } else { mode = HCh_Mode; parms = HCh_Parms; } outportb(HCtrl_Port, mode); setParms(parms, nPARMS); outportb(HCtrl_Port, HScrn_Enable); } init_gfx() { extern uchar interlace, gcolour; extern int gmax_x, gmax_y, gmax_clr; HVmode(interlace); gmax_x = gfx_xres; gmax_y = gfx_yres; gmax_clr = gfx_numclr; gcolour = gmax_clr-1; } /* gfx_erase -- clear or hide the graphics screen */ gfx_erase() { unsigned int far *s; s = (unsigned int far *) MK_FP(gfx_addr, 0); memset(s, (int)0, 0x4000); } gfx_colour(n) uchar n; { return(n>0); } /* gpeek -- get a pixel's colour */ gpeek(x, y) int x, y; { msk = GMASK(x); ofs = GBOFS(x,y); return(GPEEK); } /* boink -- light a pixel */ boink(x,y,c) int x, y; uchar c; { msk = GMASK(x); ofs = GBOFS(x,y); BOINK(c) } /* * hline -- only does horizontal lines (union regulations :-) * (called from bline(), should be optimized for speed). */ hline(x,y,n,c) int x; register int y,n; uchar c; { register int i; if (n < 0) { n = -n; x -= n; if (x < 0) { n += x; x = 0; } } /* #ifdef BIOS */ for (i=x; i < x+n; i++) boink(i, y, c); /* #else */ #ifdef notdef msk = 0xff >> (x&7); /* move mask to end of byte */ for(ofs=GBOFS(x,y); ofs < GBOFS(x+n, y); ofs++) { BOINK(c) /* solid line between end-points */ msk = 0xff; } /* remainder word mask */ msk &= ~(0xff >> ((x+n)&7)); BOINK(c) #endif } /* * vline -- vertical lines only * (again, called from bline(), should be optimized for speed). */ vline(x,y,n,c) int x,y,n; uchar c; { register int i; if (n < 0) { n = -n; y -= n; if (y < 0) { n += y; y = 0; } } /* #ifdef BIOS */ for (i=y; i < y+n; i++) boink(x, i, c); /* #else */ #ifdef notdef msk = GMASK(x); x = x >> 3; for (; n; n--, y++) { ofs = 90*(y>>2) + x + (y<<13); BOINK(c) } #endif } /* * xrun -- optimize search for runs to colour c in x direction * (called from dofill(), should be quicker that gpeek()-ing each pixel) */ xrun(x, y, c, dir) int x, y, dir; uchar c; { uchar cx; extern int gmax_x; /* #ifdef BIOS */ while (0 <= x && x < gmax_x) { cx = gpeek(x, y); /* needs optimizing! */ if (c == cx) break; x += dir; } /* #else */ #ifdef notdef uchar bm; msk = GMASK(x); ofs = GBOFS(x,y); bm = GB(ofs); while (0 <= x && x < gmax_x) { cx = ((bm & msk) == msk); if (c == cx) break; x += dir; msk = GMASK(x); if (((dir > 0) && (x&7) == 0) || ((dir < 0) && (x&7) == 7)) { ofs = GBOFS(x,y); bm = GB(ofs); } } #endif if (c == cx) x -= dir; if (x < 0) return(0); if (x >= gmax_x) return(gmax_x-1); return(x); } /* * (Comment from hrcgraph.asm ...) * compute index into Hercules screen memory for scan line 0. The * remaining seven scan lines are all at fixed offsets from the first. * * Since graphics mode treats the screen as sets of 16x4 "characters", * we need to map an 8x8 real character onto the front or back of * a pair of graphics "characters". The first four scan lines of our * 8x8 character will map to the top graphics "character", and the next * four scan lines map to the graphics character on the "line" (4 scan * lines high) below it. * * For some exotic hardware reason (probably speed), all scan line 0 * bits (i.e. every fourth scan line) are stored in memory locations * 0-2000h in the screen buffer. All scan line 1 bits are stored * 2000h-4000h. Within these banks, they are stored by rows. The first * scan line on the screen (scan line 0 of graphics character row 0) * is the first 45 words of memory in the screen buffer. The next 45 * words are the first scan line graphics row 1, and since graphics * "characters" are 4 bits high, this second scan line is physically * the fifth scan line displayed on the screen. * * SO, to display an 8x8 character, the 1st and 5th rows of dots are * both scan line 0 of the graphics "character", the 2nd and 6th are * scan line 1, and so on. * * The column (0-89) tells which byte in a scan line we need to load. * Since it takes two rows of graphics characters to hold one row of * our characters, column+90 is a index to scan line 4 rows of pixels * higher (n+4). Thus 180 bytes of screen memory in any bank (0h, 2000h, * 4000h, 6000h) represent a row of 8x8 characters. * * The starting location in screen memory for the first scan line of * a character to be displayed will be: (row*180)+column * The 5th scan line will be at: (row*180)+column+90 * * The second and 6th scan lines will be at the above offsets plus * the bank offset of 2000h. The third and 7th, add 4000h and finally * the 4th and 8th, add 6000h. */ #define CON8 8 #define CON180 180 #define IBMROM 0xf000 #define CHARTAB 0xfa6e burpg(c, x, y) int c, x, y; { unsigned int offs; char far *sp, *cp; c &= 0x7f; /* point to the character table */ cp = (char far *) MK_FP(IBMROM, CHARTAB + (CON8 * c)); offs = (CON180 * y) + x; sp = (char far *) MK_FP(gfx_addr, offs); *sp = *cp++; sp += 0x2000; *sp = *cp++; sp += 0x2000; *sp = *cp++; sp += 0x2000; *sp = *cp++; sp = (char far *) MK_FP(gfx_addr, offs+=90); *sp = *cp++; sp += 0x2000; *sp = *cp++; sp += 0x2000; *sp = *cp++; sp += 0x2000; *sp = *cp++; }