- added instructions how to update the online documentation
[bochs-mirror.git] / iodev / vga.cc
bloba34e463ed32dfc9e0344e342fab7992f8f3bf9a9
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: vga.cc,v 1.154 2008/09/18 20:16:27 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2002 MandrakeSoft S.A.
6 //
7 // MandrakeSoft S.A.
8 // 43, rue d'Aboukir
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 /////////////////////////////////////////////////////////////////////////
28 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
29 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
30 // is used to know when we are exporting symbols and when we are importing.
31 #define BX_PLUGGABLE
33 #include "iodev.h"
35 #define LOG_THIS theVga->
37 #define VGA_TRACE_FEATURE
39 // Only reference the array if the tile numbers are within the bounds
40 // of the array. If out of bounds, do nothing.
41 #define SET_TILE_UPDATED(xtile, ytile, value) \
42 do { \
43 if (((xtile) < BX_NUM_X_TILES) && ((ytile) < BX_NUM_Y_TILES)) \
44 BX_VGA_THIS s.vga_tile_updated[(xtile)][(ytile)] = value; \
45 } while (0)
47 // Only reference the array if the tile numbers are within the bounds
48 // of the array. If out of bounds, return 0.
49 #define GET_TILE_UPDATED(xtile,ytile) \
50 ((((xtile) < BX_NUM_X_TILES) && ((ytile) < BX_NUM_Y_TILES))? \
51 BX_VGA_THIS s.vga_tile_updated[(xtile)][(ytile)] \
52 : 0)
54 static const Bit16u charmap_offset[8] = {
55 0x0000, 0x4000, 0x8000, 0xc000,
56 0x2000, 0x6000, 0xa000, 0xe000
59 static const Bit8u ccdat[16][4] = {
60 { 0x00, 0x00, 0x00, 0x00 },
61 { 0xff, 0x00, 0x00, 0x00 },
62 { 0x00, 0xff, 0x00, 0x00 },
63 { 0xff, 0xff, 0x00, 0x00 },
64 { 0x00, 0x00, 0xff, 0x00 },
65 { 0xff, 0x00, 0xff, 0x00 },
66 { 0x00, 0xff, 0xff, 0x00 },
67 { 0xff, 0xff, 0xff, 0x00 },
68 { 0x00, 0x00, 0x00, 0xff },
69 { 0xff, 0x00, 0x00, 0xff },
70 { 0x00, 0xff, 0x00, 0xff },
71 { 0xff, 0xff, 0x00, 0xff },
72 { 0x00, 0x00, 0xff, 0xff },
73 { 0xff, 0x00, 0xff, 0xff },
74 { 0x00, 0xff, 0xff, 0xff },
75 { 0xff, 0xff, 0xff, 0xff },
78 bx_vga_c *theVga = NULL;
80 unsigned old_iHeight = 0, old_iWidth = 0, old_MSL = 0;
82 #if BX_SUPPORT_CLGD54XX
83 void libvga_set_smf_pointer(bx_vga_c *theVga_ptr)
85 theVga = theVga_ptr;
87 #else // BX_SUPPORT_CLGD54XX
88 int libvga_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
90 theVga = new bx_vga_c();
91 bx_devices.pluginVgaDevice = theVga;
92 BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theVga, BX_PLUGIN_VGA);
93 return(0); // Success
96 void libvga_LTX_plugin_fini(void)
98 delete theVga;
100 #endif // BX_SUPPORT_CLGD54XX
102 bx_vga_c::bx_vga_c()
104 put("VGA");
105 s.vga_mem_updated = 0;
106 s.x_tilesize = X_TILESIZE;
107 s.y_tilesize = Y_TILESIZE;
108 timer_id = BX_NULL_TIMER_HANDLE;
109 s.memory = NULL;
112 bx_vga_c::~bx_vga_c()
114 if (s.memory != NULL) {
115 delete [] s.memory;
116 s.memory = NULL;
118 SIM->get_param_num(BXPN_VGA_UPDATE_INTERVAL)->set_handler(NULL);
119 BX_DEBUG(("Exit"));
122 void bx_vga_c::init(void)
124 unsigned i,string_i;
125 unsigned x,y;
126 #if BX_SUPPORT_VBE
127 Bit16u max_xres, max_yres, max_bpp;
128 #endif
129 int argc;
130 char *argv[16];
131 char *ptr;
132 char string[512];
133 char *extname;
134 size_t len;
135 #if BX_SUPPORT_VBE
136 unsigned addr;
137 #endif
139 BX_VGA_THIS extension_init = 0;
140 BX_VGA_THIS extension_checked = 0;
141 #if !BX_SUPPORT_CLGD54XX
142 BX_VGA_THIS init_iohandlers(read_handler,write_handler);
143 #endif
145 DEV_register_memory_handlers(theVga, mem_read_handler, mem_write_handler,
146 0xa0000, 0xbffff);
148 BX_VGA_THIS s.vga_enabled = 1;
149 BX_VGA_THIS s.misc_output.color_emulation = 1;
150 BX_VGA_THIS s.misc_output.enable_ram = 1;
151 BX_VGA_THIS s.misc_output.clock_select = 0;
152 BX_VGA_THIS s.misc_output.select_high_bank = 0;
153 BX_VGA_THIS s.misc_output.horiz_sync_pol = 1;
154 BX_VGA_THIS s.misc_output.vert_sync_pol = 1;
156 BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha = 0;
157 BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type = 0;
158 BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics = 1;
159 BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity = 0;
160 BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_panning_compat = 0;
161 BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select = 0;
162 BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size = 0;
164 BX_VGA_THIS s.line_offset=80;
165 BX_VGA_THIS s.line_compare=1023;
166 BX_VGA_THIS s.vertical_display_end=399;
168 for (i=0; i<=0x18; i++)
169 BX_VGA_THIS s.CRTC.reg[i] = 0;
170 BX_VGA_THIS s.CRTC.address = 0;
171 BX_VGA_THIS s.CRTC.write_protect = 0;
173 BX_VGA_THIS s.attribute_ctrl.flip_flop = 0;
174 BX_VGA_THIS s.attribute_ctrl.address = 0;
175 BX_VGA_THIS s.attribute_ctrl.video_enabled = 1;
176 for (i=0; i<16; i++)
177 BX_VGA_THIS s.attribute_ctrl.palette_reg[i] = 0;
178 BX_VGA_THIS s.attribute_ctrl.overscan_color = 0;
179 BX_VGA_THIS s.attribute_ctrl.color_plane_enable = 0x0f;
180 BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning = 0;
181 BX_VGA_THIS s.attribute_ctrl.color_select = 0;
183 for (i=0; i<256; i++) {
184 BX_VGA_THIS s.pel.data[i].red = 0;
185 BX_VGA_THIS s.pel.data[i].green = 0;
186 BX_VGA_THIS s.pel.data[i].blue = 0;
188 BX_VGA_THIS s.pel.write_data_register = 0;
189 BX_VGA_THIS s.pel.write_data_cycle = 0;
190 BX_VGA_THIS s.pel.read_data_register = 0;
191 BX_VGA_THIS s.pel.read_data_cycle = 0;
192 BX_VGA_THIS s.pel.dac_state = 0x01;
193 BX_VGA_THIS s.pel.mask = 0xff;
195 BX_VGA_THIS s.graphics_ctrl.index = 0;
196 BX_VGA_THIS s.graphics_ctrl.set_reset = 0;
197 BX_VGA_THIS s.graphics_ctrl.enable_set_reset = 0;
198 BX_VGA_THIS s.graphics_ctrl.color_compare = 0;
199 BX_VGA_THIS s.graphics_ctrl.data_rotate = 0;
200 BX_VGA_THIS s.graphics_ctrl.raster_op = 0;
201 BX_VGA_THIS s.graphics_ctrl.read_map_select = 0;
202 BX_VGA_THIS s.graphics_ctrl.write_mode = 0;
203 BX_VGA_THIS s.graphics_ctrl.read_mode = 0;
204 BX_VGA_THIS s.graphics_ctrl.odd_even = 0;
205 BX_VGA_THIS s.graphics_ctrl.chain_odd_even = 0;
206 BX_VGA_THIS s.graphics_ctrl.shift_reg = 0;
207 BX_VGA_THIS s.graphics_ctrl.graphics_alpha = 0;
208 BX_VGA_THIS s.graphics_ctrl.memory_mapping = 2; // monochrome text mode
209 BX_VGA_THIS s.graphics_ctrl.color_dont_care = 0;
210 BX_VGA_THIS s.graphics_ctrl.bitmask = 0;
211 for (i=0; i<4; i++) {
212 BX_VGA_THIS s.graphics_ctrl.latch[i] = 0;
215 BX_VGA_THIS s.sequencer.index = 0;
216 BX_VGA_THIS s.sequencer.map_mask = 0;
217 BX_VGA_THIS s.sequencer.reset1 = 1;
218 BX_VGA_THIS s.sequencer.reset2 = 1;
219 BX_VGA_THIS s.sequencer.reg1 = 0;
220 BX_VGA_THIS s.sequencer.char_map_select = 0;
221 BX_VGA_THIS s.sequencer.extended_mem = 1; // display mem greater than 64K
222 BX_VGA_THIS s.sequencer.odd_even = 1; // use sequential addressing mode
223 BX_VGA_THIS s.sequencer.chain_four = 0; // use map mask & read map select
225 extname = SIM->get_param_string(BXPN_VGA_EXTENSION)->getptr();
226 if ((strlen(extname) == 0) || (!strcmp(extname, "none"))) {
227 BX_VGA_THIS s.memsize = 0x40000;
228 if (BX_VGA_THIS s.memory == NULL)
229 BX_VGA_THIS s.memory = new Bit8u[BX_VGA_THIS s.memsize];
230 memset(BX_VGA_THIS s.memory, 0, BX_VGA_THIS s.memsize);
233 BX_VGA_THIS s.vga_mem_updated = 0;
234 for (y=0; y<480/Y_TILESIZE; y++)
235 for (x=0; x<640/X_TILESIZE; x++)
236 SET_TILE_UPDATED (x, y, 0);
238 memset(argv, 0, sizeof(argv));
239 argc = 1;
240 argv[0] = (char *)"bochs";
241 len = strlen(SIM->get_param_string(BXPN_DISPLAYLIB_OPTIONS)->getptr());
242 if (len > 0) {
243 char *options = new char[len + 1];
244 strcpy(options, SIM->get_param_string(BXPN_DISPLAYLIB_OPTIONS)->getptr());
245 ptr = strtok(options, ",");
246 while (ptr) {
247 string_i = 0;
248 for (i=0; i<strlen(ptr); i++) {
249 if (!isspace(ptr[i])) string[string_i++] = ptr[i];
251 string[string_i] = '\0';
252 if (argv[argc] != NULL) {
253 free(argv[argc]);
254 argv[argc] = NULL;
256 if (argc < 16) {
257 argv[argc++] = strdup(string);
258 } else {
259 BX_PANIC (("too many parameters, max is 16\n"));
261 ptr = strtok(NULL, ",");
263 delete [] options;
265 bx_gui->init(argc, argv, BX_VGA_THIS s.x_tilesize, BX_VGA_THIS s.y_tilesize);
266 for (i = 1; i < (unsigned)argc; i++)
268 if (argv[i] != NULL)
270 free(argv[i]);
271 argv[i] = NULL;
275 #if !BX_SUPPORT_CLGD54XX
276 BX_VGA_THIS init_systemtimer(timer_handler, vga_param_handler);
277 #endif // !BX_SUPPORT_CLGD54XX
279 /* video card with BIOS ROM */
280 DEV_cmos_set_reg(0x14, (DEV_cmos_get_reg(0x14) & 0xcf) | 0x00);
282 BX_VGA_THIS s.charmap_address = 0;
283 BX_VGA_THIS s.x_dotclockdiv2 = 0;
284 BX_VGA_THIS s.y_doublescan = 0;
285 BX_VGA_THIS s.last_bpp = 8;
287 #if BX_SUPPORT_VBE
288 // The following is for the vbe display extension
290 BX_VGA_THIS s.vbe_enabled=0;
291 BX_VGA_THIS s.vbe_8bit_dac=0;
292 if (!strcmp(extname, "vbe")) {
293 for (addr=VBE_DISPI_IOPORT_INDEX; addr<=VBE_DISPI_IOPORT_DATA; addr++) {
294 DEV_register_ioread_handler(this, vbe_read_handler, addr, "vga video", 7);
295 DEV_register_iowrite_handler(this, vbe_write_handler, addr, "vga video", 7);
297 if (!BX_SUPPORT_PCIUSB || !SIM->get_param_bool(BXPN_USB1_ENABLED)->get()) {
298 for (addr=VBE_DISPI_IOPORT_INDEX_OLD; addr<=VBE_DISPI_IOPORT_DATA_OLD; addr++) {
299 DEV_register_ioread_handler(this, vbe_read_handler, addr, "vga video", 7);
300 DEV_register_iowrite_handler(this, vbe_write_handler, addr, "vga video", 7);
303 DEV_register_memory_handlers(theVga, mem_read_handler, mem_write_handler,
304 VBE_DISPI_LFB_PHYSICAL_ADDRESS,
305 VBE_DISPI_LFB_PHYSICAL_ADDRESS + VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES - 1);
307 if (BX_VGA_THIS s.memory == NULL)
308 BX_VGA_THIS s.memory = new Bit8u[VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES];
309 memset(BX_VGA_THIS s.memory, 0, VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES);
310 BX_VGA_THIS s.memsize = VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES;
311 BX_VGA_THIS s.vbe_cur_dispi=VBE_DISPI_ID0;
312 BX_VGA_THIS s.vbe_xres=640;
313 BX_VGA_THIS s.vbe_yres=480;
314 BX_VGA_THIS s.vbe_bpp=8;
315 BX_VGA_THIS s.vbe_bank=0;
316 BX_VGA_THIS s.vbe_curindex=0;
317 BX_VGA_THIS s.vbe_offset_x=0;
318 BX_VGA_THIS s.vbe_offset_y=0;
319 BX_VGA_THIS s.vbe_virtual_xres=640;
320 BX_VGA_THIS s.vbe_virtual_yres=480;
321 BX_VGA_THIS s.vbe_bpp_multiplier=1;
322 BX_VGA_THIS s.vbe_virtual_start=0;
323 BX_VGA_THIS s.vbe_lfb_enabled=0;
324 BX_VGA_THIS s.vbe_get_capabilities=0;
325 bx_gui->get_capabilities(&max_xres, &max_yres, &max_bpp);
326 if (max_xres > VBE_DISPI_MAX_XRES) {
327 BX_VGA_THIS s.vbe_max_xres=VBE_DISPI_MAX_XRES;
328 } else {
329 BX_VGA_THIS s.vbe_max_xres=max_xres;
331 if (max_yres > VBE_DISPI_MAX_YRES) {
332 BX_VGA_THIS s.vbe_max_yres=VBE_DISPI_MAX_YRES;
333 } else {
334 BX_VGA_THIS s.vbe_max_yres=max_yres;
336 if (max_bpp > VBE_DISPI_MAX_BPP) {
337 BX_VGA_THIS s.vbe_max_bpp=VBE_DISPI_MAX_BPP;
338 } else {
339 BX_VGA_THIS s.vbe_max_bpp=max_bpp;
341 BX_VGA_THIS extension_init = 1;
343 BX_INFO(("VBE Bochs Display Extension Enabled"));
345 #endif
348 void bx_vga_c::init_iohandlers(bx_read_handler_t f_read, bx_write_handler_t f_write)
350 unsigned addr, i;
351 Bit8u io_mask[16] = {3, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1};
352 for (addr=0x03B4; addr<=0x03B5; addr++) {
353 DEV_register_ioread_handler(this, f_read, addr, "vga video", 1);
354 DEV_register_iowrite_handler(this, f_write, addr, "vga video", 3);
357 for (addr=0x03BA; addr<=0x03BA; addr++) {
358 DEV_register_ioread_handler(this, f_read, addr, "vga video", 1);
359 DEV_register_iowrite_handler(this, f_write, addr, "vga video", 3);
362 i = 0;
363 for (addr=0x03C0; addr<=0x03CF; addr++) {
364 DEV_register_ioread_handler(this, f_read, addr, "vga video", io_mask[i++]);
365 DEV_register_iowrite_handler(this, f_write, addr, "vga video", 3);
368 for (addr=0x03D4; addr<=0x03D5; addr++) {
369 DEV_register_ioread_handler(this, f_read, addr, "vga video", 3);
370 DEV_register_iowrite_handler(this, f_write, addr, "vga video", 3);
373 for (addr=0x03DA; addr<=0x03DA; addr++) {
374 DEV_register_ioread_handler(this, f_read, addr, "vga video", 1);
375 DEV_register_iowrite_handler(this, f_write, addr, "vga video", 3);
379 void bx_vga_c::init_systemtimer(bx_timer_handler_t f_timer, param_event_handler f_param)
381 bx_param_num_c *vga_update_interval = SIM->get_param_num(BXPN_VGA_UPDATE_INTERVAL);
382 Bit64u interval = vga_update_interval->get();
383 BX_INFO(("interval=" FMT_LL "u", interval));
384 if (BX_VGA_THIS timer_id == BX_NULL_TIMER_HANDLE) {
385 BX_VGA_THIS timer_id = bx_pc_system.register_timer(this, f_timer,
386 (Bit32u)interval, 1, 1, "vga");
387 vga_update_interval->set_handler(f_param);
388 vga_update_interval->set_runtime_param(1);
390 if (interval < 300000) {
391 BX_VGA_THIS s.blink_counter = 300000 / (unsigned)interval;
392 } else {
393 BX_VGA_THIS s.blink_counter = 1;
397 void bx_vga_c::reset(unsigned type)
399 if (!BX_VGA_THIS extension_checked) {
400 char *strptr = SIM->get_param_string(BXPN_VGA_EXTENSION)->getptr();
401 if (!BX_VGA_THIS extension_init &&
402 (strlen(strptr) > 0) &&
403 strcmp(strptr, "none")) {
404 BX_PANIC(("unknown display extension: %s", strptr));
406 BX_VGA_THIS extension_checked = 1;
410 void bx_vga_c::register_state(void)
412 unsigned i;
413 char name[6];
414 bx_list_c *parent, *reg;
416 parent = SIM->get_bochs_root();
417 #if BX_SUPPORT_CLGD54XX
418 if (!strcmp(SIM->get_param_string(BXPN_VGA_EXTENSION)->getptr(), "cirrus")) {
419 parent = (bx_list_c*)SIM->get_param("svga_cirrus", parent);;
421 #endif
422 bx_list_c *list = new bx_list_c(parent, "vga", "VGA Adapter State", 17);
423 bx_list_c *misc = new bx_list_c(list, "misc_output", 6);
424 new bx_shadow_bool_c(misc, "color_emulation", &BX_VGA_THIS s.misc_output.color_emulation);
425 new bx_shadow_bool_c(misc, "enable_ram", &BX_VGA_THIS s.misc_output.enable_ram);
426 new bx_shadow_num_c(misc, "clock_select", &BX_VGA_THIS s.misc_output.clock_select);
427 new bx_shadow_bool_c(misc, "select_high_bank", &BX_VGA_THIS s.misc_output.select_high_bank);
428 new bx_shadow_bool_c(misc, "horiz_sync_pol", &BX_VGA_THIS s.misc_output.horiz_sync_pol);
429 new bx_shadow_bool_c(misc, "vert_sync_pol", &BX_VGA_THIS s.misc_output.vert_sync_pol);
430 bx_list_c *crtc = new bx_list_c(list, "CRTC", 3);
431 new bx_shadow_num_c(crtc, "address", &BX_VGA_THIS s.CRTC.address, BASE_HEX);
432 reg = new bx_list_c(crtc, "reg", 0x19);
433 for (i=0; i<=0x18; i++) {
434 sprintf(name, "0x%02x", i);
435 new bx_shadow_num_c(reg, name, &BX_VGA_THIS s.CRTC.reg[i], BASE_HEX);
437 new bx_shadow_bool_c(crtc, "write_protect", &BX_VGA_THIS s.CRTC.write_protect);
438 bx_list_c *actl = new bx_list_c(list, "attribute_ctrl", 9);
439 new bx_shadow_bool_c(actl, "flip_flop", &BX_VGA_THIS s.attribute_ctrl.flip_flop);
440 new bx_shadow_num_c(actl, "address", &BX_VGA_THIS s.attribute_ctrl.address, BASE_HEX);
441 new bx_shadow_bool_c(actl, "video_enabled", &BX_VGA_THIS s.attribute_ctrl.video_enabled);
442 reg = new bx_list_c(actl, "palette_reg", 16);
443 for (i=0; i<16; i++) {
444 sprintf(name, "0x%02x", i);
445 new bx_shadow_num_c(reg, name, &BX_VGA_THIS s.attribute_ctrl.palette_reg[i], BASE_HEX);
447 new bx_shadow_num_c(actl, "overscan_color", &BX_VGA_THIS s.attribute_ctrl.overscan_color, BASE_HEX);
448 new bx_shadow_num_c(actl, "color_plane_enable", &BX_VGA_THIS s.attribute_ctrl.color_plane_enable, BASE_HEX);
449 new bx_shadow_num_c(actl, "horiz_pel_panning", &BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning, BASE_HEX);
450 new bx_shadow_num_c(actl, "color_select", &BX_VGA_THIS s.attribute_ctrl.color_select, BASE_HEX);
451 bx_list_c *mode = new bx_list_c(actl, "mode_ctrl", 7);
452 new bx_shadow_bool_c(mode, "graphics_alpha", &BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha);
453 new bx_shadow_bool_c(mode, "display_type", &BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type);
454 new bx_shadow_bool_c(mode, "enable_line_graphics", &BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics);
455 new bx_shadow_bool_c(mode, "blink_intensity", &BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity);
456 new bx_shadow_bool_c(mode, "pixel_panning_compat", &BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_panning_compat);
457 new bx_shadow_bool_c(mode, "pixel_clock_select", &BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select);
458 new bx_shadow_bool_c(mode, "internal_palette_size", &BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size);
459 bx_list_c *pel = new bx_list_c(list, "pel", 6);
460 new bx_shadow_num_c(pel, "write_data_register", &BX_VGA_THIS s.pel.write_data_register, BASE_HEX);
461 new bx_shadow_num_c(pel, "write_data_cycle", &BX_VGA_THIS s.pel.write_data_cycle);
462 new bx_shadow_num_c(pel, "read_data_register", &BX_VGA_THIS s.pel.read_data_register, BASE_HEX);
463 new bx_shadow_num_c(pel, "read_data_cycle", &BX_VGA_THIS s.pel.read_data_cycle);
464 new bx_shadow_num_c(pel, "dac_state", &BX_VGA_THIS s.pel.dac_state);
465 new bx_shadow_num_c(pel, "mask", &BX_VGA_THIS s.pel.mask, BASE_HEX);
466 new bx_shadow_data_c(list, "pel_data", &BX_VGA_THIS s.pel.data[0].red, sizeof(BX_VGA_THIS s.pel.data));
467 bx_list_c *gfxc = new bx_list_c(list, "graphics_ctrl", 20);
468 new bx_shadow_num_c(gfxc, "index", &BX_VGA_THIS s.graphics_ctrl.index);
469 new bx_shadow_num_c(gfxc, "set_reset", &BX_VGA_THIS s.graphics_ctrl.set_reset);
470 new bx_shadow_num_c(gfxc, "enable_set_reset", &BX_VGA_THIS s.graphics_ctrl.enable_set_reset);
471 new bx_shadow_num_c(gfxc, "color_compare", &BX_VGA_THIS s.graphics_ctrl.color_compare);
472 new bx_shadow_num_c(gfxc, "data_rotate", &BX_VGA_THIS s.graphics_ctrl.data_rotate);
473 new bx_shadow_num_c(gfxc, "raster_op", &BX_VGA_THIS s.graphics_ctrl.raster_op);
474 new bx_shadow_num_c(gfxc, "read_map_select", &BX_VGA_THIS s.graphics_ctrl.read_map_select);
475 new bx_shadow_num_c(gfxc, "write_mode", &BX_VGA_THIS s.graphics_ctrl.write_mode);
476 new bx_shadow_num_c(gfxc, "read_mode", &BX_VGA_THIS s.graphics_ctrl.read_mode);
477 new bx_shadow_bool_c(gfxc, "odd_even", &BX_VGA_THIS s.graphics_ctrl.odd_even);
478 new bx_shadow_bool_c(gfxc, "chain_odd_even", &BX_VGA_THIS s.graphics_ctrl.chain_odd_even);
479 new bx_shadow_num_c(gfxc, "shift_reg", &BX_VGA_THIS s.graphics_ctrl.shift_reg);
480 new bx_shadow_bool_c(gfxc, "graphics_alpha", &BX_VGA_THIS s.graphics_ctrl.graphics_alpha);
481 new bx_shadow_num_c(gfxc, "memory_mapping", &BX_VGA_THIS s.graphics_ctrl.memory_mapping);
482 new bx_shadow_num_c(gfxc, "color_dont_care", &BX_VGA_THIS s.graphics_ctrl.color_dont_care, BASE_HEX);
483 new bx_shadow_num_c(gfxc, "bitmask", &BX_VGA_THIS s.graphics_ctrl.bitmask, BASE_HEX);
484 new bx_shadow_num_c(gfxc, "latch0", &BX_VGA_THIS s.graphics_ctrl.latch[0], BASE_HEX);
485 new bx_shadow_num_c(gfxc, "latch1", &BX_VGA_THIS s.graphics_ctrl.latch[1], BASE_HEX);
486 new bx_shadow_num_c(gfxc, "latch2", &BX_VGA_THIS s.graphics_ctrl.latch[2], BASE_HEX);
487 new bx_shadow_num_c(gfxc, "latch3", &BX_VGA_THIS s.graphics_ctrl.latch[3], BASE_HEX);
488 bx_list_c *sequ = new bx_list_c(list, "sequencer", 13);
489 new bx_shadow_num_c(sequ, "index", &BX_VGA_THIS s.sequencer.index);
490 new bx_shadow_num_c(sequ, "map_mask", &BX_VGA_THIS s.sequencer.map_mask);
491 new bx_shadow_bool_c(sequ, "reset1", &BX_VGA_THIS s.sequencer.reset1);
492 new bx_shadow_bool_c(sequ, "reset2", &BX_VGA_THIS s.sequencer.reset2);
493 new bx_shadow_num_c(sequ, "reg1", &BX_VGA_THIS s.sequencer.reg1, BASE_HEX);
494 new bx_shadow_num_c(sequ, "char_map_select", &BX_VGA_THIS s.sequencer.char_map_select);
495 new bx_shadow_bool_c(sequ, "extended_mem", &BX_VGA_THIS s.sequencer.extended_mem);
496 new bx_shadow_bool_c(sequ, "odd_even", &BX_VGA_THIS s.sequencer.odd_even);
497 new bx_shadow_bool_c(sequ, "chain_four", &BX_VGA_THIS s.sequencer.chain_four);
498 new bx_shadow_bool_c(list, "enabled", &BX_VGA_THIS s.vga_enabled);
499 new bx_shadow_num_c(list, "line_offset", &BX_VGA_THIS s.line_offset);
500 new bx_shadow_num_c(list, "line_compare", &BX_VGA_THIS s.line_compare);
501 new bx_shadow_num_c(list, "vertical_display_end", &BX_VGA_THIS s.vertical_display_end);
502 new bx_shadow_num_c(list, "charmap_address", &BX_VGA_THIS s.charmap_address);
503 new bx_shadow_bool_c(list, "x_dotclockdiv2", &BX_VGA_THIS s.x_dotclockdiv2);
504 new bx_shadow_bool_c(list, "y_doublescan", &BX_VGA_THIS s.y_doublescan);
505 new bx_shadow_num_c(list, "last_bpp", &BX_VGA_THIS s.last_bpp);
506 new bx_shadow_data_c(list, "memory", BX_VGA_THIS s.memory, BX_VGA_THIS s.memsize);
507 #if BX_SUPPORT_VBE
508 if (!strcmp(SIM->get_param_string(BXPN_VGA_EXTENSION)->getptr(), "vbe")) {
509 bx_list_c *vbe = new bx_list_c(list, "vbe", 18);
510 new bx_shadow_num_c(vbe, "cur_dispi", &BX_VGA_THIS s.vbe_cur_dispi, BASE_HEX);
511 new bx_shadow_num_c(vbe, "xres", &BX_VGA_THIS s.vbe_xres);
512 new bx_shadow_num_c(vbe, "yres", &BX_VGA_THIS s.vbe_yres);
513 new bx_shadow_num_c(vbe, "bpp", &BX_VGA_THIS s.vbe_bpp);
514 new bx_shadow_num_c(vbe, "bank", &BX_VGA_THIS s.vbe_bank);
515 new bx_shadow_bool_c(vbe, "enabled", &BX_VGA_THIS s.vbe_enabled);
516 new bx_shadow_num_c(vbe, "curindex", &BX_VGA_THIS s.vbe_curindex);
517 new bx_shadow_num_c(vbe, "visible_screen_size", &BX_VGA_THIS s.vbe_visible_screen_size);
518 new bx_shadow_num_c(vbe, "offset_x", &BX_VGA_THIS s.vbe_offset_x);
519 new bx_shadow_num_c(vbe, "offset_y", &BX_VGA_THIS s.vbe_offset_y);
520 new bx_shadow_num_c(vbe, "virtual_xres", &BX_VGA_THIS s.vbe_virtual_xres);
521 new bx_shadow_num_c(vbe, "virtual_yres", &BX_VGA_THIS s.vbe_virtual_yres);
522 new bx_shadow_num_c(vbe, "virtual_start", &BX_VGA_THIS s.vbe_virtual_start);
523 new bx_shadow_num_c(vbe, "bpp_multiplier", &BX_VGA_THIS s.vbe_bpp_multiplier);
524 new bx_shadow_bool_c(vbe, "lfb_enabled", &BX_VGA_THIS s.vbe_lfb_enabled);
525 new bx_shadow_bool_c(vbe, "get_capabilities", &BX_VGA_THIS s.vbe_get_capabilities);
526 new bx_shadow_bool_c(vbe, "8bit_dac", &BX_VGA_THIS s.vbe_8bit_dac);
528 #endif
531 void bx_vga_c::after_restore_state(void)
533 for (unsigned i=0; i<256; i++) {
534 #if BX_SUPPORT_VBE
535 if (BX_VGA_THIS s.vbe_8bit_dac) {
536 bx_gui->palette_change(i, BX_VGA_THIS s.pel.data[i].red,
537 BX_VGA_THIS s.pel.data[i].green,
538 BX_VGA_THIS s.pel.data[i].blue);
540 else
541 #endif
543 bx_gui->palette_change(i, BX_VGA_THIS s.pel.data[i].red<<2,
544 BX_VGA_THIS s.pel.data[i].green<<2,
545 BX_VGA_THIS s.pel.data[i].blue<<2);
548 bx_gui->set_text_charmap(&BX_VGA_THIS s.memory[0x20000 + BX_VGA_THIS s.charmap_address]);
549 old_iWidth = BX_MAX_XRES;
550 old_iHeight = BX_MAX_YRES;
551 BX_VGA_THIS redraw_area(0, 0, BX_MAX_XRES, BX_MAX_YRES);
552 #if BX_SUPPORT_VBE
553 if (BX_VGA_THIS s.vbe_enabled) {
554 bx_gui->dimension_update(BX_VGA_THIS s.vbe_xres, BX_VGA_THIS s.vbe_yres, 0, 0,
555 BX_VGA_THIS s.vbe_bpp);
557 #endif
558 BX_VGA_THIS update();
559 bx_gui->flush();
562 void bx_vga_c::determine_screen_dimensions(unsigned *piHeight, unsigned *piWidth)
564 int ai[0x20];
565 int i,h,v;
566 for (i = 0 ; i < 0x20 ; i++)
567 ai[i] = BX_VGA_THIS s.CRTC.reg[i];
569 h = (ai[1] + 1) * 8;
570 v = (ai[18] | ((ai[7] & 0x02) << 7) | ((ai[7] & 0x40) << 3)) + 1;
572 if (BX_VGA_THIS s.graphics_ctrl.shift_reg == 0)
574 *piWidth = 640;
575 *piHeight = 480;
577 if (BX_VGA_THIS s.CRTC.reg[6] == 0xBF)
579 if (BX_VGA_THIS s.CRTC.reg[23] == 0xA3 &&
580 BX_VGA_THIS s.CRTC.reg[20] == 0x40 &&
581 BX_VGA_THIS s.CRTC.reg[9] == 0x41)
583 *piWidth = 320;
584 *piHeight = 240;
586 else {
587 if (BX_VGA_THIS s.x_dotclockdiv2) h <<= 1;
588 *piWidth = h;
589 *piHeight = v;
592 else if ((h >= 640) && (v >= 480)) {
593 *piWidth = h;
594 *piHeight = v;
597 else if (BX_VGA_THIS s.graphics_ctrl.shift_reg == 2)
600 if (BX_VGA_THIS s.sequencer.chain_four)
602 *piWidth = h;
603 *piHeight = v;
605 else
607 *piWidth = h;
608 *piHeight = v;
611 else
613 if (BX_VGA_THIS s.x_dotclockdiv2) h <<= 1;
614 *piWidth = h;
615 *piHeight = v;
619 // static IO port read callback handler
620 // redirects to non-static class handler to avoid virtual functions
622 Bit32u bx_vga_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
624 #if BX_USE_VGA_SMF == 0
625 bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
626 return class_ptr->read(address, io_len);
629 Bit32u bx_vga_c::read(Bit32u address, unsigned io_len)
631 #else
632 UNUSED(this_ptr);
633 #endif // BX_USE_VGA_SMF == 0
634 bx_bool horiz_retrace = 0, vert_retrace = 0;
635 Bit64u usec;
636 Bit16u ret16, vertres;
637 Bit8u retval;
639 #if defined(VGA_TRACE_FEATURE)
640 Bit32u ret = 0;
641 #define RETURN(x) do { ret = (x); goto read_return; } while (0)
642 #else
643 #define RETURN return
644 #endif
646 if (io_len == 2) {
647 #if BX_USE_VGA_SMF
648 ret16 = bx_vga_c::read_handler(0, address, 1);
649 ret16 |= (bx_vga_c::read_handler(0, address+1, 1)) << 8;
650 #else
651 ret16 = bx_vga_c::read(address, 1);
652 ret16 |= (bx_vga_c::read(address+1, 1) << 8;
653 #endif
654 RETURN(ret16);
657 #ifdef __OS2__
658 if (bx_options.videomode == BX_VIDEO_DIRECT)
660 return _inp(address);
662 #endif
664 #if !defined(VGA_TRACE_FEATURE)
665 BX_DEBUG(("io read from 0x%04x", (unsigned) address));
666 #endif
668 if ((address >= 0x03b0) && (address <= 0x03bf) &&
669 (BX_VGA_THIS s.misc_output.color_emulation)) {
670 RETURN(0xff);
672 if ((address >= 0x03d0) && (address <= 0x03df) &&
673 (BX_VGA_THIS s.misc_output.color_emulation==0)) {
674 RETURN(0xff);
677 switch (address) {
678 case 0x03ba: /* Input Status 1 (monochrome emulation modes) */
679 case 0x03ca: /* Feature Control ??? */
680 case 0x03da: /* Input Status 1 (color emulation modes) */
681 // bit3: Vertical Retrace
682 // 0 = display is in the display mode
683 // 1 = display is in the vertical retrace mode
684 // bit0: Display Enable
685 // 0 = display is in the display mode
686 // 1 = display is not in the display mode; either the
687 // horizontal or vertical retrace period is active
689 // using 72 Hz vertical frequency
690 usec = bx_pc_system.time_usec();
691 switch ((BX_VGA_THIS s.misc_output.vert_sync_pol << 1) | BX_VGA_THIS s.misc_output.horiz_sync_pol)
693 case 0: vertres = 200; break;
694 case 1: vertres = 400; break;
695 case 2: vertres = 350; break;
696 default: vertres = 480; break;
698 if ((usec % 13888) < 70) {
699 vert_retrace = 1;
701 if ((usec % (13888 / vertres)) == 0) {
702 horiz_retrace = 1;
705 retval = 0;
706 if (horiz_retrace || vert_retrace)
707 retval = 0x01;
708 if (vert_retrace)
709 retval |= 0x08;
711 /* reading this port resets the flip-flop to address mode */
712 BX_VGA_THIS s.attribute_ctrl.flip_flop = 0;
713 RETURN(retval);
714 break;
717 case 0x03c0: /* */
718 if (BX_VGA_THIS s.attribute_ctrl.flip_flop == 0) {
719 //BX_INFO(("io read: 0x3c0: flip_flop = 0"));
720 retval =
721 (BX_VGA_THIS s.attribute_ctrl.video_enabled << 5) |
722 BX_VGA_THIS s.attribute_ctrl.address;
723 RETURN(retval);
725 else {
726 BX_ERROR(("io read: 0x3c0: flip_flop != 0"));
727 return(0);
729 break;
731 case 0x03c1: /* */
732 switch (BX_VGA_THIS s.attribute_ctrl.address) {
733 case 0x00: case 0x01: case 0x02: case 0x03:
734 case 0x04: case 0x05: case 0x06: case 0x07:
735 case 0x08: case 0x09: case 0x0a: case 0x0b:
736 case 0x0c: case 0x0d: case 0x0e: case 0x0f:
737 retval = BX_VGA_THIS s.attribute_ctrl.palette_reg[BX_VGA_THIS s.attribute_ctrl.address];
738 RETURN(retval);
739 break;
740 case 0x10: /* mode control register */
741 retval =
742 (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha << 0) |
743 (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type << 1) |
744 (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics << 2) |
745 (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity << 3) |
746 (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_panning_compat << 5) |
747 (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select << 6) |
748 (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size << 7);
749 RETURN(retval);
750 break;
751 case 0x11: /* overscan color register */
752 RETURN(BX_VGA_THIS s.attribute_ctrl.overscan_color);
753 break;
754 case 0x12: /* color plane enable */
755 RETURN(BX_VGA_THIS s.attribute_ctrl.color_plane_enable);
756 break;
757 case 0x13: /* horizontal PEL panning register */
758 RETURN(BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning);
759 break;
760 case 0x14: /* color select register */
761 RETURN(BX_VGA_THIS s.attribute_ctrl.color_select);
762 break;
763 default:
764 BX_INFO(("io read: 0x3c1: unknown register 0x%02x",
765 (unsigned) BX_VGA_THIS s.attribute_ctrl.address));
766 RETURN(0);
768 break;
770 case 0x03c2: /* Input Status 0 */
771 BX_DEBUG(("io read 0x3c2: input status #0: ignoring"));
772 RETURN(0);
773 break;
775 case 0x03c3: /* VGA Enable Register */
776 RETURN(BX_VGA_THIS s.vga_enabled);
777 break;
779 case 0x03c4: /* Sequencer Index Register */
780 RETURN(BX_VGA_THIS s.sequencer.index);
781 break;
783 case 0x03c5: /* Sequencer Registers 00..04 */
784 switch (BX_VGA_THIS s.sequencer.index) {
785 case 0: /* sequencer: reset */
786 BX_DEBUG(("io read 0x3c5: sequencer reset"));
787 RETURN(BX_VGA_THIS s.sequencer.reset1 | (BX_VGA_THIS s.sequencer.reset2<<1));
788 break;
789 case 1: /* sequencer: clocking mode */
790 BX_DEBUG(("io read 0x3c5: sequencer clocking mode"));
791 RETURN(BX_VGA_THIS s.sequencer.reg1);
792 break;
793 case 2: /* sequencer: map mask register */
794 RETURN(BX_VGA_THIS s.sequencer.map_mask);
795 break;
796 case 3: /* sequencer: character map select register */
797 RETURN(BX_VGA_THIS s.sequencer.char_map_select);
798 break;
799 case 4: /* sequencer: memory mode register */
800 retval =
801 (BX_VGA_THIS s.sequencer.extended_mem << 1) |
802 (BX_VGA_THIS s.sequencer.odd_even << 2) |
803 (BX_VGA_THIS s.sequencer.chain_four << 3);
804 RETURN(retval);
805 break;
807 default:
808 BX_DEBUG(("io read 0x3c5: index %u unhandled",
809 (unsigned) BX_VGA_THIS s.sequencer.index));
810 RETURN(0);
812 break;
814 case 0x03c6: /* PEL mask ??? */
815 RETURN(BX_VGA_THIS s.pel.mask);
816 break;
818 case 0x03c7: /* DAC state, read = 11b, write = 00b */
819 RETURN(BX_VGA_THIS s.pel.dac_state);
820 break;
822 case 0x03c8: /* PEL address write mode */
823 RETURN(BX_VGA_THIS s.pel.write_data_register);
824 break;
826 case 0x03c9: /* PEL Data Register, colors 00..FF */
827 if (BX_VGA_THIS s.pel.dac_state == 0x03) {
828 switch (BX_VGA_THIS s.pel.read_data_cycle) {
829 case 0:
830 retval = BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.read_data_register].red;
831 break;
832 case 1:
833 retval = BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.read_data_register].green;
834 break;
835 case 2:
836 retval = BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.read_data_register].blue;
837 break;
838 default:
839 retval = 0; // keep compiler happy
841 BX_VGA_THIS s.pel.read_data_cycle++;
842 if (BX_VGA_THIS s.pel.read_data_cycle >= 3) {
843 BX_VGA_THIS s.pel.read_data_cycle = 0;
844 BX_VGA_THIS s.pel.read_data_register++;
847 else {
848 retval = 0x3f;
850 RETURN(retval);
851 break;
853 case 0x03cc: /* Miscellaneous Output / Graphics 1 Position ??? */
854 retval =
855 ((BX_VGA_THIS s.misc_output.color_emulation & 0x01) << 0) |
856 ((BX_VGA_THIS s.misc_output.enable_ram & 0x01) << 1) |
857 ((BX_VGA_THIS s.misc_output.clock_select & 0x03) << 2) |
858 ((BX_VGA_THIS s.misc_output.select_high_bank & 0x01) << 5) |
859 ((BX_VGA_THIS s.misc_output.horiz_sync_pol & 0x01) << 6) |
860 ((BX_VGA_THIS s.misc_output.vert_sync_pol & 0x01) << 7);
861 RETURN(retval);
862 break;
864 case 0x03ce: /* Graphics Controller Index Register */
865 RETURN(BX_VGA_THIS s.graphics_ctrl.index);
866 break;
868 case 0x03cd: /* ??? */
869 BX_DEBUG(("io read from 03cd"));
870 RETURN(0x00);
871 break;
873 case 0x03cf: /* Graphics Controller Registers 00..08 */
874 switch (BX_VGA_THIS s.graphics_ctrl.index) {
875 case 0: /* Set/Reset */
876 RETURN(BX_VGA_THIS s.graphics_ctrl.set_reset);
877 break;
878 case 1: /* Enable Set/Reset */
879 RETURN(BX_VGA_THIS s.graphics_ctrl.enable_set_reset);
880 break;
881 case 2: /* Color Compare */
882 RETURN(BX_VGA_THIS s.graphics_ctrl.color_compare);
883 break;
884 case 3: /* Data Rotate */
885 retval =
886 ((BX_VGA_THIS s.graphics_ctrl.raster_op & 0x03) << 3) |
887 ((BX_VGA_THIS s.graphics_ctrl.data_rotate & 0x07) << 0);
888 RETURN(retval);
889 break;
890 case 4: /* Read Map Select */
891 RETURN(BX_VGA_THIS s.graphics_ctrl.read_map_select);
892 break;
893 case 5: /* Mode */
894 retval =
895 ((BX_VGA_THIS s.graphics_ctrl.shift_reg & 0x03) << 5) |
896 ((BX_VGA_THIS s.graphics_ctrl.odd_even & 0x01) << 4) |
897 ((BX_VGA_THIS s.graphics_ctrl.read_mode & 0x01) << 3) |
898 ((BX_VGA_THIS s.graphics_ctrl.write_mode & 0x03) << 0);
900 if (BX_VGA_THIS s.graphics_ctrl.odd_even ||
901 BX_VGA_THIS s.graphics_ctrl.shift_reg)
902 BX_DEBUG(("io read 0x3cf: reg 05 = 0x%02x", (unsigned) retval));
903 RETURN(retval);
904 break;
905 case 6: /* Miscellaneous */
906 retval =
907 ((BX_VGA_THIS s.graphics_ctrl.memory_mapping & 0x03) << 2) |
908 ((BX_VGA_THIS s.graphics_ctrl.odd_even & 0x01) << 1) |
909 ((BX_VGA_THIS s.graphics_ctrl.graphics_alpha & 0x01) << 0);
910 RETURN(retval);
911 break;
912 case 7: /* Color Don't Care */
913 RETURN(BX_VGA_THIS s.graphics_ctrl.color_dont_care);
914 break;
915 case 8: /* Bit Mask */
916 RETURN(BX_VGA_THIS s.graphics_ctrl.bitmask);
917 break;
918 default:
919 /* ??? */
920 BX_DEBUG(("io read: 0x3cf: index %u unhandled",
921 (unsigned) BX_VGA_THIS s.graphics_ctrl.index));
922 RETURN(0);
924 break;
926 case 0x03d4: /* CRTC Index Register (color emulation modes) */
927 RETURN(BX_VGA_THIS s.CRTC.address);
928 break;
930 case 0x03b5: /* CRTC Registers (monochrome emulation modes) */
931 case 0x03d5: /* CRTC Registers (color emulation modes) */
932 if (BX_VGA_THIS s.CRTC.address > 0x18) {
933 BX_DEBUG(("io read: invalid CRTC register 0x%02x",
934 (unsigned) BX_VGA_THIS s.CRTC.address));
935 RETURN(0);
937 RETURN(BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address]);
938 break;
940 case 0x03b4: /* CRTC Index Register (monochrome emulation modes) */
941 case 0x03cb: /* not sure but OpenBSD reads it a lot */
942 default:
943 BX_INFO(("io read from vga port 0x%04x", (unsigned) address));
944 RETURN(0); /* keep compiler happy */
947 #if defined(VGA_TRACE_FEATURE)
948 read_return:
949 if (io_len == 1) {
950 BX_DEBUG(("8-bit read from 0x%04x = 0x%02x", (unsigned) address, ret));
951 } else {
952 BX_DEBUG(("16-bit read from 0x%04x = 0x%04x", (unsigned) address, ret));
954 return ret;
955 #endif
957 #if defined(VGA_TRACE_FEATURE)
958 #undef RETURN
959 #endif
961 // static IO port write callback handler
962 // redirects to non-static class handler to avoid virtual functions
964 void bx_vga_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
966 #if BX_USE_VGA_SMF == 0
967 bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
968 class_ptr->write(address, value, io_len, 0);
969 #else
970 UNUSED(this_ptr);
971 theVga->write(address, value, io_len, 0);
972 #endif
975 #if BX_USE_VGA_SMF
976 void bx_vga_c::write_handler_no_log(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
978 UNUSED(this_ptr);
979 theVga->write(address, value, io_len, 1);
981 #endif
983 void bx_vga_c::write(Bit32u address, Bit32u value, unsigned io_len, bx_bool no_log)
985 Bit8u charmap1, charmap2, prev_memory_mapping;
986 bx_bool prev_video_enabled, prev_line_graphics, prev_int_pal_size;
987 bx_bool prev_graphics_alpha, prev_chain_odd_even;
988 bx_bool needs_update = 0;
990 #if defined(VGA_TRACE_FEATURE)
991 if (!no_log)
992 switch (io_len) {
993 case 1:
994 BX_DEBUG(("8-bit write to %04x = %02x", (unsigned)address, (unsigned)value));
995 break;
996 case 2:
997 BX_DEBUG(("16-bit write to %04x = %04x", (unsigned)address, (unsigned)value));
998 break;
999 default:
1000 BX_PANIC(("Weird VGA write size"));
1002 #else
1003 if (io_len == 1) {
1004 BX_DEBUG(("io write to 0x%04x = 0x%02x", (unsigned) address,
1005 (unsigned) value));
1007 #endif
1009 if (io_len == 2) {
1010 #if BX_USE_VGA_SMF
1011 bx_vga_c::write_handler_no_log(0, address, value & 0xff, 1);
1012 bx_vga_c::write_handler_no_log(0, address+1, (value >> 8) & 0xff, 1);
1013 #else
1014 bx_vga_c::write(address, value & 0xff, 1, 1);
1015 bx_vga_c::write(address+1, (value >> 8) & 0xff, 1, 1);
1016 #endif
1017 return;
1020 #ifdef __OS2__
1021 if (bx_options.videomode == BX_VIDEO_DIRECT)
1023 _outp(address, value);
1024 return;
1026 #endif
1028 if ((address >= 0x03b0) && (address <= 0x03bf) &&
1029 (BX_VGA_THIS s.misc_output.color_emulation))
1030 return;
1031 if ((address >= 0x03d0) && (address <= 0x03df) &&
1032 (BX_VGA_THIS s.misc_output.color_emulation==0))
1033 return;
1035 switch (address) {
1036 case 0x03ba: /* Feature Control (monochrome emulation modes) */
1037 #if !defined(VGA_TRACE_FEATURE)
1038 BX_DEBUG(("io write 3ba: feature control: ignoring"));
1039 #endif
1040 break;
1042 case 0x03c0: /* Attribute Controller */
1043 if (BX_VGA_THIS s.attribute_ctrl.flip_flop == 0) { /* address mode */
1044 prev_video_enabled = BX_VGA_THIS s.attribute_ctrl.video_enabled;
1045 BX_VGA_THIS s.attribute_ctrl.video_enabled = (value >> 5) & 0x01;
1046 #if !defined(VGA_TRACE_FEATURE)
1047 BX_DEBUG(("io write 3c0: video_enabled = %u",
1048 (unsigned) BX_VGA_THIS s.attribute_ctrl.video_enabled));
1049 #endif
1050 if (BX_VGA_THIS s.attribute_ctrl.video_enabled == 0)
1051 bx_gui->clear_screen();
1052 else if (!prev_video_enabled) {
1053 #if !defined(VGA_TRACE_FEATURE)
1054 BX_DEBUG(("found enable transition"));
1055 #endif
1056 needs_update = 1;
1058 value &= 0x1f; /* address = bits 0..4 */
1059 BX_VGA_THIS s.attribute_ctrl.address = value;
1060 switch (value) {
1061 case 0x00: case 0x01: case 0x02: case 0x03:
1062 case 0x04: case 0x05: case 0x06: case 0x07:
1063 case 0x08: case 0x09: case 0x0a: case 0x0b:
1064 case 0x0c: case 0x0d: case 0x0e: case 0x0f:
1065 break;
1067 default:
1068 BX_DEBUG(("io write 0x3c0: address mode reg=0x%02x",
1069 (unsigned) value));
1072 else { /* data-write mode */
1073 switch (BX_VGA_THIS s.attribute_ctrl.address) {
1074 case 0x00: case 0x01: case 0x02: case 0x03:
1075 case 0x04: case 0x05: case 0x06: case 0x07:
1076 case 0x08: case 0x09: case 0x0a: case 0x0b:
1077 case 0x0c: case 0x0d: case 0x0e: case 0x0f:
1078 if (value != BX_VGA_THIS s.attribute_ctrl.palette_reg[BX_VGA_THIS s.attribute_ctrl.address]) {
1079 BX_VGA_THIS s.attribute_ctrl.palette_reg[BX_VGA_THIS s.attribute_ctrl.address] =
1080 value;
1081 needs_update = 1;
1083 break;
1084 case 0x10: // mode control register
1085 prev_line_graphics = BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics;
1086 prev_int_pal_size = BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size;
1087 BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha =
1088 (value >> 0) & 0x01;
1089 BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type =
1090 (value >> 1) & 0x01;
1091 BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics =
1092 (value >> 2) & 0x01;
1093 BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity =
1094 (value >> 3) & 0x01;
1095 BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_panning_compat =
1096 (value >> 5) & 0x01;
1097 BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select =
1098 (value >> 6) & 0x01;
1099 BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size =
1100 (value >> 7) & 0x01;
1101 if (((value >> 2) & 0x01) != prev_line_graphics) {
1102 bx_gui->set_text_charmap(
1103 & BX_VGA_THIS s.memory[0x20000 + BX_VGA_THIS s.charmap_address]);
1104 BX_VGA_THIS s.vga_mem_updated = 1;
1106 if (((value >> 7) & 0x01) != prev_int_pal_size) {
1107 needs_update = 1;
1109 #if !defined(VGA_TRACE_FEATURE)
1110 BX_DEBUG(("io write 0x3c0: mode control: 0x%02x",
1111 (unsigned) value));
1112 #endif
1113 break;
1114 case 0x11: // Overscan Color Register
1115 BX_VGA_THIS s.attribute_ctrl.overscan_color = (value & 0x3f);
1116 #if !defined(VGA_TRACE_FEATURE)
1117 BX_DEBUG(("io write 0x3c0: overscan color = 0x%02x",
1118 (unsigned) value));
1119 #endif
1120 break;
1121 case 0x12: // Color Plane Enable Register
1122 BX_VGA_THIS s.attribute_ctrl.color_plane_enable = (value & 0x0f);
1123 needs_update = 1;
1124 #if !defined(VGA_TRACE_FEATURE)
1125 BX_DEBUG(("io write 0x3c0: color plane enable = 0x%02x",
1126 (unsigned) value));
1127 #endif
1128 break;
1129 case 0x13: // Horizontal Pixel Panning Register
1130 BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning = (value & 0x0f);
1131 needs_update = 1;
1132 #if !defined(VGA_TRACE_FEATURE)
1133 BX_DEBUG(("io write 0x3c0: horiz pel panning = 0x%02x",
1134 (unsigned) value));
1135 #endif
1136 break;
1137 case 0x14: // Color Select Register
1138 BX_VGA_THIS s.attribute_ctrl.color_select = (value & 0x0f);
1139 needs_update = 1;
1140 #if !defined(VGA_TRACE_FEATURE)
1141 BX_DEBUG(("io write 0x3c0: color select = 0x%02x",
1142 (unsigned) BX_VGA_THIS s.attribute_ctrl.color_select));
1143 #endif
1144 break;
1145 default:
1146 BX_DEBUG(("io write 0x3c0: data-write mode 0x%02x",
1147 (unsigned) BX_VGA_THIS s.attribute_ctrl.address));
1150 BX_VGA_THIS s.attribute_ctrl.flip_flop = !BX_VGA_THIS s.attribute_ctrl.flip_flop;
1151 break;
1153 case 0x03c2: // Miscellaneous Output Register
1154 BX_VGA_THIS s.misc_output.color_emulation = (value >> 0) & 0x01;
1155 BX_VGA_THIS s.misc_output.enable_ram = (value >> 1) & 0x01;
1156 BX_VGA_THIS s.misc_output.clock_select = (value >> 2) & 0x03;
1157 BX_VGA_THIS s.misc_output.select_high_bank = (value >> 5) & 0x01;
1158 BX_VGA_THIS s.misc_output.horiz_sync_pol = (value >> 6) & 0x01;
1159 BX_VGA_THIS s.misc_output.vert_sync_pol = (value >> 7) & 0x01;
1160 #if !defined(VGA_TRACE_FEATURE)
1161 BX_DEBUG(("io write 3c2:"));
1162 BX_DEBUG((" color_emulation (attempted) = %u",
1163 (value >> 0) & 0x01));
1164 BX_DEBUG((" enable_ram = %u",
1165 (unsigned) BX_VGA_THIS s.misc_output.enable_ram));
1166 BX_DEBUG((" clock_select = %u",
1167 (unsigned) BX_VGA_THIS s.misc_output.clock_select));
1168 BX_DEBUG((" select_high_bank = %u",
1169 (unsigned) BX_VGA_THIS s.misc_output.select_high_bank));
1170 BX_DEBUG((" horiz_sync_pol = %u",
1171 (unsigned) BX_VGA_THIS s.misc_output.horiz_sync_pol));
1172 BX_DEBUG((" vert_sync_pol = %u",
1173 (unsigned) BX_VGA_THIS s.misc_output.vert_sync_pol));
1174 #endif
1175 break;
1177 case 0x03c3: // VGA enable
1178 // bit0: enables VGA display if set
1179 BX_VGA_THIS s.vga_enabled = value & 0x01;
1180 #if !defined(VGA_TRACE_FEATURE)
1181 BX_DEBUG(("io write 0x03c3: VGA enable = %u", BX_VGA_THIS s.vga_enabled));
1182 #endif
1183 break;
1185 case 0x03c4: /* Sequencer Index Register */
1186 if (value > 4) {
1187 BX_DEBUG(("io write 3c4: value > 4"));
1189 BX_VGA_THIS s.sequencer.index = value;
1190 break;
1192 case 0x03c5: /* Sequencer Registers 00..04 */
1193 switch (BX_VGA_THIS s.sequencer.index) {
1194 case 0: /* sequencer: reset */
1195 #if !defined(VGA_TRACE_FEATURE)
1196 BX_DEBUG(("write 0x3c5: sequencer reset: value=0x%02x",
1197 (unsigned) value));
1198 #endif
1199 if (BX_VGA_THIS s.sequencer.reset1 && ((value & 0x01) == 0)) {
1200 BX_VGA_THIS s.sequencer.char_map_select = 0;
1201 BX_VGA_THIS s.charmap_address = 0;
1202 bx_gui->set_text_charmap(
1203 & BX_VGA_THIS s.memory[0x20000 + BX_VGA_THIS s.charmap_address]);
1204 BX_VGA_THIS s.vga_mem_updated = 1;
1206 BX_VGA_THIS s.sequencer.reset1 = (value >> 0) & 0x01;
1207 BX_VGA_THIS s.sequencer.reset2 = (value >> 1) & 0x01;
1208 break;
1209 case 1: /* sequencer: clocking mode */
1210 #if !defined(VGA_TRACE_FEATURE)
1211 BX_DEBUG(("io write 0x3c5=0x%02x: clocking mode reg: ignoring",
1212 (unsigned) value));
1213 #endif
1214 if ((value & 0x20) > 0) {
1215 bx_gui->clear_screen();
1216 } else if ((BX_VGA_THIS s.sequencer.reg1 & 0x20) > 0) {
1217 needs_update = 1;
1219 BX_VGA_THIS s.sequencer.reg1 = value & 0x3d;
1220 BX_VGA_THIS s.x_dotclockdiv2 = ((value & 0x08) > 0);
1221 break;
1222 case 2: /* sequencer: map mask register */
1223 BX_VGA_THIS s.sequencer.map_mask = (value & 0x0f);
1224 break;
1225 case 3: /* sequencer: character map select register */
1226 BX_VGA_THIS s.sequencer.char_map_select = value & 0x3f;
1227 charmap1 = value & 0x13;
1228 if (charmap1 > 3) charmap1 = (charmap1 & 3) + 4;
1229 charmap2 = (value & 0x2C) >> 2;
1230 if (charmap2 > 3) charmap2 = (charmap2 & 3) + 4;
1231 if (BX_VGA_THIS s.CRTC.reg[0x09] > 0) {
1232 BX_VGA_THIS s.charmap_address = charmap_offset[charmap1];
1233 bx_gui->set_text_charmap(
1234 & BX_VGA_THIS s.memory[0x20000 + BX_VGA_THIS s.charmap_address]);
1235 BX_VGA_THIS s.vga_mem_updated = 1;
1237 if (charmap2 != charmap1)
1238 BX_INFO(("char map select: map #2 in block #%d unused", charmap2));
1239 break;
1240 case 4: /* sequencer: memory mode register */
1241 BX_VGA_THIS s.sequencer.extended_mem = (value >> 1) & 0x01;
1242 BX_VGA_THIS s.sequencer.odd_even = (value >> 2) & 0x01;
1243 BX_VGA_THIS s.sequencer.chain_four = (value >> 3) & 0x01;
1245 #if !defined(VGA_TRACE_FEATURE)
1246 BX_DEBUG(("io write 0x3c5: memory mode:"));
1247 BX_DEBUG((" extended_mem = %u",
1248 (unsigned) BX_VGA_THIS s.sequencer.extended_mem));
1249 BX_DEBUG((" odd_even = %u",
1250 (unsigned) BX_VGA_THIS s.sequencer.odd_even));
1251 BX_DEBUG((" chain_four = %u",
1252 (unsigned) BX_VGA_THIS s.sequencer.chain_four));
1253 #endif
1254 break;
1255 default:
1256 BX_DEBUG(("io write 0x3c5: index 0x%02x unhandled",
1257 (unsigned) BX_VGA_THIS s.sequencer.index));
1259 break;
1261 case 0x03c6: /* PEL mask */
1262 BX_VGA_THIS s.pel.mask = value;
1263 if (BX_VGA_THIS s.pel.mask != 0xff)
1264 BX_DEBUG(("io write 0x3c6: PEL mask=0x%02x != 0xFF", value));
1265 // BX_VGA_THIS s.pel.mask should be and'd with final value before
1266 // indexing into color register BX_VGA_THIS s.pel.data[]
1267 break;
1269 case 0x03c7: // PEL address, read mode
1270 BX_VGA_THIS s.pel.read_data_register = value;
1271 BX_VGA_THIS s.pel.read_data_cycle = 0;
1272 BX_VGA_THIS s.pel.dac_state = 0x03;
1273 break;
1275 case 0x03c8: /* PEL address write mode */
1276 BX_VGA_THIS s.pel.write_data_register = value;
1277 BX_VGA_THIS s.pel.write_data_cycle = 0;
1278 BX_VGA_THIS s.pel.dac_state = 0x00;
1279 break;
1281 case 0x03c9: /* PEL Data Register, colors 00..FF */
1282 switch (BX_VGA_THIS s.pel.write_data_cycle) {
1283 case 0:
1284 BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].red = value;
1285 break;
1286 case 1:
1287 BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].green = value;
1288 break;
1289 case 2:
1290 BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].blue = value;
1292 #if BX_SUPPORT_VBE
1293 if (BX_VGA_THIS s.vbe_8bit_dac) {
1294 needs_update |= bx_gui->palette_change(BX_VGA_THIS s.pel.write_data_register,
1295 BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].red,
1296 BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].green,
1297 BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].blue);
1298 } else {
1299 #endif
1300 needs_update |= bx_gui->palette_change(BX_VGA_THIS s.pel.write_data_register,
1301 BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].red<<2,
1302 BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].green<<2,
1303 BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].blue<<2);
1304 #if BX_SUPPORT_VBE
1306 #endif
1307 break;
1310 BX_VGA_THIS s.pel.write_data_cycle++;
1311 if (BX_VGA_THIS s.pel.write_data_cycle >= 3) {
1312 //BX_INFO(("BX_VGA_THIS s.pel.data[%u] {r=%u, g=%u, b=%u}",
1313 // (unsigned) BX_VGA_THIS s.pel.write_data_register,
1314 // (unsigned) BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].red,
1315 // (unsigned) BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].green,
1316 // (unsigned) BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].blue);
1317 BX_VGA_THIS s.pel.write_data_cycle = 0;
1318 BX_VGA_THIS s.pel.write_data_register++;
1320 break;
1322 case 0x03ca: /* Graphics 2 Position (EGA) */
1323 // ignore, EGA only???
1324 break;
1326 case 0x03cc: /* Graphics 1 Position (EGA) */
1327 // ignore, EGA only???
1328 break;
1330 case 0x03cd: /* ??? */
1331 BX_DEBUG(("io write to 0x3cd = 0x%02x", (unsigned) value));
1332 break;
1334 case 0x03ce: /* Graphics Controller Index Register */
1335 if (value > 0x08) /* ??? */
1336 BX_DEBUG(("io write: 0x3ce: value > 8"));
1337 BX_VGA_THIS s.graphics_ctrl.index = value;
1338 break;
1340 case 0x03cf: /* Graphics Controller Registers 00..08 */
1341 switch (BX_VGA_THIS s.graphics_ctrl.index) {
1342 case 0: /* Set/Reset */
1343 BX_VGA_THIS s.graphics_ctrl.set_reset = value & 0x0f;
1344 break;
1345 case 1: /* Enable Set/Reset */
1346 BX_VGA_THIS s.graphics_ctrl.enable_set_reset = value & 0x0f;
1347 break;
1348 case 2: /* Color Compare */
1349 BX_VGA_THIS s.graphics_ctrl.color_compare = value & 0x0f;
1350 break;
1351 case 3: /* Data Rotate */
1352 BX_VGA_THIS s.graphics_ctrl.data_rotate = value & 0x07;
1353 BX_VGA_THIS s.graphics_ctrl.raster_op = (value >> 3) & 0x03;
1354 break;
1355 case 4: /* Read Map Select */
1356 BX_VGA_THIS s.graphics_ctrl.read_map_select = value & 0x03;
1357 #if !defined(VGA_TRACE_FEATURE)
1358 BX_DEBUG(("io write to 0x3cf = 0x%02x (RMS)", (unsigned) value));
1359 #endif
1360 break;
1361 case 5: /* Mode */
1362 BX_VGA_THIS s.graphics_ctrl.write_mode = value & 0x03;
1363 BX_VGA_THIS s.graphics_ctrl.read_mode = (value >> 3) & 0x01;
1364 BX_VGA_THIS s.graphics_ctrl.odd_even = (value >> 4) & 0x01;
1365 BX_VGA_THIS s.graphics_ctrl.shift_reg = (value >> 5) & 0x03;
1367 if (BX_VGA_THIS s.graphics_ctrl.odd_even)
1368 BX_DEBUG(("io write: 0x3cf: mode reg: value = 0x%02x",
1369 (unsigned) value));
1370 if (BX_VGA_THIS s.graphics_ctrl.shift_reg)
1371 BX_DEBUG(("io write: 0x3cf: mode reg: value = 0x%02x",
1372 (unsigned) value));
1373 break;
1374 case 6: /* Miscellaneous */
1375 prev_graphics_alpha = BX_VGA_THIS s.graphics_ctrl.graphics_alpha;
1376 prev_chain_odd_even = BX_VGA_THIS s.graphics_ctrl.chain_odd_even;
1377 prev_memory_mapping = BX_VGA_THIS s.graphics_ctrl.memory_mapping;
1379 BX_VGA_THIS s.graphics_ctrl.graphics_alpha = value & 0x01;
1380 BX_VGA_THIS s.graphics_ctrl.chain_odd_even = (value >> 1) & 0x01;
1381 BX_VGA_THIS s.graphics_ctrl.memory_mapping = (value >> 2) & 0x03;
1382 #if !defined(VGA_TRACE_FEATURE)
1383 BX_DEBUG(("memory_mapping set to %u",
1384 (unsigned) BX_VGA_THIS s.graphics_ctrl.memory_mapping));
1385 BX_DEBUG(("graphics mode set to %u",
1386 (unsigned) BX_VGA_THIS s.graphics_ctrl.graphics_alpha));
1387 BX_DEBUG(("odd_even mode set to %u",
1388 (unsigned) BX_VGA_THIS s.graphics_ctrl.odd_even));
1389 BX_DEBUG(("io write: 0x3cf: misc reg: value = 0x%02x",
1390 (unsigned) value));
1391 #endif
1392 if (prev_memory_mapping != BX_VGA_THIS s.graphics_ctrl.memory_mapping)
1393 needs_update = 1;
1394 if (prev_graphics_alpha != BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
1395 needs_update = 1;
1396 old_iHeight = 0;
1398 break;
1399 case 7: /* Color Don't Care */
1400 BX_VGA_THIS s.graphics_ctrl.color_dont_care = value & 0x0f;
1401 break;
1402 case 8: /* Bit Mask */
1403 BX_VGA_THIS s.graphics_ctrl.bitmask = value;
1404 break;
1405 default:
1406 /* ??? */
1407 BX_DEBUG(("io write: 0x3cf: index %u unhandled",
1408 (unsigned) BX_VGA_THIS s.graphics_ctrl.index));
1410 break;
1412 case 0x03b4: /* CRTC Index Register (monochrome emulation modes) */
1413 case 0x03d4: /* CRTC Index Register (color emulation modes) */
1414 BX_VGA_THIS s.CRTC.address = value & 0x7f;
1415 if (BX_VGA_THIS s.CRTC.address > 0x18)
1416 BX_DEBUG(("write: invalid CRTC register 0x%02x selected",
1417 (unsigned) BX_VGA_THIS s.CRTC.address));
1418 break;
1420 case 0x03b5: /* CRTC Registers (monochrome emulation modes) */
1421 case 0x03d5: /* CRTC Registers (color emulation modes) */
1422 if (BX_VGA_THIS s.CRTC.address > 0x18) {
1423 BX_DEBUG(("write: invalid CRTC register 0x%02x ignored",
1424 (unsigned) BX_VGA_THIS s.CRTC.address));
1425 return;
1427 if (BX_VGA_THIS s.CRTC.write_protect && (BX_VGA_THIS s.CRTC.address < 0x08)) {
1428 if (BX_VGA_THIS s.CRTC.address == 0x07) {
1429 BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address] &= ~0x10;
1430 BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address] |= (value & 0x10);
1431 BX_VGA_THIS s.line_compare &= 0x2ff;
1432 if (BX_VGA_THIS s.CRTC.reg[0x07] & 0x10) BX_VGA_THIS s.line_compare |= 0x100;
1433 needs_update = 1;
1434 break;
1435 } else {
1436 return;
1439 if (value != BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address]) {
1440 BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address] = value;
1441 switch (BX_VGA_THIS s.CRTC.address) {
1442 case 0x07:
1443 BX_VGA_THIS s.vertical_display_end &= 0xff;
1444 if (BX_VGA_THIS s.CRTC.reg[0x07] & 0x02) BX_VGA_THIS s.vertical_display_end |= 0x100;
1445 if (BX_VGA_THIS s.CRTC.reg[0x07] & 0x40) BX_VGA_THIS s.vertical_display_end |= 0x200;
1446 BX_VGA_THIS s.line_compare &= 0x2ff;
1447 if (BX_VGA_THIS s.CRTC.reg[0x07] & 0x10) BX_VGA_THIS s.line_compare |= 0x100;
1448 needs_update = 1;
1449 break;
1450 case 0x08:
1451 // Vertical pel panning change
1452 needs_update = 1;
1453 break;
1454 case 0x09:
1455 BX_VGA_THIS s.y_doublescan = ((value & 0x9f) > 0);
1456 BX_VGA_THIS s.line_compare &= 0x1ff;
1457 if (BX_VGA_THIS s.CRTC.reg[0x09] & 0x40) BX_VGA_THIS s.line_compare |= 0x200;
1458 needs_update = 1;
1459 break;
1460 case 0x0A:
1461 case 0x0B:
1462 case 0x0E:
1463 case 0x0F:
1464 // Cursor size / location change
1465 BX_VGA_THIS s.vga_mem_updated = 1;
1466 break;
1467 case 0x0C:
1468 case 0x0D:
1469 // Start address change
1470 if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
1471 needs_update = 1;
1472 } else {
1473 BX_VGA_THIS s.vga_mem_updated = 1;
1475 break;
1476 case 0x11:
1477 BX_VGA_THIS s.CRTC.write_protect = ((BX_VGA_THIS s.CRTC.reg[0x11] & 0x80) > 0);
1478 break;
1479 case 0x12:
1480 BX_VGA_THIS s.vertical_display_end &= 0x300;
1481 BX_VGA_THIS s.vertical_display_end |= BX_VGA_THIS s.CRTC.reg[0x12];
1482 break;
1483 case 0x13:
1484 case 0x14:
1485 case 0x17:
1486 #if BX_SUPPORT_VBE
1487 if (!BX_VGA_THIS s.vbe_enabled || (BX_VGA_THIS s.vbe_bpp == VBE_DISPI_BPP_4))
1488 #endif
1490 // Line offset change
1491 BX_VGA_THIS s.line_offset = BX_VGA_THIS s.CRTC.reg[0x13] << 1;
1492 if (BX_VGA_THIS s.CRTC.reg[0x14] & 0x40) BX_VGA_THIS s.line_offset <<= 2;
1493 else if ((BX_VGA_THIS s.CRTC.reg[0x17] & 0x40) == 0) BX_VGA_THIS s.line_offset <<= 1;
1494 needs_update = 1;
1496 break;
1497 case 0x18:
1498 BX_VGA_THIS s.line_compare &= 0x300;
1499 BX_VGA_THIS s.line_compare |= BX_VGA_THIS s.CRTC.reg[0x18];
1500 needs_update = 1;
1501 break;
1505 break;
1507 case 0x03da: /* Feature Control (color emulation modes) */
1508 BX_DEBUG(("io write: 3da: ignoring: feature ctrl & vert sync"));
1509 break;
1511 case 0x03c1: /* */
1512 default:
1513 BX_ERROR(("unsupported io write to port 0x%04x, val=0x%02x",
1514 (unsigned) address, (unsigned) value));
1517 if (needs_update) {
1518 // Mark all video as updated so the changes will go through
1519 BX_VGA_THIS redraw_area(0, 0, old_iWidth, old_iHeight);
1523 Bit64s bx_vga_c::vga_param_handler(bx_param_c *param, int set, Bit64s val)
1525 // handler for runtime parameter 'vga_update_interval'
1526 if (set) {
1527 BX_INFO (("Changing timer interval to %d", (Bit32u)val));
1528 BX_VGA_THIS timer_handler (theVga);
1529 bx_pc_system.activate_timer (BX_VGA_THIS timer_id, (Bit32u)val, 1);
1531 return val;
1534 void bx_vga_c::trigger_timer(void *this_ptr)
1536 timer_handler(this_ptr);
1539 void bx_vga_c::timer_handler(void *this_ptr)
1541 #if BX_USE_VGA_SMF == 0
1542 bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
1543 class_ptr->timer();
1546 void bx_vga_c::timer(void)
1548 #else
1549 UNUSED(this_ptr);
1550 #endif
1552 update();
1553 bx_gui->flush();
1556 void bx_vga_c::update(void)
1558 unsigned iHeight, iWidth;
1560 /* no screen update necessary */
1561 if ((BX_VGA_THIS s.vga_mem_updated==0) && BX_VGA_THIS s.graphics_ctrl.graphics_alpha)
1562 return;
1564 /* skip screen update when vga/video is disabled or the sequencer is in reset mode */
1565 if (!BX_VGA_THIS s.vga_enabled || !BX_VGA_THIS s.attribute_ctrl.video_enabled
1566 || !BX_VGA_THIS s.sequencer.reset2 || !BX_VGA_THIS s.sequencer.reset1
1567 || (BX_VGA_THIS s.sequencer.reg1 & 0x20))
1568 return;
1570 /* skip screen update if the vertical retrace is in progress
1571 (using 72 Hz vertical frequency) */
1572 if ((bx_pc_system.time_usec() % 13888) < 70)
1573 return;
1575 #if BX_SUPPORT_VBE
1576 if ((BX_VGA_THIS s.vbe_enabled) && (BX_VGA_THIS s.vbe_bpp != VBE_DISPI_BPP_4))
1578 // specific VBE code display update code
1579 unsigned pitch;
1580 unsigned xc, yc, xti, yti;
1581 unsigned r, c, w, h;
1582 int i;
1583 unsigned long red, green, blue, colour;
1584 Bit8u * vid_ptr, * vid_ptr2;
1585 Bit8u * tile_ptr, * tile_ptr2;
1586 bx_svga_tileinfo_t info;
1587 Bit8u dac_size = BX_VGA_THIS s.vbe_8bit_dac ? 8 : 6;
1589 iWidth=BX_VGA_THIS s.vbe_xres;
1590 iHeight=BX_VGA_THIS s.vbe_yres;
1591 pitch = BX_VGA_THIS s.line_offset;
1592 Bit8u *disp_ptr = &BX_VGA_THIS s.memory[BX_VGA_THIS s.vbe_virtual_start];
1594 if (bx_gui->graphics_tile_info(&info)) {
1595 if (info.is_indexed) {
1596 switch (BX_VGA_THIS s.vbe_bpp) {
1597 case 4:
1598 case 15:
1599 case 16:
1600 case 24:
1601 case 32:
1602 BX_ERROR(("current guest pixel format is unsupported on indexed colour host displays"));
1603 break;
1604 case 8:
1605 for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
1606 for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
1607 if (GET_TILE_UPDATED (xti, yti)) {
1608 vid_ptr = disp_ptr + (yc * pitch + xc);
1609 tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
1610 for (r=0; r<h; r++) {
1611 vid_ptr2 = vid_ptr;
1612 tile_ptr2 = tile_ptr;
1613 for (c=0; c<w; c++) {
1614 colour = 0;
1615 for (i=0; i<(int)BX_VGA_THIS s.vbe_bpp; i+=8) {
1616 colour |= *(vid_ptr2++) << i;
1618 if (info.is_little_endian) {
1619 for (i=0; i<info.bpp; i+=8) {
1620 *(tile_ptr2++) = (Bit8u)(colour >> i);
1623 else {
1624 for (i=info.bpp-8; i>-8; i-=8) {
1625 *(tile_ptr2++) = (Bit8u)(colour >> i);
1629 vid_ptr += pitch;
1630 tile_ptr += info.pitch;
1632 bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
1633 SET_TILE_UPDATED (xti, yti, 0);
1637 break;
1640 else {
1641 switch (BX_VGA_THIS s.vbe_bpp) {
1642 case 4:
1643 BX_ERROR(("cannot draw 4bpp SVGA"));
1644 break;
1645 case 8:
1646 for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
1647 for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
1648 if (GET_TILE_UPDATED (xti, yti)) {
1649 vid_ptr = disp_ptr + (yc * pitch + xc);
1650 tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
1651 for (r=0; r<h; r++) {
1652 vid_ptr2 = vid_ptr;
1653 tile_ptr2 = tile_ptr;
1654 for (c=0; c<w; c++) {
1655 colour = *(vid_ptr2++);
1656 colour = MAKE_COLOUR(
1657 BX_VGA_THIS s.pel.data[colour].red, dac_size, info.red_shift, info.red_mask,
1658 BX_VGA_THIS s.pel.data[colour].green, dac_size, info.green_shift, info.green_mask,
1659 BX_VGA_THIS s.pel.data[colour].blue, dac_size, info.blue_shift, info.blue_mask);
1660 if (info.is_little_endian) {
1661 for (i=0; i<info.bpp; i+=8) {
1662 *(tile_ptr2++) = (Bit8u)(colour >> i);
1665 else {
1666 for (i=info.bpp-8; i>-8; i-=8) {
1667 *(tile_ptr2++) = (Bit8u)(colour >> i);
1671 vid_ptr += pitch;
1672 tile_ptr += info.pitch;
1674 bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
1675 SET_TILE_UPDATED (xti, yti, 0);
1679 break;
1680 case 15:
1681 for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
1682 for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
1683 if (GET_TILE_UPDATED (xti, yti)) {
1684 vid_ptr = disp_ptr + (yc * pitch + (xc<<1));
1685 tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
1686 for (r=0; r<h; r++) {
1687 vid_ptr2 = vid_ptr;
1688 tile_ptr2 = tile_ptr;
1689 for (c=0; c<w; c++) {
1690 colour = *(vid_ptr2++);
1691 colour |= *(vid_ptr2++) << 8;
1692 colour = MAKE_COLOUR(
1693 colour & 0x001f, 5, info.blue_shift, info.blue_mask,
1694 colour & 0x03e0, 10, info.green_shift, info.green_mask,
1695 colour & 0x7c00, 15, info.red_shift, info.red_mask);
1696 if (info.is_little_endian) {
1697 for (i=0; i<info.bpp; i+=8) {
1698 *(tile_ptr2++) = (Bit8u)(colour >> i);
1701 else {
1702 for (i=info.bpp-8; i>-8; i-=8) {
1703 *(tile_ptr2++) = (Bit8u)(colour >> i);
1707 vid_ptr += pitch;
1708 tile_ptr += info.pitch;
1710 bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
1711 SET_TILE_UPDATED (xti, yti, 0);
1715 break;
1716 case 16:
1717 for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
1718 for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
1719 if (GET_TILE_UPDATED (xti, yti)) {
1720 vid_ptr = disp_ptr + (yc * pitch + (xc<<1));
1721 tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
1722 for (r=0; r<h; r++) {
1723 vid_ptr2 = vid_ptr;
1724 tile_ptr2 = tile_ptr;
1725 for (c=0; c<w; c++) {
1726 colour = *(vid_ptr2++);
1727 colour |= *(vid_ptr2++) << 8;
1728 colour = MAKE_COLOUR(
1729 colour & 0x001f, 5, info.blue_shift, info.blue_mask,
1730 colour & 0x07e0, 11, info.green_shift, info.green_mask,
1731 colour & 0xf800, 16, info.red_shift, info.red_mask);
1732 if (info.is_little_endian) {
1733 for (i=0; i<info.bpp; i+=8) {
1734 *(tile_ptr2++) = (Bit8u)(colour >> i);
1737 else {
1738 for (i=info.bpp-8; i>-8; i-=8) {
1739 *(tile_ptr2++) = (Bit8u)(colour >> i);
1743 vid_ptr += pitch;
1744 tile_ptr += info.pitch;
1746 bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
1747 SET_TILE_UPDATED (xti, yti, 0);
1751 break;
1752 case 24:
1753 for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
1754 for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
1755 if (GET_TILE_UPDATED (xti, yti)) {
1756 vid_ptr = disp_ptr + (yc * pitch + 3*xc);
1757 tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
1758 for (r=0; r<h; r++) {
1759 vid_ptr2 = vid_ptr;
1760 tile_ptr2 = tile_ptr;
1761 for (c=0; c<w; c++) {
1762 blue = *(vid_ptr2++);
1763 green = *(vid_ptr2++);
1764 red = *(vid_ptr2++);
1765 colour = MAKE_COLOUR(
1766 red, 8, info.red_shift, info.red_mask,
1767 green, 8, info.green_shift, info.green_mask,
1768 blue, 8, info.blue_shift, info.blue_mask);
1769 if (info.is_little_endian) {
1770 for (i=0; i<info.bpp; i+=8) {
1771 *(tile_ptr2++) = (Bit8u)(colour >> i);
1774 else {
1775 for (i=info.bpp-8; i>-8; i-=8) {
1776 *(tile_ptr2++) = (Bit8u)(colour >> i);
1780 vid_ptr += pitch;
1781 tile_ptr += info.pitch;
1783 bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
1784 SET_TILE_UPDATED (xti, yti, 0);
1788 break;
1789 case 32:
1790 for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
1791 for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
1792 if (GET_TILE_UPDATED (xti, yti)) {
1793 vid_ptr = disp_ptr + (yc * pitch + (xc<<2));
1794 tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
1795 for (r=0; r<h; r++) {
1796 vid_ptr2 = vid_ptr;
1797 tile_ptr2 = tile_ptr;
1798 for (c=0; c<w; c++) {
1799 blue = *(vid_ptr2++);
1800 green = *(vid_ptr2++);
1801 red = *(vid_ptr2++);
1802 vid_ptr2++;
1803 colour = MAKE_COLOUR(
1804 red, 8, info.red_shift, info.red_mask,
1805 green, 8, info.green_shift, info.green_mask,
1806 blue, 8, info.blue_shift, info.blue_mask);
1807 if (info.is_little_endian) {
1808 for (i=0; i<info.bpp; i+=8) {
1809 *(tile_ptr2++) = (Bit8u)(colour >> i);
1812 else {
1813 for (i=info.bpp-8; i>-8; i-=8) {
1814 *(tile_ptr2++) = (Bit8u)(colour >> i);
1818 vid_ptr += pitch;
1819 tile_ptr += info.pitch;
1821 bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
1822 SET_TILE_UPDATED (xti, yti, 0);
1826 break;
1829 old_iWidth = iWidth;
1830 old_iHeight = iHeight;
1831 BX_VGA_THIS s.vga_mem_updated = 0;
1833 else {
1834 BX_PANIC(("cannot get svga tile info"));
1837 // after a vbe display update, don't try to do any 'normal vga' updates anymore
1838 return;
1840 #endif
1841 // fields that effect the way video memory is serialized into screen output:
1842 // GRAPHICS CONTROLLER:
1843 // BX_VGA_THIS s.graphics_ctrl.shift_reg:
1844 // 0: output data in standard VGA format or CGA-compatible 640x200 2 color
1845 // graphics mode (mode 6)
1846 // 1: output data in CGA-compatible 320x200 4 color graphics mode
1847 // (modes 4 & 5)
1848 // 2: output data 8 bits at a time from the 4 bit planes
1849 // (mode 13 and variants like modeX)
1851 // if (BX_VGA_THIS s.vga_mem_updated==0 || BX_VGA_THIS s.attribute_ctrl.video_enabled == 0)
1853 if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
1854 Bit8u color;
1855 unsigned bit_no, r, c, x, y;
1856 unsigned long byte_offset, start_addr;
1857 unsigned xc, yc, xti, yti;
1859 start_addr = (BX_VGA_THIS s.CRTC.reg[0x0c] << 8) | BX_VGA_THIS s.CRTC.reg[0x0d];
1861 //BX_DEBUG(("update: shiftreg=%u, chain4=%u, mapping=%u",
1862 // (unsigned) BX_VGA_THIS s.graphics_ctrl.shift_reg,
1863 // (unsigned) BX_VGA_THIS s.sequencer.chain_four,
1864 // (unsigned) BX_VGA_THIS s.graphics_ctrl.memory_mapping);
1866 determine_screen_dimensions(&iHeight, &iWidth);
1867 if((iWidth != old_iWidth) || (iHeight != old_iHeight) ||
1868 (BX_VGA_THIS s.last_bpp > 8))
1870 bx_gui->dimension_update(iWidth, iHeight);
1871 old_iWidth = iWidth;
1872 old_iHeight = iHeight;
1873 BX_VGA_THIS s.last_bpp = 8;
1876 switch (BX_VGA_THIS s.graphics_ctrl.shift_reg) {
1877 case 0:
1878 Bit8u attribute, palette_reg_val, DAC_regno;
1879 unsigned long line_compare;
1880 Bit8u *plane0, *plane1, *plane2, *plane3;
1882 if (BX_VGA_THIS s.graphics_ctrl.memory_mapping == 3) { // CGA 640x200x2
1884 for (yc=0, yti=0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
1885 for (xc=0, xti=0; xc<iWidth; xc+=X_TILESIZE, xti++) {
1886 if (GET_TILE_UPDATED (xti, yti)) {
1887 for (r=0; r<Y_TILESIZE; r++) {
1888 y = yc + r;
1889 if (BX_VGA_THIS s.y_doublescan) y >>= 1;
1890 for (c=0; c<X_TILESIZE; c++) {
1892 x = xc + c;
1893 /* 0 or 0x2000 */
1894 byte_offset = start_addr + ((y & 1) << 13);
1895 /* to the start of the line */
1896 byte_offset += (320 / 4) * (y / 2);
1897 /* to the byte start */
1898 byte_offset += (x / 8);
1900 bit_no = 7 - (x % 8);
1901 palette_reg_val = (((BX_VGA_THIS s.memory[byte_offset]) >> bit_no) & 1);
1902 DAC_regno = BX_VGA_THIS s.attribute_ctrl.palette_reg[palette_reg_val];
1903 BX_VGA_THIS s.tile[r*X_TILESIZE + c] = DAC_regno;
1906 SET_TILE_UPDATED (xti, yti, 0);
1907 bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
1911 } else { // output data in serial fashion with each display plane
1912 // output on its associated serial output. Standard EGA/VGA format
1914 #if BX_SUPPORT_VBE
1915 if (BX_VGA_THIS s.vbe_enabled)
1917 plane0 = &BX_VGA_THIS s.memory[0<<VBE_DISPI_4BPP_PLANE_SHIFT];
1918 plane1 = &BX_VGA_THIS s.memory[1<<VBE_DISPI_4BPP_PLANE_SHIFT];
1919 plane2 = &BX_VGA_THIS s.memory[2<<VBE_DISPI_4BPP_PLANE_SHIFT];
1920 plane3 = &BX_VGA_THIS s.memory[3<<VBE_DISPI_4BPP_PLANE_SHIFT];
1921 start_addr = BX_VGA_THIS s.vbe_virtual_start;
1922 line_compare = 0xffff;
1924 else
1925 #endif
1927 plane0 = &BX_VGA_THIS s.memory[0<<16];
1928 plane1 = &BX_VGA_THIS s.memory[1<<16];
1929 plane2 = &BX_VGA_THIS s.memory[2<<16];
1930 plane3 = &BX_VGA_THIS s.memory[3<<16];
1931 line_compare = BX_VGA_THIS s.line_compare;
1932 if (BX_VGA_THIS s.y_doublescan) line_compare >>= 1;
1935 for (yc=0, yti=0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
1936 for (xc=0, xti=0; xc<iWidth; xc+=X_TILESIZE, xti++) {
1937 if (GET_TILE_UPDATED (xti, yti)) {
1938 for (r=0; r<Y_TILESIZE; r++) {
1939 y = yc + r;
1940 if (BX_VGA_THIS s.y_doublescan) y >>= 1;
1941 for (c=0; c<X_TILESIZE; c++) {
1942 x = xc + c;
1943 if (BX_VGA_THIS s.x_dotclockdiv2) x >>= 1;
1944 bit_no = 7 - (x % 8);
1945 if (y > line_compare) {
1946 byte_offset = x / 8 +
1947 ((y - line_compare - 1) * BX_VGA_THIS s.line_offset);
1948 } else {
1949 byte_offset = start_addr + x / 8 +
1950 (y * BX_VGA_THIS s.line_offset);
1952 attribute =
1953 (((plane0[byte_offset] >> bit_no) & 0x01) << 0) |
1954 (((plane1[byte_offset] >> bit_no) & 0x01) << 1) |
1955 (((plane2[byte_offset] >> bit_no) & 0x01) << 2) |
1956 (((plane3[byte_offset] >> bit_no) & 0x01) << 3);
1958 attribute &= BX_VGA_THIS s.attribute_ctrl.color_plane_enable;
1959 // undocumented feature ???: colors 0..7 high intensity, colors 8..15 blinking
1960 // using low/high intensity. Blinking is not implemented yet.
1961 if (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity) attribute ^= 0x08;
1962 palette_reg_val = BX_VGA_THIS s.attribute_ctrl.palette_reg[attribute];
1963 if (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size) {
1964 // use 4 lower bits from palette register
1965 // use 4 higher bits from color select register
1966 // 16 banks of 16-color registers
1967 DAC_regno = (palette_reg_val & 0x0f) |
1968 (BX_VGA_THIS s.attribute_ctrl.color_select << 4);
1970 else {
1971 // use 6 lower bits from palette register
1972 // use 2 higher bits from color select register
1973 // 4 banks of 64-color registers
1974 DAC_regno = (palette_reg_val & 0x3f) |
1975 ((BX_VGA_THIS s.attribute_ctrl.color_select & 0x0c) << 4);
1977 // DAC_regno &= video DAC mask register ???
1979 BX_VGA_THIS s.tile[r*X_TILESIZE + c] = DAC_regno;
1982 SET_TILE_UPDATED (xti, yti, 0);
1983 bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
1988 break; // case 0
1990 case 1: // output the data in a CGA-compatible 320x200 4 color graphics
1991 // mode. (modes 4 & 5)
1993 /* CGA 320x200x4 start */
1995 for (yc=0, yti=0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
1996 for (xc=0, xti=0; xc<iWidth; xc+=X_TILESIZE, xti++) {
1997 if (GET_TILE_UPDATED (xti, yti)) {
1998 for (r=0; r<Y_TILESIZE; r++) {
1999 y = yc + r;
2000 if (BX_VGA_THIS s.y_doublescan) y >>= 1;
2001 for (c=0; c<X_TILESIZE; c++) {
2003 x = xc + c;
2004 if (BX_VGA_THIS s.x_dotclockdiv2) x >>= 1;
2005 /* 0 or 0x2000 */
2006 byte_offset = start_addr + ((y & 1) << 13);
2007 /* to the start of the line */
2008 byte_offset += (320 / 4) * (y / 2);
2009 /* to the byte start */
2010 byte_offset += (x / 4);
2012 attribute = 6 - 2*(x % 4);
2013 palette_reg_val = (BX_VGA_THIS s.memory[byte_offset]) >> attribute;
2014 palette_reg_val &= 3;
2015 DAC_regno = BX_VGA_THIS s.attribute_ctrl.palette_reg[palette_reg_val];
2016 BX_VGA_THIS s.tile[r*X_TILESIZE + c] = DAC_regno;
2019 SET_TILE_UPDATED (xti, yti, 0);
2020 bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
2024 /* CGA 320x200x4 end */
2026 break; // case 1
2028 case 2: // output the data eight bits at a time from the 4 bit plane
2029 // (format for VGA mode 13 hex)
2030 case 3: // FIXME: is this really the same ???
2032 if (BX_VGA_THIS s.sequencer.chain_four) {
2033 unsigned long pixely, pixelx, plane;
2035 if (BX_VGA_THIS s.misc_output.select_high_bank != 1)
2036 BX_PANIC(("update: select_high_bank != 1"));
2038 for (yc=0, yti=0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
2039 for (xc=0, xti=0; xc<iWidth; xc+=X_TILESIZE, xti++) {
2040 if (GET_TILE_UPDATED (xti, yti)) {
2041 for (r=0; r<Y_TILESIZE; r++) {
2042 pixely = yc + r;
2043 if (BX_VGA_THIS s.y_doublescan) pixely >>= 1;
2044 for (c=0; c<X_TILESIZE; c++) {
2045 pixelx = (xc + c) >> 1;
2046 plane = (pixelx % 4);
2047 byte_offset = start_addr + (plane * 65536) +
2048 (pixely * BX_VGA_THIS s.line_offset) + (pixelx & ~0x03);
2049 color = BX_VGA_THIS s.memory[byte_offset];
2050 BX_VGA_THIS s.tile[r*X_TILESIZE + c] = color;
2053 SET_TILE_UPDATED (xti, yti, 0);
2054 bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
2060 else { // chain_four == 0, modeX
2061 unsigned long pixely, pixelx, plane;
2063 for (yc=0, yti=0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
2064 for (xc=0, xti=0; xc<iWidth; xc+=X_TILESIZE, xti++) {
2065 if (GET_TILE_UPDATED (xti, yti)) {
2066 for (r=0; r<Y_TILESIZE; r++) {
2067 pixely = yc + r;
2068 if (BX_VGA_THIS s.y_doublescan) pixely >>= 1;
2069 for (c=0; c<X_TILESIZE; c++) {
2070 pixelx = (xc + c) >> 1;
2071 plane = (pixelx % 4);
2072 byte_offset = (plane * 65536) +
2073 (pixely * BX_VGA_THIS s.line_offset)
2074 + (pixelx >> 2);
2075 color = BX_VGA_THIS s.memory[start_addr + byte_offset];
2076 BX_VGA_THIS s.tile[r*X_TILESIZE + c] = color;
2079 SET_TILE_UPDATED (xti, yti, 0);
2080 bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
2085 break; // case 2
2087 default:
2088 BX_PANIC(("update: shift_reg == %u", (unsigned)
2089 BX_VGA_THIS s.graphics_ctrl.shift_reg));
2092 BX_VGA_THIS s.vga_mem_updated = 0;
2093 return;
2096 else { // text mode
2097 unsigned long start_address;
2098 unsigned long cursor_address, cursor_x, cursor_y;
2099 bx_vga_tminfo_t tm_info;
2100 unsigned VDE, MSL, cols, rows, cWidth;
2101 static unsigned cs_counter = 1;
2102 static bx_bool cs_visible = 0;
2103 bx_bool cs_toggle = 0;
2105 cs_counter--;
2106 if ((BX_VGA_THIS s.vga_mem_updated==0) && (cs_counter > 0))
2107 return;
2109 tm_info.start_address = 2*((BX_VGA_THIS s.CRTC.reg[12] << 8) +
2110 BX_VGA_THIS s.CRTC.reg[13]);
2111 tm_info.cs_start = BX_VGA_THIS s.CRTC.reg[0x0a] & 0x3f;
2112 if (cs_counter == 0) {
2113 cs_toggle = 1;
2114 cs_visible = !cs_visible;
2115 cs_counter = BX_VGA_THIS s.blink_counter;
2117 if (!cs_visible) {
2118 tm_info.cs_start |= 0x20;
2120 tm_info.cs_end = BX_VGA_THIS s.CRTC.reg[0x0b] & 0x1f;
2121 tm_info.line_offset = BX_VGA_THIS s.CRTC.reg[0x13] << 2;
2122 tm_info.line_compare = BX_VGA_THIS s.line_compare;
2123 tm_info.h_panning = BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning & 0x0f;
2124 tm_info.v_panning = BX_VGA_THIS s.CRTC.reg[0x08] & 0x1f;
2125 tm_info.line_graphics = BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics;
2126 tm_info.split_hpanning = BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_panning_compat;
2127 tm_info.blink_flags = 0;
2128 if (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity) {
2129 tm_info.blink_flags |= BX_TEXT_BLINK_MODE;
2130 if (cs_toggle)
2131 tm_info.blink_flags |= BX_TEXT_BLINK_TOGGLE;
2132 if (cs_visible)
2133 tm_info.blink_flags |= BX_TEXT_BLINK_STATE;
2135 if ((BX_VGA_THIS s.sequencer.reg1 & 0x01) == 0) {
2136 if (tm_info.h_panning >= 8)
2137 tm_info.h_panning = 0;
2138 else
2139 tm_info.h_panning++;
2140 } else {
2141 tm_info.h_panning &= 0x07;
2144 // Verticle Display End: find out how many lines are displayed
2145 VDE = BX_VGA_THIS s.vertical_display_end;
2146 // Maximum Scan Line: height of character cell
2147 MSL = BX_VGA_THIS s.CRTC.reg[0x09] & 0x1f;
2148 if (MSL == 0) {
2149 BX_ERROR(("character height = 1, skipping text update"));
2150 return;
2152 cols = BX_VGA_THIS s.CRTC.reg[1] + 1;
2153 if ((MSL == 1) && (VDE == 399)) {
2154 // emulated CGA graphics mode 160x100x16 colors
2155 MSL = 3;
2157 rows = (VDE+1)/(MSL+1);
2158 if (rows > BX_MAX_TEXT_LINES) {
2159 BX_PANIC(("text rows>%d: %d",BX_MAX_TEXT_LINES,rows));
2160 return;
2162 cWidth = ((BX_VGA_THIS s.sequencer.reg1 & 0x01) == 1) ? 8 : 9;
2163 iWidth = cWidth * cols;
2164 iHeight = VDE+1;
2165 if ((iWidth != old_iWidth) || (iHeight != old_iHeight) || (MSL != old_MSL) ||
2166 (BX_VGA_THIS s.last_bpp > 8))
2168 bx_gui->dimension_update(iWidth, iHeight, MSL+1, cWidth);
2169 old_iWidth = iWidth;
2170 old_iHeight = iHeight;
2171 old_MSL = MSL;
2172 BX_VGA_THIS s.last_bpp = 8;
2174 // pass old text snapshot & new VGA memory contents
2175 start_address = tm_info.start_address;
2176 cursor_address = 2*((BX_VGA_THIS s.CRTC.reg[0x0e] << 8) +
2177 BX_VGA_THIS s.CRTC.reg[0x0f]);
2178 if (cursor_address < start_address) {
2179 cursor_x = 0xffff;
2180 cursor_y = 0xffff;
2181 } else {
2182 cursor_x = ((cursor_address - start_address)/2) % (iWidth/cWidth);
2183 cursor_y = ((cursor_address - start_address)/2) / (iWidth/cWidth);
2185 bx_gui->text_update(BX_VGA_THIS s.text_snapshot,
2186 &BX_VGA_THIS s.memory[start_address],
2187 cursor_x, cursor_y, tm_info);
2188 if (BX_VGA_THIS s.vga_mem_updated) {
2189 // screen updated, copy new VGA memory contents into text snapshot
2190 memcpy(BX_VGA_THIS s.text_snapshot,
2191 &BX_VGA_THIS s.memory[start_address],
2192 tm_info.line_offset*rows);
2193 BX_VGA_THIS s.vga_mem_updated = 0;
2198 bx_bool bx_vga_c::mem_read_handler(bx_phy_address addr, unsigned len, void *data, void *param)
2200 Bit8u *data_ptr;
2201 #ifdef BX_LITTLE_ENDIAN
2202 data_ptr = (Bit8u *) data;
2203 #else // BX_BIG_ENDIAN
2204 data_ptr = (Bit8u *) data + (len - 1);
2205 #endif
2206 for (unsigned i = 0; i < len; i++) {
2207 *data_ptr = theVga->mem_read(addr);
2208 addr++;
2209 #ifdef BX_LITTLE_ENDIAN
2210 data_ptr++;
2211 #else // BX_BIG_ENDIAN
2212 data_ptr--;
2213 #endif
2215 return 1;
2218 Bit8u bx_vga_c::mem_read(bx_phy_address addr)
2220 Bit32u offset;
2221 Bit8u *plane0, *plane1, *plane2, *plane3;
2223 #if BX_SUPPORT_VBE
2224 // if in a vbe enabled mode, read from the vbe_memory
2225 if ((BX_VGA_THIS s.vbe_enabled) && (BX_VGA_THIS s.vbe_bpp != VBE_DISPI_BPP_4))
2227 return vbe_mem_read(addr);
2229 else if (addr >= VBE_DISPI_LFB_PHYSICAL_ADDRESS)
2231 return 0xff;
2233 #endif
2235 #if defined(VGA_TRACE_FEATURE)
2236 // BX_DEBUG(("8-bit memory read from 0x%08x", addr));
2237 #endif
2239 #ifdef __OS2__
2241 #if BX_PLUGINS
2242 #error Fix the code for plugins
2243 #endif
2245 if (bx_options.videomode == BX_VIDEO_DIRECT)
2247 char value;
2248 value = devices->mem->video[addr-0xA0000];
2249 return value;
2251 #endif
2253 switch (BX_VGA_THIS s.graphics_ctrl.memory_mapping) {
2254 case 1: // 0xA0000 .. 0xAFFFF
2255 if (addr > 0xAFFFF) return 0xff;
2256 offset = addr & 0xFFFF;
2257 break;
2258 case 2: // 0xB0000 .. 0xB7FFF
2259 if ((addr < 0xB0000) || (addr > 0xB7FFF)) return 0xff;
2260 offset = addr & 0x7FFF;
2261 break;
2262 case 3: // 0xB8000 .. 0xBFFFF
2263 if (addr < 0xB8000) return 0xff;
2264 offset = addr & 0x7FFF;
2265 break;
2266 default: // 0xA0000 .. 0xBFFFF
2267 offset = addr & 0x1FFFF;
2270 if (BX_VGA_THIS s.sequencer.chain_four) {
2271 // Mode 13h: 320 x 200 256 color mode: chained pixel representation
2272 return BX_VGA_THIS s.memory[(offset & ~0x03) + (offset % 4)*65536];
2275 #if BX_SUPPORT_VBE
2276 if (BX_VGA_THIS s.vbe_enabled)
2278 plane0 = &BX_VGA_THIS s.memory[(0<<VBE_DISPI_4BPP_PLANE_SHIFT) + (BX_VGA_THIS s.vbe_bank<<16)];
2279 plane1 = &BX_VGA_THIS s.memory[(1<<VBE_DISPI_4BPP_PLANE_SHIFT) + (BX_VGA_THIS s.vbe_bank<<16)];
2280 plane2 = &BX_VGA_THIS s.memory[(2<<VBE_DISPI_4BPP_PLANE_SHIFT) + (BX_VGA_THIS s.vbe_bank<<16)];
2281 plane3 = &BX_VGA_THIS s.memory[(3<<VBE_DISPI_4BPP_PLANE_SHIFT) + (BX_VGA_THIS s.vbe_bank<<16)];
2283 else
2284 #endif
2286 plane0 = &BX_VGA_THIS s.memory[0<<16];
2287 plane1 = &BX_VGA_THIS s.memory[1<<16];
2288 plane2 = &BX_VGA_THIS s.memory[2<<16];
2289 plane3 = &BX_VGA_THIS s.memory[3<<16];
2292 /* addr between 0xA0000 and 0xAFFFF */
2293 switch (BX_VGA_THIS s.graphics_ctrl.read_mode) {
2294 case 0: /* read mode 0 */
2295 BX_VGA_THIS s.graphics_ctrl.latch[0] = plane0[offset];
2296 BX_VGA_THIS s.graphics_ctrl.latch[1] = plane1[offset];
2297 BX_VGA_THIS s.graphics_ctrl.latch[2] = plane2[offset];
2298 BX_VGA_THIS s.graphics_ctrl.latch[3] = plane3[offset];
2299 return(BX_VGA_THIS s.graphics_ctrl.latch[BX_VGA_THIS s.graphics_ctrl.read_map_select]);
2300 break;
2302 case 1: /* read mode 1 */
2304 Bit8u color_compare, color_dont_care;
2305 Bit8u latch0, latch1, latch2, latch3, retval;
2307 color_compare = BX_VGA_THIS s.graphics_ctrl.color_compare & 0x0f;
2308 color_dont_care = BX_VGA_THIS s.graphics_ctrl.color_dont_care & 0x0f;
2309 latch0 = BX_VGA_THIS s.graphics_ctrl.latch[0] = plane0[offset];
2310 latch1 = BX_VGA_THIS s.graphics_ctrl.latch[1] = plane1[offset];
2311 latch2 = BX_VGA_THIS s.graphics_ctrl.latch[2] = plane2[offset];
2312 latch3 = BX_VGA_THIS s.graphics_ctrl.latch[3] = plane3[offset];
2314 latch0 ^= ccdat[color_compare][0];
2315 latch1 ^= ccdat[color_compare][1];
2316 latch2 ^= ccdat[color_compare][2];
2317 latch3 ^= ccdat[color_compare][3];
2319 latch0 &= ccdat[color_dont_care][0];
2320 latch1 &= ccdat[color_dont_care][1];
2321 latch2 &= ccdat[color_dont_care][2];
2322 latch3 &= ccdat[color_dont_care][3];
2324 retval = ~(latch0 | latch1 | latch2 | latch3);
2326 return retval;
2328 break;
2329 default:
2330 return 0;
2334 bx_bool bx_vga_c::mem_write_handler(bx_phy_address addr, unsigned len, void *data, void *param)
2336 Bit8u *data_ptr;
2337 #ifdef BX_LITTLE_ENDIAN
2338 data_ptr = (Bit8u *) data;
2339 #else // BX_BIG_ENDIAN
2340 data_ptr = (Bit8u *) data + (len - 1);
2341 #endif
2342 for (unsigned i = 0; i < len; i++) {
2343 theVga->mem_write(addr, *data_ptr);
2344 addr++;
2345 #ifdef BX_LITTLE_ENDIAN
2346 data_ptr++;
2347 #else // BX_BIG_ENDIAN
2348 data_ptr--;
2349 #endif
2351 return 1;
2354 void bx_vga_c::mem_write(bx_phy_address addr, Bit8u value)
2356 Bit32u offset;
2357 Bit8u new_val[4];
2358 unsigned start_addr;
2359 Bit8u *plane0, *plane1, *plane2, *plane3;
2361 #if BX_SUPPORT_VBE
2362 // if in a vbe enabled mode, write to the vbe_memory
2363 if ((BX_VGA_THIS s.vbe_enabled) && (BX_VGA_THIS s.vbe_bpp != VBE_DISPI_BPP_4))
2365 vbe_mem_write(addr, value);
2366 return;
2368 else if (addr >= VBE_DISPI_LFB_PHYSICAL_ADDRESS)
2370 return;
2372 #endif
2374 #if defined(VGA_TRACE_FEATURE)
2375 //BX_DEBUG(("8-bit memory write to %08x = %02x", addr, value));
2376 #endif
2378 #ifdef __OS2__
2380 #if BX_PLUGINS
2381 #error Fix the code for plugins
2382 #endif
2384 if (bx_options.videomode == BX_VIDEO_DIRECT)
2386 devices->mem->video[addr-0xA0000] = value;
2387 return;
2389 #endif
2391 switch (BX_VGA_THIS s.graphics_ctrl.memory_mapping) {
2392 case 1: // 0xA0000 .. 0xAFFFF
2393 if (addr > 0xAFFFF) return;
2394 offset = addr - 0xA0000;
2395 break;
2396 case 2: // 0xB0000 .. 0xB7FFF
2397 if ((addr < 0xB0000) || (addr > 0xB7FFF)) return;
2398 offset = addr - 0xB0000;
2399 break;
2400 case 3: // 0xB8000 .. 0xBFFFF
2401 if (addr < 0xB8000) return;
2402 offset = addr - 0xB8000;
2403 break;
2404 default: // 0xA0000 .. 0xBFFFF
2405 offset = addr - 0xA0000;
2408 start_addr = (BX_VGA_THIS s.CRTC.reg[0x0c] << 8) | BX_VGA_THIS s.CRTC.reg[0x0d];
2410 if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
2411 if (BX_VGA_THIS s.graphics_ctrl.memory_mapping == 3) { // 0xB8000 .. 0xBFFFF
2412 unsigned x_tileno, x_tileno2, y_tileno;
2414 /* CGA 320x200x4 / 640x200x2 start */
2415 BX_VGA_THIS s.memory[offset] = value;
2416 offset -= start_addr;
2417 if (offset>=0x2000) {
2418 y_tileno = offset - 0x2000;
2419 y_tileno /= (320/4);
2420 y_tileno <<= 1; //2 * y_tileno;
2421 y_tileno++;
2422 x_tileno = (offset - 0x2000) % (320/4);
2423 x_tileno <<= 2; //*= 4;
2424 } else {
2425 y_tileno = offset / (320/4);
2426 y_tileno <<= 1; //2 * y_tileno;
2427 x_tileno = offset % (320/4);
2428 x_tileno <<= 2; //*=4;
2430 x_tileno2=x_tileno;
2431 if (BX_VGA_THIS s.graphics_ctrl.shift_reg==0) {
2432 x_tileno*=2;
2433 x_tileno2+=7;
2434 } else {
2435 x_tileno2+=3;
2437 if (BX_VGA_THIS s.x_dotclockdiv2) {
2438 x_tileno/=(X_TILESIZE/2);
2439 x_tileno2/=(X_TILESIZE/2);
2440 } else {
2441 x_tileno/=X_TILESIZE;
2442 x_tileno2/=X_TILESIZE;
2444 if (BX_VGA_THIS s.y_doublescan) {
2445 y_tileno/=(Y_TILESIZE/2);
2446 } else {
2447 y_tileno/=Y_TILESIZE;
2449 BX_VGA_THIS s.vga_mem_updated = 1;
2450 SET_TILE_UPDATED (x_tileno, y_tileno, 1);
2451 if (x_tileno2!=x_tileno) {
2452 SET_TILE_UPDATED (x_tileno2, y_tileno, 1);
2454 return;
2455 /* CGA 320x200x4 / 640x200x2 end */
2457 else if (BX_VGA_THIS s.graphics_ctrl.memory_mapping != 1) {
2458 BX_PANIC(("mem_write: graphics: mapping = %u",
2459 (unsigned) BX_VGA_THIS s.graphics_ctrl.memory_mapping));
2460 return;
2463 if (BX_VGA_THIS s.sequencer.chain_four) {
2464 unsigned x_tileno, y_tileno;
2466 // 320 x 200 256 color mode: chained pixel representation
2467 BX_VGA_THIS s.memory[(offset & ~0x03) + (offset % 4)*65536] = value;
2468 if (BX_VGA_THIS s.line_offset > 0) {
2469 offset -= start_addr;
2470 x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE/2);
2471 if (BX_VGA_THIS s.y_doublescan) {
2472 y_tileno = (offset / BX_VGA_THIS s.line_offset) / (Y_TILESIZE/2);
2473 } else {
2474 y_tileno = (offset / BX_VGA_THIS s.line_offset) / Y_TILESIZE;
2476 BX_VGA_THIS s.vga_mem_updated = 1;
2477 SET_TILE_UPDATED (x_tileno, y_tileno, 1);
2479 return;
2483 /* addr between 0xA0000 and 0xAFFFF */
2485 #if BX_SUPPORT_VBE
2486 if (BX_VGA_THIS s.vbe_enabled)
2488 plane0 = &BX_VGA_THIS s.memory[(0<<VBE_DISPI_4BPP_PLANE_SHIFT) + (BX_VGA_THIS s.vbe_bank<<16)];
2489 plane1 = &BX_VGA_THIS s.memory[(1<<VBE_DISPI_4BPP_PLANE_SHIFT) + (BX_VGA_THIS s.vbe_bank<<16)];
2490 plane2 = &BX_VGA_THIS s.memory[(2<<VBE_DISPI_4BPP_PLANE_SHIFT) + (BX_VGA_THIS s.vbe_bank<<16)];
2491 plane3 = &BX_VGA_THIS s.memory[(3<<VBE_DISPI_4BPP_PLANE_SHIFT) + (BX_VGA_THIS s.vbe_bank<<16)];
2493 else
2494 #endif
2496 plane0 = &BX_VGA_THIS s.memory[0<<16];
2497 plane1 = &BX_VGA_THIS s.memory[1<<16];
2498 plane2 = &BX_VGA_THIS s.memory[2<<16];
2499 plane3 = &BX_VGA_THIS s.memory[3<<16];
2502 switch (BX_VGA_THIS s.graphics_ctrl.write_mode) {
2503 unsigned i;
2505 case 0: /* write mode 0 */
2507 const Bit8u bitmask = BX_VGA_THIS s.graphics_ctrl.bitmask;
2508 const Bit8u set_reset = BX_VGA_THIS s.graphics_ctrl.set_reset;
2509 const Bit8u enable_set_reset = BX_VGA_THIS s.graphics_ctrl.enable_set_reset;
2510 /* perform rotate on CPU data in case its needed */
2511 if (BX_VGA_THIS s.graphics_ctrl.data_rotate) {
2512 value = (value >> BX_VGA_THIS s.graphics_ctrl.data_rotate) |
2513 (value << (8 - BX_VGA_THIS s.graphics_ctrl.data_rotate));
2515 new_val[0] = BX_VGA_THIS s.graphics_ctrl.latch[0] & ~bitmask;
2516 new_val[1] = BX_VGA_THIS s.graphics_ctrl.latch[1] & ~bitmask;
2517 new_val[2] = BX_VGA_THIS s.graphics_ctrl.latch[2] & ~bitmask;
2518 new_val[3] = BX_VGA_THIS s.graphics_ctrl.latch[3] & ~bitmask;
2519 switch (BX_VGA_THIS s.graphics_ctrl.raster_op) {
2520 case 0: // replace
2521 new_val[0] |= ((enable_set_reset & 1)
2522 ? ((set_reset & 1) ? bitmask : 0)
2523 : (value & bitmask));
2524 new_val[1] |= ((enable_set_reset & 2)
2525 ? ((set_reset & 2) ? bitmask : 0)
2526 : (value & bitmask));
2527 new_val[2] |= ((enable_set_reset & 4)
2528 ? ((set_reset & 4) ? bitmask : 0)
2529 : (value & bitmask));
2530 new_val[3] |= ((enable_set_reset & 8)
2531 ? ((set_reset & 8) ? bitmask : 0)
2532 : (value & bitmask));
2533 break;
2534 case 1: // AND
2535 new_val[0] |= ((enable_set_reset & 1)
2536 ? ((set_reset & 1)
2537 ? (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask)
2538 : 0)
2539 : (value & BX_VGA_THIS s.graphics_ctrl.latch[0]) & bitmask);
2540 new_val[1] |= ((enable_set_reset & 2)
2541 ? ((set_reset & 2)
2542 ? (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask)
2543 : 0)
2544 : (value & BX_VGA_THIS s.graphics_ctrl.latch[1]) & bitmask);
2545 new_val[2] |= ((enable_set_reset & 4)
2546 ? ((set_reset & 4)
2547 ? (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask)
2548 : 0)
2549 : (value & BX_VGA_THIS s.graphics_ctrl.latch[2]) & bitmask);
2550 new_val[3] |= ((enable_set_reset & 8)
2551 ? ((set_reset & 8)
2552 ? (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask)
2553 : 0)
2554 : (value & BX_VGA_THIS s.graphics_ctrl.latch[3]) & bitmask);
2555 break;
2556 case 2: // OR
2557 new_val[0]
2558 |= ((enable_set_reset & 1)
2559 ? ((set_reset & 1)
2560 ? bitmask
2561 : (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask))
2562 : ((value | BX_VGA_THIS s.graphics_ctrl.latch[0]) & bitmask));
2563 new_val[1]
2564 |= ((enable_set_reset & 2)
2565 ? ((set_reset & 2)
2566 ? bitmask
2567 : (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask))
2568 : ((value | BX_VGA_THIS s.graphics_ctrl.latch[1]) & bitmask));
2569 new_val[2]
2570 |= ((enable_set_reset & 4)
2571 ? ((set_reset & 4)
2572 ? bitmask
2573 : (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask))
2574 : ((value | BX_VGA_THIS s.graphics_ctrl.latch[2]) & bitmask));
2575 new_val[3]
2576 |= ((enable_set_reset & 8)
2577 ? ((set_reset & 8)
2578 ? bitmask
2579 : (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask))
2580 : ((value | BX_VGA_THIS s.graphics_ctrl.latch[3]) & bitmask));
2581 break;
2582 case 3: // XOR
2583 new_val[0]
2584 |= ((enable_set_reset & 1)
2585 ? ((set_reset & 1)
2586 ? (~BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask)
2587 : (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask))
2588 : (value ^ BX_VGA_THIS s.graphics_ctrl.latch[0]) & bitmask);
2589 new_val[1]
2590 |= ((enable_set_reset & 2)
2591 ? ((set_reset & 2)
2592 ? (~BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask)
2593 : (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask))
2594 : (value ^ BX_VGA_THIS s.graphics_ctrl.latch[1]) & bitmask);
2595 new_val[2]
2596 |= ((enable_set_reset & 4)
2597 ? ((set_reset & 4)
2598 ? (~BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask)
2599 : (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask))
2600 : (value ^ BX_VGA_THIS s.graphics_ctrl.latch[2]) & bitmask);
2601 new_val[3]
2602 |= ((enable_set_reset & 8)
2603 ? ((set_reset & 8)
2604 ? (~BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask)
2605 : (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask))
2606 : (value ^ BX_VGA_THIS s.graphics_ctrl.latch[3]) & bitmask);
2607 break;
2608 default:
2609 BX_PANIC(("vga_mem_write: write mode 0: op = %u",
2610 (unsigned) BX_VGA_THIS s.graphics_ctrl.raster_op));
2613 break;
2615 case 1: /* write mode 1 */
2616 for (i=0; i<4; i++) {
2617 new_val[i] = BX_VGA_THIS s.graphics_ctrl.latch[i];
2619 break;
2621 case 2: /* write mode 2 */
2623 const Bit8u bitmask = BX_VGA_THIS s.graphics_ctrl.bitmask;
2625 new_val[0] = BX_VGA_THIS s.graphics_ctrl.latch[0] & ~bitmask;
2626 new_val[1] = BX_VGA_THIS s.graphics_ctrl.latch[1] & ~bitmask;
2627 new_val[2] = BX_VGA_THIS s.graphics_ctrl.latch[2] & ~bitmask;
2628 new_val[3] = BX_VGA_THIS s.graphics_ctrl.latch[3] & ~bitmask;
2629 switch (BX_VGA_THIS s.graphics_ctrl.raster_op) {
2630 case 0: // write
2631 new_val[0] |= (value & 1) ? bitmask : 0;
2632 new_val[1] |= (value & 2) ? bitmask : 0;
2633 new_val[2] |= (value & 4) ? bitmask : 0;
2634 new_val[3] |= (value & 8) ? bitmask : 0;
2635 break;
2636 case 1: // AND
2637 new_val[0] |= (value & 1)
2638 ? (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask)
2639 : 0;
2640 new_val[1] |= (value & 2)
2641 ? (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask)
2642 : 0;
2643 new_val[2] |= (value & 4)
2644 ? (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask)
2645 : 0;
2646 new_val[3] |= (value & 8)
2647 ? (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask)
2648 : 0;
2649 break;
2650 case 2: // OR
2651 new_val[0] |= (value & 1)
2652 ? bitmask
2653 : (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask);
2654 new_val[1] |= (value & 2)
2655 ? bitmask
2656 : (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask);
2657 new_val[2] |= (value & 4)
2658 ? bitmask
2659 : (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask);
2660 new_val[3] |= (value & 8)
2661 ? bitmask
2662 : (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask);
2663 break;
2664 case 3: // XOR
2665 new_val[0] |= (value & 1)
2666 ? (~BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask)
2667 : (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask);
2668 new_val[1] |= (value & 2)
2669 ? (~BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask)
2670 : (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask);
2671 new_val[2] |= (value & 4)
2672 ? (~BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask)
2673 : (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask);
2674 new_val[3] |= (value & 8)
2675 ? (~BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask)
2676 : (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask);
2677 break;
2680 break;
2682 case 3: /* write mode 3 */
2684 const Bit8u bitmask = BX_VGA_THIS s.graphics_ctrl.bitmask & value;
2685 const Bit8u set_reset = BX_VGA_THIS s.graphics_ctrl.set_reset;
2687 /* perform rotate on CPU data */
2688 if (BX_VGA_THIS s.graphics_ctrl.data_rotate) {
2689 value = (value >> BX_VGA_THIS s.graphics_ctrl.data_rotate) |
2690 (value << (8 - BX_VGA_THIS s.graphics_ctrl.data_rotate));
2692 new_val[0] = BX_VGA_THIS s.graphics_ctrl.latch[0] & ~bitmask;
2693 new_val[1] = BX_VGA_THIS s.graphics_ctrl.latch[1] & ~bitmask;
2694 new_val[2] = BX_VGA_THIS s.graphics_ctrl.latch[2] & ~bitmask;
2695 new_val[3] = BX_VGA_THIS s.graphics_ctrl.latch[3] & ~bitmask;
2697 value &= bitmask;
2699 switch (BX_VGA_THIS s.graphics_ctrl.raster_op) {
2700 case 0: // write
2701 new_val[0] |= (set_reset & 1) ? value : 0;
2702 new_val[1] |= (set_reset & 2) ? value : 0;
2703 new_val[2] |= (set_reset & 4) ? value : 0;
2704 new_val[3] |= (set_reset & 8) ? value : 0;
2705 break;
2706 case 1: // AND
2707 new_val[0] |= ((set_reset & 1) ? value : 0)
2708 & BX_VGA_THIS s.graphics_ctrl.latch[0];
2709 new_val[1] |= ((set_reset & 2) ? value : 0)
2710 & BX_VGA_THIS s.graphics_ctrl.latch[1];
2711 new_val[2] |= ((set_reset & 4) ? value : 0)
2712 & BX_VGA_THIS s.graphics_ctrl.latch[2];
2713 new_val[3] |= ((set_reset & 8) ? value : 0)
2714 & BX_VGA_THIS s.graphics_ctrl.latch[3];
2715 break;
2716 case 2: // OR
2717 new_val[0] |= ((set_reset & 1) ? value : 0)
2718 | BX_VGA_THIS s.graphics_ctrl.latch[0];
2719 new_val[1] |= ((set_reset & 2) ? value : 0)
2720 | BX_VGA_THIS s.graphics_ctrl.latch[1];
2721 new_val[2] |= ((set_reset & 4) ? value : 0)
2722 | BX_VGA_THIS s.graphics_ctrl.latch[2];
2723 new_val[3] |= ((set_reset & 8) ? value : 0)
2724 | BX_VGA_THIS s.graphics_ctrl.latch[3];
2725 break;
2726 case 3: // XOR
2727 new_val[0] |= ((set_reset & 1) ? value : 0)
2728 ^ BX_VGA_THIS s.graphics_ctrl.latch[0];
2729 new_val[1] |= ((set_reset & 2) ? value : 0)
2730 ^ BX_VGA_THIS s.graphics_ctrl.latch[1];
2731 new_val[2] |= ((set_reset & 4) ? value : 0)
2732 ^ BX_VGA_THIS s.graphics_ctrl.latch[2];
2733 new_val[3] |= ((set_reset & 8) ? value : 0)
2734 ^ BX_VGA_THIS s.graphics_ctrl.latch[3];
2735 break;
2738 break;
2740 default:
2741 BX_PANIC(("vga_mem_write: write mode %u ?",
2742 (unsigned) BX_VGA_THIS s.graphics_ctrl.write_mode));
2745 if (BX_VGA_THIS s.sequencer.map_mask & 0x0f) {
2746 BX_VGA_THIS s.vga_mem_updated = 1;
2747 if (BX_VGA_THIS s.sequencer.map_mask & 0x01)
2748 plane0[offset] = new_val[0];
2749 if (BX_VGA_THIS s.sequencer.map_mask & 0x02)
2750 plane1[offset] = new_val[1];
2751 if (BX_VGA_THIS s.sequencer.map_mask & 0x04) {
2752 if ((offset & 0xe000) == BX_VGA_THIS s.charmap_address) {
2753 bx_gui->set_text_charbyte((offset & 0x1fff), new_val[2]);
2755 plane2[offset] = new_val[2];
2757 if (BX_VGA_THIS s.sequencer.map_mask & 0x08)
2758 plane3[offset] = new_val[3];
2760 unsigned x_tileno, y_tileno;
2762 if (BX_VGA_THIS s.graphics_ctrl.shift_reg == 2) {
2763 offset -= start_addr;
2764 x_tileno = (offset % BX_VGA_THIS s.line_offset) * 4 / (X_TILESIZE / 2);
2765 if (BX_VGA_THIS s.y_doublescan) {
2766 y_tileno = (offset / BX_VGA_THIS s.line_offset) / (Y_TILESIZE / 2);
2767 } else {
2768 y_tileno = (offset / BX_VGA_THIS s.line_offset) / Y_TILESIZE;
2770 SET_TILE_UPDATED (x_tileno, y_tileno, 1);
2771 } else {
2772 if (BX_VGA_THIS s.line_compare < BX_VGA_THIS s.vertical_display_end) {
2773 if (BX_VGA_THIS s.line_offset > 0) {
2774 if (BX_VGA_THIS s.x_dotclockdiv2) {
2775 x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE / 16);
2776 } else {
2777 x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE / 8);
2779 if (BX_VGA_THIS s.y_doublescan) {
2780 y_tileno = ((offset / BX_VGA_THIS s.line_offset) * 2 + BX_VGA_THIS s.line_compare + 1) / Y_TILESIZE;
2781 } else {
2782 y_tileno = ((offset / BX_VGA_THIS s.line_offset) + BX_VGA_THIS s.line_compare + 1) / Y_TILESIZE;
2784 SET_TILE_UPDATED (x_tileno, y_tileno, 1);
2787 if (offset >= start_addr) {
2788 offset -= start_addr;
2789 if (BX_VGA_THIS s.line_offset > 0) {
2790 if (BX_VGA_THIS s.x_dotclockdiv2) {
2791 x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE / 16);
2792 } else {
2793 x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE / 8);
2795 if (BX_VGA_THIS s.y_doublescan) {
2796 y_tileno = (offset / BX_VGA_THIS s.line_offset) / (Y_TILESIZE / 2);
2797 } else {
2798 y_tileno = (offset / BX_VGA_THIS s.line_offset) / Y_TILESIZE;
2800 SET_TILE_UPDATED (x_tileno, y_tileno, 1);
2807 void bx_vga_c::get_text_snapshot(Bit8u **text_snapshot, unsigned *txHeight,
2808 unsigned *txWidth)
2810 unsigned VDE, MSL;
2812 if (!BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
2813 *text_snapshot = &BX_VGA_THIS s.text_snapshot[0];
2814 VDE = BX_VGA_THIS s.vertical_display_end;
2815 MSL = BX_VGA_THIS s.CRTC.reg[0x09] & 0x1f;
2816 *txHeight = (VDE+1)/(MSL+1);
2817 *txWidth = BX_VGA_THIS s.CRTC.reg[1] + 1;
2818 } else {
2819 *txHeight = 0;
2820 *txWidth = 0;
2824 Bit8u bx_vga_c::get_actl_palette_idx(Bit8u index)
2826 return BX_VGA_THIS s.attribute_ctrl.palette_reg[index];
2829 void bx_vga_c::dump_status(void)
2831 #if BX_DEBUGGER
2832 dbg_printf("s.misc_output.color_emulation = %u\n",
2833 (unsigned) BX_VGA_THIS s.misc_output.color_emulation);
2834 dbg_printf("s.misc_output.enable_ram = %u\n",
2835 (unsigned) BX_VGA_THIS s.misc_output.enable_ram);
2836 dbg_printf("s.misc_output.clock_select = %u ",
2837 (unsigned) BX_VGA_THIS s.misc_output.clock_select);
2838 if (BX_VGA_THIS s.misc_output.clock_select == 0)
2839 dbg_printf("(25Mhz 640 horiz pixel clock)\n");
2840 else
2841 dbg_printf("(28Mhz 720 horiz pixel clock)\n");
2842 dbg_printf("s.misc_output.select_high_bank = %u\n",
2843 (unsigned) BX_VGA_THIS s.misc_output.select_high_bank);
2844 dbg_printf("s.misc_output.horiz_sync_pol = %u\n",
2845 (unsigned) BX_VGA_THIS s.misc_output.horiz_sync_pol);
2846 dbg_printf("s.misc_output.vert_sync_pol = %u ",
2847 (unsigned) BX_VGA_THIS s.misc_output.vert_sync_pol);
2848 switch ((BX_VGA_THIS s.misc_output.vert_sync_pol << 1) |
2849 BX_VGA_THIS s.misc_output.horiz_sync_pol) {
2850 case 1: dbg_printf("(400 lines)\n"); break;
2851 case 2: dbg_printf("(350 lines)\n"); break;
2852 case 3: dbg_printf("(480 lines)\n"); break;
2853 default: dbg_printf("(reserved)\n");
2856 dbg_printf("s.graphics_ctrl.odd_even = %u\n",
2857 (unsigned) BX_VGA_THIS s.graphics_ctrl.odd_even);
2858 dbg_printf("s.graphics_ctrl.chain_odd_even = %u\n",
2859 (unsigned) BX_VGA_THIS s.graphics_ctrl.chain_odd_even);
2860 dbg_printf("s.graphics_ctrl.shift_reg = %u\n",
2861 (unsigned) BX_VGA_THIS s.graphics_ctrl.shift_reg);
2862 dbg_printf("s.graphics_ctrl.graphics_alpha = %u\n",
2863 (unsigned) BX_VGA_THIS s.graphics_ctrl.graphics_alpha);
2864 dbg_printf("s.graphics_ctrl.memory_mapping = %u ",
2865 (unsigned) BX_VGA_THIS s.graphics_ctrl.memory_mapping);
2866 switch (BX_VGA_THIS s.graphics_ctrl.memory_mapping) {
2867 case 1: dbg_printf("(A0000-AFFFF)\n"); break;
2868 case 2: dbg_printf("(B0000-B7FFF)\n"); break;
2869 case 3: dbg_printf("(B8000-BFFFF)\n"); break;
2870 default: dbg_printf("(A0000-BFFFF)\n"); break;
2873 dbg_printf("s.sequencer.extended_mem = %u\n",
2874 (unsigned) BX_VGA_THIS s.sequencer.extended_mem);
2875 dbg_printf("s.sequencer.odd_even = %u (inverted)\n",
2876 (unsigned) BX_VGA_THIS s.sequencer.odd_even);
2877 dbg_printf("s.sequencer.chain_four = %u\n",
2878 (unsigned) BX_VGA_THIS s.sequencer.chain_four);
2880 dbg_printf("s.attribute_ctrl.video_enabled = %u\n",
2881 (unsigned) BX_VGA_THIS s.attribute_ctrl.video_enabled);
2882 dbg_printf("s.attribute_ctrl.mode_ctrl.graphics_alpha = %u\n",
2883 (unsigned) BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha);
2884 dbg_printf("s.attribute_ctrl.mode_ctrl.display_type = %u\n",
2885 (unsigned) BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type);
2886 dbg_printf("s.attribute_ctrl.mode_ctrl.internal_palette_size = %u\n",
2887 (unsigned) BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size);
2888 dbg_printf("s.attribute_ctrl.mode_ctrl.pixel_clock_select = %u\n",
2889 (unsigned) BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select);
2890 #endif
2893 void bx_vga_c::redraw_area(unsigned x0, unsigned y0, unsigned width,
2894 unsigned height)
2896 unsigned xti, yti, xt0, xt1, yt0, yt1, xmax, ymax;
2898 if ((width == 0) || (height == 0)) {
2899 return;
2902 BX_VGA_THIS s.vga_mem_updated = 1;
2904 #if BX_SUPPORT_VBE
2905 if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha || BX_VGA_THIS s.vbe_enabled) {
2906 #else
2907 if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
2908 #endif
2909 // graphics mode
2910 xmax = old_iWidth;
2911 ymax = old_iHeight;
2912 #if BX_SUPPORT_VBE
2913 if (BX_VGA_THIS s.vbe_enabled) {
2914 xmax = BX_VGA_THIS s.vbe_xres;
2915 ymax = BX_VGA_THIS s.vbe_yres;
2917 #endif
2918 xt0 = x0 / X_TILESIZE;
2919 yt0 = y0 / Y_TILESIZE;
2920 if (x0 < xmax) {
2921 xt1 = (x0 + width - 1) / X_TILESIZE;
2922 } else {
2923 xt1 = (xmax - 1) / X_TILESIZE;
2925 if (y0 < ymax) {
2926 yt1 = (y0 + height - 1) / Y_TILESIZE;
2927 } else {
2928 yt1 = (ymax - 1) / Y_TILESIZE;
2930 for (yti=yt0; yti<=yt1; yti++) {
2931 for (xti=xt0; xti<=xt1; xti++) {
2932 SET_TILE_UPDATED (xti, yti, 1);
2936 } else {
2937 // text mode
2938 memset(BX_VGA_THIS s.text_snapshot, 0,
2939 sizeof(BX_VGA_THIS s.text_snapshot));
2944 #if BX_SUPPORT_VBE
2945 Bit8u BX_CPP_AttrRegparmN(1)
2946 bx_vga_c::vbe_mem_read(bx_phy_address addr)
2948 Bit32u offset;
2950 if (addr >= VBE_DISPI_LFB_PHYSICAL_ADDRESS)
2952 // LFB read
2953 offset = addr - VBE_DISPI_LFB_PHYSICAL_ADDRESS;
2955 else
2957 // banked mode read
2958 offset = BX_VGA_THIS s.vbe_bank*65536 + addr - 0xA0000;
2961 // check for out of memory read
2962 if (offset > VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES)
2963 return 0;
2965 return (BX_VGA_THIS s.memory[offset]);
2968 void BX_CPP_AttrRegparmN(2)
2969 bx_vga_c::vbe_mem_write(bx_phy_address addr, Bit8u value)
2971 Bit32u offset;
2972 unsigned x_tileno, y_tileno;
2974 if (BX_VGA_THIS s.vbe_lfb_enabled)
2976 if (addr >= VBE_DISPI_LFB_PHYSICAL_ADDRESS)
2978 // LFB write
2979 offset = addr - VBE_DISPI_LFB_PHYSICAL_ADDRESS;
2981 else
2983 // banked mode write while in LFB mode -> ignore
2984 return;
2987 else
2989 if (addr < VBE_DISPI_LFB_PHYSICAL_ADDRESS)
2991 // banked mode write
2992 offset = (BX_VGA_THIS s.vbe_bank*65536) + (addr - 0xA0000);
2994 else
2996 // LFB write while in banked mode -> ignore
2997 return;
3001 // check for out of memory write
3002 if (offset < VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES)
3004 BX_VGA_THIS s.memory[offset]=value;
3006 else
3008 // make sure we don't flood the logfile
3009 static int count=0;
3010 if (count<100)
3012 count ++;
3013 BX_INFO(("VBE_mem_write out of video memory write at %x",offset));
3017 offset-=BX_VGA_THIS s.vbe_virtual_start;
3019 // only update the UI when writing 'onscreen'
3020 if (offset < BX_VGA_THIS s.vbe_visible_screen_size)
3022 y_tileno = ((offset / BX_VGA_THIS s.vbe_bpp_multiplier) / BX_VGA_THIS s.vbe_virtual_xres) / Y_TILESIZE;
3023 x_tileno = ((offset / BX_VGA_THIS s.vbe_bpp_multiplier) % BX_VGA_THIS s.vbe_virtual_xres) / X_TILESIZE;
3025 if ((y_tileno < BX_NUM_Y_TILES) && (x_tileno < BX_NUM_X_TILES))
3027 BX_VGA_THIS s.vga_mem_updated = 1;
3028 SET_TILE_UPDATED (x_tileno, y_tileno, 1);
3033 Bit32u bx_vga_c::vbe_read_handler(void *this_ptr, Bit32u address, unsigned io_len)
3035 #if BX_USE_VGA_SMF == 0
3036 bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
3037 return class_ptr->vbe_read(address, io_len);
3040 Bit32u bx_vga_c::vbe_read(Bit32u address, unsigned io_len)
3042 #else
3043 UNUSED(this_ptr);
3044 #endif // BX_USE_VGA_SMF == 0
3045 Bit16u retval;
3047 // BX_INFO(("VBE_read %x (len %x)", address, io_len));
3049 if ((address==VBE_DISPI_IOPORT_INDEX) ||
3050 (address==VBE_DISPI_IOPORT_INDEX_OLD))
3052 // index register
3053 return (Bit32u) BX_VGA_THIS s.vbe_curindex;
3055 else
3057 // data register read
3059 switch (BX_VGA_THIS s.vbe_curindex)
3061 case VBE_DISPI_INDEX_ID: // Display Interface ID check
3062 return BX_VGA_THIS s.vbe_cur_dispi;
3064 case VBE_DISPI_INDEX_XRES: // x resolution
3065 if (BX_VGA_THIS s.vbe_get_capabilities) {
3066 return BX_VGA_THIS s.vbe_max_xres;
3067 } else {
3068 return BX_VGA_THIS s.vbe_xres;
3071 case VBE_DISPI_INDEX_YRES: // y resolution
3072 if (BX_VGA_THIS s.vbe_get_capabilities) {
3073 return BX_VGA_THIS s.vbe_max_yres;
3074 } else {
3075 return BX_VGA_THIS s.vbe_yres;
3078 case VBE_DISPI_INDEX_BPP: // bpp
3079 if (BX_VGA_THIS s.vbe_get_capabilities) {
3080 return BX_VGA_THIS s.vbe_max_bpp;
3081 } else {
3082 return BX_VGA_THIS s.vbe_bpp;
3085 case VBE_DISPI_INDEX_ENABLE: // vbe enabled
3086 retval = BX_VGA_THIS s.vbe_enabled;
3087 if (BX_VGA_THIS s.vbe_get_capabilities)
3088 retval |= VBE_DISPI_GETCAPS;
3089 if (BX_VGA_THIS s.vbe_8bit_dac)
3090 retval |= VBE_DISPI_8BIT_DAC;
3091 return retval;
3093 case VBE_DISPI_INDEX_BANK: // current bank
3094 return BX_VGA_THIS s.vbe_bank;
3096 case VBE_DISPI_INDEX_X_OFFSET:
3097 return BX_VGA_THIS s.vbe_offset_x;
3099 case VBE_DISPI_INDEX_Y_OFFSET:
3100 return BX_VGA_THIS s.vbe_offset_y;
3102 case VBE_DISPI_INDEX_VIRT_WIDTH:
3103 return BX_VGA_THIS s.vbe_virtual_xres;
3105 case VBE_DISPI_INDEX_VIRT_HEIGHT:
3106 return BX_VGA_THIS s.vbe_virtual_yres;
3108 default:
3109 BX_PANIC(("VBE unknown data read index 0x%x",BX_VGA_THIS s.vbe_curindex));
3110 break;
3113 BX_PANIC(("VBE_read shouldn't reach this"));
3114 return 0; /* keep compiler happy */
3117 void bx_vga_c::vbe_write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
3119 #if BX_USE_VGA_SMF == 0
3120 bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
3121 class_ptr->vbe_write(address, value, io_len);
3124 Bit32u bx_vga_c::vbe_write(Bit32u address, Bit32u value, unsigned io_len)
3126 #else
3127 UNUSED(this_ptr);
3128 #endif
3129 bx_bool new_vbe_8bit_dac;
3130 bx_bool needs_update = 0;
3131 unsigned i;
3133 // BX_INFO(("VBE_write %x = %x (len %x)", address, value, io_len));
3135 switch(address)
3137 // index register
3138 case VBE_DISPI_IOPORT_INDEX:
3139 // legacy index register
3140 case VBE_DISPI_IOPORT_INDEX_OLD:
3142 BX_VGA_THIS s.vbe_curindex = (Bit16u) value;
3143 break;
3145 // data register
3146 // FIXME: maybe do some 'sanity' checks on received data?
3147 case VBE_DISPI_IOPORT_DATA:
3148 // legacy data register
3149 case VBE_DISPI_IOPORT_DATA_OLD:
3150 switch (BX_VGA_THIS s.vbe_curindex)
3152 case VBE_DISPI_INDEX_ID: // Display Interface ID check
3154 if ((value == VBE_DISPI_ID0) ||
3155 (value == VBE_DISPI_ID1) ||
3156 (value == VBE_DISPI_ID2) ||
3157 (value == VBE_DISPI_ID3) ||
3158 (value == VBE_DISPI_ID4))
3160 // allow backwards compatible with previous dispi bioses
3161 BX_VGA_THIS s.vbe_cur_dispi=value;
3163 else
3165 BX_PANIC(("VBE unknown Display Interface %x", value));
3168 // make sure we don't flood the logfile
3169 static int count=0;
3170 if (count < 100)
3172 count++;
3173 BX_INFO(("VBE known Display Interface %x", value));
3175 } break;
3177 case VBE_DISPI_INDEX_XRES: // set xres
3179 // check that we don't set xres during vbe enabled
3180 if (!BX_VGA_THIS s.vbe_enabled)
3182 // check for within max xres range
3183 if (value <= VBE_DISPI_MAX_XRES)
3185 BX_VGA_THIS s.vbe_xres=(Bit16u) value;
3186 BX_INFO(("VBE set xres (%d)", value));
3188 else
3190 BX_INFO(("VBE set xres more then max xres (%d)", value));
3193 else
3195 BX_INFO(("VBE set xres during vbe enabled!"));
3197 } break;
3199 case VBE_DISPI_INDEX_YRES: // set yres
3201 // check that we don't set yres during vbe enabled
3202 if (!BX_VGA_THIS s.vbe_enabled)
3204 // check for within max yres range
3205 if (value <= VBE_DISPI_MAX_YRES)
3207 BX_VGA_THIS s.vbe_yres=(Bit16u) value;
3208 BX_INFO(("VBE set yres (%d)", value));
3210 else
3212 BX_INFO(("VBE set yres more then max yres (%d)", value));
3215 else
3217 BX_INFO(("VBE set yres during vbe enabled!"));
3219 } break;
3221 case VBE_DISPI_INDEX_BPP: // set bpp
3223 // check that we don't set bpp during vbe enabled
3224 if (!BX_VGA_THIS s.vbe_enabled)
3226 // for backward compatiblity
3227 if (value == 0) value = VBE_DISPI_BPP_8;
3228 // check for correct bpp range
3229 if ((value == VBE_DISPI_BPP_4) || (value == VBE_DISPI_BPP_8) || (value == VBE_DISPI_BPP_15) ||
3230 (value == VBE_DISPI_BPP_16) || (value == VBE_DISPI_BPP_24) || (value == VBE_DISPI_BPP_32))
3232 BX_VGA_THIS s.vbe_bpp=(Bit16u) value;
3233 BX_INFO(("VBE set bpp (%d)", value));
3235 else
3237 BX_INFO(("VBE set bpp with unknown bpp (%d)", value));
3240 else
3242 BX_INFO(("VBE set bpp during vbe enabled!"));
3244 } break;
3246 case VBE_DISPI_INDEX_BANK: // set bank
3248 value=value & 0xff; // FIXME lobyte = vbe bank A?
3249 unsigned divider = (BX_VGA_THIS s.vbe_bpp!=VBE_DISPI_BPP_4)?64:256;
3250 // check for max bank nr
3251 if (value < (VBE_DISPI_TOTAL_VIDEO_MEMORY_KB / divider))
3253 if (!BX_VGA_THIS s.vbe_lfb_enabled)
3255 BX_DEBUG(("VBE set bank to %d", value));
3256 BX_VGA_THIS s.vbe_bank=value;
3258 else
3260 BX_ERROR(("VBE set bank in LFB mode ignored"));
3263 else
3265 BX_INFO(("VBE set invalid bank (%d)", value));
3267 } break;
3269 case VBE_DISPI_INDEX_ENABLE: // enable video
3271 if ((value & VBE_DISPI_ENABLED) && !BX_VGA_THIS s.vbe_enabled)
3273 unsigned depth=0;
3275 // setup virtual resolution to be the same as current reso
3276 BX_VGA_THIS s.vbe_virtual_yres=BX_VGA_THIS s.vbe_yres;
3277 BX_VGA_THIS s.vbe_virtual_xres=BX_VGA_THIS s.vbe_xres;
3279 // reset offset
3280 BX_VGA_THIS s.vbe_offset_x=0;
3281 BX_VGA_THIS s.vbe_offset_y=0;
3282 BX_VGA_THIS s.vbe_virtual_start=0;
3284 switch((BX_VGA_THIS s.vbe_bpp))
3286 // Default pixel sizes
3287 case VBE_DISPI_BPP_8:
3288 BX_VGA_THIS s.vbe_bpp_multiplier = 1;
3289 BX_VGA_THIS s.line_offset = BX_VGA_THIS s.vbe_virtual_xres;
3290 depth=8;
3291 break;
3293 case VBE_DISPI_BPP_4:
3294 BX_VGA_THIS s.vbe_bpp_multiplier = 1;
3295 BX_VGA_THIS s.line_offset = (BX_VGA_THIS s.vbe_virtual_xres >> 3);
3296 depth=4;
3297 break;
3299 case VBE_DISPI_BPP_15:
3300 BX_VGA_THIS s.vbe_bpp_multiplier = 2;
3301 BX_VGA_THIS s.line_offset = BX_VGA_THIS s.vbe_virtual_xres * 2;
3302 depth=15;
3303 break;
3305 case VBE_DISPI_BPP_16:
3306 BX_VGA_THIS s.vbe_bpp_multiplier = 2;
3307 BX_VGA_THIS s.line_offset = BX_VGA_THIS s.vbe_virtual_xres * 2;
3308 depth=16;
3309 break;
3311 case VBE_DISPI_BPP_24:
3312 BX_VGA_THIS s.vbe_bpp_multiplier = 3;
3313 BX_VGA_THIS s.line_offset = BX_VGA_THIS s.vbe_virtual_xres * 3;
3314 depth=24;
3315 break;
3317 case VBE_DISPI_BPP_32:
3318 BX_VGA_THIS s.vbe_bpp_multiplier = 4;
3319 BX_VGA_THIS s.line_offset = BX_VGA_THIS s.vbe_virtual_xres << 2;
3320 depth=32;
3321 break;
3323 BX_VGA_THIS s.vbe_visible_screen_size = BX_VGA_THIS s.line_offset * BX_VGA_THIS s.vbe_yres;
3325 BX_INFO(("VBE enabling x %d, y %d, bpp %d, %u bytes visible", BX_VGA_THIS s.vbe_xres, BX_VGA_THIS s.vbe_yres, BX_VGA_THIS s.vbe_bpp, BX_VGA_THIS s.vbe_visible_screen_size));
3327 if (depth > 4)
3329 BX_VGA_THIS s.vbe_lfb_enabled=(bx_bool)(value & VBE_DISPI_LFB_ENABLED);
3330 if ((value & VBE_DISPI_NOCLEARMEM) == 0)
3332 memset(BX_VGA_THIS s.memory, 0, BX_VGA_THIS s.vbe_visible_screen_size);
3334 bx_gui->dimension_update(BX_VGA_THIS s.vbe_xres, BX_VGA_THIS s.vbe_yres, 0, 0, depth);
3335 BX_VGA_THIS s.last_bpp = depth;
3338 else if (((value & VBE_DISPI_ENABLED) == 0) && BX_VGA_THIS s.vbe_enabled)
3340 BX_INFO(("VBE disabling"));
3341 BX_VGA_THIS s.vbe_lfb_enabled=0;
3343 BX_VGA_THIS s.vbe_enabled=(bx_bool)(value & VBE_DISPI_ENABLED);
3344 BX_VGA_THIS s.vbe_get_capabilities=(bx_bool)((value & VBE_DISPI_GETCAPS) != 0);
3345 new_vbe_8bit_dac=(bx_bool)((value & VBE_DISPI_8BIT_DAC) != 0);
3346 if (new_vbe_8bit_dac != BX_VGA_THIS s.vbe_8bit_dac)
3348 if (new_vbe_8bit_dac)
3350 for (i=0; i<256; i++)
3352 BX_VGA_THIS s.pel.data[i].red <<= 2;
3353 BX_VGA_THIS s.pel.data[i].green <<= 2;
3354 BX_VGA_THIS s.pel.data[i].blue <<= 2;
3356 BX_INFO(("DAC in 8 bit mode"));
3358 else
3360 for (i=0; i<256; i++)
3362 BX_VGA_THIS s.pel.data[i].red >>= 2;
3363 BX_VGA_THIS s.pel.data[i].green >>= 2;
3364 BX_VGA_THIS s.pel.data[i].blue >>= 2;
3366 BX_INFO(("DAC in standard mode"));
3368 BX_VGA_THIS s.vbe_8bit_dac=new_vbe_8bit_dac;
3369 needs_update = 1;
3371 } break;
3373 case VBE_DISPI_INDEX_X_OFFSET:
3375 BX_DEBUG(("VBE offset x %d", value));
3376 BX_VGA_THIS s.vbe_offset_x=(Bit16u)value;
3378 BX_VGA_THIS s.vbe_virtual_start = BX_VGA_THIS s.vbe_offset_y * BX_VGA_THIS s.line_offset;
3379 if (BX_VGA_THIS s.vbe_bpp != VBE_DISPI_BPP_4) {
3380 BX_VGA_THIS s.vbe_virtual_start += (BX_VGA_THIS s.vbe_offset_x * BX_VGA_THIS s.vbe_bpp_multiplier);
3381 } else {
3382 BX_VGA_THIS s.vbe_virtual_start += (BX_VGA_THIS s.vbe_offset_x >> 3);
3384 needs_update = 1;
3385 } break;
3387 case VBE_DISPI_INDEX_Y_OFFSET:
3389 BX_DEBUG(("VBE offset y %d", value));
3391 Bit32u new_screen_start = value * BX_VGA_THIS s.line_offset;
3392 if (BX_VGA_THIS s.vbe_bpp != VBE_DISPI_BPP_4) {
3393 if ((new_screen_start + BX_VGA_THIS s.vbe_visible_screen_size) > VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES)
3395 BX_PANIC(("VBE offset y %d out of bounds", value));
3396 break;
3398 new_screen_start += (BX_VGA_THIS s.vbe_offset_x * BX_VGA_THIS s.vbe_bpp_multiplier);
3399 } else {
3400 if ((new_screen_start + BX_VGA_THIS s.vbe_visible_screen_size) > (VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES / 4))
3402 BX_PANIC(("VBE offset y %d out of bounds", value));
3403 break;
3405 new_screen_start += (BX_VGA_THIS s.vbe_offset_x >> 3);
3407 BX_VGA_THIS s.vbe_virtual_start = new_screen_start;
3408 BX_VGA_THIS s.vbe_offset_y = (Bit16u)value;
3409 needs_update = 1;
3410 } break;
3412 case VBE_DISPI_INDEX_VIRT_WIDTH:
3414 BX_INFO(("VBE requested virtual width %d", value));
3416 // calculate virtual width & height dimensions
3417 // req:
3418 // virt_width > xres
3419 // virt_height >=yres
3420 // virt_width*virt_height < MAX_VIDEO_MEMORY
3422 // basicly 2 situations
3424 // situation 1:
3425 // MAX_VIDEO_MEMORY / virt_width >= yres
3426 // adjust result height
3427 // else
3428 // adjust result width based upon virt_height=yres
3429 Bit16u new_width=value;
3430 Bit16u new_height;
3431 if (BX_VGA_THIS s.vbe_bpp != VBE_DISPI_BPP_4) {
3432 new_height=(VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES / BX_VGA_THIS s.vbe_bpp_multiplier) / new_width;
3433 } else {
3434 new_height=(VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES * 2) / new_width;
3436 if (new_height >=BX_VGA_THIS s.vbe_yres)
3438 // we have a decent virtual width & new_height
3439 BX_INFO(("VBE decent virtual height %d",new_height));
3441 else
3443 // no decent virtual height: adjust width & height
3444 new_height=BX_VGA_THIS s.vbe_yres;
3445 if (BX_VGA_THIS s.vbe_bpp != VBE_DISPI_BPP_4) {
3446 new_width=(VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES / BX_VGA_THIS s.vbe_bpp_multiplier) / new_height;
3447 } else {
3448 new_width=(VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES * 2) / new_height;
3451 BX_INFO(("VBE recalc virtual width %d height %d",new_width, new_height));
3454 BX_VGA_THIS s.vbe_virtual_xres=new_width;
3455 BX_VGA_THIS s.vbe_virtual_yres=new_height;
3456 if (BX_VGA_THIS s.vbe_bpp != VBE_DISPI_BPP_4) {
3457 BX_VGA_THIS s.line_offset = BX_VGA_THIS s.vbe_virtual_xres * BX_VGA_THIS s.vbe_bpp_multiplier;
3458 } else {
3459 BX_VGA_THIS s.line_offset = BX_VGA_THIS s.vbe_virtual_xres >> 3;
3461 BX_VGA_THIS s.vbe_visible_screen_size = BX_VGA_THIS s.line_offset * BX_VGA_THIS s.vbe_yres;
3463 } break;
3465 case VBE_DISPI_INDEX_VIRT_HEIGHT:
3467 BX_INFO(("VBE virtual height %x", value));
3469 } break;
3471 default:
3473 BX_PANIC(("VBE unknown data write index 0x%x",BX_VGA_THIS s.vbe_curindex));
3474 } break;
3476 if (needs_update) {
3477 BX_VGA_THIS s.vga_mem_updated = 1;
3478 for (unsigned xti = 0; xti < BX_NUM_X_TILES; xti++) {
3479 for (unsigned yti = 0; yti < BX_NUM_Y_TILES; yti++) {
3480 SET_TILE_UPDATED (xti, yti, 1);
3484 break;
3486 } // end switch address
3489 #endif