summaryrefslogtreecommitdiffstats
path: root/qemu/roms/vgabios/vgabios.c
diff options
context:
space:
mode:
authorYang Zhang <yang.z.zhang@intel.com>2015-08-28 09:58:54 +0800
committerYang Zhang <yang.z.zhang@intel.com>2015-09-01 12:44:00 +0800
commite44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch)
tree66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/vgabios/vgabios.c
parent9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff)
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5 Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/vgabios/vgabios.c')
-rw-r--r--qemu/roms/vgabios/vgabios.c3923
1 files changed, 3923 insertions, 0 deletions
diff --git a/qemu/roms/vgabios/vgabios.c b/qemu/roms/vgabios/vgabios.c
new file mode 100644
index 000000000..c1e312b39
--- /dev/null
+++ b/qemu/roms/vgabios/vgabios.c
@@ -0,0 +1,3923 @@
+// ============================================================================================
+/*
+ * vgabios.c
+ */
+// ============================================================================================
+//
+// Copyright (C) 2001-2008 the LGPL VGABios developers Team
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// ============================================================================================
+//
+// This VGA Bios is specific to the plex86/bochs Emulated VGA card.
+// You can NOT drive any physical vga card with it.
+//
+// ============================================================================================
+//
+// This file contains code ripped from :
+// - rombios.c of plex86
+//
+// This VGA Bios contains fonts from :
+// - fntcol16.zip (c) by Joseph Gil avalable at :
+// ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
+// These fonts are public domain
+//
+// This VGA Bios is based on information taken from :
+// - Kevin Lawton's vga card emulation for bochs/plex86
+// - Ralf Brown's interrupts list available at http://www.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html
+// - Finn Thogersons' VGADOC4b available at http://home.worldonline.dk/~finth/
+// - Michael Abrash's Graphics Programming Black Book
+// - Francois Gervais' book "programmation des cartes graphiques cga-ega-vga" edited by sybex
+// - DOSEMU 1.0.1 source code for several tables values and formulas
+//
+// Thanks for patches, comments and ideas to :
+// - techt@pikeonline.net
+//
+// ============================================================================================
+
+#include "vgabios.h"
+
+#ifdef VBE
+#include "vbe.h"
+#endif
+
+#define USE_BX_INFO
+
+/* Declares */
+static Bit8u read_byte();
+static Bit16u read_word();
+static void write_byte();
+static void write_word();
+static Bit8u inb();
+static Bit16u inw();
+static void outb();
+static void outw();
+
+static Bit16u get_SS();
+
+// Output
+static void printf();
+static void unimplemented();
+static void unknown();
+
+static Bit8u find_vga_entry();
+
+static void memsetb();
+static void memsetw();
+static void memcpyb();
+static void memcpyw();
+
+static void biosfn_set_video_mode();
+static void biosfn_set_cursor_shape();
+static void biosfn_set_cursor_pos();
+static void biosfn_get_cursor_pos();
+static void biosfn_set_active_page();
+static void biosfn_scroll();
+static void biosfn_read_char_attr();
+static void biosfn_write_char_attr();
+static void biosfn_write_char_only();
+static void biosfn_write_pixel();
+static void biosfn_read_pixel();
+static void biosfn_write_teletype();
+static void biosfn_perform_gray_scale_summing();
+static void biosfn_load_text_user_pat();
+static void biosfn_load_text_8_14_pat();
+static void biosfn_load_text_8_8_pat();
+static void biosfn_load_text_8_16_pat();
+static void biosfn_load_gfx_8_8_chars();
+static void biosfn_load_gfx_user_chars();
+static void biosfn_load_gfx_8_14_chars();
+static void biosfn_load_gfx_8_8_dd_chars();
+static void biosfn_load_gfx_8_16_chars();
+static void biosfn_get_font_info();
+static void biosfn_alternate_prtsc();
+static void biosfn_switch_video_interface();
+static void biosfn_enable_video_refresh_control();
+static void biosfn_write_string();
+static void biosfn_read_state_info();
+static void biosfn_read_video_state_size();
+static Bit16u biosfn_save_video_state();
+static Bit16u biosfn_restore_video_state();
+extern Bit8u video_save_pointer_table[];
+
+// This is for compiling with gcc2 and gcc3
+#define ASM_START #asm
+#define ASM_END #endasm
+
+ASM_START
+
+MACRO SET_INT_VECTOR
+ push ds
+ xor ax, ax
+ mov ds, ax
+ mov ax, ?3
+ mov ?1*4, ax
+ mov ax, ?2
+ mov ?1*4+2, ax
+ pop ds
+MEND
+
+ASM_END
+
+ASM_START
+.text
+.rom
+.org 0
+
+use16 386
+
+vgabios_start:
+.byte 0x55, 0xaa /* BIOS signature, required for BIOS extensions */
+
+.byte 0x40 /* BIOS extension length in units of 512 bytes */
+
+
+vgabios_entry_point:
+
+ jmp vgabios_init_func
+
+#ifdef PCIBIOS
+.org 0x18
+.word vgabios_pci_data
+#endif
+
+// Info from Bart Oldeman
+.org 0x1e
+.ascii "IBM"
+.byte 0x00
+
+vgabios_name:
+.ascii "Plex86/Bochs VGABios"
+#ifdef PCIBIOS
+.ascii " (PCI)"
+#endif
+.ascii " "
+.byte 0x00
+
+vgabios_version:
+#ifndef VGABIOS_VERS
+.ascii "current-cvs"
+#else
+.ascii VGABIOS_VERS
+#endif
+.ascii " "
+
+vgabios_date:
+.ascii VGABIOS_DATE
+.byte 0x0a,0x0d
+.byte 0x00
+
+vgabios_copyright:
+.ascii "(C) 2008 the LGPL VGABios developers Team"
+.byte 0x0a,0x0d
+.byte 0x00
+
+vgabios_license:
+.ascii "This VGA/VBE Bios is released under the GNU LGPL"
+.byte 0x0a,0x0d
+.byte 0x0a,0x0d
+.byte 0x00
+
+vgabios_website:
+.ascii "Please visit :"
+.byte 0x0a,0x0d
+;;.ascii " . http://www.plex86.org"
+;;.byte 0x0a,0x0d
+.ascii " . http://bochs.sourceforge.net"
+.byte 0x0a,0x0d
+.ascii " . http://www.nongnu.org/vgabios"
+.byte 0x0a,0x0d
+.byte 0x0a,0x0d
+.byte 0x00
+
+#ifdef PCIBIOS
+vgabios_pci_data:
+.ascii "PCIR"
+#ifdef CIRRUS
+.word 0x1013
+.word 0x00b8 // CLGD5446
+#else
+#ifdef PCI_VID
+.word PCI_VID
+.word PCI_DID
+#else
+#error "Unknown PCI vendor and device id"
+#endif
+#endif
+.word 0 // reserved
+.word 0x18 // dlen
+.byte 0 // revision
+.byte 0x0 // class,hi: vga display
+.word 0x300 // class,lo: vga display
+.word 0x40 // bios size
+.word 1 // revision
+.byte 0 // intel x86 data
+.byte 0x80 // last image
+.word 0 // reserved
+#endif
+
+
+;; ============================================================================================
+;;
+;; Init Entry point
+;;
+;; ============================================================================================
+vgabios_init_func:
+
+;; init vga card
+ call init_vga_card
+
+;; init basic bios vars
+ call init_bios_area
+
+#ifdef VBE
+;; init vbe functions
+ call vbe_init
+#endif
+
+;; set int10 vect
+ SET_INT_VECTOR(0x10, #0xC000, #vgabios_int10_handler)
+
+#ifdef CIRRUS
+ call cirrus_init
+#endif
+
+;; display splash screen
+ call _display_splash_screen
+
+;; init video mode and clear the screen
+ mov ax,#0x0003
+ int #0x10
+
+;; show info
+ call _display_info
+
+#ifdef VBE
+;; show vbe info
+ call vbe_display_info
+#endif
+
+#ifdef CIRRUS
+;; show cirrus info
+ call cirrus_display_info
+#endif
+
+ retf
+ASM_END
+
+/*
+ * int10 handled here
+ */
+ASM_START
+vgabios_int10_handler:
+ pushf
+#ifdef DEBUG
+ push es
+ push ds
+ pusha
+ mov bx, #0xc000
+ mov ds, bx
+ call _int10_debugmsg
+ popa
+ pop ds
+ pop es
+#endif
+ cmp ah, #0x0f
+ jne int10_test_1A
+ call biosfn_get_video_mode
+ jmp int10_end
+int10_test_1A:
+ cmp ah, #0x1a
+ jne int10_test_0B
+ call biosfn_group_1A
+ jmp int10_end
+int10_test_0B:
+ cmp ah, #0x0b
+ jne int10_test_1103
+ call biosfn_group_0B
+ jmp int10_end
+int10_test_1103:
+ cmp ax, #0x1103
+ jne int10_test_12
+ call biosfn_set_text_block_specifier
+ jmp int10_end
+int10_test_12:
+ cmp ah, #0x12
+ jne int10_test_101B
+ cmp bl, #0x10
+ jne int10_test_BL30
+ call biosfn_get_ega_info
+ jmp int10_end
+int10_test_BL30:
+ cmp bl, #0x30
+ jne int10_test_BL31
+ call biosfn_select_vert_res
+ jmp int10_end
+int10_test_BL31:
+ cmp bl, #0x31
+ jne int10_test_BL32
+ call biosfn_enable_default_palette_loading
+ jmp int10_end
+int10_test_BL32:
+ cmp bl, #0x32
+ jne int10_test_BL33
+ call biosfn_enable_video_addressing
+ jmp int10_end
+int10_test_BL33:
+ cmp bl, #0x33
+ jne int10_test_BL34
+ call biosfn_enable_grayscale_summing
+ jmp int10_end
+int10_test_BL34:
+ cmp bl, #0x34
+ jne int10_normal
+ call biosfn_enable_cursor_emulation
+ jmp int10_end
+int10_test_101B:
+ cmp ax, #0x101b
+ je int10_normal
+ cmp ah, #0x10
+#ifndef VBE
+ jne int10_normal
+#else
+ jne int10_test_4F
+#endif
+ call biosfn_group_10
+ jmp int10_end
+#ifdef VBE
+int10_test_4F:
+ cmp ah, #0x4f
+ jne int10_normal
+ cmp al, #0x03
+ jne int10_test_vbe_05
+ call vbe_biosfn_return_current_mode
+ jmp int10_end
+int10_test_vbe_05:
+ cmp al, #0x05
+ jne int10_test_vbe_06
+ call vbe_biosfn_display_window_control
+ jmp int10_end
+int10_test_vbe_06:
+ cmp al, #0x06
+ jne int10_test_vbe_07
+ call vbe_biosfn_set_get_logical_scan_line_length
+ jmp int10_end
+int10_test_vbe_07:
+ cmp al, #0x07
+ jne int10_test_vbe_08
+ call vbe_biosfn_set_get_display_start
+ jmp int10_end
+int10_test_vbe_08:
+ cmp al, #0x08
+ jne int10_test_vbe_0A
+ call vbe_biosfn_set_get_dac_palette_format
+ jmp int10_end
+int10_test_vbe_0A:
+ cmp al, #0x0A
+ jne int10_normal
+ call vbe_biosfn_return_protected_mode_interface
+ jmp int10_end
+#endif
+
+int10_normal:
+ push es
+ push ds
+ pusha
+
+;; We have to set ds to access the right data segment
+ mov bx, #0xc000
+ mov ds, bx
+ call _int10_func
+
+ popa
+ pop ds
+ pop es
+int10_end:
+ popf
+ iret
+ASM_END
+
+#include "vgatables.h"
+#include "vgafonts.h"
+
+/*
+ * Boot time harware inits
+ */
+ASM_START
+init_vga_card:
+;; switch to color mode and enable CPU access 480 lines
+ mov dx, #0x3C2
+ mov al, #0xC3
+ outb dx,al
+
+;; more than 64k 3C4/04
+ mov dx, #0x3C4
+ mov al, #0x04
+ outb dx,al
+ mov dx, #0x3C5
+ mov al, #0x02
+ outb dx,al
+
+#if defined(USE_BX_INFO) || defined(DEBUG)
+ mov bx, #msg_vga_init
+ push bx
+ call _printf
+#endif
+ inc sp
+ inc sp
+ ret
+
+#if defined(USE_BX_INFO) || defined(DEBUG)
+msg_vga_init:
+.ascii "VGABios $Id$"
+.byte 0x0d,0x0a,0x00
+#endif
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+/*
+ * Boot time bios area inits
+ */
+ASM_START
+init_bios_area:
+ push ds
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+
+;; init detected hardware BIOS Area
+ mov bx, # BIOSMEM_INITIAL_MODE
+ mov ax, [bx]
+ and ax, #0xffcf
+;; set 80x25 color (not clear from RBIL but usual)
+ or ax, #0x0020
+ mov [bx], ax
+
+;; Just for the first int10 find its children
+
+;; the default char height
+ mov bx, # BIOSMEM_CHAR_HEIGHT
+ mov al, #0x10
+ mov [bx], al
+
+;; Clear the screen
+ mov bx, # BIOSMEM_VIDEO_CTL
+ mov al, #0x60
+ mov [bx], al
+
+;; Set the basic screen we have
+ mov bx, # BIOSMEM_SWITCHES
+ mov al, #0xf9
+ mov [bx], al
+
+;; Set the basic modeset options
+ mov bx, # BIOSMEM_MODESET_CTL
+ mov al, #0x51
+ mov [bx], al
+
+;; Set the default MSR
+ mov bx, # BIOSMEM_CURRENT_MSR
+ mov al, #0x09
+ mov [bx], al
+
+ pop ds
+ ret
+
+_video_save_pointer_table:
+ .word _video_param_table
+ .word 0xc000
+
+ .word 0 /* XXX: fill it */
+ .word 0
+
+ .word 0 /* XXX: fill it */
+ .word 0
+
+ .word 0 /* XXX: fill it */
+ .word 0
+
+ .word 0 /* XXX: fill it */
+ .word 0
+
+ .word 0 /* XXX: fill it */
+ .word 0
+
+ .word 0 /* XXX: fill it */
+ .word 0
+
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+/*
+ * Boot time Splash screen
+ */
+static void display_splash_screen()
+{
+}
+
+// --------------------------------------------------------------------------------------------
+/*
+ * Tell who we are
+ */
+
+static void display_info()
+{
+ASM_START
+ mov ax,#0xc000
+ mov ds,ax
+ mov si,#vgabios_name
+ call _display_string
+ mov si,#vgabios_version
+ call _display_string
+
+ ;;mov si,#vgabios_copyright
+ ;;call _display_string
+ ;;mov si,#crlf
+ ;;call _display_string
+
+ mov si,#vgabios_license
+ call _display_string
+ mov si,#vgabios_website
+ call _display_string
+ASM_END
+}
+
+static void display_string()
+{
+ // Get length of string
+ASM_START
+ mov ax,ds
+ mov es,ax
+ mov di,si
+ xor cx,cx
+ not cx
+ xor al,al
+ cld
+ repne
+ scasb
+ not cx
+ dec cx
+ push cx
+
+ mov ax,#0x0300
+ mov bx,#0x0000
+ int #0x10
+
+ pop cx
+ mov ax,#0x1301
+ mov bx,#0x000b
+ mov bp,si
+ int #0x10
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+#ifdef DEBUG
+static void int10_debugmsg(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
+ Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS;
+{
+ // 0E is write char...
+ if(GET_AH()!=0x0E)
+ printf("vgabios call ah%02x al%02x bx%04x cx%04x dx%04x\n",GET_AH(),GET_AL(),BX,CX,DX);
+}
+#endif
+
+// --------------------------------------------------------------------------------------------
+/*
+ * int10 main dispatcher
+ */
+static void int10_func(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
+ Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS;
+{
+
+ // BIOS functions
+ switch(GET_AH())
+ {
+ case 0x00:
+ biosfn_set_video_mode(GET_AL());
+ switch(GET_AL()&0x7F)
+ {case 6:
+ SET_AL(0x3F);
+ break;
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 7:
+ SET_AL(0x30);
+ break;
+ default:
+ SET_AL(0x20);
+ }
+ break;
+ case 0x01:
+ biosfn_set_cursor_shape(GET_CH(),GET_CL());
+ break;
+ case 0x02:
+ biosfn_set_cursor_pos(GET_BH(),DX);
+ break;
+ case 0x03:
+ biosfn_get_cursor_pos(GET_BH(),&CX,&DX);
+ break;
+ case 0x04:
+ // Read light pen pos (unimplemented)
+#ifdef DEBUG
+ unimplemented();
+#endif
+ AX=0x00;
+ BX=0x00;
+ CX=0x00;
+ DX=0x00;
+ break;
+ case 0x05:
+ biosfn_set_active_page(GET_AL());
+ break;
+ case 0x06:
+ biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_UP);
+ break;
+ case 0x07:
+ biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_DOWN);
+ break;
+ case 0x08:
+ biosfn_read_char_attr(GET_BH(),&AX);
+ break;
+ case 0x09:
+ biosfn_write_char_attr(GET_AL(),GET_BH(),GET_BL(),CX);
+ break;
+ case 0x0A:
+ biosfn_write_char_only(GET_AL(),GET_BH(),GET_BL(),CX);
+ break;
+ case 0x0C:
+ biosfn_write_pixel(GET_BH(),GET_AL(),CX,DX);
+ break;
+ case 0x0D:
+ biosfn_read_pixel(GET_BH(),CX,DX,&AX);
+ break;
+ case 0x0E:
+ // Ralf Brown Interrupt list is WRONG on bh(page)
+ // We do output only on the current page !
+ biosfn_write_teletype(GET_AL(),0xff,GET_BL(),NO_ATTR);
+ break;
+ case 0x10:
+ // All other functions of group AH=0x10 rewritten in assembler
+ biosfn_perform_gray_scale_summing(BX,CX);
+ break;
+ case 0x11:
+ switch(GET_AL())
+ {
+ case 0x00:
+ case 0x10:
+ biosfn_load_text_user_pat(GET_AL(),ES,BP,CX,DX,GET_BL(),GET_BH());
+ break;
+ case 0x01:
+ case 0x11:
+ biosfn_load_text_8_14_pat(GET_AL(),GET_BL());
+ break;
+ case 0x02:
+ case 0x12:
+ biosfn_load_text_8_8_pat(GET_AL(),GET_BL());
+ break;
+ case 0x04:
+ case 0x14:
+ biosfn_load_text_8_16_pat(GET_AL(),GET_BL());
+ break;
+ case 0x20:
+ biosfn_load_gfx_8_8_chars(ES,BP);
+ break;
+ case 0x21:
+ biosfn_load_gfx_user_chars(ES,BP,CX,GET_BL(),GET_DL());
+ break;
+ case 0x22:
+ biosfn_load_gfx_8_14_chars(GET_BL());
+ break;
+ case 0x23:
+ biosfn_load_gfx_8_8_dd_chars(GET_BL());
+ break;
+ case 0x24:
+ biosfn_load_gfx_8_16_chars(GET_BL());
+ break;
+ case 0x30:
+ biosfn_get_font_info(GET_BH(),&ES,&BP,&CX,&DX);
+ break;
+#ifdef DEBUG
+ default:
+ unknown();
+#endif
+ }
+
+ break;
+ case 0x12:
+ switch(GET_BL())
+ {
+ case 0x20:
+ biosfn_alternate_prtsc();
+ break;
+ case 0x35:
+ biosfn_switch_video_interface(GET_AL(),ES,DX);
+ SET_AL(0x12);
+ break;
+ case 0x36:
+ biosfn_enable_video_refresh_control(GET_AL());
+ SET_AL(0x12);
+ break;
+#ifdef DEBUG
+ default:
+ unknown();
+#endif
+ }
+ break;
+ case 0x13:
+ biosfn_write_string(GET_AL(),GET_BH(),GET_BL(),CX,GET_DH(),GET_DL(),ES,BP);
+ break;
+ case 0x1B:
+ biosfn_read_state_info(BX,ES,DI);
+ SET_AL(0x1B);
+ break;
+ case 0x1C:
+ switch(GET_AL())
+ {
+ case 0x00:
+ biosfn_read_video_state_size(CX,&BX);
+ break;
+ case 0x01:
+ biosfn_save_video_state(CX,ES,BX);
+ break;
+ case 0x02:
+ biosfn_restore_video_state(CX,ES,BX);
+ break;
+#ifdef DEBUG
+ default:
+ unknown();
+#endif
+ }
+ SET_AL(0x1C);
+ break;
+
+#ifdef VBE
+ case 0x4f:
+ if (vbe_has_vbe_display()) {
+ switch(GET_AL())
+ {
+ case 0x00:
+ vbe_biosfn_return_controller_information(&AX,ES,DI);
+ break;
+ case 0x01:
+ vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
+ break;
+ case 0x02:
+ vbe_biosfn_set_mode(&AX,BX,ES,DI);
+ break;
+ case 0x04:
+ vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
+ break;
+ case 0x09:
+ //FIXME
+#ifdef DEBUG
+ unimplemented();
+#endif
+ // function failed
+ AX=0x100;
+ break;
+ case 0x0A:
+ //FIXME
+#ifdef DEBUG
+ unimplemented();
+#endif
+ // function failed
+ AX=0x100;
+ break;
+ default:
+#ifdef DEBUG
+ unknown();
+#endif
+ // function failed
+ AX=0x100;
+ }
+ }
+ else {
+ // No VBE display
+ AX=0x0100;
+ }
+ break;
+#endif
+
+#ifdef DEBUG
+ default:
+ unknown();
+#endif
+ }
+}
+
+// ============================================================================================
+//
+// BIOS functions
+//
+// ============================================================================================
+
+static void biosfn_set_video_mode(mode) Bit8u mode;
+{// mode: Bit 7 is 1 if no clear screen
+
+ // Should we clear the screen ?
+ Bit8u noclearmem=mode&0x80;
+ Bit8u line,mmask,*palette,vpti;
+ Bit16u i,twidth,theightm1,cheight;
+ Bit8u modeset_ctl,video_ctl,vga_switches;
+ Bit16u crtc_addr;
+
+#ifdef VBE
+ if (vbe_has_vbe_display()) {
+ dispi_set_enable(VBE_DISPI_DISABLED);
+ }
+#endif // def VBE
+
+ // The real mode
+ mode=mode&0x7f;
+
+ // find the entry in the video modes
+ line=find_vga_entry(mode);
+
+#ifdef DEBUG
+ printf("mode search %02x found line %02x\n",mode,line);
+#endif
+
+ if(line==0xFF)
+ return;
+
+ vpti=line_to_vpti[line];
+ twidth=video_param_table[vpti].twidth;
+ theightm1=video_param_table[vpti].theightm1;
+ cheight=video_param_table[vpti].cheight;
+
+ // Read the bios vga control
+ video_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL);
+
+ // Read the bios vga switches
+ vga_switches=read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES);
+
+ // Read the bios mode set control
+ modeset_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
+
+ // Then we know the number of lines
+// FIXME
+
+ // if palette loading (bit 3 of modeset ctl = 0)
+ if((modeset_ctl&0x08)==0)
+ {// Set the PEL mask
+ outb(VGAREG_PEL_MASK,vga_modes[line].pelmask);
+
+ // Set the whole dac always, from 0
+ outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
+
+ // From which palette
+ switch(vga_modes[line].dacmodel)
+ {case 0:
+ palette=&palette0;
+ break;
+ case 1:
+ palette=&palette1;
+ break;
+ case 2:
+ palette=&palette2;
+ break;
+ case 3:
+ palette=&palette3;
+ break;
+ }
+ // Always 256*3 values
+ for(i=0;i<0x0100;i++)
+ {if(i<=dac_regs[vga_modes[line].dacmodel])
+ {outb(VGAREG_DAC_DATA,palette[(i*3)+0]);
+ outb(VGAREG_DAC_DATA,palette[(i*3)+1]);
+ outb(VGAREG_DAC_DATA,palette[(i*3)+2]);
+ }
+ else
+ {outb(VGAREG_DAC_DATA,0);
+ outb(VGAREG_DAC_DATA,0);
+ outb(VGAREG_DAC_DATA,0);
+ }
+ }
+ if((modeset_ctl&0x02)==0x02)
+ {
+ biosfn_perform_gray_scale_summing(0x00, 0x100);
+ }
+ }
+
+ // Reset Attribute Ctl flip-flop
+ inb(VGAREG_ACTL_RESET);
+
+ // Set Attribute Ctl
+ for(i=0;i<=0x13;i++)
+ {outb(VGAREG_ACTL_ADDRESS,i);
+ outb(VGAREG_ACTL_WRITE_DATA,video_param_table[vpti].actl_regs[i]);
+ }
+ outb(VGAREG_ACTL_ADDRESS,0x14);
+ outb(VGAREG_ACTL_WRITE_DATA,0x00);
+
+ // Set Sequencer Ctl
+ outb(VGAREG_SEQU_ADDRESS,0);
+ outb(VGAREG_SEQU_DATA,0x03);
+ for(i=1;i<=4;i++)
+ {outb(VGAREG_SEQU_ADDRESS,i);
+ outb(VGAREG_SEQU_DATA,video_param_table[vpti].sequ_regs[i - 1]);
+ }
+
+ // Set Grafx Ctl
+ for(i=0;i<=8;i++)
+ {outb(VGAREG_GRDC_ADDRESS,i);
+ outb(VGAREG_GRDC_DATA,video_param_table[vpti].grdc_regs[i]);
+ }
+
+ // Set CRTC address VGA or MDA
+ crtc_addr=vga_modes[line].memmodel==MTEXT?VGAREG_MDA_CRTC_ADDRESS:VGAREG_VGA_CRTC_ADDRESS;
+
+ // Disable CRTC write protection
+ outw(crtc_addr,0x0011);
+ // Set CRTC regs
+ for(i=0;i<=0x18;i++)
+ {outb(crtc_addr,i);
+ outb(crtc_addr+1,video_param_table[vpti].crtc_regs[i]);
+ }
+
+ // Set the misc register
+ outb(VGAREG_WRITE_MISC_OUTPUT,video_param_table[vpti].miscreg);
+
+ // Enable video
+ outb(VGAREG_ACTL_ADDRESS,0x20);
+ inb(VGAREG_ACTL_RESET);
+
+ if(noclearmem==0x00)
+ {
+ if(vga_modes[line].class==TEXT)
+ {
+ memsetw(vga_modes[line].sstart,0,0x0720,0x4000); // 32k
+ }
+ else
+ {
+ if(mode<0x0d)
+ {
+ memsetw(vga_modes[line].sstart,0,0x0000,0x4000); // 32k
+ }
+ else
+ {
+ outb( VGAREG_SEQU_ADDRESS, 0x02 );
+ mmask = inb( VGAREG_SEQU_DATA );
+ outb( VGAREG_SEQU_DATA, 0x0f ); // all planes
+ memsetw(vga_modes[line].sstart,0,0x0000,0x8000); // 64k
+ outb( VGAREG_SEQU_DATA, mmask );
+ }
+ }
+ }
+
+ // Set the BIOS mem
+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,mode);
+ write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS,twidth);
+ write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,*(Bit16u *)&video_param_table[vpti].slength_l);
+ write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS,crtc_addr);
+ write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theightm1);
+ write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,cheight);
+ write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|noclearmem));
+ write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9);
+ write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x7f);
+
+ // FIXME We nearly have the good tables. to be reworked
+ write_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,0x08); // 8 is VGA should be ok for now
+ write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER, video_save_pointer_table);
+ write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER+2, 0xc000);
+
+ // FIXME
+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x00); // Unavailable on vanilla vga, but...
+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,0x00); // Unavailable on vanilla vga, but...
+
+ // Set cursor shape
+ if(vga_modes[line].class==TEXT)
+ {
+ biosfn_set_cursor_shape(0x06,0x07);
+ }
+
+ // Set cursor pos for page 0..7
+ for(i=0;i<8;i++)
+ biosfn_set_cursor_pos(i,0x0000);
+
+ // Set active page 0
+ biosfn_set_active_page(0x00);
+
+ // Write the fonts in memory
+ if(vga_modes[line].class==TEXT)
+ {
+ASM_START
+ ;; copy and activate 8x16 font
+ mov ax, #0x1104
+ mov bl, #0x00
+ int #0x10
+ mov ax, #0x1103
+ mov bl, #0x00
+ int #0x10
+ASM_END
+ }
+
+ // Set the ints 0x1F and 0x43
+ASM_START
+ SET_INT_VECTOR(0x1f, #0xC000, #_vgafont8+128*8)
+ASM_END
+
+ switch(cheight)
+ {case 8:
+ASM_START
+ SET_INT_VECTOR(0x43, #0xC000, #_vgafont8)
+ASM_END
+ break;
+ case 14:
+ASM_START
+ SET_INT_VECTOR(0x43, #0xC000, #_vgafont14)
+ASM_END
+ break;
+ case 16:
+ASM_START
+ SET_INT_VECTOR(0x43, #0xC000, #_vgafont16)
+ASM_END
+ break;
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_set_cursor_shape (CH,CL)
+Bit8u CH;Bit8u CL;
+{Bit16u cheight,curs,crtc_addr;
+ Bit8u modeset_ctl;
+
+ CH&=0x3f;
+ CL&=0x1f;
+
+ curs=(CH<<8)+CL;
+ write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE,curs);
+
+ modeset_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
+ cheight = read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT);
+ if((modeset_ctl&0x01) && (cheight>8) && (CL<8) && (CH<0x20))
+ {
+ if(CL!=(CH+1))
+ {
+ CH = ((CH+1) * cheight / 8) -1;
+ }
+ else
+ {
+ CH = ((CL+1) * cheight / 8) - 2;
+ }
+ CL = ((CL+1) * cheight / 8) - 1;
+ }
+
+ // CTRC regs 0x0a and 0x0b
+ crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
+ outb(crtc_addr,0x0a);
+ outb(crtc_addr+1,CH);
+ outb(crtc_addr,0x0b);
+ outb(crtc_addr+1,CL);
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_set_cursor_pos (page, cursor)
+Bit8u page;Bit16u cursor;
+{
+ Bit8u xcurs,ycurs,current;
+ Bit16u nbcols,nbrows,address,crtc_addr;
+
+ // Should not happen...
+ if(page>7)return;
+
+ // Bios cursor pos
+ write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*page, cursor);
+
+ // Set the hardware cursor
+ current=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
+ if(page==current)
+ {
+ // Get the dimensions
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+
+ // Calculate the address knowing nbcols nbrows and page num
+ address=SCREEN_IO_START(nbcols,nbrows,page)+xcurs+ycurs*nbcols;
+
+ // CRTC regs 0x0e and 0x0f
+ crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
+ outb(crtc_addr,0x0e);
+ outb(crtc_addr+1,(address&0xff00)>>8);
+ outb(crtc_addr,0x0f);
+ outb(crtc_addr+1,address&0x00ff);
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_get_cursor_pos (page,shape, pos)
+Bit8u page;Bit16u *shape;Bit16u *pos;
+{
+ Bit16u ss=get_SS();
+
+ // Default
+ write_word(ss, shape, 0);
+ write_word(ss, pos, 0);
+
+ if(page>7)return;
+ // FIXME should handle VGA 14/16 lines
+ write_word(ss,shape,read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE));
+ write_word(ss,pos,read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_POS+page*2));
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_set_active_page (page)
+Bit8u page;
+{
+ Bit16u cursor,dummy,crtc_addr;
+ Bit16u nbcols,nbrows,address;
+ Bit8u mode,line;
+
+ if(page>7)return;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get pos curs pos for the right page
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+
+ if(vga_modes[line].class==TEXT)
+ {
+ // Get the dimensions
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+
+ // Calculate the address knowing nbcols nbrows and page num
+ address=SCREEN_MEM_START(nbcols,nbrows,page);
+ write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START,address);
+
+ // Start address
+ address=SCREEN_IO_START(nbcols,nbrows,page);
+ }
+ else
+ {
+ address = page * (*(Bit16u *)&video_param_table[line_to_vpti[line]].slength_l);
+ }
+
+ // CRTC regs 0x0c and 0x0d
+ crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
+ outb(crtc_addr,0x0c);
+ outb(crtc_addr+1,(address&0xff00)>>8);
+ outb(crtc_addr,0x0d);
+ outb(crtc_addr+1,address&0x00ff);
+
+ // And change the BIOS page
+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE,page);
+
+#ifdef DEBUG
+ printf("Set active page %02x address %04x\n",page,address);
+#endif
+
+ // Display the cursor, now the page is active
+ biosfn_set_cursor_pos(page,cursor);
+}
+
+// --------------------------------------------------------------------------------------------
+static void vgamem_copy_pl4(xstart,ysrc,ydest,cols,nbcols,cheight)
+Bit8u xstart;Bit8u ysrc;Bit8u ydest;Bit8u cols;Bit8u nbcols;Bit8u cheight;
+{
+ Bit16u src,dest;
+ Bit8u i;
+
+ src=ysrc*cheight*nbcols+xstart;
+ dest=ydest*cheight*nbcols+xstart;
+ outw(VGAREG_GRDC_ADDRESS, 0x0105);
+ for(i=0;i<cheight;i++)
+ {
+ memcpyb(0xa000,dest+i*nbcols,0xa000,src+i*nbcols,cols);
+ }
+ outw(VGAREG_GRDC_ADDRESS, 0x0005);
+}
+
+// --------------------------------------------------------------------------------------------
+static void vgamem_fill_pl4(xstart,ystart,cols,nbcols,cheight,attr)
+Bit8u xstart;Bit8u ystart;Bit8u cols;Bit8u nbcols;Bit8u cheight;Bit8u attr;
+{
+ Bit16u dest;
+ Bit8u i;
+
+ dest=ystart*cheight*nbcols+xstart;
+ outw(VGAREG_GRDC_ADDRESS, 0x0205);
+ for(i=0;i<cheight;i++)
+ {
+ memsetb(0xa000,dest+i*nbcols,attr,cols);
+ }
+ outw(VGAREG_GRDC_ADDRESS, 0x0005);
+}
+
+// --------------------------------------------------------------------------------------------
+static void vgamem_copy_cga(xstart,ysrc,ydest,cols,nbcols,cheight)
+Bit8u xstart;Bit8u ysrc;Bit8u ydest;Bit8u cols;Bit8u nbcols;Bit8u cheight;
+{
+ Bit16u src,dest;
+ Bit8u i;
+
+ src=((ysrc*cheight*nbcols)>>1)+xstart;
+ dest=((ydest*cheight*nbcols)>>1)+xstart;
+ for(i=0;i<cheight;i++)
+ {
+ if (i & 1)
+ memcpyb(0xb800,0x2000+dest+(i>>1)*nbcols,0xb800,0x2000+src+(i>>1)*nbcols,cols);
+ else
+ memcpyb(0xb800,dest+(i>>1)*nbcols,0xb800,src+(i>>1)*nbcols,cols);
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void vgamem_fill_cga(xstart,ystart,cols,nbcols,cheight,attr)
+Bit8u xstart;Bit8u ystart;Bit8u cols;Bit8u nbcols;Bit8u cheight;Bit8u attr;
+{
+ Bit16u dest;
+ Bit8u i;
+
+ dest=((ystart*cheight*nbcols)>>1)+xstart;
+ for(i=0;i<cheight;i++)
+ {
+ if (i & 1)
+ memsetb(0xb800,0x2000+dest+(i>>1)*nbcols,attr,cols);
+ else
+ memsetb(0xb800,dest+(i>>1)*nbcols,attr,cols);
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_scroll (nblines,attr,rul,cul,rlr,clr,page,dir)
+Bit8u nblines;Bit8u attr;Bit8u rul;Bit8u cul;Bit8u rlr;Bit8u clr;Bit8u page;Bit8u dir;
+{
+ // page == 0xFF if current
+
+ Bit8u mode,line,cheight,bpp,cols;
+ Bit16u nbcols,nbrows,i;
+ Bit16u address;
+
+ if(rul>rlr)return;
+ if(cul>clr)return;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ // Get the current page
+ if(page==0xFF)
+ page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
+
+ if(rlr>=nbrows)rlr=nbrows-1;
+ if(clr>=nbcols)clr=nbcols-1;
+ if(nblines>nbrows)nblines=0;
+ cols=clr-cul+1;
+
+ if(vga_modes[line].class==TEXT)
+ {
+ // Compute the address
+ address=SCREEN_MEM_START(nbcols,nbrows,page);
+#ifdef DEBUG
+ printf("Scroll, address %04x (%04x %04x %02x)\n",address,nbrows,nbcols,page);
+#endif
+
+ if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
+ {
+ memsetw(vga_modes[line].sstart,address,(Bit16u)attr*0x100+' ',nbrows*nbcols);
+ }
+ else
+ {// if Scroll up
+ if(dir==SCROLL_UP)
+ {for(i=rul;i<=rlr;i++)
+ {
+ if((i+nblines>rlr)||(nblines==0))
+ memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(Bit16u)attr*0x100+' ',cols);
+ else
+ memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i+nblines)*nbcols+cul)*2,cols);
+ }
+ }
+ else
+ {for(i=rlr;i>=rul;i--)
+ {
+ if((i<rul+nblines)||(nblines==0))
+ memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(Bit16u)attr*0x100+' ',cols);
+ else
+ memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i-nblines)*nbcols+cul)*2,cols);
+ if (i>rlr) break;
+ }
+ }
+ }
+ }
+ else
+ {
+ // FIXME gfx mode not complete
+ cheight=video_param_table[line_to_vpti[line]].cheight;
+ switch(vga_modes[line].memmodel)
+ {
+ case PLANAR4:
+ case PLANAR1:
+ if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
+ {
+ outw(VGAREG_GRDC_ADDRESS, 0x0205);
+ memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight);
+ outw(VGAREG_GRDC_ADDRESS, 0x0005);
+ }
+ else
+ {// if Scroll up
+ if(dir==SCROLL_UP)
+ {for(i=rul;i<=rlr;i++)
+ {
+ if((i+nblines>rlr)||(nblines==0))
+ vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
+ else
+ vgamem_copy_pl4(cul,i+nblines,i,cols,nbcols,cheight);
+ }
+ }
+ else
+ {for(i=rlr;i>=rul;i--)
+ {
+ if((i<rul+nblines)||(nblines==0))
+ vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
+ else
+ vgamem_copy_pl4(cul,i,i-nblines,cols,nbcols,cheight);
+ if (i>rlr) break;
+ }
+ }
+ }
+ break;
+ case CGA:
+ bpp=vga_modes[line].pixbits;
+ if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
+ {
+ memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight*bpp);
+ }
+ else
+ {
+ if(bpp==2)
+ {
+ cul<<=1;
+ cols<<=1;
+ nbcols<<=1;
+ }
+ // if Scroll up
+ if(dir==SCROLL_UP)
+ {for(i=rul;i<=rlr;i++)
+ {
+ if((i+nblines>rlr)||(nblines==0))
+ vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
+ else
+ vgamem_copy_cga(cul,i+nblines,i,cols,nbcols,cheight);
+ }
+ }
+ else
+ {for(i=rlr;i>=rul;i--)
+ {
+ if((i<rul+nblines)||(nblines==0))
+ vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
+ else
+ vgamem_copy_cga(cul,i,i-nblines,cols,nbcols,cheight);
+ if (i>rlr) break;
+ }
+ }
+ }
+ break;
+#ifdef DEBUG
+ default:
+ printf("Scroll in graphics mode ");
+ unimplemented();
+#endif
+ }
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_read_char_attr (page,car)
+Bit8u page;Bit16u *car;
+{Bit16u ss=get_SS();
+ Bit8u xcurs,ycurs,mode,line;
+ Bit16u nbcols,nbrows,address;
+ Bit16u cursor,dummy;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the cursor pos for the page
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ if(vga_modes[line].class==TEXT)
+ {
+ // Compute the address
+ address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
+
+ write_word(ss,car,read_word(vga_modes[line].sstart,address));
+ }
+ else
+ {
+ // FIXME gfx mode
+#ifdef DEBUG
+ unimplemented();
+#endif
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight)
+Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;Bit8u cheight;
+{
+ Bit8u i,j,mask;
+ Bit8u *fdata;
+ Bit16u addr,dest,src;
+
+ switch(cheight)
+ {case 14:
+ fdata = &vgafont14;
+ break;
+ case 16:
+ fdata = &vgafont16;
+ break;
+ default:
+ fdata = &vgafont8;
+ }
+ addr=xcurs+ycurs*cheight*nbcols;
+ src = car * cheight;
+ outw(VGAREG_SEQU_ADDRESS, 0x0f02);
+ outw(VGAREG_GRDC_ADDRESS, 0x0205);
+ if(attr&0x80)
+ {
+ outw(VGAREG_GRDC_ADDRESS, 0x1803);
+ }
+ else
+ {
+ outw(VGAREG_GRDC_ADDRESS, 0x0003);
+ }
+ for(i=0;i<cheight;i++)
+ {
+ dest=addr+i*nbcols;
+ for(j=0;j<8;j++)
+ {
+ mask=0x80>>j;
+ outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08);
+ read_byte(0xa000,dest);
+ if(fdata[src+i]&mask)
+ {
+ write_byte(0xa000,dest,attr&0x0f);
+ }
+ else
+ {
+ write_byte(0xa000,dest,0x00);
+ }
+ }
+ }
+ASM_START
+ mov dx, # VGAREG_GRDC_ADDRESS
+ mov ax, #0xff08
+ out dx, ax
+ mov ax, #0x0005
+ out dx, ax
+ mov ax, #0x0003
+ out dx, ax
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp)
+Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;Bit8u bpp;
+{
+ Bit8u i,j,mask,data;
+ Bit8u *fdata;
+ Bit16u addr,dest,src;
+
+ fdata = &vgafont8;
+ addr=(xcurs*bpp)+ycurs*320;
+ src = car * 8;
+ for(i=0;i<8;i++)
+ {
+ dest=addr+(i>>1)*80;
+ if (i & 1) dest += 0x2000;
+ mask = 0x80;
+ if (bpp == 1)
+ {
+ if (attr & 0x80)
+ {
+ data = read_byte(0xb800,dest);
+ }
+ else
+ {
+ data = 0x00;
+ }
+ for(j=0;j<8;j++)
+ {
+ if (fdata[src+i] & mask)
+ {
+ if (attr & 0x80)
+ {
+ data ^= (attr & 0x01) << (7-j);
+ }
+ else
+ {
+ data |= (attr & 0x01) << (7-j);
+ }
+ }
+ mask >>= 1;
+ }
+ write_byte(0xb800,dest,data);
+ }
+ else
+ {
+ while (mask > 0)
+ {
+ if (attr & 0x80)
+ {
+ data = read_byte(0xb800,dest);
+ }
+ else
+ {
+ data = 0x00;
+ }
+ for(j=0;j<4;j++)
+ {
+ if (fdata[src+i] & mask)
+ {
+ if (attr & 0x80)
+ {
+ data ^= (attr & 0x03) << ((3-j)*2);
+ }
+ else
+ {
+ data |= (attr & 0x03) << ((3-j)*2);
+ }
+ }
+ mask >>= 1;
+ }
+ write_byte(0xb800,dest,data);
+ dest += 1;
+ }
+ }
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols)
+Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;
+{
+ Bit8u i,j,mask,data;
+ Bit8u *fdata;
+ Bit16u addr,dest,src;
+
+ fdata = &vgafont8;
+ addr=xcurs*8+ycurs*nbcols*64;
+ src = car * 8;
+ for(i=0;i<8;i++)
+ {
+ dest=addr+i*nbcols*8;
+ mask = 0x80;
+ for(j=0;j<8;j++)
+ {
+ data = 0x00;
+ if (fdata[src+i] & mask)
+ {
+ data = attr;
+ }
+ write_byte(0xa000,dest+j,data);
+ mask >>= 1;
+ }
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_char_attr (car,page,attr,count)
+Bit8u car;Bit8u page;Bit8u attr;Bit16u count;
+{
+ Bit8u cheight,xcurs,ycurs,mode,line,bpp;
+ Bit16u nbcols,nbrows,address;
+ Bit16u cursor,dummy;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the cursor pos for the page
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ if(vga_modes[line].class==TEXT)
+ {
+ // Compute the address
+ address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
+
+ dummy=((Bit16u)attr<<8)+car;
+ memsetw(vga_modes[line].sstart,address,dummy,count);
+ }
+ else
+ {
+ // FIXME gfx mode not complete
+ cheight=video_param_table[line_to_vpti[line]].cheight;
+ bpp=vga_modes[line].pixbits;
+ while((count-->0) && (xcurs<nbcols))
+ {
+ switch(vga_modes[line].memmodel)
+ {
+ case PLANAR4:
+ case PLANAR1:
+ write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
+ break;
+ case CGA:
+ write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
+ break;
+ case LINEAR8:
+ write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
+ break;
+#ifdef DEBUG
+ default:
+ unimplemented();
+#endif
+ }
+ xcurs++;
+ }
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_char_only (car,page,attr,count)
+Bit8u car;Bit8u page;Bit8u attr;Bit16u count;
+{
+ Bit8u cheight,xcurs,ycurs,mode,line,bpp;
+ Bit16u nbcols,nbrows,address;
+ Bit16u cursor,dummy;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the cursor pos for the page
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ if(vga_modes[line].class==TEXT)
+ {
+ // Compute the address
+ address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
+
+ while(count-->0)
+ {write_byte(vga_modes[line].sstart,address,car);
+ address+=2;
+ }
+ }
+ else
+ {
+ // FIXME gfx mode not complete
+ cheight=video_param_table[line_to_vpti[line]].cheight;
+ bpp=vga_modes[line].pixbits;
+ while((count-->0) && (xcurs<nbcols))
+ {
+ switch(vga_modes[line].memmodel)
+ {
+ case PLANAR4:
+ case PLANAR1:
+ write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
+ break;
+ case CGA:
+ write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
+ break;
+ case LINEAR8:
+ write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
+ break;
+#ifdef DEBUG
+ default:
+ unimplemented();
+#endif
+ }
+ xcurs++;
+ }
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_group_0B:
+ cmp bh, #0x00
+ je biosfn_set_border_color
+ cmp bh, #0x01
+ je biosfn_set_palette
+#ifdef DEBUG
+ call _unknown
+#endif
+ ret
+biosfn_set_border_color:
+ push ax
+ push bx
+ push cx
+ push dx
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x00
+ out dx, al
+ mov al, bl
+ and al, #0x0f
+ test al, #0x08
+ jz set_low_border
+ add al, #0x08
+set_low_border:
+ out dx, al
+ mov cl, #0x01
+ and bl, #0x10
+set_intensity_loop:
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, cl
+ out dx, al
+ mov dx, # VGAREG_ACTL_READ_DATA
+ in al, dx
+ and al, #0xef
+ or al, bl
+ mov dx, # VGAREG_ACTL_ADDRESS
+ out dx, al
+ inc cl
+ cmp cl, #0x04
+ jne set_intensity_loop
+ mov al, #0x20
+ out dx, al
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+biosfn_set_palette:
+ push ax
+ push bx
+ push cx
+ push dx
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov cl, #0x01
+ and bl, #0x01
+set_cga_palette_loop:
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, cl
+ out dx, al
+ mov dx, # VGAREG_ACTL_READ_DATA
+ in al, dx
+ and al, #0xfe
+ or al, bl
+ mov dx, # VGAREG_ACTL_ADDRESS
+ out dx, al
+ inc cl
+ cmp cl, #0x04
+ jne set_cga_palette_loop
+ mov al, #0x20
+ out dx, al
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_pixel (BH,AL,CX,DX) Bit8u BH;Bit8u AL;Bit16u CX;Bit16u DX;
+{
+ Bit8u mode,line,mask,attr,data;
+ Bit16u addr;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+ if(vga_modes[line].class==TEXT)return;
+
+ switch(vga_modes[line].memmodel)
+ {
+ case PLANAR4:
+ case PLANAR1:
+ addr = CX/8+DX*read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+ mask = 0x80 >> (CX & 0x07);
+ outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08);
+ outw(VGAREG_GRDC_ADDRESS, 0x0205);
+ data = read_byte(0xa000,addr);
+ if (AL & 0x80)
+ {
+ outw(VGAREG_GRDC_ADDRESS, 0x1803);
+ }
+ write_byte(0xa000,addr,AL);
+ASM_START
+ mov dx, # VGAREG_GRDC_ADDRESS
+ mov ax, #0xff08
+ out dx, ax
+ mov ax, #0x0005
+ out dx, ax
+ mov ax, #0x0003
+ out dx, ax
+ASM_END
+ break;
+ case CGA:
+ if(vga_modes[line].pixbits==2)
+ {
+ addr=(CX>>2)+(DX>>1)*80;
+ }
+ else
+ {
+ addr=(CX>>3)+(DX>>1)*80;
+ }
+ if (DX & 1) addr += 0x2000;
+ data = read_byte(0xb800,addr);
+ if(vga_modes[line].pixbits==2)
+ {
+ attr = (AL & 0x03) << ((3 - (CX & 0x03)) * 2);
+ mask = 0x03 << ((3 - (CX & 0x03)) * 2);
+ }
+ else
+ {
+ attr = (AL & 0x01) << (7 - (CX & 0x07));
+ mask = 0x01 << (7 - (CX & 0x07));
+ }
+ if (AL & 0x80)
+ {
+ data ^= attr;
+ }
+ else
+ {
+ data &= ~mask;
+ data |= attr;
+ }
+ write_byte(0xb800,addr,data);
+ break;
+ case LINEAR8:
+ addr=CX+DX*(read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8);
+ write_byte(0xa000,addr,AL);
+ break;
+#ifdef DEBUG
+ default:
+ unimplemented();
+#endif
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_read_pixel (BH,CX,DX,AX) Bit8u BH;Bit16u CX;Bit16u DX;Bit16u *AX;
+{
+ Bit8u mode,line,mask,attr,data,i;
+ Bit16u addr;
+ Bit16u ss=get_SS();
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+ if(vga_modes[line].class==TEXT)return;
+
+ switch(vga_modes[line].memmodel)
+ {
+ case PLANAR4:
+ case PLANAR1:
+ addr = CX/8+DX*read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+ mask = 0x80 >> (CX & 0x07);
+ attr = 0x00;
+ for(i=0;i<4;i++)
+ {
+ outw(VGAREG_GRDC_ADDRESS, (i << 8) | 0x04);
+ data = read_byte(0xa000,addr) & mask;
+ if (data > 0) attr |= (0x01 << i);
+ }
+ break;
+ case CGA:
+ addr=(CX>>2)+(DX>>1)*80;
+ if (DX & 1) addr += 0x2000;
+ data = read_byte(0xb800,addr);
+ if(vga_modes[line].pixbits==2)
+ {
+ attr = (data >> ((3 - (CX & 0x03)) * 2)) & 0x03;
+ }
+ else
+ {
+ attr = (data >> (7 - (CX & 0x07))) & 0x01;
+ }
+ break;
+ case LINEAR8:
+ addr=CX+DX*(read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8);
+ attr=read_byte(0xa000,addr);
+ break;
+ default:
+#ifdef DEBUG
+ unimplemented();
+#endif
+ attr = 0;
+ }
+ write_word(ss,AX,(read_word(ss,AX) & 0xff00) | attr);
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_teletype (car, page, attr, flag)
+Bit8u car;Bit8u page;Bit8u attr;Bit8u flag;
+{// flag = WITH_ATTR / NO_ATTR
+
+ Bit8u cheight,xcurs,ycurs,mode,line,bpp;
+ Bit16u nbcols,nbrows,address;
+ Bit16u cursor,dummy;
+
+ // special case if page is 0xff, use current page
+ if(page==0xff)
+ page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the cursor pos for the page
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ switch(car)
+ {
+ case 7:
+ //FIXME should beep
+ break;
+
+ case 8:
+ if(xcurs>0)xcurs--;
+ break;
+
+ case '\r':
+ xcurs=0;
+ break;
+
+ case '\n':
+ ycurs++;
+ break;
+
+ case '\t':
+ do
+ {
+ biosfn_write_teletype(' ',page,attr,flag);
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+ }while(xcurs%8==0);
+ break;
+
+ default:
+
+ if(vga_modes[line].class==TEXT)
+ {
+ // Compute the address
+ address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
+
+ // Write the char
+ write_byte(vga_modes[line].sstart,address,car);
+
+ if(flag==WITH_ATTR)
+ write_byte(vga_modes[line].sstart,address+1,attr);
+ }
+ else
+ {
+ // FIXME gfx mode not complete
+ cheight=video_param_table[line_to_vpti[line]].cheight;
+ bpp=vga_modes[line].pixbits;
+ switch(vga_modes[line].memmodel)
+ {
+ case PLANAR4:
+ case PLANAR1:
+ write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
+ break;
+ case CGA:
+ write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
+ break;
+ case LINEAR8:
+ write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
+ break;
+#ifdef DEBUG
+ default:
+ unimplemented();
+#endif
+ }
+ }
+ xcurs++;
+ }
+
+ // Do we need to wrap ?
+ if(xcurs==nbcols)
+ {xcurs=0;
+ ycurs++;
+ }
+
+ // Do we need to scroll ?
+ if(ycurs==nbrows)
+ {
+ if(vga_modes[line].class==TEXT)
+ {
+ address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+(ycurs-1)*nbcols)*2;
+ attr=read_byte(vga_modes[line].sstart,address+1);
+ biosfn_scroll(0x01,attr,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
+ }
+ else
+ {
+ biosfn_scroll(0x01,0x00,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
+ }
+ ycurs-=1;
+ }
+
+ // Set the cursor for the page
+ cursor=ycurs; cursor<<=8; cursor+=xcurs;
+ biosfn_set_cursor_pos(page,cursor);
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_get_video_mode:
+ push ds
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ push bx
+ mov bx, # BIOSMEM_CURRENT_PAGE
+ mov al, [bx]
+ pop bx
+ mov bh, al
+ push bx
+ mov bx, # BIOSMEM_VIDEO_CTL
+ mov ah, [bx]
+ and ah, #0x80
+ mov bx, # BIOSMEM_CURRENT_MODE
+ mov al, [bx]
+ or al, ah
+ mov bx, # BIOSMEM_NB_COLS
+ mov ah, [bx]
+ pop bx
+ pop ds
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_group_10:
+ cmp al, #0x00
+ jne int10_test_1001
+ jmp biosfn_set_single_palette_reg
+int10_test_1001:
+ cmp al, #0x01
+ jne int10_test_1002
+ jmp biosfn_set_overscan_border_color
+int10_test_1002:
+ cmp al, #0x02
+ jne int10_test_1003
+ jmp biosfn_set_all_palette_reg
+int10_test_1003:
+ cmp al, #0x03
+ jne int10_test_1007
+ jmp biosfn_toggle_intensity
+int10_test_1007:
+ cmp al, #0x07
+ jne int10_test_1008
+ jmp biosfn_get_single_palette_reg
+int10_test_1008:
+ cmp al, #0x08
+ jne int10_test_1009
+ jmp biosfn_read_overscan_border_color
+int10_test_1009:
+ cmp al, #0x09
+ jne int10_test_1010
+ jmp biosfn_get_all_palette_reg
+int10_test_1010:
+ cmp al, #0x10
+ jne int10_test_1012
+ jmp biosfn_set_single_dac_reg
+int10_test_1012:
+ cmp al, #0x12
+ jne int10_test_1013
+ jmp biosfn_set_all_dac_reg
+int10_test_1013:
+ cmp al, #0x13
+ jne int10_test_1015
+ jmp biosfn_select_video_dac_color_page
+int10_test_1015:
+ cmp al, #0x15
+ jne int10_test_1017
+ jmp biosfn_read_single_dac_reg
+int10_test_1017:
+ cmp al, #0x17
+ jne int10_test_1018
+ jmp biosfn_read_all_dac_reg
+int10_test_1018:
+ cmp al, #0x18
+ jne int10_test_1019
+ jmp biosfn_set_pel_mask
+int10_test_1019:
+ cmp al, #0x19
+ jne int10_test_101A
+ jmp biosfn_read_pel_mask
+int10_test_101A:
+ cmp al, #0x1a
+ jne int10_group_10_unknown
+ jmp biosfn_read_video_dac_state
+int10_group_10_unknown:
+#ifdef DEBUG
+ call _unknown
+#endif
+ ret
+
+biosfn_set_single_palette_reg:
+ cmp bl, #0x14
+ ja no_actl_reg1
+ push ax
+ push dx
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, bl
+ out dx, al
+ mov al, bh
+ out dx, al
+ mov al, #0x20
+ out dx, al
+ pop dx
+ pop ax
+no_actl_reg1:
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_overscan_border_color:
+ push bx
+ mov bl, #0x11
+ call biosfn_set_single_palette_reg
+ pop bx
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_all_palette_reg:
+ push ax
+ push bx
+ push cx
+ push dx
+ mov bx, dx
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov cl, #0x00
+ mov dx, # VGAREG_ACTL_ADDRESS
+set_palette_loop:
+ mov al, cl
+ out dx, al
+ seg es
+ mov al, [bx]
+ out dx, al
+ inc bx
+ inc cl
+ cmp cl, #0x10
+ jne set_palette_loop
+ mov al, #0x11
+ out dx, al
+ seg es
+ mov al, [bx]
+ out dx, al
+ mov al, #0x20
+ out dx, al
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_toggle_intensity:
+ push ax
+ push bx
+ push dx
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x10
+ out dx, al
+ mov dx, # VGAREG_ACTL_READ_DATA
+ in al, dx
+ and al, #0xf7
+ and bl, #0x01
+ shl bl, 3
+ or al, bl
+ mov dx, # VGAREG_ACTL_ADDRESS
+ out dx, al
+ mov al, #0x20
+ out dx, al
+ pop dx
+ pop bx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_get_single_palette_reg:
+ cmp bl, #0x14
+ ja no_actl_reg2
+ push ax
+ push dx
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, bl
+ out dx, al
+ mov dx, # VGAREG_ACTL_READ_DATA
+ in al, dx
+ mov bh, al
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x20
+ out dx, al
+ pop dx
+ pop ax
+no_actl_reg2:
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_overscan_border_color:
+ push ax
+ push bx
+ mov bl, #0x11
+ call biosfn_get_single_palette_reg
+ mov al, bh
+ pop bx
+ mov bh, al
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_get_all_palette_reg:
+ push ax
+ push bx
+ push cx
+ push dx
+ mov bx, dx
+ mov cl, #0x00
+get_palette_loop:
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, cl
+ out dx, al
+ mov dx, # VGAREG_ACTL_READ_DATA
+ in al, dx
+ seg es
+ mov [bx], al
+ inc bx
+ inc cl
+ cmp cl, #0x10
+ jne get_palette_loop
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x11
+ out dx, al
+ mov dx, # VGAREG_ACTL_READ_DATA
+ in al, dx
+ seg es
+ mov [bx], al
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x20
+ out dx, al
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_single_dac_reg:
+ push ax
+ push dx
+ mov dx, # VGAREG_DAC_WRITE_ADDRESS
+ mov al, bl
+ out dx, al
+ mov dx, # VGAREG_DAC_DATA
+ pop ax
+ push ax
+ mov al, ah
+ out dx, al
+ mov al, ch
+ out dx, al
+ mov al, cl
+ out dx, al
+ pop dx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_all_dac_reg:
+ push ax
+ push bx
+ push cx
+ push dx
+ mov dx, # VGAREG_DAC_WRITE_ADDRESS
+ mov al, bl
+ out dx, al
+ pop dx
+ push dx
+ mov bx, dx
+ mov dx, # VGAREG_DAC_DATA
+set_dac_loop:
+ seg es
+ mov al, [bx]
+ out dx, al
+ inc bx
+ seg es
+ mov al, [bx]
+ out dx, al
+ inc bx
+ seg es
+ mov al, [bx]
+ out dx, al
+ inc bx
+ dec cx
+ jnz set_dac_loop
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_select_video_dac_color_page:
+ push ax
+ push bx
+ push dx
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x10
+ out dx, al
+ mov dx, # VGAREG_ACTL_READ_DATA
+ in al, dx
+ and bl, #0x01
+ jnz set_dac_page
+ and al, #0x7f
+ shl bh, 7
+ or al, bh
+ mov dx, # VGAREG_ACTL_ADDRESS
+ out dx, al
+ jmp set_actl_normal
+set_dac_page:
+ push ax
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x14
+ out dx, al
+ pop ax
+ and al, #0x80
+ jnz set_dac_16_page
+ shl bh, 2
+set_dac_16_page:
+ and bh, #0x0f
+ mov al, bh
+ out dx, al
+set_actl_normal:
+ mov al, #0x20
+ out dx, al
+ pop dx
+ pop bx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_single_dac_reg:
+ push ax
+ push dx
+ mov dx, # VGAREG_DAC_READ_ADDRESS
+ mov al, bl
+ out dx, al
+ pop ax
+ mov ah, al
+ mov dx, # VGAREG_DAC_DATA
+ in al, dx
+ xchg al, ah
+ push ax
+ in al, dx
+ mov ch, al
+ in al, dx
+ mov cl, al
+ pop dx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_all_dac_reg:
+ push ax
+ push bx
+ push cx
+ push dx
+ mov dx, # VGAREG_DAC_READ_ADDRESS
+ mov al, bl
+ out dx, al
+ pop dx
+ push dx
+ mov bx, dx
+ mov dx, # VGAREG_DAC_DATA
+read_dac_loop:
+ in al, dx
+ seg es
+ mov [bx], al
+ inc bx
+ in al, dx
+ seg es
+ mov [bx], al
+ inc bx
+ in al, dx
+ seg es
+ mov [bx], al
+ inc bx
+ dec cx
+ jnz read_dac_loop
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_pel_mask:
+ push ax
+ push dx
+ mov dx, # VGAREG_PEL_MASK
+ mov al, bl
+ out dx, al
+ pop dx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_pel_mask:
+ push ax
+ push dx
+ mov dx, # VGAREG_PEL_MASK
+ in al, dx
+ mov bl, al
+ pop dx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_video_dac_state:
+ push ax
+ push dx
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x10
+ out dx, al
+ mov dx, # VGAREG_ACTL_READ_DATA
+ in al, dx
+ mov bl, al
+ shr bl, 7
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x14
+ out dx, al
+ mov dx, # VGAREG_ACTL_READ_DATA
+ in al, dx
+ mov bh, al
+ and bh, #0x0f
+ test bl, #0x01
+ jnz get_dac_16_page
+ shr bh, 2
+get_dac_16_page:
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x20
+ out dx, al
+ pop dx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_perform_gray_scale_summing (start,count)
+Bit16u start;Bit16u count;
+{Bit8u r,g,b;
+ Bit16u i;
+ Bit16u index;
+
+ inb(VGAREG_ACTL_RESET);
+ outb(VGAREG_ACTL_ADDRESS,0x00);
+
+ for( index = 0; index < count; index++ )
+ {
+ // set read address and switch to read mode
+ outb(VGAREG_DAC_READ_ADDRESS,start);
+ // get 6-bit wide RGB data values
+ r=inb( VGAREG_DAC_DATA );
+ g=inb( VGAREG_DAC_DATA );
+ b=inb( VGAREG_DAC_DATA );
+
+ // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
+ i = ( ( 77*r + 151*g + 28*b ) + 0x80 ) >> 8;
+
+ if(i>0x3f)i=0x3f;
+
+ // set write address and switch to write mode
+ outb(VGAREG_DAC_WRITE_ADDRESS,start);
+ // write new intensity value
+ outb( VGAREG_DAC_DATA, i&0xff );
+ outb( VGAREG_DAC_DATA, i&0xff );
+ outb( VGAREG_DAC_DATA, i&0xff );
+ start++;
+ }
+ inb(VGAREG_ACTL_RESET);
+ outb(VGAREG_ACTL_ADDRESS,0x20);
+}
+
+// --------------------------------------------------------------------------------------------
+static void get_font_access()
+{
+ASM_START
+ mov dx, # VGAREG_SEQU_ADDRESS
+ mov ax, #0x0100
+ out dx, ax
+ mov ax, #0x0402
+ out dx, ax
+ mov ax, #0x0704
+ out dx, ax
+ mov ax, #0x0300
+ out dx, ax
+ mov dx, # VGAREG_GRDC_ADDRESS
+ mov ax, #0x0204
+ out dx, ax
+ mov ax, #0x0005
+ out dx, ax
+ mov ax, #0x0406
+ out dx, ax
+ASM_END
+}
+
+static void release_font_access()
+{
+ASM_START
+ mov dx, # VGAREG_SEQU_ADDRESS
+ mov ax, #0x0100
+ out dx, ax
+ mov ax, #0x0302
+ out dx, ax
+ mov ax, #0x0304
+ out dx, ax
+ mov ax, #0x0300
+ out dx, ax
+ mov dx, # VGAREG_READ_MISC_OUTPUT
+ in al, dx
+ and al, #0x01
+ shl al, 2
+ or al, #0x0a
+ mov ah, al
+ mov al, #0x06
+ mov dx, # VGAREG_GRDC_ADDRESS
+ out dx, ax
+ mov ax, #0x0004
+ out dx, ax
+ mov ax, #0x1005
+ out dx, ax
+ASM_END
+}
+
+ASM_START
+idiv_u:
+ xor dx,dx
+ div bx
+ ret
+ASM_END
+
+static void set_scan_lines(lines) Bit8u lines;
+{
+ Bit16u crtc_addr,cols,page,vde;
+ Bit8u crtc_r9,ovl,rows;
+
+ crtc_addr = read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
+ outb(crtc_addr, 0x09);
+ crtc_r9 = inb(crtc_addr+1);
+ crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
+ outb(crtc_addr+1, crtc_r9);
+ if(lines==8)
+ {
+ biosfn_set_cursor_shape(0x06,0x07);
+ }
+ else
+ {
+ biosfn_set_cursor_shape(lines-4,lines-3);
+ }
+ write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, lines);
+ outb(crtc_addr, 0x12);
+ vde = inb(crtc_addr+1);
+ outb(crtc_addr, 0x07);
+ ovl = inb(crtc_addr+1);
+ vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
+ rows = vde / lines;
+ write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, rows-1);
+ cols = read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+ write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, rows * cols * 2);
+}
+
+static void biosfn_load_text_user_pat (AL,ES,BP,CX,DX,BL,BH) Bit8u AL;Bit16u ES;Bit16u BP;Bit16u CX;Bit16u DX;Bit8u BL;Bit8u BH;
+{
+ Bit16u blockaddr,dest,i,src;
+
+ get_font_access();
+ blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
+ for(i=0;i<CX;i++)
+ {
+ src = BP + i * BH;
+ dest = blockaddr + (DX + i) * 32;
+ memcpyb(0xA000, dest, ES, src, BH);
+ }
+ release_font_access();
+ if(AL>=0x10)
+ {
+ set_scan_lines(BH);
+ }
+}
+
+static void biosfn_load_text_8_14_pat (AL,BL) Bit8u AL;Bit8u BL;
+{
+ Bit16u blockaddr,dest,i,src;
+
+ get_font_access();
+ blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
+ for(i=0;i<0x100;i++)
+ {
+ src = i * 14;
+ dest = blockaddr + i * 32;
+ memcpyb(0xA000, dest, 0xC000, vgafont14+src, 14);
+ }
+ release_font_access();
+ if(AL>=0x10)
+ {
+ set_scan_lines(14);
+ }
+}
+
+static void biosfn_load_text_8_8_pat (AL,BL) Bit8u AL;Bit8u BL;
+{
+ Bit16u blockaddr,dest,i,src;
+
+ get_font_access();
+ blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
+ for(i=0;i<0x100;i++)
+ {
+ src = i * 8;
+ dest = blockaddr + i * 32;
+ memcpyb(0xA000, dest, 0xC000, vgafont8+src, 8);
+ }
+ release_font_access();
+ if(AL>=0x10)
+ {
+ set_scan_lines(8);
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_text_block_specifier:
+ push ax
+ push dx
+ mov dx, # VGAREG_SEQU_ADDRESS
+ mov ah, bl
+ mov al, #0x03
+ out dx, ax
+ pop dx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_load_text_8_16_pat (AL,BL) Bit8u AL;Bit8u BL;
+{
+ Bit16u blockaddr,dest,i,src;
+
+ get_font_access();
+ blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
+ for(i=0;i<0x100;i++)
+ {
+ src = i * 16;
+ dest = blockaddr + i * 32;
+ memcpyb(0xA000, dest, 0xC000, vgafont16+src, 16);
+ }
+ release_font_access();
+ if(AL>=0x10)
+ {
+ set_scan_lines(16);
+ }
+}
+
+static void biosfn_load_gfx_8_8_chars (ES,BP) Bit16u ES;Bit16u BP;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_load_gfx_user_chars (ES,BP,CX,BL,DL) Bit16u ES;Bit16u BP;Bit16u CX;Bit8u BL;Bit8u DL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_load_gfx_8_14_chars (BL) Bit8u BL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_load_gfx_8_8_dd_chars (BL) Bit8u BL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_load_gfx_8_16_chars (BL) Bit8u BL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+// --------------------------------------------------------------------------------------------
+static void biosfn_get_font_info (BH,ES,BP,CX,DX)
+Bit8u BH;Bit16u *ES;Bit16u *BP;Bit16u *CX;Bit16u *DX;
+{Bit16u ss=get_SS();
+
+ switch(BH)
+ {case 0x00:
+ write_word(ss,ES,read_word(0x00,0x1f*4));
+ write_word(ss,BP,read_word(0x00,(0x1f*4)+2));
+ break;
+ case 0x01:
+ write_word(ss,ES,read_word(0x00,0x43*4));
+ write_word(ss,BP,read_word(0x00,(0x43*4)+2));
+ break;
+ case 0x02:
+ write_word(ss,ES,0xC000);
+ write_word(ss,BP,vgafont14);
+ break;
+ case 0x03:
+ write_word(ss,ES,0xC000);
+ write_word(ss,BP,vgafont8);
+ break;
+ case 0x04:
+ write_word(ss,ES,0xC000);
+ write_word(ss,BP,vgafont8+128*8);
+ break;
+ case 0x05:
+ write_word(ss,ES,0xC000);
+ write_word(ss,BP,vgafont14alt);
+ break;
+ case 0x06:
+ write_word(ss,ES,0xC000);
+ write_word(ss,BP,vgafont16);
+ break;
+ case 0x07:
+ write_word(ss,ES,0xC000);
+ write_word(ss,BP,vgafont16alt);
+ break;
+ default:
+ #ifdef DEBUG
+ printf("Get font info BH(%02x) was discarded\n",BH);
+ #endif
+ return;
+ }
+ // Set byte/char of on screen font
+ write_word(ss,CX,(Bit16u)read_byte(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT));
+
+ // Set Highest char row
+ write_word(ss,DX,(Bit16u)read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS));
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_get_ega_info:
+ push ds
+ push ax
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ xor ch, ch
+ mov bx, # BIOSMEM_SWITCHES
+ mov cl, [bx]
+ and cl, #0x0f
+ mov bx, # BIOSMEM_CRTC_ADDRESS
+ mov ax, [bx]
+ mov bx, #0x0003
+ cmp ax, # VGAREG_MDA_CRTC_ADDRESS
+ jne mode_ega_color
+ mov bh, #0x01
+mode_ega_color:
+ pop ax
+ pop ds
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_alternate_prtsc()
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_select_vert_res:
+
+; res : 00 200 lines, 01 350 lines, 02 400 lines
+
+ push ds
+ push bx
+ push dx
+ mov dl, al
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ mov bx, # BIOSMEM_MODESET_CTL
+ mov al, [bx]
+ mov bx, # BIOSMEM_SWITCHES
+ mov ah, [bx]
+ cmp dl, #0x01
+ je vert_res_350
+ jb vert_res_200
+ cmp dl, #0x02
+ je vert_res_400
+#ifdef DEBUG
+ mov al, dl
+ xor ah, ah
+ push ax
+ mov bx, #msg_vert_res
+ push bx
+ call _printf
+ add sp, #4
+#endif
+ jmp set_retcode
+vert_res_400:
+
+ ; reset modeset ctl bit 7 and set bit 4
+ ; set switches bit 3-0 to 0x09
+
+ and al, #0x7f
+ or al, #0x10
+ and ah, #0xf0
+ or ah, #0x09
+ jnz set_vert_res
+vert_res_350:
+
+ ; reset modeset ctl bit 7 and bit 4
+ ; set switches bit 3-0 to 0x09
+
+ and al, #0x6f
+ and ah, #0xf0
+ or ah, #0x09
+ jnz set_vert_res
+vert_res_200:
+
+ ; set modeset ctl bit 7 and reset bit 4
+ ; set switches bit 3-0 to 0x08
+
+ and al, #0xef
+ or al, #0x80
+ and ah, #0xf0
+ or ah, #0x08
+set_vert_res:
+ mov bx, # BIOSMEM_MODESET_CTL
+ mov [bx], al
+ mov bx, # BIOSMEM_SWITCHES
+ mov [bx], ah
+set_retcode:
+ mov ax, #0x1212
+ pop dx
+ pop bx
+ pop ds
+ ret
+
+#ifdef DEBUG
+msg_vert_res:
+.ascii "Select vert res (%02x) was discarded"
+.byte 0x0d,0x0a,0x00
+#endif
+
+
+biosfn_enable_default_palette_loading:
+ push ds
+ push bx
+ push dx
+ mov dl, al
+ and dl, #0x01
+ shl dl, 3
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ mov bx, # BIOSMEM_MODESET_CTL
+ mov al, [bx]
+ and al, #0xf7
+ or al, dl
+ mov [bx], al
+ mov ax, #0x1212
+ pop dx
+ pop bx
+ pop ds
+ ret
+
+
+biosfn_enable_video_addressing:
+ push bx
+ push dx
+ mov bl, al
+ and bl, #0x01
+ xor bl, #0x01
+ shl bl, 1
+ mov dx, # VGAREG_READ_MISC_OUTPUT
+ in al, dx
+ and al, #0xfd
+ or al, bl
+ mov dx, # VGAREG_WRITE_MISC_OUTPUT
+ out dx, al
+ mov ax, #0x1212
+ pop dx
+ pop bx
+ ret
+
+
+biosfn_enable_grayscale_summing:
+ push ds
+ push bx
+ push dx
+ mov dl, al
+ and dl, #0x01
+ xor dl, #0x01
+ shl dl, 1
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ mov bx, # BIOSMEM_MODESET_CTL
+ mov al, [bx]
+ and al, #0xfd
+ or al, dl
+ mov [bx], al
+ mov ax, #0x1212
+ pop dx
+ pop bx
+ pop ds
+ ret
+
+
+biosfn_enable_cursor_emulation:
+ push ds
+ push bx
+ push dx
+ mov dl, al
+ and dl, #0x01
+ xor dl, #0x01
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ mov bx, # BIOSMEM_MODESET_CTL
+ mov al, [bx]
+ and al, #0xfe
+ or al, dl
+ mov [bx], al
+ mov ax, #0x1212
+ pop dx
+ pop bx
+ pop ds
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_switch_video_interface (AL,ES,DX) Bit8u AL;Bit16u ES;Bit16u DX;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_enable_video_refresh_control (AL) Bit8u AL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_string (flag,page,attr,count,row,col,seg,offset)
+Bit8u flag;Bit8u page;Bit8u attr;Bit16u count;Bit8u row;Bit8u col;Bit16u seg;Bit16u offset;
+{
+ Bit16u newcurs,oldcurs,dummy;
+ Bit8u car,carattr;
+
+ // Read curs info for the page
+ biosfn_get_cursor_pos(page,&dummy,&oldcurs);
+
+ // if row=0xff special case : use current cursor position
+ if(row==0xff)
+ {col=oldcurs&0x00ff;
+ row=(oldcurs&0xff00)>>8;
+ }
+
+ newcurs=row; newcurs<<=8; newcurs+=col;
+ biosfn_set_cursor_pos(page,newcurs);
+
+ while(count--!=0)
+ {
+ car=read_byte(seg,offset++);
+ if((flag&0x02)!=0)
+ attr=read_byte(seg,offset++);
+
+ biosfn_write_teletype(car,page,attr,WITH_ATTR);
+ }
+
+ // Set back curs pos
+ if((flag&0x01)==0)
+ biosfn_set_cursor_pos(page,oldcurs);
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_group_1A:
+ cmp al, #0x00
+ je biosfn_read_display_code
+ cmp al, #0x01
+ je biosfn_set_display_code
+#ifdef DEBUG
+ call _unknown
+#endif
+ ret
+biosfn_read_display_code:
+ push ds
+ push ax
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ mov bx, # BIOSMEM_DCC_INDEX
+ mov al, [bx]
+ mov bl, al
+ xor bh, bh
+ pop ax
+ mov al, ah
+ pop ds
+ ret
+biosfn_set_display_code:
+ push ds
+ push ax
+ push bx
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ mov ax, bx
+ mov bx, # BIOSMEM_DCC_INDEX
+ mov [bx], al
+#ifdef DEBUG
+ mov al, ah
+ xor ah, ah
+ push ax
+ mov bx, #msg_alt_dcc
+ push bx
+ call _printf
+ add sp, #4
+#endif
+ pop bx
+ pop ax
+ mov al, ah
+ pop ds
+ ret
+
+#ifdef DEBUG
+msg_alt_dcc:
+.ascii "Alternate Display code (%02x) was discarded"
+.byte 0x0d,0x0a,0x00
+#endif
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_read_state_info (BX,ES,DI)
+Bit16u BX;Bit16u ES;Bit16u DI;
+{
+ // Address of static functionality table
+ write_word(ES,DI+0x00,&static_functionality);
+ write_word(ES,DI+0x02,0xC000);
+
+ // Hard coded copy from BIOS area. Should it be cleaner ?
+ memcpyb(ES,DI+0x04,BIOSMEM_SEG,0x49,30);
+ memcpyb(ES,DI+0x22,BIOSMEM_SEG,0x84,3);
+
+ write_byte(ES,DI+0x25,read_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX));
+ write_byte(ES,DI+0x26,0);
+ write_byte(ES,DI+0x27,16);
+ write_byte(ES,DI+0x28,0);
+ write_byte(ES,DI+0x29,8);
+ write_byte(ES,DI+0x2a,2);
+ write_byte(ES,DI+0x2b,0);
+ write_byte(ES,DI+0x2c,0);
+ write_byte(ES,DI+0x31,3);
+ write_byte(ES,DI+0x32,0);
+
+ memsetb(ES,DI+0x33,0,13);
+}
+
+// --------------------------------------------------------------------------------------------
+// --------------------------------------------------------------------------------------------
+static Bit16u biosfn_read_video_state_size2 (CX)
+ Bit16u CX;
+{
+ Bit16u size;
+ size = 0;
+ if (CX & 1) {
+ size += 0x46;
+ }
+ if (CX & 2) {
+ size += (5 + 8 + 5) * 2 + 6;
+ }
+ if (CX & 4) {
+ size += 3 + 256 * 3 + 1;
+}
+ return size;
+}
+
+static void biosfn_read_video_state_size (CX, BX)
+ Bit16u CX; Bit16u *BX;
+{
+ Bit16u ss=get_SS();
+ write_word(ss, BX, biosfn_read_video_state_size2(CX));
+}
+
+static Bit16u biosfn_save_video_state (CX,ES,BX)
+ Bit16u CX;Bit16u ES;Bit16u BX;
+{
+ Bit16u i, v, crtc_addr, ar_index;
+
+ crtc_addr = read_word(BIOSMEM_SEG, BIOSMEM_CRTC_ADDRESS);
+ if (CX & 1) {
+ write_byte(ES, BX, inb(VGAREG_SEQU_ADDRESS)); BX++;
+ write_byte(ES, BX, inb(crtc_addr)); BX++;
+ write_byte(ES, BX, inb(VGAREG_GRDC_ADDRESS)); BX++;
+ inb(VGAREG_ACTL_RESET);
+ ar_index = inb(VGAREG_ACTL_ADDRESS);
+ write_byte(ES, BX, ar_index); BX++;
+ write_byte(ES, BX, inb(VGAREG_READ_FEATURE_CTL)); BX++;
+
+ for(i=1;i<=4;i++){
+ outb(VGAREG_SEQU_ADDRESS, i);
+ write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
+ }
+ outb(VGAREG_SEQU_ADDRESS, 0);
+ write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
+
+ for(i=0;i<=0x18;i++) {
+ outb(crtc_addr,i);
+ write_byte(ES, BX, inb(crtc_addr+1)); BX++;
+ }
+
+ for(i=0;i<=0x13;i++) {
+ inb(VGAREG_ACTL_RESET);
+ outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
+ write_byte(ES, BX, inb(VGAREG_ACTL_READ_DATA)); BX++;
+ }
+ inb(VGAREG_ACTL_RESET);
+
+ for(i=0;i<=8;i++) {
+ outb(VGAREG_GRDC_ADDRESS,i);
+ write_byte(ES, BX, inb(VGAREG_GRDC_DATA)); BX++;
+ }
+
+ write_word(ES, BX, crtc_addr); BX+= 2;
+
+ /* XXX: read plane latches */
+ write_byte(ES, BX, 0); BX++;
+ write_byte(ES, BX, 0); BX++;
+ write_byte(ES, BX, 0); BX++;
+ write_byte(ES, BX, 0); BX++;
+ }
+ if (CX & 2) {
+ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)); BX++;
+ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)); BX += 2;
+ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE)); BX += 2;
+ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)); BX += 2;
+ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)); BX++;
+ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT)); BX += 2;
+ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL)); BX++;
+ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES)); BX++;
+ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)); BX++;
+ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE)); BX += 2;
+ for(i=0;i<8;i++) {
+ write_word(ES, BX, read_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i));
+ BX += 2;
+ }
+ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START)); BX += 2;
+ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE)); BX++;
+ /* current font */
+ write_word(ES, BX, read_word(0, 0x1f * 4)); BX += 2;
+ write_word(ES, BX, read_word(0, 0x1f * 4 + 2)); BX += 2;
+ write_word(ES, BX, read_word(0, 0x43 * 4)); BX += 2;
+ write_word(ES, BX, read_word(0, 0x43 * 4 + 2)); BX += 2;
+ }
+ if (CX & 4) {
+ /* XXX: check this */
+ write_byte(ES, BX, inb(VGAREG_DAC_STATE)); BX++; /* read/write mode dac */
+ write_byte(ES, BX, inb(VGAREG_DAC_WRITE_ADDRESS)); BX++; /* pix address */
+ write_byte(ES, BX, inb(VGAREG_PEL_MASK)); BX++;
+ // Set the whole dac always, from 0
+ outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
+ for(i=0;i<256*3;i++) {
+ write_byte(ES, BX, inb(VGAREG_DAC_DATA)); BX++;
+ }
+ write_byte(ES, BX, 0); BX++; /* color select register */
+ }
+ return BX;
+}
+
+static Bit16u biosfn_restore_video_state (CX,ES,BX)
+ Bit16u CX;Bit16u ES;Bit16u BX;
+{
+ Bit16u i, crtc_addr, v, addr1, ar_index;
+
+ if (CX & 1) {
+ // Reset Attribute Ctl flip-flop
+ inb(VGAREG_ACTL_RESET);
+
+ crtc_addr = read_word(ES, BX + 0x40);
+ addr1 = BX;
+ BX += 5;
+
+ for(i=1;i<=4;i++){
+ outb(VGAREG_SEQU_ADDRESS, i);
+ outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
+ }
+ outb(VGAREG_SEQU_ADDRESS, 0);
+ outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
+
+ // Disable CRTC write protection
+ outw(crtc_addr,0x0011);
+ // Set CRTC regs
+ for(i=0;i<=0x18;i++) {
+ if (i != 0x11) {
+ outb(crtc_addr,i);
+ outb(crtc_addr+1, read_byte(ES, BX));
+ }
+ BX++;
+ }
+ // select crtc base address
+ v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
+ if (crtc_addr = 0x3d4)
+ v |= 0x01;
+ outb(VGAREG_WRITE_MISC_OUTPUT, v);
+
+ // enable write protection if needed
+ outb(crtc_addr, 0x11);
+ outb(crtc_addr+1, read_byte(ES, BX - 0x18 + 0x11));
+
+ // Set Attribute Ctl
+ ar_index = read_byte(ES, addr1 + 0x03);
+ inb(VGAREG_ACTL_RESET);
+ for(i=0;i<=0x13;i++) {
+ outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
+ outb(VGAREG_ACTL_WRITE_DATA, read_byte(ES, BX)); BX++;
+ }
+ outb(VGAREG_ACTL_ADDRESS, ar_index);
+ inb(VGAREG_ACTL_RESET);
+
+ for(i=0;i<=8;i++) {
+ outb(VGAREG_GRDC_ADDRESS,i);
+ outb(VGAREG_GRDC_DATA, read_byte(ES, BX)); BX++;
+ }
+ BX += 2; /* crtc_addr */
+ BX += 4; /* plane latches */
+
+ outb(VGAREG_SEQU_ADDRESS, read_byte(ES, addr1)); addr1++;
+ outb(crtc_addr, read_byte(ES, addr1)); addr1++;
+ outb(VGAREG_GRDC_ADDRESS, read_byte(ES, addr1)); addr1++;
+ addr1++;
+ outb(crtc_addr - 0x4 + 0xa, read_byte(ES, addr1)); addr1++;
+ }
+ if (CX & 2) {
+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE, read_byte(ES, BX)); BX++;
+ write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS, read_word(ES, BX)); BX += 2;
+ write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, read_word(ES, BX)); BX += 2;
+ write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS, read_word(ES, BX)); BX += 2;
+ write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, read_byte(ES, BX)); BX++;
+ write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, read_word(ES, BX)); BX += 2;
+ write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL, read_byte(ES, BX)); BX++;
+ write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES, read_byte(ES, BX)); BX++;
+ write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL, read_byte(ES, BX)); BX++;
+ write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE, read_word(ES, BX)); BX += 2;
+ for(i=0;i<8;i++) {
+ write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i, read_word(ES, BX));
+ BX += 2;
+ }
+ write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START, read_word(ES, BX)); BX += 2;
+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE, read_byte(ES, BX)); BX++;
+ /* current font */
+ write_word(0, 0x1f * 4, read_word(ES, BX)); BX += 2;
+ write_word(0, 0x1f * 4 + 2, read_word(ES, BX)); BX += 2;
+ write_word(0, 0x43 * 4, read_word(ES, BX)); BX += 2;
+ write_word(0, 0x43 * 4 + 2, read_word(ES, BX)); BX += 2;
+ }
+ if (CX & 4) {
+ BX++;
+ v = read_byte(ES, BX); BX++;
+ outb(VGAREG_PEL_MASK, read_byte(ES, BX)); BX++;
+ // Set the whole dac always, from 0
+ outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
+ for(i=0;i<256*3;i++) {
+ outb(VGAREG_DAC_DATA, read_byte(ES, BX)); BX++;
+ }
+ BX++;
+ outb(VGAREG_DAC_WRITE_ADDRESS, v);
+ }
+ return BX;
+}
+
+// ============================================================================================
+//
+// Video Utils
+//
+// ============================================================================================
+
+// --------------------------------------------------------------------------------------------
+static Bit8u find_vga_entry(mode)
+Bit8u mode;
+{
+ Bit8u i,line=0xFF;
+ for(i=0;i<=MODE_MAX;i++)
+ if(vga_modes[i].svgamode==mode)
+ {line=i;
+ break;
+ }
+ return line;
+}
+
+/* =========================================================== */
+/*
+ * Misc Utils
+*/
+/* =========================================================== */
+
+// --------------------------------------------------------------------------------------------
+static void memsetb(seg,offset,value,count)
+ Bit16u seg;
+ Bit16u offset;
+ Bit16u value;
+ Bit16u count;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push cx
+ push es
+ push di
+
+ mov cx, 10[bp] ; count
+ cmp cx, #0x00
+ je memsetb_end
+ mov ax, 4[bp] ; segment
+ mov es, ax
+ mov ax, 6[bp] ; offset
+ mov di, ax
+ mov al, 8[bp] ; value
+ cld
+ rep
+ stosb
+
+memsetb_end:
+ pop di
+ pop es
+ pop cx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void memsetw(seg,offset,value,count)
+ Bit16u seg;
+ Bit16u offset;
+ Bit16u value;
+ Bit16u count;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push cx
+ push es
+ push di
+
+ mov cx, 10[bp] ; count
+ cmp cx, #0x00
+ je memsetw_end
+ mov ax, 4[bp] ; segment
+ mov es, ax
+ mov ax, 6[bp] ; offset
+ mov di, ax
+ mov ax, 8[bp] ; value
+ cld
+ rep
+ stosw
+
+memsetw_end:
+ pop di
+ pop es
+ pop cx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void memcpyb(dseg,doffset,sseg,soffset,count)
+ Bit16u dseg;
+ Bit16u doffset;
+ Bit16u sseg;
+ Bit16u soffset;
+ Bit16u count;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push cx
+ push es
+ push di
+ push ds
+ push si
+
+ mov cx, 12[bp] ; count
+ cmp cx, #0x0000
+ je memcpyb_end
+ mov ax, 4[bp] ; dsegment
+ mov es, ax
+ mov ax, 6[bp] ; doffset
+ mov di, ax
+ mov ax, 8[bp] ; ssegment
+ mov ds, ax
+ mov ax, 10[bp] ; soffset
+ mov si, ax
+ cld
+ rep
+ movsb
+
+memcpyb_end:
+ pop si
+ pop ds
+ pop di
+ pop es
+ pop cx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void memcpyw(dseg,doffset,sseg,soffset,count)
+ Bit16u dseg;
+ Bit16u doffset;
+ Bit16u sseg;
+ Bit16u soffset;
+ Bit16u count;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push cx
+ push es
+ push di
+ push ds
+ push si
+
+ mov cx, 12[bp] ; count
+ cmp cx, #0x0000
+ je memcpyw_end
+ mov ax, 4[bp] ; dsegment
+ mov es, ax
+ mov ax, 6[bp] ; doffset
+ mov di, ax
+ mov ax, 8[bp] ; ssegment
+ mov ds, ax
+ mov ax, 10[bp] ; soffset
+ mov si, ax
+ cld
+ rep
+ movsw
+
+memcpyw_end:
+ pop si
+ pop ds
+ pop di
+ pop es
+ pop cx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+/* =========================================================== */
+/*
+ * These functions where ripped from Kevin's rombios.c
+*/
+/* =========================================================== */
+
+// --------------------------------------------------------------------------------------------
+static Bit8u
+read_byte(seg, offset)
+ Bit16u seg;
+ Bit16u offset;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push bx
+ push ds
+ mov ax, 4[bp] ; segment
+ mov ds, ax
+ mov bx, 6[bp] ; offset
+ mov al, [bx]
+ ;; al = return value (byte)
+ pop ds
+ pop bx
+
+ pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static Bit16u
+read_word(seg, offset)
+ Bit16u seg;
+ Bit16u offset;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push bx
+ push ds
+ mov ax, 4[bp] ; segment
+ mov ds, ax
+ mov bx, 6[bp] ; offset
+ mov ax, [bx]
+ ;; ax = return value (word)
+ pop ds
+ pop bx
+
+ pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void
+write_byte(seg, offset, data)
+ Bit16u seg;
+ Bit16u offset;
+ Bit8u data;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push bx
+ push ds
+ mov ax, 4[bp] ; segment
+ mov ds, ax
+ mov bx, 6[bp] ; offset
+ mov al, 8[bp] ; data byte
+ mov [bx], al ; write data byte
+ pop ds
+ pop bx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void
+write_word(seg, offset, data)
+ Bit16u seg;
+ Bit16u offset;
+ Bit16u data;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push bx
+ push ds
+ mov ax, 4[bp] ; segment
+ mov ds, ax
+ mov bx, 6[bp] ; offset
+ mov ax, 8[bp] ; data word
+ mov [bx], ax ; write data word
+ pop ds
+ pop bx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+ Bit8u
+inb(port)
+ Bit16u port;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push dx
+ mov dx, 4[bp]
+ in al, dx
+ pop dx
+
+ pop bp
+ASM_END
+}
+
+ Bit16u
+inw(port)
+ Bit16u port;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push dx
+ mov dx, 4[bp]
+ in ax, dx
+ pop dx
+
+ pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+ void
+outb(port, val)
+ Bit16u port;
+ Bit8u val;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push dx
+ mov dx, 4[bp]
+ mov al, 6[bp]
+ out dx, al
+ pop dx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+ void
+outw(port, val)
+ Bit16u port;
+ Bit16u val;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push dx
+ mov dx, 4[bp]
+ mov ax, 6[bp]
+ out dx, ax
+ pop dx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+Bit16u get_SS()
+{
+ASM_START
+ mov ax, ss
+ASM_END
+}
+
+#ifdef DEBUG
+void unimplemented()
+{
+ printf("--> Unimplemented\n");
+}
+
+void unknown()
+{
+ printf("--> Unknown int10\n");
+}
+#endif
+
+// --------------------------------------------------------------------------------------------
+#if defined(USE_BX_INFO) || defined(DEBUG) || defined(CIRRUS_DEBUG)
+void printf(s)
+ Bit8u *s;
+{
+ Bit8u c, format_char;
+ Boolean in_format;
+ unsigned format_width, i;
+ Bit16u *arg_ptr;
+ Bit16u arg_seg, arg, digit, nibble, shift_count;
+
+ arg_ptr = &s;
+ arg_seg = get_SS();
+
+ in_format = 0;
+ format_width = 0;
+
+ while (c = read_byte(0xc000, s)) {
+ if ( c == '%' ) {
+ in_format = 1;
+ format_width = 0;
+ }
+ else if (in_format) {
+ if ( (c>='0') && (c<='9') ) {
+ format_width = (format_width * 10) + (c - '0');
+ }
+ else if (c == 'x') {
+ arg_ptr++; // increment to next arg
+ arg = read_word(arg_seg, arg_ptr);
+ if (format_width == 0)
+ format_width = 4;
+ i = 0;
+ digit = format_width - 1;
+ for (i=0; i<format_width; i++) {
+ nibble = (arg >> (4 * digit)) & 0x000f;
+ if (nibble <= 9)
+ outb(0x0500, nibble + '0');
+ else
+ outb(0x0500, (nibble - 10) + 'A');
+ digit--;
+ }
+ in_format = 0;
+ }
+ //else if (c == 'd') {
+ // in_format = 0;
+ // }
+ }
+ else {
+ outb(0x0500, c);
+ }
+ s ++;
+ }
+}
+#endif
+
+ASM_START
+ ; get LFB address from PCI
+ ; in - ax: PCI device vendor
+ ; out - ax: LFB address (high 16 bit)
+ ;; NOTE - may be called in protected mode
+_pci_get_lfb_addr:
+ push bx
+ push cx
+ push dx
+ push eax
+ mov bx, ax
+ xor cx, cx
+ mov dl, #0x00
+ call pci_read_reg
+ cmp ax, #0xffff
+ jz pci_get_lfb_addr_fail
+ pci_get_lfb_addr_next_dev:
+ mov dl, #0x00
+ call pci_read_reg
+ cmp ax, bx ;; check vendor
+ jz pci_get_lfb_addr_found
+ add cx, #0x8
+ cmp cx, #0x200 ;; search bus #0 and #1
+ jb pci_get_lfb_addr_next_dev
+ pci_get_lfb_addr_fail:
+ xor dx, dx ;; no LFB
+ jmp pci_get_lfb_addr_return
+ pci_get_lfb_addr_found:
+ mov dl, #0x10 ;; I/O space #0
+ call pci_read_reg
+ test ax, #0xfff1
+ jz pci_get_lfb_addr_success
+ mov dl, #0x14 ;; I/O space #1
+ call pci_read_reg
+ test ax, #0xfff1
+ jnz pci_get_lfb_addr_fail
+ pci_get_lfb_addr_success:
+ shr eax, #16
+ mov dx, ax ;; LFB address
+ pci_get_lfb_addr_return:
+ pop eax
+ mov ax, dx
+ pop dx
+ pop cx
+ pop bx
+ ret
+
+ ; read PCI register
+ ; in - cx: device/function
+ ; in - dl: register
+ ; out - eax: value
+pci_read_reg:
+ mov eax, #0x00800000
+ mov ax, cx
+ shl eax, #8
+ mov al, dl
+ mov dx, #0xcf8
+ out dx, eax
+ add dl, #4
+ in eax, dx
+ ret
+ASM_END
+
+#ifdef VBE
+#include "vbe.c"
+#endif
+
+#ifdef CIRRUS
+#include "clext.c"
+#endif
+
+// --------------------------------------------------------------------------------------------
+
+ASM_START
+;; DATA_SEG_DEFS_HERE
+ASM_END
+
+ASM_START
+.ascii "vgabios ends here"
+.byte 0x00
+vgabios_end:
+.byte 0xCB
+;; BLOCK_STRINGS_BEGIN
+ASM_END