Page 1 of 1

Setting VGA 640*480 mode without interrupts or V8086

Posted: Sat Apr 25, 2015 3:05 am
by osdever
I need to switch to VGA 640*480 graphics mode, but i can't use interrupts and V8086. How to change graphics mode without interrupts and V8086 (e.g. out* and in*)?

Re: Setting VGA 640*480 mode without interrupts or V8086

Posted: Sat Apr 25, 2015 3:59 am
by Brendan
Hi,
catnikita255 wrote:I need to switch to VGA 640*480 graphics mode, but i can't use interrupts and V8086. How to change graphics mode without interrupts and V8086 (e.g. out* and in*)?
For which specific video card when it's using which specific video mode beforehand?

If you like potentially dodgy hacks; you can cross your fingers and hope the previous video mode wasn't an "SVGA or better" mode and assume the video card is using ancient "VGA compatibility", and assume that this compatibility is "good enough" (e.g. closer to 99% compatible at the hardware level rather than just 80% compatible); then you can put a Michael Jackson cassette tape in your walkman (to get that authentic 1980s vibe happening) and diddle with the "VGA" hardware directly. 8)


Cheers,

Brendan

Re: Setting VGA 640*480 mode without interrupts or V8086

Posted: Sat Apr 25, 2015 7:55 am
by osdever
I'm read it, but how do i write the values to the registers? I'm found the tutorial, but it's not opening =(. This is the tutorial: http://www.osdever.net/index.php/tutori ... UI_tut.pdf. Is anybody has a copy of it?

Re: Setting VGA 640*480 mode without interrupts or V8086

Posted: Sat Apr 25, 2015 8:52 am
by Techel
The correct way is really to use the BIOS.
catnikita255 wrote:I'm read it, but how do i write the values to the registers? I'm found the tutorial, but it's not opening =(. This is the tutorial: http://www.osdever.net/index.php/tutori ... UI_tut.pdf. Is anybody has a copy of it?
with in/out ?

Re: Setting VGA 640*480 mode without interrupts or V8086

Posted: Wed Apr 29, 2015 10:21 am
by 0fb1d8
Use the code below:
the functions are documented with comments, showing the registers for the parameters.
Use set_mode_0x13 to switch to 640 * 480 VGA mode, and put_0x13_pixel for pixel plotting.

Hope this helps!

Code: Select all

[BITS 32]

; symbol exports
[GLOBAL set_mode_0x03]
[GLOBAL set_mode_0x13]
[GLOBAL put_0x13_pixel]

    ;-------------------;
    ;   VGA palettes    ;
    ;-------------------;

         palette256      db   00, 00, 00, 00, 10, 41, 12, 28, 18, 02, 43, 22, 35
                         db   19, 09, 58, 00, 00, 57, 35, 12, 43, 43, 47, 24, 24
                         db   28, 20, 24, 60, 10, 60, 15, 31, 47, 63, 62, 56, 20
                         db   60, 56, 22, 63, 61, 36, 63, 63, 63, 00, 00, 00, 05
                         db   05, 05, 08, 08, 08, 11, 11, 11, 14, 14, 14, 17, 17
                         db   17, 20, 20, 20, 24, 24, 24, 28, 28, 28, 32, 32, 32
                         db   36, 36, 36, 40, 40, 40, 45, 45, 45, 50, 50, 50, 56
                         db   56, 56, 63, 63, 63, 13, 12, 15, 15, 16, 22, 17, 20
                         db   29, 19, 24, 36, 21, 28, 43, 23, 31, 50, 25, 34, 57
                         db   26, 42, 63, 00, 15, 02, 01, 22, 04, 02, 29, 06, 03
                         db   36, 08, 04, 43, 10, 05, 50, 12, 06, 57, 14, 20, 63
                         db   40, 18, 06, 07, 25, 12, 11, 33, 17, 14, 40, 23, 18
                         db   48, 28, 21, 55, 34, 25, 62, 39, 27, 63, 48, 36, 15
                         db   03, 02, 22, 06, 04, 29, 09, 06, 36, 12, 08, 43, 15
                         db   10, 50, 18, 12, 57, 21, 14, 63, 28, 20, 15, 00, 00
                         db   22, 07, 00, 29, 15, 00, 36, 23, 00, 43, 31, 00, 50
                         db   39, 00, 57, 47, 00, 63, 55, 00, 15, 05, 03, 22, 11
                         db   07, 29, 17, 11, 36, 23, 15, 43, 29, 19, 50, 35, 23
                         db   57, 41, 27, 63, 53, 34, 28, 14, 12, 33, 20, 14, 38
                         db   26, 16, 43, 32, 18, 48, 38, 20, 53, 44, 22, 58, 50
                         db   24, 63, 56, 30, 05, 05, 06, 10, 10, 13, 15, 15, 20
                         db   20, 20, 27, 25, 25, 34, 30, 30, 41, 35, 35, 48, 44
                         db   44, 63, 03, 06, 05, 05, 11, 09, 07, 16, 13, 09, 21
                         db   17, 11, 26, 21, 13, 31, 25, 15, 36, 29, 20, 48, 38
                         db   06, 06, 07, 13, 13, 15, 20, 20, 23, 27, 27, 31, 34
                         db   34, 39, 41, 41, 47, 48, 48, 55, 57, 57, 63, 06, 15
                         db   04, 12, 22, 08, 18, 29, 12, 24, 36, 16, 30, 43, 20
                         db   36, 50, 24, 42, 57, 28, 54, 63, 35, 15, 10, 10, 22
                         db   16, 16, 29, 21, 21, 36, 27, 27, 43, 32, 32, 50, 38
                         db   38, 57, 43, 43, 63, 54, 54, 15, 15, 06, 22, 22, 12
                         db   29, 29, 18, 36, 36, 24, 43, 43, 30, 50, 50, 36, 57
                         db   57, 42, 63, 63, 54, 02, 04, 14, 06, 12, 21, 10, 20
                         db   28, 14, 28, 35, 18, 36, 42, 22, 44, 49, 26, 52, 56
                         db   36, 63, 63, 18, 04, 14, 24, 08, 21, 31, 12, 28, 37
                         db   16, 35, 44, 20, 42, 50, 24, 49, 57, 28, 56, 63, 38
                         db   63, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
                         db   00, 00, 00, 00, 00, 00, 00, 00, 00, 53, 44, 22, 09
                         db   08, 12, 16, 14, 16, 22, 21, 20, 29, 27, 24, 35, 34
                         db   28, 42, 40, 32, 48, 47, 36, 57, 56, 43, 08, 12, 16
                         db   14, 16, 22, 21, 20, 29, 27, 24, 35, 34, 28, 42, 40
                         db   32, 48, 47, 36, 57, 56, 43, 63, 13, 09, 11, 21, 16
                         db   15, 27, 22, 18, 36, 29, 22, 42, 35, 25, 51, 42, 29
                         db   57, 48, 32, 63, 56, 39, 06, 14, 09, 12, 21, 14, 18
                         db   27, 22, 24, 33, 28, 30, 39, 36, 36, 46, 42, 42, 52
                         db   47, 50, 59, 53, 00, 00, 00, 00, 00, 00, 00, 00, 00
                         db   00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
                         db   00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
                         db   00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
                         db   00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
                         db   00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
                         db   00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
                         db   00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
                         db   00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
                         db   00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
                         db   00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
                         db   00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
                         db   00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
                         db   00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
                         db   00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
                         db   00

         palette16       db   00, 00, 00, 00, 00, 42, 00, 42, 00, 00, 42, 42, 42
                         db   00, 00, 42, 00, 42, 42, 21, 00, 42, 42, 42, 21, 21
                         db   21, 21, 21, 63, 21, 63, 21, 21, 63, 63, 63, 21, 21
                         db   63, 21, 63, 63, 63, 21, 63, 63, 63

    ;---------------------;
    ;  VGA mode values.   ;
    ;---------------------;
         mode0x03        db   0x67, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x5F, 0x4F
                         db   0x50, 0x82, 0x55, 0x81, 0xBF, 0x1F, 0x00, 0x4F, 0x0E
                         db   0x0F, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x0E, 0x8F, 0x28
                         db   0x01, 0x96, 0xB9, 0xA3, 0xFF, 0x00, 0x00, 0x00, 0x00
                         db   0x00, 0x10, 0x0E, 0x00, 0xFF, 0x00, 0x01, 0x02, 0x03
                         db   0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B, 0x3C
                         db   0x3D, 0x3E, 0x3F, 0x0C, 0x00, 0x0F, 0x08, 0x00

         mode0x13        db   0x63, 0x00, 0x03, 0x01, 0x0F, 0x00, 0x0E, 0x5F, 0x4F
                         db   0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0x41, 0x00
                         db   0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x0E, 0x8F, 0x28
                         db   0x40, 0x96, 0xB9, 0xA3, 0xFF, 0x00, 0x00, 0x00, 0x00
                         db   0x00, 0x40, 0x05, 0x0F, 0xFF, 0x00, 0x01, 0x02, 0x03
                         db   0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C
                         db   0x0D, 0x0E, 0x0F, 0x41, 0x00, 0x0F, 0x00, 0x00


         vga_buff        dd   0

