Bochs/bochs/iodev/display/vga.cc
Volker Ruppert d641af80bb Removed lfb_enabled switch from Bochs VBE code. Now banked and LFB writes to
VRAM are possible at the same time without changing mode. This makes the GRUB
bootloader menu visible when using the Bochs VBE adapter instead of Cirrus.
2020-01-11 06:07:18 +00:00

1298 lines
45 KiB
C++

/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2020 The Bochs Project
// PCI VGA dummy adapter Copyright (C) 2002,2003 Mike Nordell
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
// Standard VGA emulation + Bochs VBE support + PCI VGA interface
// NOTE from the original pcivga code:
// This "driver" was created for the SOLE PURPOSE of getting BeOS
// to boot. It currently does NOTHING more than presenting a generic VGA
// device on the PCI bus. ALL gfx in/out-put is still handled by the VGA code.
// Furthermore, almost all of the PCI registers are currently acting like RAM.
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#include "vgacore.h"
#include "ddc.h"
#include "vga.h"
#include "virt_timer.h"
#define LOG_THIS theVga->
bx_vga_c *theVga = NULL;
int CDECL libvga_LTX_plugin_init(plugin_t *plugin, plugintype_t type)
{
if (type == PLUGTYPE_CORE) {
theVga = new bx_vga_c();
bx_devices.pluginVgaDevice = theVga;
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theVga, BX_PLUGIN_VGA);
return 0; // Success
} else {
return -1;
}
}
void CDECL libvga_LTX_plugin_fini(void)
{
delete theVga;
}
bx_vga_c::bx_vga_c() : bx_vgacore_c()
{
put("VGA");
}
bx_vga_c::~bx_vga_c()
{
SIM->get_bochs_root()->remove("vga");
BX_DEBUG(("Exit"));
}
bx_bool bx_vga_c::init_vga_extension(void)
{
unsigned addr;
Bit16u max_xres, max_yres, max_bpp;
bx_bool ret = 0;
BX_VGA_THIS init_iohandlers(read_handler, write_handler);
BX_VGA_THIS pci_enabled = SIM->is_pci_device("pcivga");
// The following is for the VBE display extension
BX_VGA_THIS vbe_present = 0;
BX_VGA_THIS vbe.enabled = 0;
BX_VGA_THIS vbe.dac_8bit = 0;
BX_VGA_THIS vbe.ddc_enabled = 0;
BX_VGA_THIS vbe.base_address = 0x0000;
if (!strcmp(BX_VGA_THIS vgaext->getptr(), "vbe")) {
BX_VGA_THIS put("BXVGA");
for (addr=VBE_DISPI_IOPORT_INDEX; addr<=VBE_DISPI_IOPORT_DATA; addr++) {
DEV_register_ioread_handler(this, vbe_read_handler, addr, "vga video", 7);
DEV_register_iowrite_handler(this, vbe_write_handler, addr, "vga video", 7);
}
if (!BX_VGA_THIS pci_enabled) {
BX_VGA_THIS vbe.base_address = VBE_DISPI_LFB_PHYSICAL_ADDRESS;
DEV_register_memory_handlers(theVga, mem_read_handler, mem_write_handler,
BX_VGA_THIS vbe.base_address,
BX_VGA_THIS vbe.base_address + VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES - 1);
}
if (BX_VGA_THIS s.memory == NULL)
BX_VGA_THIS s.memory = new Bit8u[VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES];
memset(BX_VGA_THIS s.memory, 0, VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES);
BX_VGA_THIS s.memsize = VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES;
BX_VGA_THIS vbe.cur_dispi=VBE_DISPI_ID0;
BX_VGA_THIS vbe.xres=640;
BX_VGA_THIS vbe.yres=480;
BX_VGA_THIS vbe.bpp=8;
BX_VGA_THIS vbe.bank=0;
BX_VGA_THIS vbe.curindex=0;
BX_VGA_THIS vbe.offset_x=0;
BX_VGA_THIS vbe.offset_y=0;
BX_VGA_THIS vbe.virtual_xres=640;
BX_VGA_THIS vbe.virtual_yres=480;
BX_VGA_THIS vbe.bpp_multiplier=1;
BX_VGA_THIS vbe.virtual_start=0;
BX_VGA_THIS vbe.get_capabilities=0;
bx_gui->get_capabilities(&max_xres, &max_yres, &max_bpp);
if (max_xres > VBE_DISPI_MAX_XRES) {
BX_VGA_THIS vbe.max_xres=VBE_DISPI_MAX_XRES;
} else {
BX_VGA_THIS vbe.max_xres=max_xres;
}
if (max_yres > VBE_DISPI_MAX_YRES) {
BX_VGA_THIS vbe.max_yres=VBE_DISPI_MAX_YRES;
} else {
BX_VGA_THIS vbe.max_yres=max_yres;
}
if (max_bpp > VBE_DISPI_MAX_BPP) {
BX_VGA_THIS vbe.max_bpp=VBE_DISPI_MAX_BPP;
} else {
BX_VGA_THIS vbe.max_bpp=max_bpp;
}
BX_VGA_THIS s.max_xres = BX_VGA_THIS vbe.max_xres;
BX_VGA_THIS s.max_yres = BX_VGA_THIS vbe.max_yres;
BX_VGA_THIS vbe_present = 1;
ret = 1;
BX_INFO(("VBE Bochs Display Extension Enabled"));
}
#if BX_SUPPORT_PCI
Bit8u devfunc = 0x00;
if (BX_VGA_THIS pci_enabled) {
DEV_register_pci_handlers(this, &devfunc, "pcivga", "Experimental PCI VGA");
// initialize readonly registers
// Note that the values for vendor and device id are selected at random!
// There might actually be "real" values for "experimental" vendor and
// device that should be used!
init_pci_conf(0x1234, 0x1111, 0x00, 0x030000, 0x00, 0);
if (BX_VGA_THIS vbe_present) {
BX_VGA_THIS pci_conf[0x10] = 0x08;
BX_VGA_THIS init_bar_mem(0, VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES,
mem_read_handler, mem_write_handler);
}
BX_VGA_THIS pci_rom_address = 0;
BX_VGA_THIS pci_rom_read_handler = mem_read_handler;
BX_VGA_THIS load_pci_rom(SIM->get_param_string(BXPN_VGA_ROM_PATH)->getptr());
}
#endif
#if BX_DEBUGGER
// register device for the 'info device' command (calls debug_dump())
bx_dbg_register_debug_info("vga", this);
#endif
return ret;
}
void bx_vga_c::reset(unsigned type)
{
#if BX_SUPPORT_PCI
if (BX_VGA_THIS pci_enabled) {
static const struct reset_vals_t {
unsigned addr;
unsigned char val;
} reset_vals[] = {
{ 0x04, 0x03 }, { 0x05, 0x00 }, // command_io + command_mem
{ 0x06, 0x00 }, { 0x07, 0x02 } // status_devsel_medium
};
for (unsigned i = 0; i < sizeof(reset_vals) / sizeof(*reset_vals); ++i) {
BX_VGA_THIS pci_conf[reset_vals[i].addr] = reset_vals[i].val;
}
}
#endif
}
void bx_vga_c::register_state(void)
{
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "vga", "VGA Adapter State");
bx_vgacore_c::register_state(list);
#if BX_SUPPORT_PCI
if (BX_VGA_THIS pci_enabled) {
register_pci_state(list);
}
#endif
// register state for Bochs VBE
if (BX_VGA_THIS vbe_present) {
bx_list_c *vbe = new bx_list_c(list, "vbe");
new bx_shadow_num_c(vbe, "cur_dispi", &BX_VGA_THIS vbe.cur_dispi, BASE_HEX);
new bx_shadow_num_c(vbe, "xres", &BX_VGA_THIS vbe.xres);
new bx_shadow_num_c(vbe, "yres", &BX_VGA_THIS vbe.yres);
new bx_shadow_num_c(vbe, "bpp", &BX_VGA_THIS vbe.bpp);
new bx_shadow_num_c(vbe, "bank", &BX_VGA_THIS vbe.bank);
new bx_shadow_bool_c(vbe, "enabled", &BX_VGA_THIS vbe.enabled);
new bx_shadow_num_c(vbe, "curindex", &BX_VGA_THIS vbe.curindex);
new bx_shadow_num_c(vbe, "visible_screen_size", &BX_VGA_THIS vbe.visible_screen_size);
new bx_shadow_num_c(vbe, "offset_x", &BX_VGA_THIS vbe.offset_x);
new bx_shadow_num_c(vbe, "offset_y", &BX_VGA_THIS vbe.offset_y);
new bx_shadow_num_c(vbe, "virtual_xres", &BX_VGA_THIS vbe.virtual_xres);
new bx_shadow_num_c(vbe, "virtual_yres", &BX_VGA_THIS vbe.virtual_yres);
new bx_shadow_num_c(vbe, "virtual_start", &BX_VGA_THIS vbe.virtual_start);
new bx_shadow_num_c(vbe, "bpp_multiplier", &BX_VGA_THIS vbe.bpp_multiplier);
new bx_shadow_bool_c(vbe, "get_capabilities", &BX_VGA_THIS vbe.get_capabilities);
new bx_shadow_bool_c(vbe, "dac_8bit", &BX_VGA_THIS vbe.dac_8bit);
new bx_shadow_bool_c(vbe, "ddc_enabled", &BX_VGA_THIS vbe.ddc_enabled);
}
}
void bx_vga_c::after_restore_state(void)
{
bx_vgacore_c::after_restore_state();
#if BX_SUPPORT_PCI
if (BX_VGA_THIS pci_enabled) {
bx_pci_device_c::after_restore_pci_state(mem_read_handler);
}
#endif
if (BX_VGA_THIS vbe.enabled) {
bx_gui->dimension_update(BX_VGA_THIS vbe.xres, BX_VGA_THIS vbe.yres, 0, 0,
BX_VGA_THIS vbe.bpp);
}
}
// static IO port write callback handler
// redirects to non-static class handler to avoid virtual functions
void bx_vga_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
#if BX_USE_VGA_SMF == 0
bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
class_ptr->write(address, value, io_len, 0);
#else
UNUSED(this_ptr);
theVga->write(address, value, io_len, 0);
#endif
}
#if BX_USE_VGA_SMF
void bx_vga_c::write_handler_no_log(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
UNUSED(this_ptr);
theVga->write(address, value, io_len, 1);
}
#endif
void bx_vga_c::write(Bit32u address, Bit32u value, unsigned io_len, bx_bool no_log)
{
if (io_len == 2) {
#if BX_USE_VGA_SMF
bx_vga_c::write_handler_no_log(0, address, value & 0xff, 1);
bx_vga_c::write_handler_no_log(0, address+1, (value >> 8) & 0xff, 1);
#else
bx_vga_c::write(address, value & 0xff, 1, 1);
bx_vga_c::write(address+1, (value >> 8) & 0xff, 1, 1);
#endif
return;
}
if ((address >= 0x03b0) && (address <= 0x03bf) &&
(BX_VGA_THIS s.misc_output.color_emulation))
return;
if ((address >= 0x03d0) && (address <= 0x03df) &&
(BX_VGA_THIS s.misc_output.color_emulation==0))
return;
switch (address) {
case 0x03b5: /* CRTC Registers (monochrome emulation modes) */
case 0x03d5: /* CRTC Registers (color emulation modes) */
if (BX_VGA_THIS s.CRTC.address > 0x18) {
BX_DEBUG(("write: invalid CRTC register 0x%02x ignored",
(unsigned) BX_VGA_THIS s.CRTC.address));
return;
}
if (value != BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address]) {
switch (BX_VGA_THIS s.CRTC.address) {
case 0x13:
case 0x14:
case 0x17:
if (!BX_VGA_THIS vbe.enabled || (BX_VGA_THIS vbe.bpp == VBE_DISPI_BPP_4)) {
// Line offset change
bx_vgacore_c::write(address, value, io_len, no_log);
} else {
BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address] = value;
}
break;
default:
bx_vgacore_c::write(address, value, io_len, no_log);
}
}
break;
default:
bx_vgacore_c::write(address, value, io_len, no_log);
}
}
void bx_vga_c::update(void)
{
unsigned iHeight, iWidth;
if (BX_VGA_THIS vbe.enabled) {
/* no screen update necessary */
if ((BX_VGA_THIS s.vga_mem_updated==0) && BX_VGA_THIS s.graphics_ctrl.graphics_alpha)
return;
/* skip screen update when vga/video is disabled or the sequencer is in reset mode */
if (!BX_VGA_THIS s.vga_enabled || !BX_VGA_THIS s.attribute_ctrl.video_enabled
|| !BX_VGA_THIS s.sequencer.reset2 || !BX_VGA_THIS s.sequencer.reset1
|| (BX_VGA_THIS s.sequencer.reg1 & 0x20))
return;
/* skip screen update if the vertical retrace is in progress
(using 72 Hz vertical frequency) */
if ((bx_virt_timer.time_usec(BX_VGA_THIS vsync_realtime) % 13888) < 70)
return;
if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {
// specific VBE code display update code
unsigned pitch;
unsigned xc, yc, xti, yti;
unsigned r, c, w, h;
int i;
unsigned long red, green, blue, colour;
Bit8u * vid_ptr, * vid_ptr2;
Bit8u * tile_ptr, * tile_ptr2;
bx_svga_tileinfo_t info;
Bit8u dac_size = BX_VGA_THIS vbe.dac_8bit ? 8 : 6;
iWidth=BX_VGA_THIS vbe.xres;
iHeight=BX_VGA_THIS vbe.yres;
pitch = BX_VGA_THIS s.line_offset;
Bit8u *disp_ptr = &BX_VGA_THIS s.memory[BX_VGA_THIS vbe.virtual_start];
if (bx_gui->graphics_tile_info_common(&info)) {
if (info.snapshot_mode) {
vid_ptr = disp_ptr;
tile_ptr = bx_gui->get_snapshot_buffer();
if (tile_ptr != NULL) {
for (yc = 0; yc < iHeight; yc++) {
memcpy(tile_ptr, vid_ptr, info.pitch);
vid_ptr += pitch;
tile_ptr += info.pitch;
}
}
} else if (info.is_indexed) {
switch (BX_VGA_THIS vbe.bpp) {
case 4:
case 15:
case 16:
case 24:
case 32:
BX_ERROR(("current guest pixel format is unsupported on indexed colour host displays"));
break;
case 8:
for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
if (GET_TILE_UPDATED (xti, yti)) {
vid_ptr = disp_ptr + (yc * pitch + xc);
tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
for (r=0; r<h; r++) {
vid_ptr2 = vid_ptr;
tile_ptr2 = tile_ptr;
for (c=0; c<w; c++) {
colour = 0;
for (i=0; i<(int)BX_VGA_THIS vbe.bpp; i+=8) {
colour |= *(vid_ptr2++) << i;
}
if (info.is_little_endian) {
for (i=0; i<info.bpp; i+=8) {
*(tile_ptr2++) = (Bit8u)(colour >> i);
}
} else {
for (i=info.bpp-8; i>-8; i-=8) {
*(tile_ptr2++) = (Bit8u)(colour >> i);
}
}
}
vid_ptr += pitch;
tile_ptr += info.pitch;
}
bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
}
}
}
break;
}
} else {
switch (BX_VGA_THIS vbe.bpp) {
case 4:
BX_ERROR(("cannot draw 4bpp SVGA"));
break;
case 8:
for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
if (GET_TILE_UPDATED (xti, yti)) {
vid_ptr = disp_ptr + (yc * pitch + xc);
tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
for (r=0; r<h; r++) {
vid_ptr2 = vid_ptr;
tile_ptr2 = tile_ptr;
for (c=0; c<w; c++) {
colour = *(vid_ptr2++);
colour = MAKE_COLOUR(
BX_VGA_THIS s.pel.data[colour].red, dac_size, info.red_shift, info.red_mask,
BX_VGA_THIS s.pel.data[colour].green, dac_size, info.green_shift, info.green_mask,
BX_VGA_THIS s.pel.data[colour].blue, dac_size, info.blue_shift, info.blue_mask);
if (info.is_little_endian) {
for (i=0; i<info.bpp; i+=8) {
*(tile_ptr2++) = (Bit8u)(colour >> i);
}
} else {
for (i=info.bpp-8; i>-8; i-=8) {
*(tile_ptr2++) = (Bit8u)(colour >> i);
}
}
}
vid_ptr += pitch;
tile_ptr += info.pitch;
}
bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
}
}
}
break;
case 15:
for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
if (GET_TILE_UPDATED (xti, yti)) {
vid_ptr = disp_ptr + (yc * pitch + (xc<<1));
tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
for (r=0; r<h; r++) {
vid_ptr2 = vid_ptr;
tile_ptr2 = tile_ptr;
for (c=0; c<w; c++) {
colour = *(vid_ptr2++);
colour |= *(vid_ptr2++) << 8;
colour = MAKE_COLOUR(
colour & 0x001f, 5, info.blue_shift, info.blue_mask,
colour & 0x03e0, 10, info.green_shift, info.green_mask,
colour & 0x7c00, 15, info.red_shift, info.red_mask);
if (info.is_little_endian) {
for (i=0; i<info.bpp; i+=8) {
*(tile_ptr2++) = (Bit8u)(colour >> i);
}
} else {
for (i=info.bpp-8; i>-8; i-=8) {
*(tile_ptr2++) = (Bit8u)(colour >> i);
}
}
}
vid_ptr += pitch;
tile_ptr += info.pitch;
}
bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
}
}
}
break;
case 16:
for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
if (GET_TILE_UPDATED (xti, yti)) {
vid_ptr = disp_ptr + (yc * pitch + (xc<<1));
tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
for (r=0; r<h; r++) {
vid_ptr2 = vid_ptr;
tile_ptr2 = tile_ptr;
for (c=0; c<w; c++) {
colour = *(vid_ptr2++);
colour |= *(vid_ptr2++) << 8;
colour = MAKE_COLOUR(
colour & 0x001f, 5, info.blue_shift, info.blue_mask,
colour & 0x07e0, 11, info.green_shift, info.green_mask,
colour & 0xf800, 16, info.red_shift, info.red_mask);
if (info.is_little_endian) {
for (i=0; i<info.bpp; i+=8) {
*(tile_ptr2++) = (Bit8u)(colour >> i);
}
} else {
for (i=info.bpp-8; i>-8; i-=8) {
*(tile_ptr2++) = (Bit8u)(colour >> i);
}
}
}
vid_ptr += pitch;
tile_ptr += info.pitch;
}
bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
}
}
}
break;
case 24:
for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
if (GET_TILE_UPDATED (xti, yti)) {
vid_ptr = disp_ptr + (yc * pitch + 3*xc);
tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
for (r=0; r<h; r++) {
vid_ptr2 = vid_ptr;
tile_ptr2 = tile_ptr;
for (c=0; c<w; c++) {
blue = *(vid_ptr2++);
green = *(vid_ptr2++);
red = *(vid_ptr2++);
colour = MAKE_COLOUR(
red, 8, info.red_shift, info.red_mask,
green, 8, info.green_shift, info.green_mask,
blue, 8, info.blue_shift, info.blue_mask);
if (info.is_little_endian) {
for (i=0; i<info.bpp; i+=8) {
*(tile_ptr2++) = (Bit8u)(colour >> i);
}
} else {
for (i=info.bpp-8; i>-8; i-=8) {
*(tile_ptr2++) = (Bit8u)(colour >> i);
}
}
}
vid_ptr += pitch;
tile_ptr += info.pitch;
}
bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
}
}
}
break;
case 32:
for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
if (GET_TILE_UPDATED (xti, yti)) {
vid_ptr = disp_ptr + (yc * pitch + (xc<<2));
tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
for (r=0; r<h; r++) {
vid_ptr2 = vid_ptr;
tile_ptr2 = tile_ptr;
for (c=0; c<w; c++) {
blue = *(vid_ptr2++);
green = *(vid_ptr2++);
red = *(vid_ptr2++);
vid_ptr2++;
colour = MAKE_COLOUR(
red, 8, info.red_shift, info.red_mask,
green, 8, info.green_shift, info.green_mask,
blue, 8, info.blue_shift, info.blue_mask);
if (info.is_little_endian) {
for (i=0; i<info.bpp; i+=8) {
*(tile_ptr2++) = (Bit8u)(colour >> i);
}
} else {
for (i=info.bpp-8; i>-8; i-=8) {
*(tile_ptr2++) = (Bit8u)(colour >> i);
}
}
}
vid_ptr += pitch;
tile_ptr += info.pitch;
}
bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
}
}
}
break;
}
}
BX_VGA_THIS s.last_xres = iWidth;
BX_VGA_THIS s.last_yres = iHeight;
BX_VGA_THIS s.vga_mem_updated = 0;
} else {
BX_PANIC(("cannot get svga tile info"));
}
} else {
unsigned r, c, x, y;
unsigned xc, yc, xti, yti;
Bit8u *plane[4];
BX_VGA_THIS determine_screen_dimensions(&iHeight, &iWidth);
if ((iWidth != BX_VGA_THIS s.last_xres) || (iHeight != BX_VGA_THIS s.last_yres) ||
(BX_VGA_THIS s.last_bpp > 8)) {
bx_gui->dimension_update(iWidth, iHeight);
BX_VGA_THIS s.last_xres = iWidth;
BX_VGA_THIS s.last_yres = iHeight;
BX_VGA_THIS s.last_bpp = 8;
}
plane[0] = &BX_VGA_THIS s.memory[0<<VBE_DISPI_4BPP_PLANE_SHIFT];
plane[1] = &BX_VGA_THIS s.memory[1<<VBE_DISPI_4BPP_PLANE_SHIFT];
plane[2] = &BX_VGA_THIS s.memory[2<<VBE_DISPI_4BPP_PLANE_SHIFT];
plane[3] = &BX_VGA_THIS s.memory[3<<VBE_DISPI_4BPP_PLANE_SHIFT];
for (yc=0, yti=0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
for (xc=0, xti=0; xc<iWidth; xc+=X_TILESIZE, xti++) {
if (GET_TILE_UPDATED (xti, yti)) {
for (r=0; r<Y_TILESIZE; r++) {
y = yc + r;
if (BX_VGA_THIS s.y_doublescan) y >>= 1;
for (c=0; c<X_TILESIZE; c++) {
x = xc + c;
BX_VGA_THIS s.tile[r*X_TILESIZE + c] =
BX_VGA_THIS get_vga_pixel(x, y, BX_VGA_THIS vbe.virtual_start, 0xffff, 0, plane);
}
}
SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
bx_gui->graphics_tile_update_common(BX_VGA_THIS s.tile, xc, yc);
}
}
}
}
} else {
BX_VGA_THIS bx_vgacore_c::update();
}
}
bx_bool bx_vga_c::mem_read_handler(bx_phy_address addr, unsigned len, void *data, void *param)
{
Bit8u *data_ptr;
#ifdef BX_LITTLE_ENDIAN
data_ptr = (Bit8u *) data;
#else // BX_BIG_ENDIAN
data_ptr = (Bit8u *) data + (len - 1);
#endif
for (unsigned i = 0; i < len; i++) {
*data_ptr = theVga->mem_read(addr);
addr++;
#ifdef BX_LITTLE_ENDIAN
data_ptr++;
#else // BX_BIG_ENDIAN
data_ptr--;
#endif
}
return 1;
}
Bit8u bx_vga_c::mem_read(bx_phy_address addr)
{
#if BX_SUPPORT_PCI
if ((BX_VGA_THIS pci_enabled) && (BX_VGA_THIS pci_rom_size > 0)) {
Bit32u mask = (BX_VGA_THIS pci_rom_size - 1);
if ((addr & ~mask) == BX_VGA_THIS pci_rom_address) {
if (BX_VGA_THIS pci_conf[0x30] & 0x01) {
return BX_VGA_THIS pci_rom[addr & mask];
} else {
return 0xff;
}
}
}
#endif
// if in a vbe enabled mode, read from the vbe_memory
if ((BX_VGA_THIS vbe.enabled) && (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4)) {
return vbe_mem_read(addr);
} else if ((BX_VGA_THIS vbe.base_address != 0) && (addr >= BX_VGA_THIS vbe.base_address)) {
return 0xff;
}
return bx_vgacore_c::mem_read(addr);
}
bx_bool bx_vga_c::mem_write_handler(bx_phy_address addr, unsigned len, void *data, void *param)
{
Bit8u *data_ptr;
#ifdef BX_LITTLE_ENDIAN
data_ptr = (Bit8u *) data;
#else // BX_BIG_ENDIAN
data_ptr = (Bit8u *) data + (len - 1);
#endif
for (unsigned i = 0; i < len; i++) {
theVga->mem_write(addr, *data_ptr);
addr++;
#ifdef BX_LITTLE_ENDIAN
data_ptr++;
#else // BX_BIG_ENDIAN
data_ptr--;
#endif
}
return 1;
}
void bx_vga_c::mem_write(bx_phy_address addr, Bit8u value)
{
// if in a vbe enabled mode, write to the vbe_memory
if ((BX_VGA_THIS vbe.enabled) && (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4)) {
vbe_mem_write(addr, value);
return;
} else if ((BX_VGA_THIS vbe.base_address != 0) && (addr >= BX_VGA_THIS vbe.base_address)) {
return;
}
bx_vgacore_c::mem_write(addr, value);
}
void bx_vga_c::redraw_area(unsigned x0, unsigned y0, unsigned width,
unsigned height)
{
unsigned xti, yti, xt0, xt1, yt0, yt1, xmax, ymax;
if (BX_VGA_THIS vbe.enabled) {
BX_VGA_THIS s.vga_mem_updated = 1;
xmax = BX_VGA_THIS vbe.xres;
ymax = BX_VGA_THIS vbe.yres;
xt0 = x0 / X_TILESIZE;
yt0 = y0 / Y_TILESIZE;
if (x0 < xmax) {
xt1 = (x0 + width - 1) / X_TILESIZE;
} else {
xt1 = (xmax - 1) / X_TILESIZE;
}
if (y0 < ymax) {
yt1 = (y0 + height - 1) / Y_TILESIZE;
} else {
yt1 = (ymax - 1) / Y_TILESIZE;
}
for (yti=yt0; yti<=yt1; yti++) {
for (xti=xt0; xti<=xt1; xti++) {
SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 1);
}
}
} else {
bx_vgacore_c::redraw_area(x0, y0, width, height);
}
}
#if BX_SUPPORT_PCI
void bx_vga_c::pci_bar_change_notify(void)
{
BX_VGA_THIS vbe.base_address = pci_bar[0].addr;
}
#endif
Bit8u BX_CPP_AttrRegparmN(1)
bx_vga_c::vbe_mem_read(bx_phy_address addr)
{
Bit32u offset;
if (addr >= BX_VGA_THIS vbe.base_address) {
// LFB read
offset = (Bit32u)(addr - BX_VGA_THIS vbe.base_address);
} else {
// banked mode read
offset = (Bit32u)(BX_VGA_THIS vbe.bank*65536 + addr - 0xA0000);
}
// check for out of memory read
if (offset > VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES)
return 0;
return (BX_VGA_THIS s.memory[offset]);
}
void BX_CPP_AttrRegparmN(2)
bx_vga_c::vbe_mem_write(bx_phy_address addr, Bit8u value)
{
Bit32u offset;
unsigned x_tileno, y_tileno;
if (addr >= BX_VGA_THIS vbe.base_address) {
// LFB write
offset = (Bit32u)(addr - BX_VGA_THIS vbe.base_address);
} else {
// banked mode write
offset = (Bit32u)(BX_VGA_THIS vbe.bank*65536 + (addr - 0xA0000));
}
// check for out of memory write
if (offset < VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES) {
BX_VGA_THIS s.memory[offset] = value;
} else {
// make sure we don't flood the logfile
static int count=0;
if (count<100) {
count ++;
BX_INFO(("VBE_mem_write out of video memory write at %x",offset));
}
}
offset -= BX_VGA_THIS vbe.virtual_start;
// only update the UI when writing 'onscreen'
if (offset < BX_VGA_THIS vbe.visible_screen_size) {
y_tileno = ((offset / BX_VGA_THIS vbe.bpp_multiplier) / BX_VGA_THIS vbe.virtual_xres) / Y_TILESIZE;
x_tileno = ((offset / BX_VGA_THIS vbe.bpp_multiplier) % BX_VGA_THIS vbe.virtual_xres) / X_TILESIZE;
if ((y_tileno < BX_VGA_THIS s.num_y_tiles) && (x_tileno < BX_VGA_THIS s.num_x_tiles))
{
BX_VGA_THIS s.vga_mem_updated = 1;
SET_TILE_UPDATED(BX_VGA_THIS, x_tileno, y_tileno, 1);
}
}
}
Bit32u bx_vga_c::vbe_read_handler(void *this_ptr, Bit32u address, unsigned io_len)
{
#if BX_USE_VGA_SMF == 0
bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
return class_ptr->vbe_read(address, io_len);
}
Bit32u bx_vga_c::vbe_read(Bit32u address, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // BX_USE_VGA_SMF == 0
Bit16u retval = 0;
// BX_INFO(("VBE_read %x (len %x)", address, io_len));
if (address==VBE_DISPI_IOPORT_INDEX)
{
// index register
return (Bit32u) BX_VGA_THIS vbe.curindex;
}
else
{
// data register read
switch (BX_VGA_THIS vbe.curindex)
{
case VBE_DISPI_INDEX_ID: // Display Interface ID check
return BX_VGA_THIS vbe.cur_dispi;
case VBE_DISPI_INDEX_XRES: // x resolution
if (BX_VGA_THIS vbe.get_capabilities) {
return BX_VGA_THIS vbe.max_xres;
} else {
return BX_VGA_THIS vbe.xres;
}
case VBE_DISPI_INDEX_YRES: // y resolution
if (BX_VGA_THIS vbe.get_capabilities) {
return BX_VGA_THIS vbe.max_yres;
} else {
return BX_VGA_THIS vbe.yres;
}
case VBE_DISPI_INDEX_BPP: // bpp
if (BX_VGA_THIS vbe.get_capabilities) {
return BX_VGA_THIS vbe.max_bpp;
} else {
return BX_VGA_THIS vbe.bpp;
}
case VBE_DISPI_INDEX_ENABLE: // vbe enabled
retval = BX_VGA_THIS vbe.enabled;
if (BX_VGA_THIS vbe.get_capabilities)
retval |= VBE_DISPI_GETCAPS;
if (BX_VGA_THIS vbe.dac_8bit)
retval |= VBE_DISPI_8BIT_DAC;
return retval;
case VBE_DISPI_INDEX_BANK: // current bank
return BX_VGA_THIS vbe.bank;
case VBE_DISPI_INDEX_X_OFFSET:
return BX_VGA_THIS vbe.offset_x;
case VBE_DISPI_INDEX_Y_OFFSET:
return BX_VGA_THIS vbe.offset_y;
case VBE_DISPI_INDEX_VIRT_WIDTH:
return BX_VGA_THIS vbe.virtual_xres;
case VBE_DISPI_INDEX_VIRT_HEIGHT:
return BX_VGA_THIS vbe.virtual_yres;
case VBE_DISPI_INDEX_VIDEO_MEMORY_64K:
return (VBE_DISPI_TOTAL_VIDEO_MEMORY_KB >> 6);
case VBE_DISPI_INDEX_DDC:
if (BX_VGA_THIS vbe.ddc_enabled) {
retval = (1 << 7) | BX_VGA_THIS ddc.read();
} else {
retval = 0x000f;
}
break;
default:
BX_ERROR(("VBE unknown data read index 0x%x",BX_VGA_THIS vbe.curindex));
break;
}
}
return retval;
}
void bx_vga_c::vbe_write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
#if BX_USE_VGA_SMF == 0
bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
class_ptr->vbe_write(address, value, io_len);
}
Bit32u bx_vga_c::vbe_write(Bit32u address, Bit32u value, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif
bx_bool new_vbe_8bit_dac;
bx_bool needs_update = 0;
unsigned i;
// BX_INFO(("VBE_write %x = %x (len %x)", address, value, io_len));
switch(address)
{
// index register
case VBE_DISPI_IOPORT_INDEX:
BX_VGA_THIS vbe.curindex = (Bit16u) value;
break;
// data register
// FIXME: maybe do some 'sanity' checks on received data?
case VBE_DISPI_IOPORT_DATA:
switch (BX_VGA_THIS vbe.curindex)
{
case VBE_DISPI_INDEX_ID: // Display Interface ID check
{
if ((value == VBE_DISPI_ID0) ||
(value == VBE_DISPI_ID1) ||
(value == VBE_DISPI_ID2) ||
(value == VBE_DISPI_ID3) ||
(value == VBE_DISPI_ID4) ||
(value == VBE_DISPI_ID5))
{
// allow backwards compatible with previous dispi bioses
BX_VGA_THIS vbe.cur_dispi=value;
}
else
{
BX_PANIC(("VBE unknown Display Interface %x", value));
}
// make sure we don't flood the logfile
static int count=0;
if (count < 100)
{
count++;
BX_INFO(("VBE known Display Interface %x", value));
}
} break;
case VBE_DISPI_INDEX_XRES: // set xres
{
// check that we don't set xres during vbe enabled
if (!BX_VGA_THIS vbe.enabled)
{
// check for within max xres range
if (value <= VBE_DISPI_MAX_XRES)
{
BX_VGA_THIS vbe.xres=(Bit16u) value;
BX_INFO(("VBE set xres (%d)", value));
}
else
{
BX_INFO(("VBE set xres more then max xres (%d)", value));
}
}
else
{
BX_ERROR(("VBE set xres during vbe enabled!"));
}
} break;
case VBE_DISPI_INDEX_YRES: // set yres
{
// check that we don't set yres during vbe enabled
if (!BX_VGA_THIS vbe.enabled)
{
// check for within max yres range
if (value <= VBE_DISPI_MAX_YRES)
{
BX_VGA_THIS vbe.yres=(Bit16u) value;
BX_INFO(("VBE set yres (%d)", value));
}
else
{
BX_INFO(("VBE set yres more then max yres (%d)", value));
}
}
else
{
BX_ERROR(("VBE set yres during vbe enabled!"));
}
} break;
case VBE_DISPI_INDEX_BPP: // set bpp
{
// check that we don't set bpp during vbe enabled
if (!BX_VGA_THIS vbe.enabled)
{
// for backward compatiblity
if (value == 0) value = VBE_DISPI_BPP_8;
// check for correct bpp range
if ((value == VBE_DISPI_BPP_4) || (value == VBE_DISPI_BPP_8) || (value == VBE_DISPI_BPP_15) ||
(value == VBE_DISPI_BPP_16) || (value == VBE_DISPI_BPP_24) || (value == VBE_DISPI_BPP_32))
{
BX_VGA_THIS vbe.bpp=(Bit16u) value;
BX_INFO(("VBE set bpp (%d)", value));
}
else
{
BX_ERROR(("VBE set bpp with unknown bpp (%d)", value));
}
}
else
{
BX_ERROR(("VBE set bpp during vbe enabled!"));
}
} break;
case VBE_DISPI_INDEX_BANK: // set bank
{
value=value & 0xff; // FIXME lobyte = vbe bank A?
unsigned divider = (BX_VGA_THIS vbe.bpp!=VBE_DISPI_BPP_4)?64:256;
// check for max bank nr
if (value < (VBE_DISPI_TOTAL_VIDEO_MEMORY_KB / divider)) {
BX_DEBUG(("VBE set bank to %d", value));
BX_VGA_THIS vbe.bank = value;
BX_VGA_THIS s.plane_offset = (BX_VGA_THIS vbe.bank << 16);
} else {
BX_ERROR(("VBE set invalid bank (%d)", value));
}
} break;
case VBE_DISPI_INDEX_ENABLE: // enable video
{
if ((value & VBE_DISPI_ENABLED) && !BX_VGA_THIS vbe.enabled)
{
unsigned depth=0;
// setup virtual resolution to be the same as current reso
BX_VGA_THIS vbe.virtual_yres=BX_VGA_THIS vbe.yres;
BX_VGA_THIS vbe.virtual_xres=BX_VGA_THIS vbe.xres;
// reset offset
BX_VGA_THIS vbe.offset_x=0;
BX_VGA_THIS vbe.offset_y=0;
BX_VGA_THIS vbe.virtual_start=0;
switch((BX_VGA_THIS vbe.bpp))
{
// Default pixel sizes
case VBE_DISPI_BPP_8:
BX_VGA_THIS vbe.bpp_multiplier = 1;
BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres;
depth=8;
break;
case VBE_DISPI_BPP_4:
BX_VGA_THIS vbe.bpp_multiplier = 1;
BX_VGA_THIS s.line_offset = (BX_VGA_THIS vbe.virtual_xres >> 3);
depth=4;
break;
case VBE_DISPI_BPP_15:
BX_VGA_THIS vbe.bpp_multiplier = 2;
BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres * 2;
depth=15;
break;
case VBE_DISPI_BPP_16:
BX_VGA_THIS vbe.bpp_multiplier = 2;
BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres * 2;
depth=16;
break;
case VBE_DISPI_BPP_24:
BX_VGA_THIS vbe.bpp_multiplier = 3;
BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres * 3;
depth=24;
break;
case VBE_DISPI_BPP_32:
BX_VGA_THIS vbe.bpp_multiplier = 4;
BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres << 2;
depth=32;
break;
}
BX_VGA_THIS vbe.visible_screen_size = BX_VGA_THIS s.line_offset * BX_VGA_THIS vbe.yres;
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));
if (depth > 4) {
if ((value & VBE_DISPI_NOCLEARMEM) == 0) {
memset(BX_VGA_THIS s.memory, 0, BX_VGA_THIS vbe.visible_screen_size);
}
bx_gui->dimension_update(BX_VGA_THIS vbe.xres, BX_VGA_THIS vbe.yres, 0, 0, depth);
BX_VGA_THIS s.last_bpp = depth;
BX_VGA_THIS s.last_fh = 0;
} else {
BX_VGA_THIS s.plane_shift = VBE_DISPI_4BPP_PLANE_SHIFT;
BX_VGA_THIS s.plane_offset = (BX_VGA_THIS vbe.bank << 16);
}
} else if (((value & VBE_DISPI_ENABLED) == 0) && BX_VGA_THIS vbe.enabled) {
BX_INFO(("VBE disabling"));
BX_VGA_THIS s.plane_shift = 16;
BX_VGA_THIS s.plane_offset = 0;
}
BX_VGA_THIS vbe.enabled = (bx_bool)((value & VBE_DISPI_ENABLED) != 0);
BX_VGA_THIS vbe.get_capabilities = (bx_bool)((value & VBE_DISPI_GETCAPS) != 0);
new_vbe_8bit_dac = (bx_bool)((value & VBE_DISPI_8BIT_DAC) != 0);
if (new_vbe_8bit_dac != BX_VGA_THIS vbe.dac_8bit) {
if (new_vbe_8bit_dac) {
for (i=0; i<256; i++) {
BX_VGA_THIS s.pel.data[i].red <<= 2;
BX_VGA_THIS s.pel.data[i].green <<= 2;
BX_VGA_THIS s.pel.data[i].blue <<= 2;
}
BX_INFO(("DAC in 8 bit mode"));
} else {
for (i=0; i<256; i++) {
BX_VGA_THIS s.pel.data[i].red >>= 2;
BX_VGA_THIS s.pel.data[i].green >>= 2;
BX_VGA_THIS s.pel.data[i].blue >>= 2;
}
BX_INFO(("DAC in standard mode"));
}
BX_VGA_THIS vbe.dac_8bit = new_vbe_8bit_dac;
BX_VGA_THIS s.dac_shift = new_vbe_8bit_dac ? 0 : 2;
needs_update = 1;
}
} break;
case VBE_DISPI_INDEX_X_OFFSET:
{
BX_DEBUG(("VBE offset x %d", value));
BX_VGA_THIS vbe.offset_x=(Bit16u)value;
BX_VGA_THIS vbe.virtual_start = BX_VGA_THIS vbe.offset_y * BX_VGA_THIS s.line_offset;
if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {
BX_VGA_THIS vbe.virtual_start += (BX_VGA_THIS vbe.offset_x * BX_VGA_THIS vbe.bpp_multiplier);
} else {
BX_VGA_THIS vbe.virtual_start += (BX_VGA_THIS vbe.offset_x >> 3);
}
needs_update = 1;
} break;
case VBE_DISPI_INDEX_Y_OFFSET:
{
BX_DEBUG(("VBE offset y %d", value));
Bit32u new_screen_start = value * BX_VGA_THIS s.line_offset;
if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {
if ((new_screen_start + BX_VGA_THIS vbe.visible_screen_size) > VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES)
{
BX_PANIC(("VBE offset y %d out of bounds", value));
break;
}
new_screen_start += (BX_VGA_THIS vbe.offset_x * BX_VGA_THIS vbe.bpp_multiplier);
} else {
if ((new_screen_start + BX_VGA_THIS vbe.visible_screen_size) > (VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES / 4))
{
BX_PANIC(("VBE offset y %d out of bounds", value));
break;
}
new_screen_start += (BX_VGA_THIS vbe.offset_x >> 3);
}
BX_VGA_THIS vbe.virtual_start = new_screen_start;
BX_VGA_THIS vbe.offset_y = (Bit16u)value;
needs_update = 1;
} break;
case VBE_DISPI_INDEX_VIRT_WIDTH:
{
BX_INFO(("VBE requested virtual width %d", value));
// calculate virtual width & height dimensions
// req:
// virt_width > xres
// virt_height >=yres
// virt_width*virt_height < MAX_VIDEO_MEMORY
// basically 2 situations
// situation 1:
// MAX_VIDEO_MEMORY / virt_width >= yres
// adjust result height
// else
// adjust result width based upon virt_height=yres
Bit16u new_width=value;
Bit16u new_height;
if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {
new_height=(VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES / BX_VGA_THIS vbe.bpp_multiplier) / new_width;
} else {
new_height=(VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES * 2) / new_width;
}
if (new_height >=BX_VGA_THIS vbe.yres)
{
// we have a decent virtual width & new_height
BX_INFO(("VBE decent virtual height %d",new_height));
}
else
{
// no decent virtual height: adjust width & height
new_height=BX_VGA_THIS vbe.yres;
if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {
new_width=(VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES / BX_VGA_THIS vbe.bpp_multiplier) / new_height;
} else {
new_width=(VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES * 2) / new_height;
}
BX_INFO(("VBE recalc virtual width %d height %d",new_width, new_height));
}
BX_VGA_THIS vbe.virtual_xres=new_width;
BX_VGA_THIS vbe.virtual_yres=new_height;
if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {
BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres * BX_VGA_THIS vbe.bpp_multiplier;
} else {
BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres >> 3;
}
BX_VGA_THIS vbe.visible_screen_size = BX_VGA_THIS s.line_offset * BX_VGA_THIS vbe.yres;
} break;
case VBE_DISPI_INDEX_VIRT_HEIGHT:
BX_ERROR(("VBE: write to virtual height register ignored"));
break;
case VBE_DISPI_INDEX_DDC:
if ((value >> 7) & 1) {
BX_VGA_THIS vbe.ddc_enabled = 1;
BX_VGA_THIS ddc.write(value & 1, (value >> 1) & 1);
} else {
BX_VGA_THIS vbe.ddc_enabled = 0;
}
break;
default:
BX_ERROR(("VBE: write unsupported register at index 0x%x",BX_VGA_THIS vbe.curindex));
break;
}
if (needs_update) {
BX_VGA_THIS s.vga_mem_updated = 1;
for (unsigned xti = 0; xti < BX_VGA_THIS s.num_x_tiles; xti++) {
for (unsigned yti = 0; yti < BX_VGA_THIS s.num_y_tiles; yti++) {
SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 1);
}
}
}
break;
} // end switch address
}
#if BX_SUPPORT_PCI
// static pci configuration space write callback handler
void bx_vga_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
{
if ((address >= 0x14) && (address < 0x30))
return;
BX_DEBUG_PCI_WRITE(address, value, io_len);
for (unsigned i = 0; i < io_len; i++) {
unsigned write_addr = address + i;
// Bit8u old_value = BX_VGA_THIS pci_conf[write_addr];
Bit8u new_value = (Bit8u)(value & 0xff);
switch (write_addr) {
case 0x04: // disallowing write to command
case 0x06: // disallowing write to status lo-byte (is that expected?)
break;
default:
BX_VGA_THIS pci_conf[write_addr] = new_value;
}
value >>= 8;
}
}
#endif
#if BX_DEBUGGER
void bx_vga_c::debug_dump(int argc, char **argv)
{
if (BX_VGA_THIS vbe.enabled) {
dbg_printf("Bochs VGA/VBE adapter\n\n");
dbg_printf("current mode : %u x %u x %u\n", BX_VGA_THIS vbe.xres,
BX_VGA_THIS vbe.yres, BX_VGA_THIS vbe.bpp);
} else {
bx_vgacore_c::debug_dump();
}
if (argc > 0) {
dbg_printf("\nAdditional options not supported\n");
}
}
#endif