1 /////////////////////////////////////////////////////////////////////////
2 // $Id: vga.cc 14286 2021-06-20 07:30:29Z vruppert $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2002-2021 The Bochs Project
6 // PCI VGA dummy adapter Copyright (C) 2002,2003 Mike Nordell
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 //
22 /////////////////////////////////////////////////////////////////////////
23
24 // Standard VGA emulation + Bochs VBE support + PCI VGA interface
25
26 // NOTE from the original pcivga code:
27 // This "driver" was created for the SOLE PURPOSE of getting BeOS
28 // to boot. It currently does NOTHING more than presenting a generic VGA
29 // device on the PCI bus. ALL gfx in/out-put is still handled by the VGA code.
30 // Furthermore, almost all of the PCI registers are currently acting like RAM.
31
32 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
33 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
34 // is used to know when we are exporting symbols and when we are importing.
35 #define BX_PLUGGABLE
36
37 #include "iodev.h"
38 #include "vgacore.h"
39 #include "ddc.h"
40 #include "vga.h"
41 #include "virt_timer.h"
42
43 #define LOG_THIS theVga->
44
45 bx_vga_c *theVga = NULL;
46
PLUGIN_ENTRY_FOR_MODULE(vga)47 PLUGIN_ENTRY_FOR_MODULE(vga)
48 {
49 if (mode == PLUGIN_INIT) {
50 theVga = new bx_vga_c();
51 bx_devices.pluginVgaDevice = theVga;
52 BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theVga, BX_PLUGIN_VGA);
53 } else if (mode == PLUGIN_FINI) {
54 delete theVga;
55 } else if (mode == PLUGIN_PROBE) {
56 return (int)PLUGTYPE_VGA;
57 } else if (mode == PLUGIN_FLAGS) {
58 return PLUGFLAG_PCI;
59 }
60 return 0; // Success
61 }
62
bx_vga_c()63 bx_vga_c::bx_vga_c() : bx_vgacore_c()
64 {
65 put("VGA");
66 }
67
~bx_vga_c()68 bx_vga_c::~bx_vga_c()
69 {
70 SIM->get_bochs_root()->remove("vga");
71 BX_DEBUG(("Exit"));
72 }
73
init_vga_extension(void)74 bool bx_vga_c::init_vga_extension(void)
75 {
76 unsigned addr;
77 bool ret = 0;
78
79 BX_VGA_THIS init_iohandlers(read_handler, write_handler);
80 BX_VGA_THIS pci_enabled = SIM->is_pci_device("pcivga");
81
82 // The following is for the VBE display extension
83 BX_VGA_THIS vbe_present = 0;
84 BX_VGA_THIS vbe.enabled = 0;
85 BX_VGA_THIS vbe.dac_8bit = 0;
86 BX_VGA_THIS vbe.ddc_enabled = 0;
87 BX_VGA_THIS vbe.base_address = 0x0000;
88 if (!strcmp(BX_VGA_THIS vga_ext->get_selected(), "vbe")) {
89 BX_VGA_THIS put("BXVGA");
90 for (addr=VBE_DISPI_IOPORT_INDEX; addr<=VBE_DISPI_IOPORT_DATA; addr++) {
91 DEV_register_ioread_handler(this, vbe_read_handler, addr, "vga video", 7);
92 DEV_register_iowrite_handler(this, vbe_write_handler, addr, "vga video", 7);
93 }
94 if (!BX_VGA_THIS pci_enabled) {
95 BX_VGA_THIS vbe.base_address = VBE_DISPI_LFB_PHYSICAL_ADDRESS;
96 DEV_register_memory_handlers(theVga, mem_read_handler, mem_write_handler,
97 BX_VGA_THIS vbe.base_address,
98 BX_VGA_THIS vbe.base_address + VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES - 1);
99 }
100 if (BX_VGA_THIS s.memory == NULL)
101 BX_VGA_THIS s.memory = new Bit8u[VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES];
102 memset(BX_VGA_THIS s.memory, 0, VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES);
103 BX_VGA_THIS s.memsize = VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES;
104 BX_VGA_THIS vbe.cur_dispi=VBE_DISPI_ID0;
105 BX_VGA_THIS vbe.xres=640;
106 BX_VGA_THIS vbe.yres=480;
107 BX_VGA_THIS vbe.bpp=8;
108 BX_VGA_THIS vbe.bank[0] = 0;
109 BX_VGA_THIS vbe.bank[1] = 0;
110 BX_VGA_THIS vbe.bank_granularity_kb=64;
111 BX_VGA_THIS vbe.curindex=0;
112 BX_VGA_THIS vbe.offset_x=0;
113 BX_VGA_THIS vbe.offset_y=0;
114 BX_VGA_THIS vbe.virtual_xres=640;
115 BX_VGA_THIS vbe.virtual_yres=480;
116 BX_VGA_THIS vbe.bpp_multiplier=1;
117 BX_VGA_THIS vbe.virtual_start=0;
118 BX_VGA_THIS vbe.get_capabilities=0;
119 BX_VGA_THIS vbe.max_xres=VBE_DISPI_MAX_XRES;
120 BX_VGA_THIS vbe.max_yres=VBE_DISPI_MAX_YRES;
121 BX_VGA_THIS vbe.max_bpp=VBE_DISPI_MAX_BPP;
122 BX_VGA_THIS s.max_xres = BX_VGA_THIS vbe.max_xres;
123 BX_VGA_THIS s.max_yres = BX_VGA_THIS vbe.max_yres;
124 BX_VGA_THIS vbe_present = 1;
125 ret = 1;
126
127 BX_INFO(("VBE Bochs Display Extension Enabled"));
128 }
129 #if BX_SUPPORT_PCI
130 Bit8u devfunc = 0x00;
131
132 if (BX_VGA_THIS pci_enabled) {
133 DEV_register_pci_handlers(this, &devfunc, "pcivga", "Experimental PCI VGA");
134
135 // initialize readonly registers
136 // Note that the values for vendor and device id are selected at random!
137 // There might actually be "real" values for "experimental" vendor and
138 // device that should be used!
139 init_pci_conf(0x1234, 0x1111, 0x00, 0x030000, 0x00, 0);
140
141 if (BX_VGA_THIS vbe_present) {
142 BX_VGA_THIS pci_conf[0x10] = 0x08;
143 BX_VGA_THIS init_bar_mem(0, VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES,
144 mem_read_handler, mem_write_handler);
145 }
146 BX_VGA_THIS pci_rom_address = 0;
147 BX_VGA_THIS pci_rom_read_handler = mem_read_handler;
148 BX_VGA_THIS load_pci_rom(SIM->get_param_string(BXPN_VGA_ROM_PATH)->getptr());
149 }
150 #endif
151 #if BX_DEBUGGER
152 // register device for the 'info device' command (calls debug_dump())
153 bx_dbg_register_debug_info("vga", this);
154 #endif
155 return ret;
156 }
157
reset(unsigned type)158 void bx_vga_c::reset(unsigned type)
159 {
160 #if BX_SUPPORT_PCI
161 if (BX_VGA_THIS pci_enabled) {
162 static const struct reset_vals_t {
163 unsigned addr;
164 unsigned char val;
165 } reset_vals[] = {
166 { 0x04, 0x03 }, { 0x05, 0x00 }, // command_io + command_mem
167 { 0x06, 0x00 }, { 0x07, 0x02 } // status_devsel_medium
168 };
169 for (unsigned i = 0; i < sizeof(reset_vals) / sizeof(*reset_vals); ++i) {
170 BX_VGA_THIS pci_conf[reset_vals[i].addr] = reset_vals[i].val;
171 }
172 }
173 #endif
174 }
175
register_state(void)176 void bx_vga_c::register_state(void)
177 {
178 bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "vga", "VGA Adapter State");
179 BX_VGA_THIS vgacore_register_state(list);
180 #if BX_SUPPORT_PCI
181 if (BX_VGA_THIS pci_enabled) {
182 register_pci_state(list);
183 }
184 #endif
185 // register state for Bochs VBE
186 if (BX_VGA_THIS vbe_present) {
187 bx_list_c *vbe = new bx_list_c(list, "vbe");
188 new bx_shadow_num_c(vbe, "cur_dispi", &BX_VGA_THIS vbe.cur_dispi, BASE_HEX);
189 new bx_shadow_num_c(vbe, "xres", &BX_VGA_THIS vbe.xres);
190 new bx_shadow_num_c(vbe, "yres", &BX_VGA_THIS vbe.yres);
191 new bx_shadow_num_c(vbe, "bpp", &BX_VGA_THIS vbe.bpp);
192 new bx_shadow_num_c(vbe, "bank0", &BX_VGA_THIS vbe.bank[0]);
193 new bx_shadow_num_c(vbe, "bank1", &BX_VGA_THIS vbe.bank[1]);
194 new bx_shadow_num_c(vbe, "bank_granularity_kb", &BX_VGA_THIS vbe.bank_granularity_kb);
195 BXRS_PARAM_BOOL(vbe, enabled, BX_VGA_THIS vbe.enabled);
196 new bx_shadow_num_c(vbe, "curindex", &BX_VGA_THIS vbe.curindex);
197 new bx_shadow_num_c(vbe, "visible_screen_size", &BX_VGA_THIS vbe.visible_screen_size);
198 new bx_shadow_num_c(vbe, "offset_x", &BX_VGA_THIS vbe.offset_x);
199 new bx_shadow_num_c(vbe, "offset_y", &BX_VGA_THIS vbe.offset_y);
200 new bx_shadow_num_c(vbe, "virtual_xres", &BX_VGA_THIS vbe.virtual_xres);
201 new bx_shadow_num_c(vbe, "virtual_yres", &BX_VGA_THIS vbe.virtual_yres);
202 new bx_shadow_num_c(vbe, "virtual_start", &BX_VGA_THIS vbe.virtual_start);
203 new bx_shadow_num_c(vbe, "bpp_multiplier", &BX_VGA_THIS vbe.bpp_multiplier);
204 BXRS_PARAM_BOOL(vbe, get_capabilities, BX_VGA_THIS vbe.get_capabilities);
205 BXRS_PARAM_BOOL(vbe, dac_8bit, BX_VGA_THIS vbe.dac_8bit);
206 BXRS_PARAM_BOOL(vbe, ddc_enabled, BX_VGA_THIS vbe.ddc_enabled);
207 }
208 }
209
after_restore_state(void)210 void bx_vga_c::after_restore_state(void)
211 {
212 bx_vgacore_c::after_restore_state();
213 #if BX_SUPPORT_PCI
214 if (BX_VGA_THIS pci_enabled) {
215 bx_pci_device_c::after_restore_pci_state(mem_read_handler);
216 }
217 #endif
218 if (BX_VGA_THIS vbe.enabled) {
219 bx_gui->dimension_update(BX_VGA_THIS vbe.xres, BX_VGA_THIS vbe.yres, 0, 0,
220 BX_VGA_THIS vbe.bpp);
221 }
222 }
223
224 // static IO port write callback handler
225 // redirects to non-static class handler to avoid virtual functions
226
write_handler(void * this_ptr,Bit32u address,Bit32u value,unsigned io_len)227 void bx_vga_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
228 {
229 #if BX_USE_VGA_SMF == 0
230 bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
231 class_ptr->write(address, value, io_len, 0);
232 #else
233 UNUSED(this_ptr);
234 theVga->write(address, value, io_len, 0);
235 #endif
236 }
237
238 #if BX_USE_VGA_SMF
write_handler_no_log(void * this_ptr,Bit32u address,Bit32u value,unsigned io_len)239 void bx_vga_c::write_handler_no_log(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
240 {
241 UNUSED(this_ptr);
242 theVga->write(address, value, io_len, 1);
243 }
244 #endif
245
write(Bit32u address,Bit32u value,unsigned io_len,bool no_log)246 void bx_vga_c::write(Bit32u address, Bit32u value, unsigned io_len, bool no_log)
247 {
248 if (io_len == 2) {
249 #if BX_USE_VGA_SMF
250 bx_vga_c::write_handler_no_log(0, address, value & 0xff, 1);
251 bx_vga_c::write_handler_no_log(0, address+1, (value >> 8) & 0xff, 1);
252 #else
253 bx_vga_c::write(address, value & 0xff, 1, 1);
254 bx_vga_c::write(address+1, (value >> 8) & 0xff, 1, 1);
255 #endif
256 return;
257 }
258
259 if ((address >= 0x03b0) && (address <= 0x03bf) &&
260 (BX_VGA_THIS s.misc_output.color_emulation))
261 return;
262 if ((address >= 0x03d0) && (address <= 0x03df) &&
263 (BX_VGA_THIS s.misc_output.color_emulation==0))
264 return;
265
266 switch (address) {
267 case 0x03b5: /* CRTC Registers (monochrome emulation modes) */
268 case 0x03d5: /* CRTC Registers (color emulation modes) */
269 if (BX_VGA_THIS s.CRTC.address > 0x18) {
270 BX_DEBUG(("write: invalid CRTC register 0x%02x ignored",
271 (unsigned) BX_VGA_THIS s.CRTC.address));
272 return;
273 }
274 if (value != BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address]) {
275 switch (BX_VGA_THIS s.CRTC.address) {
276 case 0x13:
277 case 0x14:
278 case 0x17:
279 if (!BX_VGA_THIS vbe.enabled || (BX_VGA_THIS vbe.bpp == VBE_DISPI_BPP_4)) {
280 // Line offset change
281 bx_vgacore_c::write(address, value, io_len, no_log);
282 } else {
283 BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address] = value;
284 }
285 break;
286 default:
287 bx_vgacore_c::write(address, value, io_len, no_log);
288 }
289 }
290 break;
291 default:
292 bx_vgacore_c::write(address, value, io_len, no_log);
293 }
294 }
295
update(void)296 void bx_vga_c::update(void)
297 {
298 unsigned iHeight, iWidth;
299
300 if (BX_VGA_THIS vbe.enabled) {
301 /* no screen update necessary */
302 if ((BX_VGA_THIS s.vga_mem_updated==0) && BX_VGA_THIS s.graphics_ctrl.graphics_alpha)
303 return;
304
305 /* skip screen update when vga/video is disabled or the sequencer is in reset mode */
306 if (!BX_VGA_THIS s.vga_enabled || !BX_VGA_THIS s.attribute_ctrl.video_enabled
307 || !BX_VGA_THIS s.sequencer.reset2 || !BX_VGA_THIS s.sequencer.reset1
308 || (BX_VGA_THIS s.sequencer.reg1 & 0x20))
309 return;
310
311 /* skip screen update if the vertical retrace is in progress
312 (using 72 Hz vertical frequency) */
313 if ((bx_virt_timer.time_usec(BX_VGA_THIS vsync_realtime) % 13888) < 70)
314 return;
315
316 if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {
317 // specific VBE code display update code
318 unsigned pitch;
319 unsigned xc, yc, xti, yti;
320 unsigned r, c, w, h;
321 int i;
322 unsigned long red, green, blue, colour;
323 Bit8u * vid_ptr, * vid_ptr2;
324 Bit8u * tile_ptr, * tile_ptr2;
325 bx_svga_tileinfo_t info;
326 Bit8u dac_size = BX_VGA_THIS vbe.dac_8bit ? 8 : 6;
327
328 iWidth=BX_VGA_THIS vbe.xres;
329 iHeight=BX_VGA_THIS vbe.yres;
330 pitch = BX_VGA_THIS s.line_offset;
331 Bit8u *disp_ptr = &BX_VGA_THIS s.memory[BX_VGA_THIS vbe.virtual_start];
332
333 if (bx_gui->graphics_tile_info_common(&info)) {
334 if (info.snapshot_mode) {
335 vid_ptr = disp_ptr;
336 tile_ptr = bx_gui->get_snapshot_buffer();
337 if (tile_ptr != NULL) {
338 for (yc = 0; yc < iHeight; yc++) {
339 memcpy(tile_ptr, vid_ptr, info.pitch);
340 vid_ptr += pitch;
341 tile_ptr += info.pitch;
342 }
343 }
344 } else if (info.is_indexed) {
345 switch (BX_VGA_THIS vbe.bpp) {
346 case 4:
347 case 15:
348 case 16:
349 case 24:
350 case 32:
351 BX_ERROR(("current guest pixel format is unsupported on indexed colour host displays"));
352 break;
353 case 8:
354 for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
355 for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
356 if (GET_TILE_UPDATED (xti, yti)) {
357 vid_ptr = disp_ptr + (yc * pitch + xc);
358 tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
359 for (r=0; r<h; r++) {
360 vid_ptr2 = vid_ptr;
361 tile_ptr2 = tile_ptr;
362 for (c=0; c<w; c++) {
363 colour = 0;
364 for (i=0; i<(int)BX_VGA_THIS vbe.bpp; i+=8) {
365 colour |= *(vid_ptr2++) << i;
366 }
367 if (info.is_little_endian) {
368 for (i=0; i<info.bpp; i+=8) {
369 *(tile_ptr2++) = (Bit8u)(colour >> i);
370 }
371 } else {
372 for (i=info.bpp-8; i>-8; i-=8) {
373 *(tile_ptr2++) = (Bit8u)(colour >> i);
374 }
375 }
376 }
377 vid_ptr += pitch;
378 tile_ptr += info.pitch;
379 }
380 bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
381 SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
382 }
383 }
384 }
385 break;
386 }
387 } else {
388 switch (BX_VGA_THIS vbe.bpp) {
389 case 4:
390 BX_ERROR(("cannot draw 4bpp SVGA"));
391 break;
392 case 8:
393 for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
394 for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
395 if (GET_TILE_UPDATED (xti, yti)) {
396 vid_ptr = disp_ptr + (yc * pitch + xc);
397 tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
398 for (r=0; r<h; r++) {
399 vid_ptr2 = vid_ptr;
400 tile_ptr2 = tile_ptr;
401 for (c=0; c<w; c++) {
402 colour = *(vid_ptr2++);
403 colour = MAKE_COLOUR(
404 BX_VGA_THIS s.pel.data[colour].red, dac_size, info.red_shift, info.red_mask,
405 BX_VGA_THIS s.pel.data[colour].green, dac_size, info.green_shift, info.green_mask,
406 BX_VGA_THIS s.pel.data[colour].blue, dac_size, info.blue_shift, info.blue_mask);
407 if (info.is_little_endian) {
408 for (i=0; i<info.bpp; i+=8) {
409 *(tile_ptr2++) = (Bit8u)(colour >> i);
410 }
411 } else {
412 for (i=info.bpp-8; i>-8; i-=8) {
413 *(tile_ptr2++) = (Bit8u)(colour >> i);
414 }
415 }
416 }
417 vid_ptr += pitch;
418 tile_ptr += info.pitch;
419 }
420 bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
421 SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
422 }
423 }
424 }
425 break;
426 case 15:
427 for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
428 for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
429 if (GET_TILE_UPDATED (xti, yti)) {
430 vid_ptr = disp_ptr + (yc * pitch + (xc<<1));
431 tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
432 for (r=0; r<h; r++) {
433 vid_ptr2 = vid_ptr;
434 tile_ptr2 = tile_ptr;
435 for (c=0; c<w; c++) {
436 colour = *(vid_ptr2++);
437 colour |= *(vid_ptr2++) << 8;
438 colour = MAKE_COLOUR(
439 colour & 0x001f, 5, info.blue_shift, info.blue_mask,
440 colour & 0x03e0, 10, info.green_shift, info.green_mask,
441 colour & 0x7c00, 15, info.red_shift, info.red_mask);
442 if (info.is_little_endian) {
443 for (i=0; i<info.bpp; i+=8) {
444 *(tile_ptr2++) = (Bit8u)(colour >> i);
445 }
446 } else {
447 for (i=info.bpp-8; i>-8; i-=8) {
448 *(tile_ptr2++) = (Bit8u)(colour >> i);
449 }
450 }
451 }
452 vid_ptr += pitch;
453 tile_ptr += info.pitch;
454 }
455 bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
456 SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
457 }
458 }
459 }
460 break;
461 case 16:
462 for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
463 for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
464 if (GET_TILE_UPDATED (xti, yti)) {
465 vid_ptr = disp_ptr + (yc * pitch + (xc<<1));
466 tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
467 for (r=0; r<h; r++) {
468 vid_ptr2 = vid_ptr;
469 tile_ptr2 = tile_ptr;
470 for (c=0; c<w; c++) {
471 colour = *(vid_ptr2++);
472 colour |= *(vid_ptr2++) << 8;
473 colour = MAKE_COLOUR(
474 colour & 0x001f, 5, info.blue_shift, info.blue_mask,
475 colour & 0x07e0, 11, info.green_shift, info.green_mask,
476 colour & 0xf800, 16, info.red_shift, info.red_mask);
477 if (info.is_little_endian) {
478 for (i=0; i<info.bpp; i+=8) {
479 *(tile_ptr2++) = (Bit8u)(colour >> i);
480 }
481 } else {
482 for (i=info.bpp-8; i>-8; i-=8) {
483 *(tile_ptr2++) = (Bit8u)(colour >> i);
484 }
485 }
486 }
487 vid_ptr += pitch;
488 tile_ptr += info.pitch;
489 }
490 bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
491 SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
492 }
493 }
494 }
495 break;
496 case 24:
497 for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
498 for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
499 if (GET_TILE_UPDATED (xti, yti)) {
500 vid_ptr = disp_ptr + (yc * pitch + 3*xc);
501 tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
502 for (r=0; r<h; r++) {
503 vid_ptr2 = vid_ptr;
504 tile_ptr2 = tile_ptr;
505 for (c=0; c<w; c++) {
506 blue = *(vid_ptr2++);
507 green = *(vid_ptr2++);
508 red = *(vid_ptr2++);
509 colour = MAKE_COLOUR(
510 red, 8, info.red_shift, info.red_mask,
511 green, 8, info.green_shift, info.green_mask,
512 blue, 8, info.blue_shift, info.blue_mask);
513 if (info.is_little_endian) {
514 for (i=0; i<info.bpp; i+=8) {
515 *(tile_ptr2++) = (Bit8u)(colour >> i);
516 }
517 } else {
518 for (i=info.bpp-8; i>-8; i-=8) {
519 *(tile_ptr2++) = (Bit8u)(colour >> i);
520 }
521 }
522 }
523 vid_ptr += pitch;
524 tile_ptr += info.pitch;
525 }
526 bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
527 SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
528 }
529 }
530 }
531 break;
532 case 32:
533 for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
534 for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
535 if (GET_TILE_UPDATED (xti, yti)) {
536 vid_ptr = disp_ptr + (yc * pitch + (xc<<2));
537 tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
538 for (r=0; r<h; r++) {
539 vid_ptr2 = vid_ptr;
540 tile_ptr2 = tile_ptr;
541 for (c=0; c<w; c++) {
542 blue = *(vid_ptr2++);
543 green = *(vid_ptr2++);
544 red = *(vid_ptr2++);
545 vid_ptr2++;
546 colour = MAKE_COLOUR(
547 red, 8, info.red_shift, info.red_mask,
548 green, 8, info.green_shift, info.green_mask,
549 blue, 8, info.blue_shift, info.blue_mask);
550 if (info.is_little_endian) {
551 for (i=0; i<info.bpp; i+=8) {
552 *(tile_ptr2++) = (Bit8u)(colour >> i);
553 }
554 } else {
555 for (i=info.bpp-8; i>-8; i-=8) {
556 *(tile_ptr2++) = (Bit8u)(colour >> i);
557 }
558 }
559 }
560 vid_ptr += pitch;
561 tile_ptr += info.pitch;
562 }
563 bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
564 SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
565 }
566 }
567 }
568 break;
569 }
570 }
571 BX_VGA_THIS s.last_xres = iWidth;
572 BX_VGA_THIS s.last_yres = iHeight;
573 BX_VGA_THIS s.vga_mem_updated = 0;
574 } else {
575 BX_PANIC(("cannot get svga tile info"));
576 }
577 } else {
578 unsigned r, c, x, y;
579 unsigned xc, yc, xti, yti;
580 Bit8u *plane[4];
581
582 BX_VGA_THIS determine_screen_dimensions(&iHeight, &iWidth);
583 if ((iWidth != BX_VGA_THIS s.last_xres) || (iHeight != BX_VGA_THIS s.last_yres) ||
584 (BX_VGA_THIS s.last_bpp > 8)) {
585 bx_gui->dimension_update(iWidth, iHeight);
586 BX_VGA_THIS s.last_xres = iWidth;
587 BX_VGA_THIS s.last_yres = iHeight;
588 BX_VGA_THIS s.last_bpp = 8;
589 }
590
591 plane[0] = &BX_VGA_THIS s.memory[0<<VBE_DISPI_4BPP_PLANE_SHIFT];
592 plane[1] = &BX_VGA_THIS s.memory[1<<VBE_DISPI_4BPP_PLANE_SHIFT];
593 plane[2] = &BX_VGA_THIS s.memory[2<<VBE_DISPI_4BPP_PLANE_SHIFT];
594 plane[3] = &BX_VGA_THIS s.memory[3<<VBE_DISPI_4BPP_PLANE_SHIFT];
595
596 for (yc=0, yti=0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
597 for (xc=0, xti=0; xc<iWidth; xc+=X_TILESIZE, xti++) {
598 if (GET_TILE_UPDATED (xti, yti)) {
599 for (r=0; r<Y_TILESIZE; r++) {
600 y = yc + r;
601 if (BX_VGA_THIS s.y_doublescan) y >>= 1;
602 for (c=0; c<X_TILESIZE; c++) {
603 x = xc + c;
604 BX_VGA_THIS s.tile[r*X_TILESIZE + c] =
605 BX_VGA_THIS get_vga_pixel(x, y, BX_VGA_THIS vbe.virtual_start, 0xffff, 0, plane);
606 }
607 }
608 SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
609 bx_gui->graphics_tile_update_common(BX_VGA_THIS s.tile, xc, yc);
610 }
611 }
612 }
613 }
614 } else {
615 BX_VGA_THIS bx_vgacore_c::update();
616 }
617 }
618
mem_read_handler(bx_phy_address addr,unsigned len,void * data,void * param)619 bool bx_vga_c::mem_read_handler(bx_phy_address addr, unsigned len, void *data, void *param)
620 {
621 Bit8u *data_ptr;
622 #ifdef BX_LITTLE_ENDIAN
623 data_ptr = (Bit8u *) data;
624 #else // BX_BIG_ENDIAN
625 data_ptr = (Bit8u *) data + (len - 1);
626 #endif
627 for (unsigned i = 0; i < len; i++) {
628 *data_ptr = theVga->mem_read(addr);
629 addr++;
630 #ifdef BX_LITTLE_ENDIAN
631 data_ptr++;
632 #else // BX_BIG_ENDIAN
633 data_ptr--;
634 #endif
635 }
636 return 1;
637 }
638
mem_read(bx_phy_address addr)639 Bit8u bx_vga_c::mem_read(bx_phy_address addr)
640 {
641 #if BX_SUPPORT_PCI
642 if ((BX_VGA_THIS pci_enabled) && (BX_VGA_THIS pci_rom_size > 0)) {
643 Bit32u mask = (BX_VGA_THIS pci_rom_size - 1);
644 if (((Bit32u)addr & ~mask) == BX_VGA_THIS pci_rom_address) {
645 if (BX_VGA_THIS pci_conf[0x30] & 0x01) {
646 return BX_VGA_THIS pci_rom[addr & mask];
647 } else {
648 return 0xff;
649 }
650 }
651 }
652 #endif
653 // if in a vbe enabled mode, read from the vbe_memory
654 if ((BX_VGA_THIS vbe.enabled) && (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4)) {
655 return vbe_mem_read(addr);
656 } else if ((BX_VGA_THIS vbe.base_address != 0) && (addr >= BX_VGA_THIS vbe.base_address)) {
657 return 0xff;
658 }
659
660 return bx_vgacore_c::mem_read(addr);
661 }
662
mem_write_handler(bx_phy_address addr,unsigned len,void * data,void * param)663 bool bx_vga_c::mem_write_handler(bx_phy_address addr, unsigned len, void *data, void *param)
664 {
665 Bit8u *data_ptr;
666 #ifdef BX_LITTLE_ENDIAN
667 data_ptr = (Bit8u *) data;
668 #else // BX_BIG_ENDIAN
669 data_ptr = (Bit8u *) data + (len - 1);
670 #endif
671 for (unsigned i = 0; i < len; i++) {
672 theVga->mem_write(addr, *data_ptr);
673 addr++;
674 #ifdef BX_LITTLE_ENDIAN
675 data_ptr++;
676 #else // BX_BIG_ENDIAN
677 data_ptr--;
678 #endif
679 }
680 return 1;
681 }
682
mem_write(bx_phy_address addr,Bit8u value)683 void bx_vga_c::mem_write(bx_phy_address addr, Bit8u value)
684 {
685 // if in a vbe enabled mode, write to the vbe_memory
686 if ((BX_VGA_THIS vbe.enabled) && (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4)) {
687 vbe_mem_write(addr, value);
688 return;
689 } else if ((BX_VGA_THIS vbe.base_address != 0) && (addr >= BX_VGA_THIS vbe.base_address)) {
690 return;
691 }
692
693 bx_vgacore_c::mem_write(addr, value);
694 }
695
redraw_area(unsigned x0,unsigned y0,unsigned width,unsigned height)696 void bx_vga_c::redraw_area(unsigned x0, unsigned y0, unsigned width,
697 unsigned height)
698 {
699 unsigned xti, yti, xt0, xt1, yt0, yt1, xmax, ymax;
700
701 if (BX_VGA_THIS vbe.enabled) {
702 BX_VGA_THIS s.vga_mem_updated = 1;
703 xmax = BX_VGA_THIS vbe.xres;
704 ymax = BX_VGA_THIS vbe.yres;
705 xt0 = x0 / X_TILESIZE;
706 yt0 = y0 / Y_TILESIZE;
707 if (x0 < xmax) {
708 xt1 = (x0 + width - 1) / X_TILESIZE;
709 } else {
710 xt1 = (xmax - 1) / X_TILESIZE;
711 }
712 if (y0 < ymax) {
713 yt1 = (y0 + height - 1) / Y_TILESIZE;
714 } else {
715 yt1 = (ymax - 1) / Y_TILESIZE;
716 }
717 for (yti=yt0; yti<=yt1; yti++) {
718 for (xti=xt0; xti<=xt1; xti++) {
719 SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 1);
720 }
721 }
722
723 } else {
724 bx_vgacore_c::redraw_area(x0, y0, width, height);
725 }
726 }
727
728 #if BX_SUPPORT_PCI
pci_bar_change_notify(void)729 void bx_vga_c::pci_bar_change_notify(void)
730 {
731 BX_VGA_THIS vbe.base_address = pci_bar[0].addr;
732 }
733 #endif
734
735 Bit8u BX_CPP_AttrRegparmN(1)
vbe_mem_read(bx_phy_address addr)736 bx_vga_c::vbe_mem_read(bx_phy_address addr)
737 {
738 Bit32u offset;
739
740 if (addr >= BX_VGA_THIS vbe.base_address) {
741 // LFB read
742 offset = (Bit32u)(addr - BX_VGA_THIS vbe.base_address);
743 } else if (addr < 0xB0000) {
744 // banked mode read
745 offset = (Bit32u)(BX_VGA_THIS vbe.bank[1] * (BX_VGA_THIS vbe.bank_granularity_kb << 10) +
746 (addr & 0xffff));
747 } else {
748 // out of bounds read
749 return 0;
750 }
751
752 // check for out of memory read
753 if (offset > VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES)
754 return 0;
755
756 return (BX_VGA_THIS s.memory[offset]);
757 }
758
759 void BX_CPP_AttrRegparmN(2)
vbe_mem_write(bx_phy_address addr,Bit8u value)760 bx_vga_c::vbe_mem_write(bx_phy_address addr, Bit8u value)
761 {
762 Bit32u offset;
763 unsigned x_tileno, y_tileno;
764
765 if (addr >= BX_VGA_THIS vbe.base_address) {
766 // LFB write
767 offset = (Bit32u)(addr - BX_VGA_THIS vbe.base_address);
768 } else if (addr < 0xB0000) {
769 // banked mode write
770 offset = (Bit32u)(BX_VGA_THIS vbe.bank[0] * (BX_VGA_THIS vbe.bank_granularity_kb << 10) +
771 (addr & 0xffff));
772 } else {
773 // ignore out of bounds write
774 return;
775 }
776
777 // check for out of memory write
778 if (offset < VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES) {
779 BX_VGA_THIS s.memory[offset] = value;
780 } else {
781 // make sure we don't flood the logfile
782 static int count=0;
783 if (count<100) {
784 count ++;
785 BX_INFO(("VBE_mem_write out of video memory write at %x",offset));
786 }
787 }
788
789 offset -= BX_VGA_THIS vbe.virtual_start;
790
791 // only update the UI when writing 'onscreen'
792 if (offset < BX_VGA_THIS vbe.visible_screen_size) {
793 y_tileno = ((offset / BX_VGA_THIS vbe.bpp_multiplier) / BX_VGA_THIS vbe.virtual_xres) / Y_TILESIZE;
794 x_tileno = ((offset / BX_VGA_THIS vbe.bpp_multiplier) % BX_VGA_THIS vbe.virtual_xres) / X_TILESIZE;
795
796 if ((y_tileno < BX_VGA_THIS s.num_y_tiles) && (x_tileno < BX_VGA_THIS s.num_x_tiles))
797 {
798 BX_VGA_THIS s.vga_mem_updated = 1;
799 SET_TILE_UPDATED(BX_VGA_THIS, x_tileno, y_tileno, 1);
800 }
801 }
802 }
803
vbe_read_handler(void * this_ptr,Bit32u address,unsigned io_len)804 Bit32u bx_vga_c::vbe_read_handler(void *this_ptr, Bit32u address, unsigned io_len)
805 {
806 #if BX_USE_VGA_SMF == 0
807 bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
808 return class_ptr->vbe_read(address, io_len);
809 }
810
vbe_read(Bit32u address,unsigned io_len)811 Bit32u bx_vga_c::vbe_read(Bit32u address, unsigned io_len)
812 {
813 #else
814 UNUSED(this_ptr);
815 #endif // BX_USE_VGA_SMF == 0
816 Bit16u retval = 0;
817
818 // BX_INFO(("VBE_read %x (len %x)", address, io_len));
819
820 if (address==VBE_DISPI_IOPORT_INDEX)
821 {
822 // index register
823 return (Bit32u) BX_VGA_THIS vbe.curindex;
824 }
825 else
826 {
827 // data register read
828
829 switch (BX_VGA_THIS vbe.curindex)
830 {
831 case VBE_DISPI_INDEX_ID: // Display Interface ID check
832 return BX_VGA_THIS vbe.cur_dispi;
833
834 case VBE_DISPI_INDEX_XRES: // x resolution
835 if (BX_VGA_THIS vbe.get_capabilities) {
836 return BX_VGA_THIS vbe.max_xres;
837 } else {
838 return BX_VGA_THIS vbe.xres;
839 }
840
841 case VBE_DISPI_INDEX_YRES: // y resolution
842 if (BX_VGA_THIS vbe.get_capabilities) {
843 return BX_VGA_THIS vbe.max_yres;
844 } else {
845 return BX_VGA_THIS vbe.yres;
846 }
847
848 case VBE_DISPI_INDEX_BPP: // bpp
849 if (BX_VGA_THIS vbe.get_capabilities) {
850 return BX_VGA_THIS vbe.max_bpp;
851 } else {
852 return BX_VGA_THIS vbe.bpp;
853 }
854
855 case VBE_DISPI_INDEX_ENABLE: // vbe enabled
856 retval = BX_VGA_THIS vbe.enabled;
857 if (BX_VGA_THIS vbe.get_capabilities)
858 retval |= VBE_DISPI_GETCAPS;
859 if (BX_VGA_THIS vbe.dac_8bit)
860 retval |= VBE_DISPI_8BIT_DAC;
861 if (BX_VGA_THIS vbe.bank_granularity_kb == 32)
862 retval |= VBE_DISPI_BANK_GRANULARITY_32K;
863 return retval;
864
865 case VBE_DISPI_INDEX_BANK: // current bank
866 if (BX_VGA_THIS vbe.get_capabilities) {
867 return (VBE_DISPI_BANK_GRANULARITY_32K << 8);
868 } else {
869 return BX_VGA_THIS vbe.bank[0];
870 }
871
872 case VBE_DISPI_INDEX_X_OFFSET:
873 return BX_VGA_THIS vbe.offset_x;
874
875 case VBE_DISPI_INDEX_Y_OFFSET:
876 return BX_VGA_THIS vbe.offset_y;
877
878 case VBE_DISPI_INDEX_VIRT_WIDTH:
879 return BX_VGA_THIS vbe.virtual_xres;
880
881 case VBE_DISPI_INDEX_VIRT_HEIGHT:
882 return BX_VGA_THIS vbe.virtual_yres;
883
884 case VBE_DISPI_INDEX_VIDEO_MEMORY_64K:
885 return (VBE_DISPI_TOTAL_VIDEO_MEMORY_KB >> 6);
886
887 case VBE_DISPI_INDEX_DDC:
888 if (BX_VGA_THIS vbe.ddc_enabled) {
889 retval = (1 << 7) | BX_VGA_THIS ddc.read();
890 } else {
891 retval = 0x000f;
892 }
893 break;
894
895 default:
896 BX_ERROR(("VBE unknown data read index 0x%x",BX_VGA_THIS vbe.curindex));
897 break;
898 }
899 }
900 return retval;
901 }
902
vbe_write_handler(void * this_ptr,Bit32u address,Bit32u value,unsigned io_len)903 void bx_vga_c::vbe_write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
904 {
905 #if BX_USE_VGA_SMF == 0
906 bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
907 class_ptr->vbe_write(address, value, io_len);
908 }
909
vbe_write(Bit32u address,Bit32u value,unsigned io_len)910 Bit32u bx_vga_c::vbe_write(Bit32u address, Bit32u value, unsigned io_len)
911 {
912 #else
913 UNUSED(this_ptr);
914 #endif
915 Bit16u max_xres, max_yres, max_bpp, new_bank_gran;
916 bool new_vbe_8bit_dac;
917 bool needs_update = 0;
918 unsigned i;
919
920 // BX_INFO(("VBE_write %x = %x (len %x)", address, value, io_len));
921
922 switch(address)
923 {
924 // index register
925 case VBE_DISPI_IOPORT_INDEX:
926
927 BX_VGA_THIS vbe.curindex = (Bit16u) value;
928 break;
929
930 // data register
931 // FIXME: maybe do some 'sanity' checks on received data?
932 case VBE_DISPI_IOPORT_DATA:
933 switch (BX_VGA_THIS vbe.curindex)
934 {
935 case VBE_DISPI_INDEX_ID: // Display Interface ID check
936 {
937 if ((value == VBE_DISPI_ID0) ||
938 (value == VBE_DISPI_ID1) ||
939 (value == VBE_DISPI_ID2) ||
940 (value == VBE_DISPI_ID3) ||
941 (value == VBE_DISPI_ID4) ||
942 (value == VBE_DISPI_ID5))
943 {
944 // allow backwards compatible with previous dispi bioses
945 BX_VGA_THIS vbe.cur_dispi=value;
946 }
947 else
948 {
949 BX_PANIC(("VBE unknown Display Interface %x", value));
950 }
951
952 // make sure we don't flood the logfile
953 static int count=0;
954 if (count < 100)
955 {
956 count++;
957 BX_INFO(("VBE known Display Interface %x", value));
958 }
959 } break;
960
961 case VBE_DISPI_INDEX_XRES: // set xres
962 {
963 // check that we don't set xres during vbe enabled
964 if (!BX_VGA_THIS vbe.enabled)
965 {
966 // check for within max xres range
967 if (value <= BX_VGA_THIS vbe.max_xres)
968 {
969 BX_VGA_THIS vbe.xres=(Bit16u) value;
970 BX_INFO(("VBE set xres (%d)", value));
971 }
972 else
973 {
974 BX_INFO(("VBE set xres more then max xres (%d)", value));
975 }
976 }
977 else
978 {
979 BX_ERROR(("VBE set xres during vbe enabled!"));
980 }
981 } break;
982
983 case VBE_DISPI_INDEX_YRES: // set yres
984 {
985 // check that we don't set yres during vbe enabled
986 if (!BX_VGA_THIS vbe.enabled)
987 {
988 // check for within max yres range
989 if (value <= BX_VGA_THIS vbe.max_yres)
990 {
991 BX_VGA_THIS vbe.yres=(Bit16u) value;
992 BX_INFO(("VBE set yres (%d)", value));
993 }
994 else
995 {
996 BX_INFO(("VBE set yres more then max yres (%d)", value));
997 }
998 }
999 else
1000 {
1001 BX_ERROR(("VBE set yres during vbe enabled!"));
1002 }
1003 } break;
1004
1005 case VBE_DISPI_INDEX_BPP: // set bpp
1006 {
1007 // check that we don't set bpp during vbe enabled
1008 if (!BX_VGA_THIS vbe.enabled)
1009 {
1010 // for backward compatiblity
1011 if (value == 0) value = VBE_DISPI_BPP_8;
1012 // check for correct bpp range
1013 if ((value == VBE_DISPI_BPP_4) || (value == VBE_DISPI_BPP_8) || (value == VBE_DISPI_BPP_15) ||
1014 (value == VBE_DISPI_BPP_16) || (value == VBE_DISPI_BPP_24) || (value == VBE_DISPI_BPP_32))
1015 {
1016 BX_VGA_THIS vbe.bpp=(Bit16u) value;
1017 BX_INFO(("VBE set bpp (%d)", value));
1018 }
1019 else
1020 {
1021 BX_ERROR(("VBE set bpp with unknown bpp (%d)", value));
1022 }
1023 }
1024 else
1025 {
1026 BX_ERROR(("VBE set bpp during vbe enabled!"));
1027 }
1028 } break;
1029
1030 case VBE_DISPI_INDEX_BANK: // set bank
1031 {
1032 Bit16u num_banks = (Bit16u)(VBE_DISPI_TOTAL_VIDEO_MEMORY_KB / BX_VGA_THIS vbe.bank_granularity_kb);
1033 Bit16u rw_mode = VBE_DISPI_BANK_RW; // compatibility mode
1034 if (BX_VGA_THIS vbe.bpp == VBE_DISPI_BPP_4) num_banks >>= 2;
1035 if ((value & VBE_DISPI_BANK_RW) != 0) {
1036 rw_mode = (value & VBE_DISPI_BANK_RW);
1037 }
1038 value &= 0x1ff;
1039 // check for max bank nr
1040 if (value < num_banks) {
1041 BX_DEBUG(("VBE set bank to %d", value));
1042 if ((rw_mode & VBE_DISPI_BANK_WR) != 0) {
1043 BX_VGA_THIS vbe.bank[0] = value;
1044 }
1045 if ((rw_mode & VBE_DISPI_BANK_RD) != 0) {
1046 BX_VGA_THIS vbe.bank[1] = value;
1047 }
1048 if (BX_VGA_THIS vbe.bank_granularity_kb == 64) {
1049 BX_VGA_THIS s.ext_offset = (BX_VGA_THIS vbe.bank[0] << 16);
1050 } else {
1051 BX_VGA_THIS s.ext_offset = (BX_VGA_THIS vbe.bank[0] << 15);
1052 }
1053 } else {
1054 BX_ERROR(("VBE set invalid bank (%d)", value));
1055 }
1056 } break;
1057
1058 case VBE_DISPI_INDEX_ENABLE: // enable video
1059 {
1060 if ((value & VBE_DISPI_ENABLED) && !BX_VGA_THIS vbe.enabled)
1061 {
1062 unsigned depth=0;
1063
1064 // setup virtual resolution to be the same as current reso
1065 BX_VGA_THIS vbe.virtual_yres=BX_VGA_THIS vbe.yres;
1066 BX_VGA_THIS vbe.virtual_xres=BX_VGA_THIS vbe.xres;
1067
1068 // reset offset
1069 BX_VGA_THIS vbe.offset_x=0;
1070 BX_VGA_THIS vbe.offset_y=0;
1071 BX_VGA_THIS vbe.virtual_start=0;
1072
1073 switch((BX_VGA_THIS vbe.bpp))
1074 {
1075 // Default pixel sizes
1076 case VBE_DISPI_BPP_8:
1077 BX_VGA_THIS vbe.bpp_multiplier = 1;
1078 BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres;
1079 depth=8;
1080 break;
1081
1082 case VBE_DISPI_BPP_4:
1083 BX_VGA_THIS vbe.bpp_multiplier = 1;
1084 BX_VGA_THIS s.line_offset = (BX_VGA_THIS vbe.virtual_xres >> 3);
1085 depth=4;
1086 break;
1087
1088 case VBE_DISPI_BPP_15:
1089 BX_VGA_THIS vbe.bpp_multiplier = 2;
1090 BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres * 2;
1091 depth=15;
1092 break;
1093
1094 case VBE_DISPI_BPP_16:
1095 BX_VGA_THIS vbe.bpp_multiplier = 2;
1096 BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres * 2;
1097 depth=16;
1098 break;
1099
1100 case VBE_DISPI_BPP_24:
1101 BX_VGA_THIS vbe.bpp_multiplier = 3;
1102 BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres * 3;
1103 depth=24;
1104 break;
1105
1106 case VBE_DISPI_BPP_32:
1107 BX_VGA_THIS vbe.bpp_multiplier = 4;
1108 BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres << 2;
1109 depth=32;
1110 break;
1111 }
1112 BX_VGA_THIS vbe.visible_screen_size = BX_VGA_THIS s.line_offset * BX_VGA_THIS vbe.yres;
1113
1114 BX_INFO(("VBE enabling x %d, y %d, bpp %d, %u bytes visible", BX_VGA_THIS vbe.xres, BX_VGA_THIS vbe.yres, BX_VGA_THIS vbe.bpp, BX_VGA_THIS vbe.visible_screen_size));
1115
1116 if ((value & VBE_DISPI_NOCLEARMEM) == 0) {
1117 memset(BX_VGA_THIS s.memory, 0, VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES);
1118 }
1119 if (depth > 4) {
1120 bx_gui->dimension_update(BX_VGA_THIS vbe.xres, BX_VGA_THIS vbe.yres, 0, 0, depth);
1121 BX_VGA_THIS s.last_bpp = depth;
1122 BX_VGA_THIS s.last_fh = 0;
1123 } else {
1124 BX_VGA_THIS s.plane_shift = VBE_DISPI_4BPP_PLANE_SHIFT;
1125 BX_VGA_THIS s.ext_offset = (BX_VGA_THIS vbe.bank[0] << 16);
1126 }
1127 } else if (((value & VBE_DISPI_ENABLED) == 0) && BX_VGA_THIS vbe.enabled) {
1128 BX_INFO(("VBE disabling"));
1129 BX_VGA_THIS s.plane_shift = 16;
1130 BX_VGA_THIS s.ext_offset = 0;
1131 }
1132 BX_VGA_THIS vbe.enabled = ((value & VBE_DISPI_ENABLED) != 0);
1133 BX_VGA_THIS vbe.get_capabilities = ((value & VBE_DISPI_GETCAPS) != 0);
1134 if (BX_VGA_THIS vbe.get_capabilities) {
1135 bx_gui->get_capabilities(&max_xres, &max_yres, &max_bpp);
1136 if (max_xres < BX_VGA_THIS vbe.max_xres) {
1137 BX_VGA_THIS vbe.max_xres = max_xres;
1138 }
1139 if (max_yres < BX_VGA_THIS vbe.max_yres) {
1140 BX_VGA_THIS vbe.max_yres = max_yres;
1141 }
1142 if (max_bpp < BX_VGA_THIS vbe.max_bpp) {
1143 BX_VGA_THIS vbe.max_bpp = max_bpp;
1144 }
1145 }
1146 if ((value & VBE_DISPI_BANK_GRANULARITY_32K) != 0) {
1147 new_bank_gran = 32;
1148 } else {
1149 new_bank_gran = 64;
1150 }
1151 if (new_bank_gran != BX_VGA_THIS vbe.bank_granularity_kb) {
1152 BX_VGA_THIS vbe.bank_granularity_kb = new_bank_gran;
1153 BX_VGA_THIS vbe.bank[0] = 0;
1154 BX_VGA_THIS vbe.bank[1] = 0;
1155 BX_VGA_THIS s.ext_offset = 0;
1156 }
1157 new_vbe_8bit_dac = ((value & VBE_DISPI_8BIT_DAC) != 0);
1158 if (new_vbe_8bit_dac != BX_VGA_THIS vbe.dac_8bit) {
1159 if (new_vbe_8bit_dac) {
1160 for (i=0; i<256; i++) {
1161 BX_VGA_THIS s.pel.data[i].red <<= 2;
1162 BX_VGA_THIS s.pel.data[i].green <<= 2;
1163 BX_VGA_THIS s.pel.data[i].blue <<= 2;
1164 }
1165 BX_INFO(("DAC in 8 bit mode"));
1166 } else {
1167 for (i=0; i<256; i++) {
1168 BX_VGA_THIS s.pel.data[i].red >>= 2;
1169 BX_VGA_THIS s.pel.data[i].green >>= 2;
1170 BX_VGA_THIS s.pel.data[i].blue >>= 2;
1171 }
1172 BX_INFO(("DAC in standard mode"));
1173 }
1174 BX_VGA_THIS vbe.dac_8bit = new_vbe_8bit_dac;
1175 BX_VGA_THIS s.dac_shift = new_vbe_8bit_dac ? 0 : 2;
1176 needs_update = 1;
1177 }
1178 } break;
1179
1180 case VBE_DISPI_INDEX_X_OFFSET:
1181 {
1182 BX_DEBUG(("VBE offset x %d", value));
1183 BX_VGA_THIS vbe.offset_x=(Bit16u)value;
1184
1185 BX_VGA_THIS vbe.virtual_start = BX_VGA_THIS vbe.offset_y * BX_VGA_THIS s.line_offset;
1186 if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {
1187 BX_VGA_THIS vbe.virtual_start += (BX_VGA_THIS vbe.offset_x * BX_VGA_THIS vbe.bpp_multiplier);
1188 } else {
1189 BX_VGA_THIS vbe.virtual_start += (BX_VGA_THIS vbe.offset_x >> 3);
1190 }
1191 needs_update = 1;
1192 } break;
1193
1194 case VBE_DISPI_INDEX_Y_OFFSET:
1195 {
1196 BX_DEBUG(("VBE offset y %d", value));
1197
1198 Bit32u new_screen_start = value * BX_VGA_THIS s.line_offset;
1199 if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {
1200 if ((new_screen_start + BX_VGA_THIS vbe.visible_screen_size) > VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES)
1201 {
1202 BX_PANIC(("VBE offset y %d out of bounds", value));
1203 break;
1204 }
1205 new_screen_start += (BX_VGA_THIS vbe.offset_x * BX_VGA_THIS vbe.bpp_multiplier);
1206 } else {
1207 if ((new_screen_start + BX_VGA_THIS vbe.visible_screen_size) > (VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES / 4))
1208 {
1209 BX_PANIC(("VBE offset y %d out of bounds", value));
1210 break;
1211 }
1212 new_screen_start += (BX_VGA_THIS vbe.offset_x >> 3);
1213 }
1214 BX_VGA_THIS vbe.virtual_start = new_screen_start;
1215 BX_VGA_THIS vbe.offset_y = (Bit16u)value;
1216 needs_update = 1;
1217 } break;
1218
1219 case VBE_DISPI_INDEX_VIRT_WIDTH:
1220 {
1221 BX_INFO(("VBE requested virtual width %d", value));
1222
1223 // calculate virtual width & height dimensions
1224 // req:
1225 // virt_width > xres
1226 // virt_height >=yres
1227 // virt_width*virt_height < MAX_VIDEO_MEMORY
1228
1229 // basically 2 situations
1230
1231 // situation 1:
1232 // MAX_VIDEO_MEMORY / virt_width >= yres
1233 // adjust result height
1234 // else
1235 // adjust result width based upon virt_height=yres
1236 Bit16u new_width=value;
1237 Bit16u new_height;
1238 if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {
1239 new_height=(VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES / BX_VGA_THIS vbe.bpp_multiplier) / new_width;
1240 } else {
1241 new_height=(VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES * 2) / new_width;
1242 }
1243 if (new_height >=BX_VGA_THIS vbe.yres)
1244 {
1245 // we have a decent virtual width & new_height
1246 BX_INFO(("VBE decent virtual height %d",new_height));
1247 }
1248 else
1249 {
1250 // no decent virtual height: adjust width & height
1251 new_height=BX_VGA_THIS vbe.yres;
1252 if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {
1253 new_width=(VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES / BX_VGA_THIS vbe.bpp_multiplier) / new_height;
1254 } else {
1255 new_width=(VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES * 2) / new_height;
1256 }
1257
1258 BX_INFO(("VBE recalc virtual width %d height %d",new_width, new_height));
1259 }
1260
1261 BX_VGA_THIS vbe.virtual_xres=new_width;
1262 BX_VGA_THIS vbe.virtual_yres=new_height;
1263 if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {
1264 BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres * BX_VGA_THIS vbe.bpp_multiplier;
1265 } else {
1266 BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres >> 3;
1267 }
1268 BX_VGA_THIS vbe.visible_screen_size = BX_VGA_THIS s.line_offset * BX_VGA_THIS vbe.yres;
1269
1270 } break;
1271 case VBE_DISPI_INDEX_VIRT_HEIGHT:
1272 BX_ERROR(("VBE: write to virtual height register ignored"));
1273 break;
1274 case VBE_DISPI_INDEX_DDC:
1275 if ((value >> 7) & 1) {
1276 BX_VGA_THIS vbe.ddc_enabled = 1;
1277 BX_VGA_THIS ddc.write(value & 1, (value >> 1) & 1);
1278 } else {
1279 BX_VGA_THIS vbe.ddc_enabled = 0;
1280 }
1281 break;
1282 default:
1283 BX_ERROR(("VBE: write unsupported register at index 0x%x",BX_VGA_THIS vbe.curindex));
1284 break;
1285 }
1286 if (needs_update) {
1287 BX_VGA_THIS s.vga_mem_updated = 1;
1288 for (unsigned xti = 0; xti < BX_VGA_THIS s.num_x_tiles; xti++) {
1289 for (unsigned yti = 0; yti < BX_VGA_THIS s.num_y_tiles; yti++) {
1290 SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 1);
1291 }
1292 }
1293 }
1294 break;
1295
1296 } // end switch address
1297 }
1298
1299 #if BX_SUPPORT_PCI
1300 // static pci configuration space write callback handler
pci_write_handler(Bit8u address,Bit32u value,unsigned io_len)1301 void bx_vga_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
1302 {
1303 if ((address >= 0x14) && (address < 0x30))
1304 return;
1305
1306 BX_DEBUG_PCI_WRITE(address, value, io_len);
1307 for (unsigned i = 0; i < io_len; i++) {
1308 unsigned write_addr = address + i;
1309 // Bit8u old_value = BX_VGA_THIS pci_conf[write_addr];
1310 Bit8u new_value = (Bit8u)(value & 0xff);
1311 switch (write_addr) {
1312 case 0x04: // disallowing write to command
1313 case 0x06: // disallowing write to status lo-byte (is that expected?)
1314 break;
1315 default:
1316 BX_VGA_THIS pci_conf[write_addr] = new_value;
1317 }
1318 value >>= 8;
1319 }
1320
1321 }
1322 #endif
1323
1324 #if BX_DEBUGGER
debug_dump(int argc,char ** argv)1325 void bx_vga_c::debug_dump(int argc, char **argv)
1326 {
1327 if (BX_VGA_THIS vbe.enabled) {
1328 dbg_printf("Bochs VGA/VBE adapter\n\n");
1329 dbg_printf("current mode : %u x %u x %u\n", BX_VGA_THIS vbe.xres,
1330 BX_VGA_THIS vbe.yres, BX_VGA_THIS vbe.bpp);
1331 if (argc > 0) {
1332 dbg_printf("\nAdditional options not supported\n");
1333 }
1334 } else {
1335 bx_vgacore_c::debug_dump(argc, argv);
1336 }
1337 }
1338 #endif
1339