;---------------------------------;
;  sets the screen to mode 0x03   ;
;---------------------------------;
set_mode_0x03:
         pushad
         push    ax

         mov     esi, mode0x03
         call    set_regs

         ;call    load_font                           ; IT WORKS!! FINALLY!

         mov     esi, palette16
         call    set_palette16

         pop     ax
         cmp     ax, 1
         jne     .cont
         ;call    cls                                 ; in text.inc
    .cont:

         popad
         ret



;---------------------------------;
;  sets the screen to mode 0x13   ;
;---------------------------------;
set_mode_0x13:
         pushad
         push    ax

         mov     esi, mode0x13
         call    set_regs

         mov     esi, palette256
         call    set_palette256

         pop     ax
         cmp     ax, 1
         jne     .cont
         mov     edi, 0xa0000                        ; write directly to mem
         mov     ax, 0x0000                          ; clear all 256kb with color 0
         mov     ecx, 0x20000                        ; 256kb, 0x20000 = (256*1024)/2
         rep     stosw                               ; by wordwrites
    .cont:

         popad
         ret

;------------------------------------;
;  put a pixel at x, y with color    ;
;           used only in mode 0x13   ;
;                                    ;
; input:   bx = x                    ;
;          cx = y                    ;
;          al = color                ;
;                                    ;
; output:  none.                     ;
;------------------------------------;
put_0x13_pixel:
         push    ax
         push    bx
         push    cx
         push    edi

         mov     edi, 0xa0000                        ; directly to mem
         add     di, bx
         mov     bx, cx
         shl     cx, 8
         shl     bx, 6
         add     cx, bx
         add     di, cx
         stosb

         pop     edi
         pop     cx
         pop     bx
         pop     ax
         ret


;-----------------------------------------------------;
;  put a sprite at x, y.  only for mode 0x13          ;
;                                                     ;
; input:   ax  = x, bx = y, cx = width, dx = height   ;
;          esi = pointer to sprite                    ;
;                                                     ;
; output:  none.                                      ;
;-----------------------------------------------------;
put_0x13_sprite:
         pushad                                      ; this was a
    .row_loop:                                       ; nightmare to write.
         dec     dx                                  ; guess how many times
         push    cx                                  ; i got lost in the push
         push    ax                                  ; and pops here.. ;)
    .col_loop:                                       ; not to mention what
         dec     cx                                  ; time it was when i wrote
         push    ax                                  ; it.. :P
         push    bx
         push    cx
         mov     cx, bx
         mov     bx, ax
         lodsb
         call    put_0x13_pixel
         pop     cx
         pop     bx
         pop     ax
         inc     ax
         cmp     cx, 0
         jne     .col_loop
         pop     ax
         pop     cx
         inc     bx
         cmp     dx, 0
         jne     .row_loop
         popad
         ret


;---------------------------------------------;
;  sets the palette (256 colors)              ;
;                                             ;
; input:  esi = palette.                      ;
; output: none.                               ;
;---------------------------------------------;
set_palette256:
         push    ax
         push    cx
         push    dx

         xor     cx, cx
    .l1:
         mov     dx, 0x03C8
         mov     al, cl                              ; color no. = loop no.
         out     dx, al
         inc     dx                                  ; port 0x3C9
         mov     al, byte [esi]                      ; red
         out     dx, al
         inc     esi
         mov     al, byte [esi]                      ; green
         out     dx, al
         inc     esi
         mov     al, byte [esi]                      ; blue
         out     dx, al
         inc     esi

         inc     cx
         cmp     cx, 256
         jl      .l1

         pop     dx
         pop     cx
         pop     ax
         ret


;---------------------------------------------;
;  sets the palette (16 colors)               ;
;                                             ;
; input:  esi = pointer to palette.           ;
; output: none.                               ;
;---------------------------------------------;
set_palette16:
         push    ax
         push    cx
         push    dx

         xor     cx, cx
    .l1:
         mov     dx, 0x3DA
         in      al, dx
         mov     al, cl                              ; color no.
         mov     dx, 0x3C0
         out     dx, al
         inc     dx                                  ; port 0x3C1
         in      al, dx
         mov     dx, 0x3C8
         out     dx, al

         inc     dx                                  ; port 0x3C9
         mov     al, byte [esi]                      ; red
         out     dx, al
         inc     esi
         mov     al, byte [esi]                      ; green
         out     dx, al
         inc     esi
         mov     al, byte [esi]                      ; blue
         out     dx, al
         inc     esi

         inc     cx
         cmp     cx, 16
         jl      .l1

         mov     dx, 0x3DA
         in      al, dx
         mov     al, 0x20
         mov     dx, 0x3C0
         out     dx, al

         pop     dx
         pop     cx
         pop     ax
         ret



;---------------------------------;
;  Set VGA regs to choosen mode   ;
;           internal use.         ;
;---------------------------------;
set_regs:
         cli
         mov     dx, 0x3C2
         lodsb
         out     dx, al

         mov     dx, 0x3DA
         lodsb
         out     dx, al

         xor     ecx, ecx
         mov     dx, 0x3C4
    .l1:
         lodsb
         xchg    al, ah
         mov     al, cl
         out     dx, ax
         inc     ecx
         cmp     cl, 4
         jbe     .l1

         mov     dx, 0x3D4
         mov     ax, 0x0E11
         out     dx, ax

         xor     ecx, ecx
         mov     dx, 0x3D4
    .l2:
         lodsb
         xchg    al, ah
         mov     al, cl
         out     dx, ax
         inc     ecx
         cmp     cl, 0x18
         jbe     .l2

         xor     ecx, ecx
         mov     dx, 0x3CE
    .l3:
         lodsb
         xchg    al, ah
         mov     al, cl
         out     dx, ax
         inc     ecx
         cmp     cl, 8
         jbe     .l3

         mov     dx, 0x3DA
         in      al, dx

         xor     ecx, ecx
         mov     dx, 0x3C0
    .l4:
         in      ax, dx
         mov     al, cl
         out     dx, al
         lodsb
         out     dx, al
         inc     ecx
         cmp     cl, 0x14
         jbe     .l4

         mov     al, 0x20
         out     dx, al

         sti
         ret
btw, this is what i use in my C code for calling the putpixel routine

Code: Select all

extern void put_0x13_pixel();
void putpixel (uint16_t x, uint16_t y, uint8_t c) {
	__asm__ __volatile__ ("mov %0, %%bx\n\t"
						  "mov %1, %%cx\n\t"
						  "mov %2, %%al"
						  : /* NULL */
						  : "X"(x), "X"(y), "X"(c));
	put_0x13_pixel();
}

Re: Setting VGA 640*480 mode without interrupts or V8086

Posted: Wed Apr 29, 2015 3:06 pm
by Brendan
Hi,
0fb1d8 wrote:Use the code below:
the functions are documented with comments, showing the registers for the parameters.
Use set_mode_0x13 to switch to 640 * 480 VGA mode, and put_0x13_pixel for pixel plotting.
That code only sets mode 0x13 (320*200 with 256 colours) and doesn't set mode 0x12 (640*480 with 16 colours).


Cheers,

Brendan

Re: Setting VGA 640*480 mode without interrupts or V8086

Posted: Thu Apr 30, 2015 10:01 am
by Unsigned
Refer to the IBM VGA register specification to know the meaning of each register so that you can set up any video mode you want. That's what I did to be able to make my routine to set VGA-compatible text and graphic modes. Here is my code:

Code: Select all

typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned int dword;
typedef unsigned long long int qword;

inline byte inb(word port)
{
	byte r;
	asm volatile(
	".intel_syntax noprefix\n\t"
	"in al,dx\n\t"
	".att_syntax"
	:"=a"(r)
	:"d"(port)
	);
	return(r);
}

inline void outb(word port,byte val)
{
	asm volatile(
	".intel_syntax noprefix\n\t"
	"out dx,al\n\t"
	".att_syntax"
	:
	:"d"(port),"a"(val)
	);
}

//constants
#define VGA_CRT 0              //CRT set
#define VGA_ACT 1              //attribute controller set
#define VGA_GEN 2              //general registers set
#define VGA_SEQ 3              //sequencer set
#define VGA_GCT 4              //graphics controller set
#define VGA_OLD 5              //old pallete enable

#define VGA__GEN__MIS 0        //miscellaneous in the generals set
#define VGA__GEN__ST1 1        //status 1 in the generals set, readonly
#define VGA__OLD__ENA 0        //old pallete enable index

#define VGA__GEN_MISC_R 0x3cc  //general miscellaneous, read
#define VGA__GEN_MISC_W 0x3c2  //general miscellaneous, write
#define VGA__GEN_STATUS1 0x3da //general status 1
#define VGA__SEQ_ADDR 0x3c4    //sequencer, address
#define VGA__SEQ_DATA 0x3c5    //sequencer, data
#define VGA__SEQ__RST 0        //sequencer, reset
#define VGA__SEQ__CLK 1        //sequencer, clock mode
#define VGA__SEQ__MAP 2        //sequencer, map selection
#define VGA__SEQ__FNT 3        //sequencer, font selection
#define VGA__SEQ__MEM 4        //sequencer, memory mode
#define VGA__CRT_ADDR 0x3d4    //CRT, address
#define VGA__CRT_DATA 0x3d5    //CRT, data
#define VGA__CRT__HTO 0        //CRT, horizontal total
#define VGA__CRT__HDE 1        //CRT, horizontal display-enable end
#define VGA__CRT__HBS 2        //CRT, horizontal blanking start
#define VGA__CRT__HBE 3        //CRT, horizontal blanking end
#define VGA__CRT__HRS 4        //CRT, horizontal retrace start
#define VGA__CRT__HRE 5        //CRT, horizontal retrace end
#define VGA__CRT__VTO 6        //CRT, vertical total
#define VGA__CRT__MSB 7        //CRT, most significant bits
#define VGA__CRT__PRS 8        //CRT, preset scanline
#define VGA__CRT__MSL 9        //CRT, maximum scanline
#define VGA__CRT__CSL 10       //CRT, cursor start
#define VGA__CRT__CEL 11       //CRT, cursor end
#define VGA__CRT__SAH 12       //CRT, start address (high)
#define VGA__CRT__SAL 13       //CRT, start address (low)
#define VGA__CRT__CLH 14       //CRT, cursor location (high)
#define VGA__CRT__CLL 15       //CRT, cursor location (low)
#define VGA__CRT__VRS 16       //CRT, vertical retrace start
#define VGA__CRT__VRE 17       //CRT, vertical retrace end
#define VGA__CRT__VDE 18       //CRT, vertical display-enable end
#define VGA__CRT__OFF 19       //CRT, offset (logical line width)
#define VGA__CRT__ULL 20       //CRT, underline location
#define VGA__CRT__VBS 21       //CRT, vertical blanking start
#define VGA__CRT__VBE 22       //CRT, vertical blanking end
#define VGA__CRT__MOD 23       //CRT, mode
#define VGA__CRT__SSL 24       //CRT, line compare (split screen line)
#define VGA__GCT_ADDR 0x3ce    //graphics controller, address
#define VGA__GCT_DATA 0x3cf    //graphics controller, data
#define VGA__GCT__WRV 0        //graphics controller, write value
#define VGA__GCT__WRS 1        //graphics controller, write selection
#define VGA__GCT__COC 2        //graphics controller, color compare
#define VGA__GCT__DRO 3        //graphics controller, data rotate
#define VGA__GCT__RDM 4        //graphics controller, read map
#define VGA__GCT__GMO 5        //graphics controller, graphics mode
#define VGA__GCT__MIS 6        //graphics controller, miscelaneous
#define VGA__GCT__CSE 7        //graphics controller, color selection
#define VGA__GCT__BIT 8        //graphics controller, bit mask
#define VGA__ACT_ADDA 0x3c0    //attribute controller, address and data
#define VGA__ACT_READ 0x3c1    //attribute controller, read
#define VGA__ACT__ATB 16       //attribute controller, attributes
#define VGA__ACT__BOR 17       //attribute controller, border color
#define VGA__ACT__PEN 18       //attribute controller, plane enable
#define VGA__ACT__OFF 19       //attribute controller, offset
#define VGA__ACT__CSE 20       //attribute controller, color selection
#define VGA__DAC_ADDR_R 0x3c7  //pallete, read address
#define VGA__DAC_ADDR_W 0x3c8  //pallete, write address
#define VGA__DAC_DATA 0x3c9    //pallete, data
#define VGA__DAC_MASK 0x3c6    //pallete, bit mask

//VGA register structure
typedef struct
{
byte
gen_mis,
seq[5],
crt[25],
gct[9],
act[5];
}vgaregs_t;

//tables for horizontal configurations
//SEQ_CLK,SEQ_MEM,CRT_HTO,CRT_HDE,CRT_HBS,CRT_HBE,CRT_HRS,CRT_HRE,CRT_OFF,GCT_GMO,GCT_MIS,ACT_ATB
byte tbl_hor_txt40[12]={0x08,0x00,0x2d,0x27,0x28,0x10,0x2b,0xa0,0x14,0x10,0x0e,0x00};
byte tbl_hor_txt80[12]={0x00,0x00,0x5f,0x4f,0x50,0x02,0x55,0x81,0x28,0x10,0x0e,0x00};
byte tbl_hor_txt90[12]={0x00,0x00,0x6b,0x59,0x5a,0x0e,0x5f,0xac,0x2d,0x10,0x0e,0x00};
                                                    //0x5e,0xaa
byte tbl_hor_gra640[12]={0x01,0x04,0x5f,0x4f,0x50,0x02,0x54,0x80,0x28,0x00,0x05,0x01};
                                                     //0x55,0x81
byte tbl_hor_gra720[12]={0x01,0x04,0x6b,0x59,0x5a,0x0e,0x5e,0xaa,0x2d,0x00,0x05,0x01};
                                                     //0x5f,0xac
byte tbl_hor_gra320[12]={0x01,0x04,0x5f,0x4f,0x50,0x02,0x54,0x80,0x28,0x40,0x05,0x41};
                                                     //0x55,0x81
byte tbl_hor_gra360[12]={0x01,0x04,0x6b,0x59,0x5a,0x0e,0x5e,0xaa,0x2d,0x40,0x05,0x41};
                                                     //0x5f,0xac

//tables for vertical configurations
//GEN_MIS,CRT_VTO,CRT_MSB,CRT_MSL,CRT_VRS,CRT_VRE,CRT_VDE,CRT_VBS,CRT_VBE
byte tbl_ver_txt20_12[9]={0xc0,0x0b,0x3e,0xcb,0xea,0x0c,0xdf,0xe7,0x04};
byte tbl_ver_txt25_8[9]={0x40,0xbf,0x1f,0xc7,0x9c,0x2e,0x8f,0x96,0xb9};
byte tbl_ver_txt25_14[9]={0x80,0xbf,0x1f,0x4d,0x83,0x35,0x5d,0x63,0xba};
byte tbl_ver_txt25_16[9]={0x40,0xbf,0x1f,0x4f,0x9c,0x2e,0x8f,0x96,0xb9};
byte tbl_ver_txt30_8[9]={0xc0,0x0b,0x3e,0xc7,0xea,0x0c,0xdf,0xe7,0x04};
byte tbl_ver_txt30_16[9]={0xc0,0x0b,0x3e,0x4f,0xea,0x0c,0xdf,0xe7,0x04};
byte tbl_ver_txt40_12[9]={0xc0,0x0b,0x3e,0x4b,0xea,0x0c,0xdf,0xe7,0x04};
byte tbl_ver_txt50_8[9]={0x40,0xbf,0x1f,0x47,0x9c,0x2e,0x8f,0x96,0xb9};
byte tbl_ver_txt60_8[9]={0xc0,0x0b,0x3e,0x47,0xea,0x0c,0xdf,0xe7,0x04};
byte tbl_ver_gra200[9]={0x40,0xbf,0x1f,0x41,0x9c,0x2e,0x8f,0x96,0xb9};
byte tbl_ver_gra240[9]={0xc0,0x0b,0x3e,0x41,0xea,0x0c,0xdf,0xe7,0x04};
byte tbl_ver_gra350[9]={0x80,0xbf,0x1f,0x40,0x83,0x35,0x5d,0x63,0xba};
byte tbl_ver_gra400[9]={0x40,0xbf,0x1f,0x40,0x9c,0x2e,0x8f,0x96,0xb9};
byte tbl_ver_gra480[9]={0xc0,0x0b,0x3e,0x40,0xea,0x0c,0xdf,0xe7,0x04};

//tables for video modes
//SEQ_CLK,ACT_OFF,CRT_MOD
byte tbl_mod_txt8p[]={0x01,0x00,0x00};
byte tbl_mod_txt9p[]={0x00,0x08,0x00};
byte tbl_mod_gra16c[]={0x01,0x00,0x40};
byte tbl_mod_gra256c[]={0x01,0x00,0x40};

//functions

//writes a value in a VGA register
//set is 0 for CRT controller, 1 for attribute controller, 2 for
//generals, 3 for sequencer, 4 for graphics controller, 5 for
//old pallete enable
void VGAWriteReg(byte set, byte index, byte value)
{
	switch(set)
	{
		case VGA_CRT:
			if(index<=24)
			{
				outb(VGA__CRT_ADDR,index);
				outb(VGA__CRT_DATA,value);
			}
			break;
		case VGA_ACT:
			if(index<=20)
			{
				inb(VGA__GEN_STATUS1);
				index=(inb(VGA__ACT_ADDA)&0x20)|index;
				inb(VGA__GEN_STATUS1);
				outb(VGA__ACT_ADDA,index);
				outb(VGA__ACT_ADDA,value);
			}
			break;
		case VGA_GEN:
			if(index==0)
			{
				outb(VGA__GEN_MISC_W,value);
			}
			break;
		case VGA_SEQ:
			if(index<=4)
			{
				outb(VGA__SEQ_ADDR,index);
				outb(VGA__SEQ_DATA,value);
			}
			break;
		case VGA_GCT:
			if(index<=8)
			{
				outb(VGA__GCT_ADDR,index);
				outb(VGA__GCT_DATA,value);
			}
			break;
		case VGA_OLD:
			if(index==0)
			{
				value=value?0x20:0;
				inb(VGA__GEN_STATUS1);
				outb(VGA__ACT_ADDA,value);
			}
			break;
	}
}

//reads a value from a VGA register
//set is 0 for CRT controller, 1 for attribute controller, 2 for
//generals, 3 for sequencer, 4 for graphics controller, 5 for
//old pallete enable
byte VGAReadReg(byte set, byte index)
{
	byte r=0;
	switch(set)
	{
	case VGA_CRT:
		if(index<=24)
		{
			outb(VGA__CRT_ADDR,index);
			r=inb(VGA__CRT_DATA);
		}
		break;
	case VGA_ACT:
		if(index<=20)
		{
			inb(VGA__GEN_STATUS1);
			index=(inb(VGA__ACT_ADDA)&0x20)|index;
			inb(VGA__GEN_STATUS1);
			outb(VGA__ACT_ADDA,index);
			r=inb(VGA__ACT_READ);
		}
		break;
	case VGA_GEN:
		if(index==VGA__GEN__MIS)
		{
			r=inb(VGA__GEN_MISC_R);
		}
		if(index==VGA__GEN__ST1)
		{
			r=inb(VGA__GEN_STATUS1);
		}
		break;
	case VGA_SEQ:
		if(index<=4)
		{
			outb(VGA__SEQ_ADDR,index);
			r=inb(VGA__SEQ_DATA);
		}
		break;
	case VGA_GCT:
		if(index<=8)
		{
			outb(VGA__GCT_ADDR,index);
			r=inb(VGA__GCT_DATA);
		}
		break;
	case VGA_OLD:
		if(index==0)
		{
			inb(VGA__GEN_STATUS1);
			r=(inb(VGA__ACT_ADDA)>>5)&1;
		}
		break;
	}
return(r);
}

//resets the registers in a VGA register structure
void resetregs(vgaregs_t*regs)
{
	dword i;
	byte*p=(byte*)regs;
	for(i=0;i<sizeof(vgaregs_t);i++)
	{
		*p++=0;
	}
	regs->gen_mis=0x23;//enable video memory, normal mode, upper 64KB page
	regs->seq[VGA__SEQ__CLK]=0x02;//set bit to 1
	regs->seq[VGA__SEQ__MAP]=0x0f;//select the 4 planes
	regs->seq[VGA__SEQ__MEM]=0x02;//enable 256KB
	regs->crt[VGA__CRT__HBE]=0x80;//set bit to 1
	regs->crt[VGA__CRT__VRE]=0x30;//disable IRQs
	regs->crt[VGA__CRT__ULL]=31;//underline location
	regs->crt[VGA__CRT__MSB]=0x10;//split screen
	regs->crt[VGA__CRT__MSL]=0x40;
	regs->crt[VGA__CRT__SSL]=0xff;
	regs->crt[VGA__CRT__MOD]=0xa3;//normal mode
	regs->gct[VGA__GCT__BIT]=0xff;//bit mask
	regs->act[VGA__ACT__ATB-16]=0x04;//enable line characters
	regs->act[VGA__ACT__PEN-16]=0x0f;//enable the 4 planes
}

//changes the video mode by writing in all the VGA registers
void vgachangemode(vgaregs_t*regs)
{
	word i;
	//unlock some CRTC registrrs
	VGAWriteReg(VGA_CRT,VGA__CRT__VRE,VGAReadReg(VGA_CRT,VGA__CRT__VRE)&0x7f);
	//enable pallete
	outb(VGA__DAC_MASK,0xff);
	//wait until display-enable start
	//while(!(VGAReadReg(VGA_GEN,VGA__GEN__ST1)&0x08));
	//while(VGAReadReg(VGA_GEN,VGA__GEN__ST1)&0x08);
	//stop sequencer
	VGAWriteReg(VGA_SEQ,VGA__SEQ__RST,0x01);
	//write in the registers
	VGAWriteReg(VGA_GEN,VGA__GEN__MIS,regs->gen_mis);
	for(i=1;i<5;i++)
		VGAWriteReg(VGA_SEQ,i,regs->seq[i]);
	for(i=0;i<25;i++)
		VGAWriteReg(VGA_CRT,i,regs->crt[i]);
	for(i=0;i<9;i++)
		VGAWriteReg(VGA_GCT,i,regs->gct[i]);
	for(i=0;i<5;i++)
		VGAWriteReg(VGA_ACT,i+16,regs->act[i]);
	//reset old pallete
	VGAWriteReg(VGA_OLD,VGA__OLD__ENA,0);
	for(i=0;i<16;i++)
		VGAWriteReg(VGA_ACT,i,i);
	VGAWriteReg(VGA_OLD,VGA__OLD__ENA,1);
	//resume sequencer
	VGAWriteReg(VGA_SEQ,VGA__SEQ__RST,0x03);
}

//selects the text plane
void settextplane(void)
{
	VGAWriteReg(VGA_GCT,VGA__GCT__GMO,0x10);
	VGAWriteReg(VGA_GCT,VGA__GCT__MIS,(VGAReadReg(VGA_GCT,VGA__GCT__MIS)&0x0c)|2);
	VGAWriteReg(VGA_SEQ,VGA__SEQ__MAP,0x03);
	VGAWriteReg(VGA_GCT,VGA__GCT__RDM,1);
	VGAWriteReg(VGA_SEQ,VGA__SEQ__MEM,0x02);
}

//selects the font plane
void setfontplane(void)
{
	VGAWriteReg(VGA_GCT,VGA__GCT__GMO,0x00);
	VGAWriteReg(VGA_GCT,VGA__GCT__MIS,VGAReadReg(VGA_GCT,VGA__GCT__MIS)&0x0c);
	VGAWriteReg(VGA_SEQ,VGA__SEQ__MAP,0x04);
	VGAWriteReg(VGA_GCT,VGA__GCT__RDM,2);
	VGAWriteReg(VGA_SEQ,VGA__SEQ__MEM,0x06);
}

//modifies the VGA pallete
//pal=pointer to the first pallete color to be used
//first=first color to modify
//num=number of colors to modify
void VGASetPal(byte*pal,byte first,word num)
{
	if((num+first)>256)num=256-first;
	if(!num)return;
	num*=3;
	outb(VGA__DAC_ADDR_W,first);
	while(num--)
	{
		outb(VGA__DAC_DATA,(*pal)>>2);
		pal++;
	}
}

//obtains the VGA pallete
//pal=pointer to the first pallete color to be overwritten
//first=first color to read
//num=number of colors to read
void VGAGetPal(byte*pal,byte first,word num)
{
	if((num+first)>256)num=256-first;
	if(!num)return;
	num*=3;
	outb(VGA__DAC_ADDR_R,first);
	while(num--)
	{
		*pal=inb(VGA__DAC_DATA)<<2;
		pal++;
	}
}

//puts the text cursor in the x,y coordinates
//w is the visual screen width in characters
void VGAGotoXY(byte x,byte y,byte w)
{
	word c;
	c=y;c*=w;
	c+=x;
	VGAWriteReg(VGA_CRT,VGA__CRT__CLH,c>>8);
	VGAWriteReg(VGA_CRT,VGA__CRT__CLL,c);
}

//gets the cursor coordinates and returns them in x,y
//w is the visual screen width in characters
void VGAWhereXY(byte*x,byte*y,byte w)
{
	word c;
	c=VGAReadReg(VGA_CRT,VGA__CRT__CLH);
	c<<=8;
	c|=VGAReadReg(VGA_CRT,VGA__CRT__CLL);
	*x=c%w;
	*y=c/w;
}

//changes the text cursor appearence
//y=first line
//h=block height
void VGASetCursor(byte y,byte h)
{
	VGAWriteReg(VGA_CRT,VGA__CRT__CSL,y&31);
	VGAWriteReg(VGA_CRT,VGA__CRT__CEL,(y+h-1)&31);
}

//gets the text cursor appearence
//y=first line
//h=block height
void VGAGetCursor(byte*y,byte*h)
{
	*y=VGAReadReg(VGA_CRT,VGA__CRT__CSL)&31;
	*h=VGAReadReg(VGA_CRT,VGA__CRT__CEL)&31;
	*h-=*y;
	(*h)++;
}

//enables or disables the text cursor
void VGACursor(byte e)
{
	e=e?0:0x20;
	VGAWriteReg(VGA_CRT,VGA__CRT__CSL,(VGAReadReg(VGA_CRT,VGA__CRT__CSL)&31)|e);
}/*end function*/

//modifies the text font
//fnt=pointer to the first font character to be used
//ch=character height in the font
//first=first character in the VGA font to modify
//num=number of characters to modify
void VGASetFont(byte*fnt,byte ch,word first,word num)
{
	byte*v=(byte*)0xb8000;
	word i,j;
	if((num+first)>512)num=512-first;
	if(!num)return;
	v+=first*32;
	setfontplane();
	for(i=0;i<num;i++)
	{
		for(j=0;j<ch;j++)
		{
			v[j]=fnt[j];
		}
		for(j=ch;j<32;j++)
		{
			v[j]=0;
		}
		fnt+=ch;
		v+=32;
	}
	settextplane();
}

//obtains the text font
//fnt=pointer to the first font character to be overwritten
//ch=character height in the font
//first=first character in the VGA font to read
//num=number of characters to read
void VGAGetFont(byte*fnt,byte ch,word first,word num)
{
	byte*v=(byte*)0xb8000;
	word i,j;
	if((num+first)>512)num=512-first;
	if(!num)return;
	v+=first*32;
	setfontplane();
	for(i=0;i<num;i++)
	{
		for(j=0;j<ch;j++)
		{
			fnt[j]=v[j];
		}
		fnt+=ch;
		v+=32;
	}
	settextplane();
}

//waits until a vertical retrace period starts
void VGAWaitVBL(void)
{
	while(VGAReadReg(VGA_GEN,VGA__GEN__ST1)&8);
	while(!(VGAReadReg(VGA_GEN,VGA__GEN__ST1)&8));
}/*end function*/

//sets a VGA video mode
//returns 1 if the mode is valid, 0 if not
//m=mode
//  0=text (8-pixels-wide characters)
//  1=text (9-pixels-wide characters)
//  2=graphics 16 colors
//  3=graphics 256 colors
//w=width (in characters or in pixels)
//h=height (in characters or in pixels)
//o=option
//  text modes:
//    8=8-pixels-high characters
//    12=12-pixels-high characters
//    14=14-pixels-high characters
//    16=16-pixels-high characters
//  graphic modes:
//    0=normal
//    1=chained mode
//----------------------------------------------------------------
//text mode widths (8p): 40, 80, 90
//text mode widths (9p): 40, 80
//text mode heights (8-pix-h): 25, 30, 50, 60
//text mode heights (12-pix-h): 20, 40
//text mode heights (14-pix-h): 25
//text mode heights (16-pix-h): 25, 30
//graphic mode widths (16c): 640, 720
//graphic mode widths (256c): 320, 360
//graphic mode heights: 200, 240, 350, 400, 480
//chained mode only allows 320*200 at 256 colors
byte VGAMode(byte m,word w,word h,byte o)
{
	byte*tbl_hor,*tbl_ver,*tbl_mod;
	byte*v;
	dword i;
	vgaregs_t regs;
	byte chained=0;
	byte curstart=0,curheight=0;
	resetregs(&regs);
	switch(m)
	{
		case 0://txt 8p
		case 1://txt 9p
			if(m)
			{
				tbl_mod=tbl_mod_txt9p;
				regs.gen_mis|=0x04;
			}
			else
			{
				tbl_mod=tbl_mod_txt8p;
			}
			switch(w)
			{
				case 40:
					tbl_hor=tbl_hor_txt40;
					break;
				case 80:
					tbl_hor=tbl_hor_txt80;
					break;
				case 90:
					if(m==1)return(0);
					tbl_hor=tbl_hor_txt90;
					regs.gen_mis|=0x04;
					break;
				default:
					return(0);
			}
			switch(h)
			{
				case 20:
					switch(o)
					{
						case 12:
							tbl_ver=tbl_ver_txt20_12;
							break;
						default:
							return(0);
					}
					break;
				case 25:
					switch(o)
					{
						case 8:
							tbl_ver=tbl_ver_txt25_8;
							break;
						case 14:
							tbl_ver=tbl_ver_txt25_14;
							break;
						case 16:
							tbl_ver=tbl_ver_txt25_16;
							break;
						default:
							return(0);
					}
					break;
				case 30:
					switch(o)
					{
						case 8:
							tbl_ver=tbl_ver_txt30_8;
							break;
						case 16:
							tbl_ver=tbl_ver_txt30_16;
							break;
						default:
							return(0);
					}
					break;
				case 40:
					switch(o)
					{
						case 12:
							tbl_ver=tbl_ver_txt40_12;
							break;
						default:
							return(0);
					}
					break;
				case 50:
					switch(o)
					{
						case 8:
							tbl_ver=tbl_ver_txt50_8;
							break;
						default:
							return(0);
					}
					break;
				case 60:
					switch(o)
					{
						case 8:
							tbl_ver=tbl_ver_txt60_8;
							break;
						default:
							return(0);
					}
					break;
				default:
					return(0);
			}
			break;
		case 2://gra 16c
			if(o)return(0);
			tbl_mod=tbl_mod_gra16c;
			switch(w)
			{
				case 640:
					tbl_hor=tbl_hor_gra640;
					break;
				case 720:
					regs.gen_mis|=0x04;
					tbl_hor=tbl_hor_gra720;
					break;
				default:
					return(0);
			}
			switch(h)
			{
				case 200:
					tbl_ver=tbl_ver_gra200;
					break;
				case 240:
					tbl_ver=tbl_ver_gra240;
					break;
				case 350:
					tbl_ver=tbl_ver_gra350;
					break;
				case 400:
					tbl_ver=tbl_ver_gra400;
					break;
				case 480:
					tbl_ver=tbl_ver_gra480;
					break;
				default:
					return(0);
			}
			break;
		case 3://gra 256c
			tbl_mod=tbl_mod_gra256c;
			switch(w)
			{
				case 320:
					tbl_hor=tbl_hor_gra320;
					break;
				case 360:
					regs.gen_mis|=0x04;
					tbl_hor=tbl_hor_gra360;
					break;
				default:
					return(0);
			}
			switch(h)
			{
				case 200:
					tbl_ver=tbl_ver_gra200;
					break;
				case 240:
					tbl_ver=tbl_ver_gra240;
					break;
				case 350:
					tbl_ver=tbl_ver_gra350;
					break;
				case 400:
					tbl_ver=tbl_ver_gra400;
					break;
				case 480:
					tbl_ver=tbl_ver_gra480;
					break;
				default:
					return(0);
			}
			switch(o)
			{
				case 0:
					break;
				case 1:
					chained=1;
					if((w!=320)||(h!=200))
						return(0);
					break;
				default:
					return(0);
			}
			break;
		default:
			return(0);
	}
	regs.seq[VGA__SEQ__CLK]|=tbl_hor[0];
	regs.seq[VGA__SEQ__MEM]|=tbl_hor[1];
	regs.crt[VGA__CRT__HTO]|=tbl_hor[2];
	regs.crt[VGA__CRT__HDE]|=tbl_hor[3];
	regs.crt[VGA__CRT__HBS]|=tbl_hor[4];
	regs.crt[VGA__CRT__HBE]|=tbl_hor[5];
	regs.crt[VGA__CRT__HRS]|=tbl_hor[6];
	regs.crt[VGA__CRT__HRE]|=tbl_hor[7];
	regs.crt[VGA__CRT__OFF]|=tbl_hor[8];
	regs.gct[VGA__GCT__GMO]|=tbl_hor[9];
	regs.gct[VGA__GCT__MIS]|=tbl_hor[10];
	regs.act[VGA__ACT__ATB-16]|=tbl_hor[11];

	regs.gen_mis|=tbl_ver[0];
	regs.crt[VGA__CRT__VTO]|=tbl_ver[1];
	regs.crt[VGA__CRT__MSB]|=tbl_ver[2];
	regs.crt[VGA__CRT__MSL]|=tbl_ver[3];
	regs.crt[VGA__CRT__VRS]|=tbl_ver[4];
	regs.crt[VGA__CRT__VRE]|=tbl_ver[5];
	regs.crt[VGA__CRT__VDE]|=tbl_ver[6];
	regs.crt[VGA__CRT__VBS]|=tbl_ver[7];
	regs.crt[VGA__CRT__VBE]|=tbl_ver[8];

	regs.seq[VGA__SEQ__CLK]|=tbl_mod[0];
	regs.act[VGA__ACT__OFF-16]|=tbl_mod[1];
	regs.crt[VGA__CRT__MOD]|=tbl_mod[2];

	if(chained)
	{
		regs.seq[VGA__SEQ__MEM]|=0x08;
		regs.crt[VGA__CRT__ULL]|=0x40;
		regs.crt[VGA__CRT__MOD]&=0xbf;
	}

	vgachangemode(&regs);
	switch(m)
	{
		case 0:
		case 1:
			setfontplane();
			v=(byte*)0xb8000;
			for(i=0;i<32768;i++)*v++=0;
			settextplane();
			v=(byte*)0xb8000;
			for(i=0;i<32768;i++)*v++=0;
			switch(o)
			{
				case 8:
					curstart=o-2;
					curheight=2;
					break;
				case 12:
					curstart=o-4;
					curheight=2;
					break;
				case 14:
					curstart=o-4;
					curheight=2;
					break;
				case 16:
					curstart=o-6;
					curheight=2;
			}
			VGASetCursor(curstart,curheight);
			break;
		case 2:
		case 3:
			v=(byte*)0xa0000;
			VGAWriteReg(VGA_SEQ,VGA__SEQ__MAP,15);
			for(i=0;i<65536;i++)*v++=0;
	}
	return(1);
}
You would use it like this:

Code: Select all

VGAMode(2,640,480,0);//set 640*480 at 16 colors
//VGASetFont(FONT,fontheight,0,256);//this only in text mode to set the font
//VGACursor(0);//this only in text mode in case you want to disable the cursor
VGASetPal(PAL16,0,16);//set the pallete
Hope this helps. :wink:

Re: Setting VGA 640*480 mode without interrupts or V8086

Posted: Thu Apr 30, 2015 11:03 am
by osdever
Thank you very much, but what is PAL16? Anything except this seems working for me.

Re: Setting VGA 640*480 mode without interrupts or V8086

Posted: Thu Apr 30, 2015 11:08 am
by Unsigned
catnikita255 wrote:Thank you very much, but what is PAL16? Anything except this seems working for me.
You should know that. It is a 16 color pallete. It would be defined as:

Code: Select all

byte PAL16[48]=
{
0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x00,
0x80,0x00,0x80,0x80,0x80,0x00,0xc0,0xc0,0xc0,0x80,0x80,0x80,0x00,0x00,0xff,
0x00,0xff,0x00,0x00,0xff,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0xff,0xff,0x00,
0xff,0xff,0xff
};
Or you can define a diffefent one to ger other colors.

Re: Setting VGA 640*480 mode without interrupts or V8086

Posted: Thu Apr 30, 2015 11:18 am
by osdever
Ok, now the last thing. How to write putpixel()?

Re: Setting VGA 640*480 mode without interrupts or V8086

Posted: Thu Apr 30, 2015 12:22 pm
by Unsigned
catnikita255 wrote:Ok, now the last thing. How to write putpixel()?
You first need to understand how the memory is accessed in this bit-planar mode. The putpixel function would work OK, but drawing images with it would be extremly slow, so more functions are needed for other things like drawing rectangles or images.
The VGA has 4 planes, and you can choose which planes to write to, and which plane to read from. There's only a 64KB memory window to access the 256KB video memory. With four planes, you can access the entire VGA memory. The memory is organized as follows: imagine you're in a monocrome mode with 1 bit per pixel, accessing a byte in video memory allows you to access 8 pixels at a time, the VGA added 3 more planes and instead of having 1bpp there are 4bpp, where each different bit in a pixel comes from a different plane, so all the 4 planes are read by the VGA each time a pixel has to be got from memory and drawn to the screen. It's not easy at the beginning, but it's just a matter of reordering the bits when converting from a normal image (in packed-pixel format) to a VGA-like image (in bit planar format). Well, this is how it works for 16 color modes, for 256 color unchained modes it's different, but the planes are used in a similar way.

The putpixel funcion would be like this, remember this is only for 16 color modes, you can't use this function for 256 color modes, wether chained or unchained.

Code: Select all

//puts a pixel in 16 color mode
//x,y=pixel coordinates
//color=pixel color
//w,h=screen dimensions
void VGAPix16(word x,word y,byte color,word w,word h)
{
	byte*v=(byte*)0xa0000;
	dword off;
	int plane;
	byte mask;
	if((x>=w)||(y>=h))return;
	off=(y*w+x)>>3;
	v+=off;
	mask=1<<(7-(x&7));
	for(plane=0;plane<4;plane++)
	{
		VGAWriteReg(VGA_SEQ,VGA__SEQ__MAP,1<<plane);
		VGAWriteReg(VGA_GCT,VGA__GCT__RDM,plane);
		if(color&(1<<plane))
			*v|=mask;
		else
			*v&=~mask;
	}
}