Bochs/bochs/iodev/vga.cc
Volker Ruppert aad2d89c83 - rewrite of the optional plugin control feature. Now the plugins are loaded
directly while parsing the bochsrc or command line. If plugin support is enabled,
  the option could load all optional plugins, not only the ones supported before.
  NOTE #1: The old option had all plugins enabled by default and gave the user
           a chance to diable them. Now the plugins are only loaded if they
           appear in the config line and they are set to "1".
  NOTE #2: Loading a plugin that is controlled by a bochsrc option is possible,
           but it currently leads to a panic, since the load command is still
           present in devices.cc.
  NOTE #3: The plugin init code creates the device object and registers the
           optional plugin device. As an option, it can create config parameters
           and register an option parser. The device init, register state and
           reset is still handled in devices.cc, but in the order the devices
           have been loaded with the plugin control.
  NOTE #4: If plugin support is disabled, the plugin control only accepts the
           devices listed in plugin.cc.
- plugin init of core plugins now fails if they are not loaded with the expected
  type. For core plugins the load order is important and they cannot be handled
  with the chained devices list (used for optional and user plugins).
- some additions for calling config.cc functions from a plugin device
2011-12-25 08:52:34 +00:00

3537 lines
131 KiB
C++

/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2011 The Bochs Project
//
// 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
//
/////////////////////////////////////////////////////////////////////////
// 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 "param_names.h"
#include "vga.h"
#include "virt_timer.h"
#define LOG_THIS theVga->
#define VGA_TRACE_FEATURE
// Only reference the array if the tile numbers are within the bounds
// of the array. If out of bounds, do nothing.
#define SET_TILE_UPDATED(xtile, ytile, value) \
do { \
if (((xtile) < BX_NUM_X_TILES) && ((ytile) < BX_NUM_Y_TILES)) \
BX_VGA_THIS s.vga_tile_updated[(xtile)][(ytile)] = value; \
} while (0)
// Only reference the array if the tile numbers are within the bounds
// of the array. If out of bounds, return 0.
#define GET_TILE_UPDATED(xtile,ytile) \
((((xtile) < BX_NUM_X_TILES) && ((ytile) < BX_NUM_Y_TILES))? \
BX_VGA_THIS s.vga_tile_updated[(xtile)][(ytile)] \
: 0)
static const Bit16u charmap_offset[8] = {
0x0000, 0x4000, 0x8000, 0xc000,
0x2000, 0x6000, 0xa000, 0xe000
};
static const Bit8u ccdat[16][4] = {
{ 0x00, 0x00, 0x00, 0x00 },
{ 0xff, 0x00, 0x00, 0x00 },
{ 0x00, 0xff, 0x00, 0x00 },
{ 0xff, 0xff, 0x00, 0x00 },
{ 0x00, 0x00, 0xff, 0x00 },
{ 0xff, 0x00, 0xff, 0x00 },
{ 0x00, 0xff, 0xff, 0x00 },
{ 0xff, 0xff, 0xff, 0x00 },
{ 0x00, 0x00, 0x00, 0xff },
{ 0xff, 0x00, 0x00, 0xff },
{ 0x00, 0xff, 0x00, 0xff },
{ 0xff, 0xff, 0x00, 0xff },
{ 0x00, 0x00, 0xff, 0xff },
{ 0xff, 0x00, 0xff, 0xff },
{ 0x00, 0xff, 0xff, 0xff },
{ 0xff, 0xff, 0xff, 0xff },
};
bx_vga_c *theVga = NULL;
unsigned old_MSL = 0;
#if BX_SUPPORT_CLGD54XX
void bx_vga_set_smf_pointer(bx_vga_c *theVga_ptr)
{
theVga = theVga_ptr;
}
#else // BX_SUPPORT_CLGD54XX
int libvga_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
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 libvga_LTX_plugin_fini(void)
{
delete theVga;
}
#endif // BX_SUPPORT_CLGD54XX
bx_vga_c::bx_vga_c()
{
put("VGA");
s.vga_mem_updated = 0;
s.x_tilesize = X_TILESIZE;
s.y_tilesize = Y_TILESIZE;
timer_id = BX_NULL_TIMER_HANDLE;
s.memory = NULL;
}
bx_vga_c::~bx_vga_c()
{
if (s.memory != NULL) {
delete [] s.memory;
s.memory = NULL;
}
SIM->get_param_num(BXPN_VGA_UPDATE_FREQUENCY)->set_handler(NULL);
BX_DEBUG(("Exit"));
}
void bx_vga_c::init(void)
{
BX_VGA_THIS extension_init = 0;
BX_VGA_THIS pci_enabled = 0;
BX_VGA_THIS init_standard_vga();
BX_VGA_THIS init_vga_extension();
char *strptr = SIM->get_param_string(BXPN_VGA_EXTENSION)->getptr();
if (!BX_VGA_THIS extension_init &&
(strlen(strptr) > 0) && strcmp(strptr, "none")) {
BX_PANIC(("unknown display extension: %s", strptr));
}
if (!BX_VGA_THIS pci_enabled) {
BX_MEM(0)->load_ROM(SIM->get_param_string(BXPN_VGA_ROM_PATH)->getptr(), 0xc0000, 1);
}
}
void bx_vga_c::init_standard_vga(void)
{
unsigned i,string_i;
unsigned x,y;
int argc;
char *argv[16];
char *ptr;
char string[512];
char *extname;
size_t len;
// initialize VGA controllers and other internal stuff
BX_VGA_THIS s.vga_enabled = 1;
BX_VGA_THIS s.misc_output.color_emulation = 1;
BX_VGA_THIS s.misc_output.enable_ram = 1;
BX_VGA_THIS s.misc_output.clock_select = 0;
BX_VGA_THIS s.misc_output.select_high_bank = 0;
BX_VGA_THIS s.misc_output.horiz_sync_pol = 1;
BX_VGA_THIS s.misc_output.vert_sync_pol = 1;
BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha = 0;
BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type = 0;
BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics = 1;
BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity = 0;
BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_panning_compat = 0;
BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select = 0;
BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size = 0;
BX_VGA_THIS s.line_offset=80;
BX_VGA_THIS s.line_compare=1023;
BX_VGA_THIS s.vertical_display_end=399;
for (i=0; i<=0x18; i++)
BX_VGA_THIS s.CRTC.reg[i] = 0;
BX_VGA_THIS s.CRTC.address = 0;
BX_VGA_THIS s.CRTC.write_protect = 0;
BX_VGA_THIS s.attribute_ctrl.flip_flop = 0;
BX_VGA_THIS s.attribute_ctrl.address = 0;
BX_VGA_THIS s.attribute_ctrl.video_enabled = 1;
for (i=0; i<16; i++)
BX_VGA_THIS s.attribute_ctrl.palette_reg[i] = 0;
BX_VGA_THIS s.attribute_ctrl.overscan_color = 0;
BX_VGA_THIS s.attribute_ctrl.color_plane_enable = 0x0f;
BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning = 0;
BX_VGA_THIS s.attribute_ctrl.color_select = 0;
for (i=0; i<256; i++) {
BX_VGA_THIS s.pel.data[i].red = 0;
BX_VGA_THIS s.pel.data[i].green = 0;
BX_VGA_THIS s.pel.data[i].blue = 0;
}
BX_VGA_THIS s.pel.write_data_register = 0;
BX_VGA_THIS s.pel.write_data_cycle = 0;
BX_VGA_THIS s.pel.read_data_register = 0;
BX_VGA_THIS s.pel.read_data_cycle = 0;
BX_VGA_THIS s.pel.dac_state = 0x01;
BX_VGA_THIS s.pel.mask = 0xff;
BX_VGA_THIS s.graphics_ctrl.index = 0;
BX_VGA_THIS s.graphics_ctrl.set_reset = 0;
BX_VGA_THIS s.graphics_ctrl.enable_set_reset = 0;
BX_VGA_THIS s.graphics_ctrl.color_compare = 0;
BX_VGA_THIS s.graphics_ctrl.data_rotate = 0;
BX_VGA_THIS s.graphics_ctrl.raster_op = 0;
BX_VGA_THIS s.graphics_ctrl.read_map_select = 0;
BX_VGA_THIS s.graphics_ctrl.write_mode = 0;
BX_VGA_THIS s.graphics_ctrl.read_mode = 0;
BX_VGA_THIS s.graphics_ctrl.odd_even = 0;
BX_VGA_THIS s.graphics_ctrl.chain_odd_even = 0;
BX_VGA_THIS s.graphics_ctrl.shift_reg = 0;
BX_VGA_THIS s.graphics_ctrl.graphics_alpha = 0;
BX_VGA_THIS s.graphics_ctrl.memory_mapping = 2; // monochrome text mode
BX_VGA_THIS s.graphics_ctrl.color_dont_care = 0;
BX_VGA_THIS s.graphics_ctrl.bitmask = 0;
for (i=0; i<4; i++) {
BX_VGA_THIS s.graphics_ctrl.latch[i] = 0;
}
BX_VGA_THIS s.sequencer.index = 0;
BX_VGA_THIS s.sequencer.map_mask = 0;
BX_VGA_THIS s.sequencer.reset1 = 1;
BX_VGA_THIS s.sequencer.reset2 = 1;
BX_VGA_THIS s.sequencer.reg1 = 0;
BX_VGA_THIS s.sequencer.char_map_select = 0;
BX_VGA_THIS s.sequencer.extended_mem = 1; // display mem greater than 64K
BX_VGA_THIS s.sequencer.odd_even = 1; // use sequential addressing mode
BX_VGA_THIS s.sequencer.chain_four = 0; // use map mask & read map select
BX_VGA_THIS s.charmap_address = 0;
BX_VGA_THIS s.x_dotclockdiv2 = 0;
BX_VGA_THIS s.y_doublescan = 0;
BX_VGA_THIS s.last_xres = 0;
BX_VGA_THIS s.last_yres = 0;
BX_VGA_THIS s.last_bpp = 8;
BX_VGA_THIS s.vga_mem_updated = 0;
for (y=0; y<480/Y_TILESIZE; y++)
for (x=0; x<640/X_TILESIZE; x++)
SET_TILE_UPDATED (x, y, 0);
// initialize memory, handlers and timer (depending on extension)
extname = SIM->get_param_string(BXPN_VGA_EXTENSION)->getptr();
if ((strlen(extname) == 0) || (!strcmp(extname, "none"))) {
BX_VGA_THIS s.memsize = 0x40000;
if (BX_VGA_THIS s.memory == NULL)
BX_VGA_THIS s.memory = new Bit8u[BX_VGA_THIS s.memsize];
memset(BX_VGA_THIS s.memory, 0, BX_VGA_THIS s.memsize);
}
DEV_register_memory_handlers(theVga, mem_read_handler, mem_write_handler,
0xa0000, 0xbffff);
// video card with BIOS ROM
DEV_cmos_set_reg(0x14, (DEV_cmos_get_reg(0x14) & 0xcf) | 0x00);
// set up display library options and start gui
memset(argv, 0, sizeof(argv));
argc = 1;
argv[0] = (char *)"bochs";
len = strlen(SIM->get_param_string(BXPN_DISPLAYLIB_OPTIONS)->getptr());
if (len > 0) {
char *options = new char[len + 1];
strcpy(options, SIM->get_param_string(BXPN_DISPLAYLIB_OPTIONS)->getptr());
ptr = strtok(options, ",");
while (ptr) {
string_i = 0;
for (i=0; i<strlen(ptr); i++) {
if (!isspace(ptr[i])) string[string_i++] = ptr[i];
}
string[string_i] = '\0';
if (argv[argc] != NULL) {
free(argv[argc]);
argv[argc] = NULL;
}
if (argc < 16) {
argv[argc++] = strdup(string);
} else {
BX_PANIC (("too many parameters, max is 16\n"));
}
ptr = strtok(NULL, ",");
}
delete [] options;
}
bx_gui->init(argc, argv, BX_VGA_THIS s.x_tilesize, BX_VGA_THIS s.y_tilesize);
for (i = 1; i < (unsigned)argc; i++)
{
if (argv[i] != NULL)
{
free(argv[i]);
argv[i] = NULL;
}
}
}
void bx_vga_c::init_vga_extension(void)
{
unsigned addr;
Bit16u max_xres, max_yres, max_bpp;
BX_VGA_THIS init_iohandlers(read_handler, write_handler);
BX_VGA_THIS init_systemtimer(timer_handler, vga_param_handler);
BX_VGA_THIS pci_enabled = DEV_is_pci_device(BX_PLUGIN_PCIVGA);
// The following is for the VBE display extension
BX_VGA_THIS vbe.enabled=0;
BX_VGA_THIS vbe.dac_8bit=0;
BX_VGA_THIS vbe.base_address = 0x0000;
if (!strcmp(SIM->get_param_string(BXPN_VGA_EXTENSION)->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.lfb_enabled=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 extension_init = 1;
BX_INFO(("VBE Bochs Display Extension Enabled"));
}
}
void bx_vga_c::init_iohandlers(bx_read_handler_t f_read, bx_write_handler_t f_write)
{
unsigned addr, i;
Bit8u io_mask[16] = {3, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1};
for (addr=0x03B4; addr<=0x03B5; addr++) {
DEV_register_ioread_handler(this, f_read, addr, "vga video", 1);
DEV_register_iowrite_handler(this, f_write, addr, "vga video", 3);
}
for (addr=0x03BA; addr<=0x03BA; addr++) {
DEV_register_ioread_handler(this, f_read, addr, "vga video", 1);
DEV_register_iowrite_handler(this, f_write, addr, "vga video", 3);
}
i = 0;
for (addr=0x03C0; addr<=0x03CF; addr++) {
DEV_register_ioread_handler(this, f_read, addr, "vga video", io_mask[i++]);
DEV_register_iowrite_handler(this, f_write, addr, "vga video", 3);
}
for (addr=0x03D4; addr<=0x03D5; addr++) {
DEV_register_ioread_handler(this, f_read, addr, "vga video", 3);
DEV_register_iowrite_handler(this, f_write, addr, "vga video", 3);
}
for (addr=0x03DA; addr<=0x03DA; addr++) {
DEV_register_ioread_handler(this, f_read, addr, "vga video", 1);
DEV_register_iowrite_handler(this, f_write, addr, "vga video", 3);
}
}
void bx_vga_c::init_systemtimer(bx_timer_handler_t f_timer, param_event_handler f_param)
{
bx_param_num_c *vga_update_freq = SIM->get_param_num(BXPN_VGA_UPDATE_FREQUENCY);
Bit64u interval = 1000000 / vga_update_freq->get();
BX_INFO(("interval=" FMT_LL "u", interval));
if (BX_VGA_THIS timer_id == BX_NULL_TIMER_HANDLE) {
BX_VGA_THIS timer_id = bx_virt_timer.register_timer(this, f_timer,
(Bit32u)interval, 1, 1, "vga");
vga_update_freq->set_handler(f_param);
vga_update_freq->set_runtime_param(1);
}
if (interval < 300000) {
BX_VGA_THIS s.blink_counter = 300000 / (unsigned)interval;
} else {
BX_VGA_THIS s.blink_counter = 1;
}
}
void bx_vga_c::register_state(void)
{
unsigned i;
char name[6];
bx_list_c *parent, *reg;
parent = SIM->get_bochs_root();
#if BX_SUPPORT_CLGD54XX
if (!strcmp(SIM->get_param_string(BXPN_VGA_EXTENSION)->getptr(), "cirrus")) {
parent = (bx_list_c*)SIM->get_param("svga_cirrus", parent);
}
#endif
bx_list_c *list = new bx_list_c(parent, "vga", "VGA Adapter State", 17);
bx_list_c *misc = new bx_list_c(list, "misc_output", 6);
new bx_shadow_bool_c(misc, "color_emulation", &BX_VGA_THIS s.misc_output.color_emulation);
new bx_shadow_bool_c(misc, "enable_ram", &BX_VGA_THIS s.misc_output.enable_ram);
new bx_shadow_num_c(misc, "clock_select", &BX_VGA_THIS s.misc_output.clock_select);
new bx_shadow_bool_c(misc, "select_high_bank", &BX_VGA_THIS s.misc_output.select_high_bank);
new bx_shadow_bool_c(misc, "horiz_sync_pol", &BX_VGA_THIS s.misc_output.horiz_sync_pol);
new bx_shadow_bool_c(misc, "vert_sync_pol", &BX_VGA_THIS s.misc_output.vert_sync_pol);
bx_list_c *crtc = new bx_list_c(list, "CRTC", 3);
new bx_shadow_num_c(crtc, "address", &BX_VGA_THIS s.CRTC.address, BASE_HEX);
reg = new bx_list_c(crtc, "reg", 0x19);
for (i=0; i<=0x18; i++) {
sprintf(name, "0x%02x", i);
new bx_shadow_num_c(reg, name, &BX_VGA_THIS s.CRTC.reg[i], BASE_HEX);
}
new bx_shadow_bool_c(crtc, "write_protect", &BX_VGA_THIS s.CRTC.write_protect);
bx_list_c *actl = new bx_list_c(list, "attribute_ctrl", 9);
new bx_shadow_bool_c(actl, "flip_flop", &BX_VGA_THIS s.attribute_ctrl.flip_flop);
new bx_shadow_num_c(actl, "address", &BX_VGA_THIS s.attribute_ctrl.address, BASE_HEX);
new bx_shadow_bool_c(actl, "video_enabled", &BX_VGA_THIS s.attribute_ctrl.video_enabled);
reg = new bx_list_c(actl, "palette_reg", 16);
for (i=0; i<16; i++) {
sprintf(name, "0x%02x", i);
new bx_shadow_num_c(reg, name, &BX_VGA_THIS s.attribute_ctrl.palette_reg[i], BASE_HEX);
}
new bx_shadow_num_c(actl, "overscan_color", &BX_VGA_THIS s.attribute_ctrl.overscan_color, BASE_HEX);
new bx_shadow_num_c(actl, "color_plane_enable", &BX_VGA_THIS s.attribute_ctrl.color_plane_enable, BASE_HEX);
new bx_shadow_num_c(actl, "horiz_pel_panning", &BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning, BASE_HEX);
new bx_shadow_num_c(actl, "color_select", &BX_VGA_THIS s.attribute_ctrl.color_select, BASE_HEX);
bx_list_c *mode = new bx_list_c(actl, "mode_ctrl", 7);
new bx_shadow_bool_c(mode, "graphics_alpha", &BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha);
new bx_shadow_bool_c(mode, "display_type", &BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type);
new bx_shadow_bool_c(mode, "enable_line_graphics", &BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics);
new bx_shadow_bool_c(mode, "blink_intensity", &BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity);
new bx_shadow_bool_c(mode, "pixel_panning_compat", &BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_panning_compat);
new bx_shadow_bool_c(mode, "pixel_clock_select", &BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select);
new bx_shadow_bool_c(mode, "internal_palette_size", &BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size);
bx_list_c *pel = new bx_list_c(list, "pel", 6);
new bx_shadow_num_c(pel, "write_data_register", &BX_VGA_THIS s.pel.write_data_register, BASE_HEX);
new bx_shadow_num_c(pel, "write_data_cycle", &BX_VGA_THIS s.pel.write_data_cycle);
new bx_shadow_num_c(pel, "read_data_register", &BX_VGA_THIS s.pel.read_data_register, BASE_HEX);
new bx_shadow_num_c(pel, "read_data_cycle", &BX_VGA_THIS s.pel.read_data_cycle);
new bx_shadow_num_c(pel, "dac_state", &BX_VGA_THIS s.pel.dac_state);
new bx_shadow_num_c(pel, "mask", &BX_VGA_THIS s.pel.mask, BASE_HEX);
new bx_shadow_data_c(list, "pel_data", &BX_VGA_THIS s.pel.data[0].red, sizeof(BX_VGA_THIS s.pel.data));
bx_list_c *gfxc = new bx_list_c(list, "graphics_ctrl", 20);
new bx_shadow_num_c(gfxc, "index", &BX_VGA_THIS s.graphics_ctrl.index);
new bx_shadow_num_c(gfxc, "set_reset", &BX_VGA_THIS s.graphics_ctrl.set_reset);
new bx_shadow_num_c(gfxc, "enable_set_reset", &BX_VGA_THIS s.graphics_ctrl.enable_set_reset);
new bx_shadow_num_c(gfxc, "color_compare", &BX_VGA_THIS s.graphics_ctrl.color_compare);
new bx_shadow_num_c(gfxc, "data_rotate", &BX_VGA_THIS s.graphics_ctrl.data_rotate);
new bx_shadow_num_c(gfxc, "raster_op", &BX_VGA_THIS s.graphics_ctrl.raster_op);
new bx_shadow_num_c(gfxc, "read_map_select", &BX_VGA_THIS s.graphics_ctrl.read_map_select);
new bx_shadow_num_c(gfxc, "write_mode", &BX_VGA_THIS s.graphics_ctrl.write_mode);
new bx_shadow_num_c(gfxc, "read_mode", &BX_VGA_THIS s.graphics_ctrl.read_mode);
new bx_shadow_bool_c(gfxc, "odd_even", &BX_VGA_THIS s.graphics_ctrl.odd_even);
new bx_shadow_bool_c(gfxc, "chain_odd_even", &BX_VGA_THIS s.graphics_ctrl.chain_odd_even);
new bx_shadow_num_c(gfxc, "shift_reg", &BX_VGA_THIS s.graphics_ctrl.shift_reg);
new bx_shadow_bool_c(gfxc, "graphics_alpha", &BX_VGA_THIS s.graphics_ctrl.graphics_alpha);
new bx_shadow_num_c(gfxc, "memory_mapping", &BX_VGA_THIS s.graphics_ctrl.memory_mapping);
new bx_shadow_num_c(gfxc, "color_dont_care", &BX_VGA_THIS s.graphics_ctrl.color_dont_care, BASE_HEX);
new bx_shadow_num_c(gfxc, "bitmask", &BX_VGA_THIS s.graphics_ctrl.bitmask, BASE_HEX);
new bx_shadow_num_c(gfxc, "latch0", &BX_VGA_THIS s.graphics_ctrl.latch[0], BASE_HEX);
new bx_shadow_num_c(gfxc, "latch1", &BX_VGA_THIS s.graphics_ctrl.latch[1], BASE_HEX);
new bx_shadow_num_c(gfxc, "latch2", &BX_VGA_THIS s.graphics_ctrl.latch[2], BASE_HEX);
new bx_shadow_num_c(gfxc, "latch3", &BX_VGA_THIS s.graphics_ctrl.latch[3], BASE_HEX);
bx_list_c *sequ = new bx_list_c(list, "sequencer", 13);
new bx_shadow_num_c(sequ, "index", &BX_VGA_THIS s.sequencer.index);
new bx_shadow_num_c(sequ, "map_mask", &BX_VGA_THIS s.sequencer.map_mask);
new bx_shadow_bool_c(sequ, "reset1", &BX_VGA_THIS s.sequencer.reset1);
new bx_shadow_bool_c(sequ, "reset2", &BX_VGA_THIS s.sequencer.reset2);
new bx_shadow_num_c(sequ, "reg1", &BX_VGA_THIS s.sequencer.reg1, BASE_HEX);
new bx_shadow_num_c(sequ, "char_map_select", &BX_VGA_THIS s.sequencer.char_map_select);
new bx_shadow_bool_c(sequ, "extended_mem", &BX_VGA_THIS s.sequencer.extended_mem);
new bx_shadow_bool_c(sequ, "odd_even", &BX_VGA_THIS s.sequencer.odd_even);
new bx_shadow_bool_c(sequ, "chain_four", &BX_VGA_THIS s.sequencer.chain_four);
new bx_shadow_bool_c(list, "enabled", &BX_VGA_THIS s.vga_enabled);
new bx_shadow_num_c(list, "line_offset", &BX_VGA_THIS s.line_offset);
new bx_shadow_num_c(list, "line_compare", &BX_VGA_THIS s.line_compare);
new bx_shadow_num_c(list, "vertical_display_end", &BX_VGA_THIS s.vertical_display_end);
new bx_shadow_num_c(list, "charmap_address", &BX_VGA_THIS s.charmap_address);
new bx_shadow_bool_c(list, "x_dotclockdiv2", &BX_VGA_THIS s.x_dotclockdiv2);
new bx_shadow_bool_c(list, "y_doublescan", &BX_VGA_THIS s.y_doublescan);
new bx_shadow_num_c(list, "last_bpp", &BX_VGA_THIS s.last_bpp);
new bx_shadow_data_c(list, "memory", BX_VGA_THIS s.memory, BX_VGA_THIS s.memsize);
// register state for Bochs VBE
if (!strcmp(SIM->get_param_string(BXPN_VGA_EXTENSION)->getptr(), "vbe")) {
bx_list_c *vbe = new bx_list_c(list, "vbe", 18);
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, "lfb_enabled", &BX_VGA_THIS vbe.lfb_enabled);
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);
}
}
void bx_vga_c::after_restore_state(void)
{
for (unsigned i=0; i<256; i++) {
if (BX_VGA_THIS vbe.dac_8bit) {
bx_gui->palette_change(i, BX_VGA_THIS s.pel.data[i].red,
BX_VGA_THIS s.pel.data[i].green,
BX_VGA_THIS s.pel.data[i].blue);
} else {
bx_gui->palette_change(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_gui->set_text_charmap(&BX_VGA_THIS s.memory[0x20000 + BX_VGA_THIS s.charmap_address]);
BX_VGA_THIS s.last_xres = BX_MAX_XRES;
BX_VGA_THIS s.last_yres = BX_MAX_YRES;
BX_VGA_THIS redraw_area(0, 0, BX_MAX_XRES, BX_MAX_YRES);
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);
}
BX_VGA_THIS update();
bx_gui->flush();
}
void bx_vga_c::determine_screen_dimensions(unsigned *piHeight, unsigned *piWidth)
{
int ai[0x20];
int i,h,v;
for (i = 0 ; i < 0x20 ; i++)
ai[i] = BX_VGA_THIS s.CRTC.reg[i];
h = (ai[1] + 1) * 8;
v = (ai[18] | ((ai[7] & 0x02) << 7) | ((ai[7] & 0x40) << 3)) + 1;
if (BX_VGA_THIS s.graphics_ctrl.shift_reg == 0) {
*piWidth = 640;
*piHeight = 480;
if (BX_VGA_THIS s.CRTC.reg[6] == 0xBF) {
if (BX_VGA_THIS s.CRTC.reg[23] == 0xA3 &&
BX_VGA_THIS s.CRTC.reg[20] == 0x40 &&
BX_VGA_THIS s.CRTC.reg[9] == 0x41) {
*piWidth = 320;
*piHeight = 240;
} else {
if (BX_VGA_THIS s.x_dotclockdiv2) h <<= 1;
*piWidth = h;
*piHeight = v;
}
} else if ((h >= 640) && (v >= 400)) {
*piWidth = h;
*piHeight = v;
}
} else if (BX_VGA_THIS s.graphics_ctrl.shift_reg == 2) {
*piWidth = h;
*piHeight = v;
} else {
if (BX_VGA_THIS s.x_dotclockdiv2) h <<= 1;
*piWidth = h;
*piHeight = v;
}
}
// static IO port read callback handler
// redirects to non-static class handler to avoid virtual functions
Bit32u bx_vga_c::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->read(address, io_len);
}
Bit32u bx_vga_c::read(Bit32u address, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // BX_USE_VGA_SMF == 0
bx_bool horiz_retrace = 0, vert_retrace = 0;
Bit64u usec;
Bit16u ret16, vertres;
Bit8u retval;
#if defined(VGA_TRACE_FEATURE)
Bit32u ret = 0;
#define RETURN(x) do { ret = (x); goto read_return; } while (0)
#else
#define RETURN return
#endif
if (io_len == 2) {
#if BX_USE_VGA_SMF
ret16 = bx_vga_c::read_handler(0, address, 1);
ret16 |= (bx_vga_c::read_handler(0, address+1, 1)) << 8;
#else
ret16 = bx_vga_c::read(address, 1);
ret16 |= (bx_vga_c::read(address+1, 1) << 8;
#endif
RETURN(ret16);
}
#if !defined(VGA_TRACE_FEATURE)
BX_DEBUG(("io read from 0x%04x", (unsigned) address));
#endif
if ((address >= 0x03b0) && (address <= 0x03bf) &&
(BX_VGA_THIS s.misc_output.color_emulation)) {
RETURN(0xff);
}
if ((address >= 0x03d0) && (address <= 0x03df) &&
(BX_VGA_THIS s.misc_output.color_emulation==0)) {
RETURN(0xff);
}
switch (address) {
case 0x03ba: /* Input Status 1 (monochrome emulation modes) */
case 0x03ca: /* Feature Control ??? */
case 0x03da: /* Input Status 1 (color emulation modes) */
// bit3: Vertical Retrace
// 0 = display is in the display mode
// 1 = display is in the vertical retrace mode
// bit0: Display Enable
// 0 = display is in the display mode
// 1 = display is not in the display mode; either the
// horizontal or vertical retrace period is active
// using 72 Hz vertical frequency
usec = bx_pc_system.time_usec();
switch ((BX_VGA_THIS s.misc_output.vert_sync_pol << 1) | BX_VGA_THIS s.misc_output.horiz_sync_pol)
{
case 0: vertres = 200; break;
case 1: vertres = 400; break;
case 2: vertres = 350; break;
default: vertres = 480; break;
}
if ((usec % 13888) < 70) {
vert_retrace = 1;
}
if ((usec % (13888 / vertres)) == 0) {
horiz_retrace = 1;
}
retval = 0;
if (horiz_retrace || vert_retrace)
retval = 0x01;
if (vert_retrace)
retval |= 0x08;
/* reading this port resets the flip-flop to address mode */
BX_VGA_THIS s.attribute_ctrl.flip_flop = 0;
RETURN(retval);
break;
case 0x03c0: /* */
if (BX_VGA_THIS s.attribute_ctrl.flip_flop == 0) {
//BX_INFO(("io read: 0x3c0: flip_flop = 0"));
retval =
(BX_VGA_THIS s.attribute_ctrl.video_enabled << 5) |
BX_VGA_THIS s.attribute_ctrl.address;
RETURN(retval);
}
else {
BX_ERROR(("io read: 0x3c0: flip_flop != 0"));
return(0);
}
break;
case 0x03c1: /* */
switch (BX_VGA_THIS s.attribute_ctrl.address) {
case 0x00: case 0x01: case 0x02: case 0x03:
case 0x04: case 0x05: case 0x06: case 0x07:
case 0x08: case 0x09: case 0x0a: case 0x0b:
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
retval = BX_VGA_THIS s.attribute_ctrl.palette_reg[BX_VGA_THIS s.attribute_ctrl.address];
RETURN(retval);
break;
case 0x10: /* mode control register */
retval =
(BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha << 0) |
(BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type << 1) |
(BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics << 2) |
(BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity << 3) |
(BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_panning_compat << 5) |
(BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select << 6) |
(BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size << 7);
RETURN(retval);
break;
case 0x11: /* overscan color register */
RETURN(BX_VGA_THIS s.attribute_ctrl.overscan_color);
break;
case 0x12: /* color plane enable */
RETURN(BX_VGA_THIS s.attribute_ctrl.color_plane_enable);
break;
case 0x13: /* horizontal PEL panning register */
RETURN(BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning);
break;
case 0x14: /* color select register */
RETURN(BX_VGA_THIS s.attribute_ctrl.color_select);
break;
default:
BX_INFO(("io read: 0x3c1: unknown register 0x%02x",
(unsigned) BX_VGA_THIS s.attribute_ctrl.address));
RETURN(0);
}
break;
case 0x03c2: /* Input Status 0 */
BX_DEBUG(("io read 0x3c2: input status #0: ignoring"));
RETURN(0);
break;
case 0x03c3: /* VGA Enable Register */
RETURN(BX_VGA_THIS s.vga_enabled);
break;
case 0x03c4: /* Sequencer Index Register */
RETURN(BX_VGA_THIS s.sequencer.index);
break;
case 0x03c5: /* Sequencer Registers 00..04 */
switch (BX_VGA_THIS s.sequencer.index) {
case 0: /* sequencer: reset */
BX_DEBUG(("io read 0x3c5: sequencer reset"));
RETURN(BX_VGA_THIS s.sequencer.reset1 | (BX_VGA_THIS s.sequencer.reset2<<1));
break;
case 1: /* sequencer: clocking mode */
BX_DEBUG(("io read 0x3c5: sequencer clocking mode"));
RETURN(BX_VGA_THIS s.sequencer.reg1);
break;
case 2: /* sequencer: map mask register */
RETURN(BX_VGA_THIS s.sequencer.map_mask);
break;
case 3: /* sequencer: character map select register */
RETURN(BX_VGA_THIS s.sequencer.char_map_select);
break;
case 4: /* sequencer: memory mode register */
retval =
(BX_VGA_THIS s.sequencer.extended_mem << 1) |
(BX_VGA_THIS s.sequencer.odd_even << 2) |
(BX_VGA_THIS s.sequencer.chain_four << 3);
RETURN(retval);
break;
default:
BX_DEBUG(("io read 0x3c5: index %u unhandled",
(unsigned) BX_VGA_THIS s.sequencer.index));
RETURN(0);
}
break;
case 0x03c6: /* PEL mask ??? */
RETURN(BX_VGA_THIS s.pel.mask);
break;
case 0x03c7: /* DAC state, read = 11b, write = 00b */
RETURN(BX_VGA_THIS s.pel.dac_state);
break;
case 0x03c8: /* PEL address write mode */
RETURN(BX_VGA_THIS s.pel.write_data_register);
break;
case 0x03c9: /* PEL Data Register, colors 00..FF */
if (BX_VGA_THIS s.pel.dac_state == 0x03) {
switch (BX_VGA_THIS s.pel.read_data_cycle) {
case 0:
retval = BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.read_data_register].red;
break;
case 1:
retval = BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.read_data_register].green;
break;
case 2:
retval = BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.read_data_register].blue;
break;
default:
retval = 0; // keep compiler happy
}
BX_VGA_THIS s.pel.read_data_cycle++;
if (BX_VGA_THIS s.pel.read_data_cycle >= 3) {
BX_VGA_THIS s.pel.read_data_cycle = 0;
BX_VGA_THIS s.pel.read_data_register++;
}
}
else {
retval = 0x3f;
}
RETURN(retval);
break;
case 0x03cc: /* Miscellaneous Output / Graphics 1 Position ??? */
retval =
((BX_VGA_THIS s.misc_output.color_emulation & 0x01) << 0) |
((BX_VGA_THIS s.misc_output.enable_ram & 0x01) << 1) |
((BX_VGA_THIS s.misc_output.clock_select & 0x03) << 2) |
((BX_VGA_THIS s.misc_output.select_high_bank & 0x01) << 5) |
((BX_VGA_THIS s.misc_output.horiz_sync_pol & 0x01) << 6) |
((BX_VGA_THIS s.misc_output.vert_sync_pol & 0x01) << 7);
RETURN(retval);
break;
case 0x03ce: /* Graphics Controller Index Register */
RETURN(BX_VGA_THIS s.graphics_ctrl.index);
break;
case 0x03cd: /* ??? */
BX_DEBUG(("io read from 03cd"));
RETURN(0x00);
break;
case 0x03cf: /* Graphics Controller Registers 00..08 */
switch (BX_VGA_THIS s.graphics_ctrl.index) {
case 0: /* Set/Reset */
RETURN(BX_VGA_THIS s.graphics_ctrl.set_reset);
break;
case 1: /* Enable Set/Reset */
RETURN(BX_VGA_THIS s.graphics_ctrl.enable_set_reset);
break;
case 2: /* Color Compare */
RETURN(BX_VGA_THIS s.graphics_ctrl.color_compare);
break;
case 3: /* Data Rotate */
retval =
((BX_VGA_THIS s.graphics_ctrl.raster_op & 0x03) << 3) |
((BX_VGA_THIS s.graphics_ctrl.data_rotate & 0x07) << 0);
RETURN(retval);
break;
case 4: /* Read Map Select */
RETURN(BX_VGA_THIS s.graphics_ctrl.read_map_select);
break;
case 5: /* Mode */
retval =
((BX_VGA_THIS s.graphics_ctrl.shift_reg & 0x03) << 5) |
((BX_VGA_THIS s.graphics_ctrl.odd_even & 0x01) << 4) |
((BX_VGA_THIS s.graphics_ctrl.read_mode & 0x01) << 3) |
((BX_VGA_THIS s.graphics_ctrl.write_mode & 0x03) << 0);
if (BX_VGA_THIS s.graphics_ctrl.odd_even ||
BX_VGA_THIS s.graphics_ctrl.shift_reg)
BX_DEBUG(("io read 0x3cf: reg 05 = 0x%02x", (unsigned) retval));
RETURN(retval);
break;
case 6: /* Miscellaneous */
retval =
((BX_VGA_THIS s.graphics_ctrl.memory_mapping & 0x03) << 2) |
((BX_VGA_THIS s.graphics_ctrl.odd_even & 0x01) << 1) |
((BX_VGA_THIS s.graphics_ctrl.graphics_alpha & 0x01) << 0);
RETURN(retval);
break;
case 7: /* Color Don't Care */
RETURN(BX_VGA_THIS s.graphics_ctrl.color_dont_care);
break;
case 8: /* Bit Mask */
RETURN(BX_VGA_THIS s.graphics_ctrl.bitmask);
break;
default:
/* ??? */
BX_DEBUG(("io read: 0x3cf: index %u unhandled",
(unsigned) BX_VGA_THIS s.graphics_ctrl.index));
RETURN(0);
}
break;
case 0x03d4: /* CRTC Index Register (color emulation modes) */
RETURN(BX_VGA_THIS s.CRTC.address);
break;
case 0x03b5: /* CRTC Registers (monochrome emulation modes) */
case 0x03d5: /* CRTC Registers (color emulation modes) */
if (BX_VGA_THIS s.CRTC.address > 0x18) {
BX_DEBUG(("io read: invalid CRTC register 0x%02x",
(unsigned) BX_VGA_THIS s.CRTC.address));
RETURN(0);
}
RETURN(BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address]);
break;
case 0x03b4: /* CRTC Index Register (monochrome emulation modes) */
case 0x03cb: /* not sure but OpenBSD reads it a lot */
default:
BX_INFO(("io read from vga port 0x%04x", (unsigned) address));
RETURN(0); /* keep compiler happy */
}
#if defined(VGA_TRACE_FEATURE)
read_return:
if (io_len == 1) {
BX_DEBUG(("8-bit read from 0x%04x = 0x%02x", (unsigned) address, ret));
} else {
BX_DEBUG(("16-bit read from 0x%04x = 0x%04x", (unsigned) address, ret));
}
return ret;
#endif
}
#if defined(VGA_TRACE_FEATURE)
#undef RETURN
#endif
// 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)
{
Bit8u charmap1, charmap2, prev_memory_mapping;
bx_bool prev_video_enabled, prev_line_graphics, prev_int_pal_size, prev_graphics_alpha;
//bx_bool prev_chain_odd_even;
bx_bool needs_update = 0, charmap_update = 0;
#if defined(VGA_TRACE_FEATURE)
if (!no_log)
switch (io_len) {
case 1:
BX_DEBUG(("8-bit write to %04x = %02x", (unsigned)address, (unsigned)value));
break;
case 2:
BX_DEBUG(("16-bit write to %04x = %04x", (unsigned)address, (unsigned)value));
break;
default:
BX_PANIC(("Weird VGA write size"));
}
#else
if (io_len == 1) {
BX_DEBUG(("io write to 0x%04x = 0x%02x", (unsigned) address, (unsigned) value));
}
#endif
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 0x03ba: /* Feature Control (monochrome emulation modes) */
#if !defined(VGA_TRACE_FEATURE)
BX_DEBUG(("io write 3ba: feature control: ignoring"));
#endif
break;
case 0x03c0: /* Attribute Controller */
if (BX_VGA_THIS s.attribute_ctrl.flip_flop == 0) { /* address mode */
prev_video_enabled = BX_VGA_THIS s.attribute_ctrl.video_enabled;
BX_VGA_THIS s.attribute_ctrl.video_enabled = (value >> 5) & 0x01;
#if !defined(VGA_TRACE_FEATURE)
BX_DEBUG(("io write 3c0: video_enabled = %u",
(unsigned) BX_VGA_THIS s.attribute_ctrl.video_enabled));
#endif
if (BX_VGA_THIS s.attribute_ctrl.video_enabled == 0)
bx_gui->clear_screen();
else if (!prev_video_enabled) {
#if !defined(VGA_TRACE_FEATURE)
BX_DEBUG(("found enable transition"));
#endif
needs_update = 1;
}
value &= 0x1f; /* address = bits 0..4 */
BX_VGA_THIS s.attribute_ctrl.address = value;
switch (value) {
case 0x00: case 0x01: case 0x02: case 0x03:
case 0x04: case 0x05: case 0x06: case 0x07:
case 0x08: case 0x09: case 0x0a: case 0x0b:
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
break;
default:
BX_DEBUG(("io write 0x3c0: address mode reg=0x%02x",
(unsigned) value));
}
}
else { /* data-write mode */
switch (BX_VGA_THIS s.attribute_ctrl.address) {
case 0x00: case 0x01: case 0x02: case 0x03:
case 0x04: case 0x05: case 0x06: case 0x07:
case 0x08: case 0x09: case 0x0a: case 0x0b:
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
if (value != BX_VGA_THIS s.attribute_ctrl.palette_reg[BX_VGA_THIS s.attribute_ctrl.address]) {
BX_VGA_THIS s.attribute_ctrl.palette_reg[BX_VGA_THIS s.attribute_ctrl.address] =
value;
needs_update = 1;
}
break;
case 0x10: // mode control register
prev_line_graphics = BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics;
prev_int_pal_size = BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size;
BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha =
(value >> 0) & 0x01;
BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type =
(value >> 1) & 0x01;
BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics =
(value >> 2) & 0x01;
BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity =
(value >> 3) & 0x01;
BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_panning_compat =
(value >> 5) & 0x01;
BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select =
(value >> 6) & 0x01;
BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size =
(value >> 7) & 0x01;
if (((value >> 2) & 0x01) != prev_line_graphics) {
charmap_update = 1;
}
if (((value >> 7) & 0x01) != prev_int_pal_size) {
needs_update = 1;
}
#if !defined(VGA_TRACE_FEATURE)
BX_DEBUG(("io write 0x3c0: mode control: 0x%02x",
(unsigned) value));
#endif
break;
case 0x11: // Overscan Color Register
BX_VGA_THIS s.attribute_ctrl.overscan_color = (value & 0x3f);
#if !defined(VGA_TRACE_FEATURE)
BX_DEBUG(("io write 0x3c0: overscan color = 0x%02x",
(unsigned) value));
#endif
break;
case 0x12: // Color Plane Enable Register
BX_VGA_THIS s.attribute_ctrl.color_plane_enable = (value & 0x0f);
needs_update = 1;
#if !defined(VGA_TRACE_FEATURE)
BX_DEBUG(("io write 0x3c0: color plane enable = 0x%02x",
(unsigned) value));
#endif
break;
case 0x13: // Horizontal Pixel Panning Register
BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning = (value & 0x0f);
needs_update = 1;
#if !defined(VGA_TRACE_FEATURE)
BX_DEBUG(("io write 0x3c0: horiz pel panning = 0x%02x",
(unsigned) value));
#endif
break;
case 0x14: // Color Select Register
BX_VGA_THIS s.attribute_ctrl.color_select = (value & 0x0f);
needs_update = 1;
#if !defined(VGA_TRACE_FEATURE)
BX_DEBUG(("io write 0x3c0: color select = 0x%02x",
(unsigned) BX_VGA_THIS s.attribute_ctrl.color_select));
#endif
break;
default:
BX_DEBUG(("io write 0x3c0: data-write mode 0x%02x",
(unsigned) BX_VGA_THIS s.attribute_ctrl.address));
}
}
BX_VGA_THIS s.attribute_ctrl.flip_flop = !BX_VGA_THIS s.attribute_ctrl.flip_flop;
break;
case 0x03c2: // Miscellaneous Output Register
BX_VGA_THIS s.misc_output.color_emulation = (value >> 0) & 0x01;
BX_VGA_THIS s.misc_output.enable_ram = (value >> 1) & 0x01;
BX_VGA_THIS s.misc_output.clock_select = (value >> 2) & 0x03;
BX_VGA_THIS s.misc_output.select_high_bank = (value >> 5) & 0x01;
BX_VGA_THIS s.misc_output.horiz_sync_pol = (value >> 6) & 0x01;
BX_VGA_THIS s.misc_output.vert_sync_pol = (value >> 7) & 0x01;
#if !defined(VGA_TRACE_FEATURE)
BX_DEBUG(("io write 3c2:"));
BX_DEBUG((" color_emulation (attempted) = %u",
(value >> 0) & 0x01));
BX_DEBUG((" enable_ram = %u",
(unsigned) BX_VGA_THIS s.misc_output.enable_ram));
BX_DEBUG((" clock_select = %u",
(unsigned) BX_VGA_THIS s.misc_output.clock_select));
BX_DEBUG((" select_high_bank = %u",
(unsigned) BX_VGA_THIS s.misc_output.select_high_bank));
BX_DEBUG((" horiz_sync_pol = %u",
(unsigned) BX_VGA_THIS s.misc_output.horiz_sync_pol));
BX_DEBUG((" vert_sync_pol = %u",
(unsigned) BX_VGA_THIS s.misc_output.vert_sync_pol));
#endif
break;
case 0x03c3: // VGA enable
// bit0: enables VGA display if set
BX_VGA_THIS s.vga_enabled = value & 0x01;
#if !defined(VGA_TRACE_FEATURE)
BX_DEBUG(("io write 0x03c3: VGA enable = %u", BX_VGA_THIS s.vga_enabled));
#endif
break;
case 0x03c4: /* Sequencer Index Register */
if (value > 4) {
BX_DEBUG(("io write 3c4: value > 4"));
}
BX_VGA_THIS s.sequencer.index = value;
break;
case 0x03c5: /* Sequencer Registers 00..04 */
switch (BX_VGA_THIS s.sequencer.index) {
case 0: /* sequencer: reset */
#if !defined(VGA_TRACE_FEATURE)
BX_DEBUG(("write 0x3c5: sequencer reset: value=0x%02x",
(unsigned) value));
#endif
if (BX_VGA_THIS s.sequencer.reset1 && ((value & 0x01) == 0)) {
BX_VGA_THIS s.sequencer.char_map_select = 0;
BX_VGA_THIS s.charmap_address = 0;
charmap_update = 1;
}
BX_VGA_THIS s.sequencer.reset1 = (value >> 0) & 0x01;
BX_VGA_THIS s.sequencer.reset2 = (value >> 1) & 0x01;
break;
case 1: /* sequencer: clocking mode */
#if !defined(VGA_TRACE_FEATURE)
BX_DEBUG(("io write 0x3c5=0x%02x: clocking mode reg: ignoring",
(unsigned) value));
#endif
if ((value & 0x20) > 0) {
bx_gui->clear_screen();
} else if ((BX_VGA_THIS s.sequencer.reg1 & 0x20) > 0) {
needs_update = 1;
}
BX_VGA_THIS s.sequencer.reg1 = value & 0x3d;
BX_VGA_THIS s.x_dotclockdiv2 = ((value & 0x08) > 0);
break;
case 2: /* sequencer: map mask register */
BX_VGA_THIS s.sequencer.map_mask = (value & 0x0f);
break;
case 3: /* sequencer: character map select register */
BX_VGA_THIS s.sequencer.char_map_select = value & 0x3f;
charmap1 = value & 0x13;
if (charmap1 > 3) charmap1 = (charmap1 & 3) + 4;
charmap2 = (value & 0x2C) >> 2;
if (charmap2 > 3) charmap2 = (charmap2 & 3) + 4;
if (BX_VGA_THIS s.CRTC.reg[0x09] > 0) {
BX_VGA_THIS s.charmap_address = charmap_offset[charmap1];
charmap_update = 1;
}
if (charmap2 != charmap1)
BX_INFO(("char map select: map #2 in block #%d unused", charmap2));
break;
case 4: /* sequencer: memory mode register */
BX_VGA_THIS s.sequencer.extended_mem = (value >> 1) & 0x01;
BX_VGA_THIS s.sequencer.odd_even = (value >> 2) & 0x01;
BX_VGA_THIS s.sequencer.chain_four = (value >> 3) & 0x01;
#if !defined(VGA_TRACE_FEATURE)
BX_DEBUG(("io write 0x3c5: memory mode:"));
BX_DEBUG((" extended_mem = %u",
(unsigned) BX_VGA_THIS s.sequencer.extended_mem));
BX_DEBUG((" odd_even = %u",
(unsigned) BX_VGA_THIS s.sequencer.odd_even));
BX_DEBUG((" chain_four = %u",
(unsigned) BX_VGA_THIS s.sequencer.chain_four));
#endif
break;
default:
BX_DEBUG(("io write 0x3c5: index 0x%02x unhandled",
(unsigned) BX_VGA_THIS s.sequencer.index));
}
break;
case 0x03c6: /* PEL mask */
BX_VGA_THIS s.pel.mask = value;
if (BX_VGA_THIS s.pel.mask != 0xff)
BX_DEBUG(("io write 0x3c6: PEL mask=0x%02x != 0xFF", value));
// BX_VGA_THIS s.pel.mask should be and'd with final value before
// indexing into color register BX_VGA_THIS s.pel.data[]
break;
case 0x03c7: // PEL address, read mode
BX_VGA_THIS s.pel.read_data_register = value;
BX_VGA_THIS s.pel.read_data_cycle = 0;
BX_VGA_THIS s.pel.dac_state = 0x03;
break;
case 0x03c8: /* PEL address write mode */
BX_VGA_THIS s.pel.write_data_register = value;
BX_VGA_THIS s.pel.write_data_cycle = 0;
BX_VGA_THIS s.pel.dac_state = 0x00;
break;
case 0x03c9: /* PEL Data Register, colors 00..FF */
switch (BX_VGA_THIS s.pel.write_data_cycle) {
case 0:
BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].red = value;
break;
case 1:
BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].green = value;
break;
case 2:
BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].blue = value;
if (BX_VGA_THIS vbe.dac_8bit) {
needs_update |= bx_gui->palette_change(BX_VGA_THIS s.pel.write_data_register,
BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].red,
BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].green,
BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].blue);
} else {
needs_update |= bx_gui->palette_change(BX_VGA_THIS s.pel.write_data_register,
BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].red<<2,
BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].green<<2,
BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].blue<<2);
}
break;
}
BX_VGA_THIS s.pel.write_data_cycle++;
if (BX_VGA_THIS s.pel.write_data_cycle >= 3) {
//BX_INFO(("BX_VGA_THIS s.pel.data[%u] {r=%u, g=%u, b=%u}",
// (unsigned) BX_VGA_THIS s.pel.write_data_register,
// (unsigned) BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].red,
// (unsigned) BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].green,
// (unsigned) BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].blue);
BX_VGA_THIS s.pel.write_data_cycle = 0;
BX_VGA_THIS s.pel.write_data_register++;
}
break;
case 0x03ca: /* Graphics 2 Position (EGA) */
// ignore, EGA only???
break;
case 0x03cc: /* Graphics 1 Position (EGA) */
// ignore, EGA only???
break;
case 0x03cd: /* ??? */
BX_DEBUG(("io write to 0x3cd = 0x%02x", (unsigned) value));
break;
case 0x03ce: /* Graphics Controller Index Register */
if (value > 0x08) /* ??? */
BX_DEBUG(("io write: 0x3ce: value > 8"));
BX_VGA_THIS s.graphics_ctrl.index = value;
break;
case 0x03cf: /* Graphics Controller Registers 00..08 */
switch (BX_VGA_THIS s.graphics_ctrl.index) {
case 0: /* Set/Reset */
BX_VGA_THIS s.graphics_ctrl.set_reset = value & 0x0f;
break;
case 1: /* Enable Set/Reset */
BX_VGA_THIS s.graphics_ctrl.enable_set_reset = value & 0x0f;
break;
case 2: /* Color Compare */
BX_VGA_THIS s.graphics_ctrl.color_compare = value & 0x0f;
break;
case 3: /* Data Rotate */
BX_VGA_THIS s.graphics_ctrl.data_rotate = value & 0x07;
BX_VGA_THIS s.graphics_ctrl.raster_op = (value >> 3) & 0x03;
break;
case 4: /* Read Map Select */
BX_VGA_THIS s.graphics_ctrl.read_map_select = value & 0x03;
#if !defined(VGA_TRACE_FEATURE)
BX_DEBUG(("io write to 0x3cf = 0x%02x (RMS)", (unsigned) value));
#endif
break;
case 5: /* Mode */
BX_VGA_THIS s.graphics_ctrl.write_mode = value & 0x03;
BX_VGA_THIS s.graphics_ctrl.read_mode = (value >> 3) & 0x01;
BX_VGA_THIS s.graphics_ctrl.odd_even = (value >> 4) & 0x01;
BX_VGA_THIS s.graphics_ctrl.shift_reg = (value >> 5) & 0x03;
if (BX_VGA_THIS s.graphics_ctrl.odd_even)
BX_DEBUG(("io write: 0x3cf: mode reg: value = 0x%02x",
(unsigned) value));
if (BX_VGA_THIS s.graphics_ctrl.shift_reg)
BX_DEBUG(("io write: 0x3cf: mode reg: value = 0x%02x",
(unsigned) value));
break;
case 6: /* Miscellaneous */
prev_graphics_alpha = BX_VGA_THIS s.graphics_ctrl.graphics_alpha;
// prev_chain_odd_even = BX_VGA_THIS s.graphics_ctrl.chain_odd_even;
prev_memory_mapping = BX_VGA_THIS s.graphics_ctrl.memory_mapping;
BX_VGA_THIS s.graphics_ctrl.graphics_alpha = value & 0x01;
BX_VGA_THIS s.graphics_ctrl.chain_odd_even = (value >> 1) & 0x01;
BX_VGA_THIS s.graphics_ctrl.memory_mapping = (value >> 2) & 0x03;
#if !defined(VGA_TRACE_FEATURE)
BX_DEBUG(("memory_mapping set to %u",
(unsigned) BX_VGA_THIS s.graphics_ctrl.memory_mapping));
BX_DEBUG(("graphics mode set to %u",
(unsigned) BX_VGA_THIS s.graphics_ctrl.graphics_alpha));
BX_DEBUG(("odd_even mode set to %u",
(unsigned) BX_VGA_THIS s.graphics_ctrl.odd_even));
BX_DEBUG(("io write: 0x3cf: misc reg: value = 0x%02x",
(unsigned) value));
#endif
if (prev_memory_mapping != BX_VGA_THIS s.graphics_ctrl.memory_mapping)
needs_update = 1;
if (prev_graphics_alpha != BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
needs_update = 1;
BX_VGA_THIS s.last_yres = 0;
}
break;
case 7: /* Color Don't Care */
BX_VGA_THIS s.graphics_ctrl.color_dont_care = value & 0x0f;
break;
case 8: /* Bit Mask */
BX_VGA_THIS s.graphics_ctrl.bitmask = value;
break;
default:
/* ??? */
BX_DEBUG(("io write: 0x3cf: index %u unhandled",
(unsigned) BX_VGA_THIS s.graphics_ctrl.index));
}
break;
case 0x03b4: /* CRTC Index Register (monochrome emulation modes) */
case 0x03d4: /* CRTC Index Register (color emulation modes) */
BX_VGA_THIS s.CRTC.address = value & 0x7f;
if (BX_VGA_THIS s.CRTC.address > 0x18)
BX_DEBUG(("write: invalid CRTC register 0x%02x selected",
(unsigned) BX_VGA_THIS s.CRTC.address));
break;
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 (BX_VGA_THIS s.CRTC.write_protect && (BX_VGA_THIS s.CRTC.address < 0x08)) {
if (BX_VGA_THIS s.CRTC.address == 0x07) {
BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address] &= ~0x10;
BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address] |= (value & 0x10);
BX_VGA_THIS s.line_compare &= 0x2ff;
if (BX_VGA_THIS s.CRTC.reg[0x07] & 0x10) BX_VGA_THIS s.line_compare |= 0x100;
needs_update = 1;
break;
} else {
return;
}
}
if (value != BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address]) {
BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address] = value;
switch (BX_VGA_THIS s.CRTC.address) {
case 0x07:
BX_VGA_THIS s.vertical_display_end &= 0xff;
if (BX_VGA_THIS s.CRTC.reg[0x07] & 0x02) BX_VGA_THIS s.vertical_display_end |= 0x100;
if (BX_VGA_THIS s.CRTC.reg[0x07] & 0x40) BX_VGA_THIS s.vertical_display_end |= 0x200;
BX_VGA_THIS s.line_compare &= 0x2ff;
if (BX_VGA_THIS s.CRTC.reg[0x07] & 0x10) BX_VGA_THIS s.line_compare |= 0x100;
needs_update = 1;
break;
case 0x08:
// Vertical pel panning change
needs_update = 1;
break;
case 0x09:
BX_VGA_THIS s.y_doublescan = ((value & 0x9f) > 0);
BX_VGA_THIS s.line_compare &= 0x1ff;
if (BX_VGA_THIS s.CRTC.reg[0x09] & 0x40) BX_VGA_THIS s.line_compare |= 0x200;
charmap_update = 1;
needs_update = 1;
break;
case 0x0A:
case 0x0B:
case 0x0E:
case 0x0F:
// Cursor size / location change
BX_VGA_THIS s.vga_mem_updated = 1;
break;
case 0x0C:
case 0x0D:
// Start address change
if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
needs_update = 1;
} else {
BX_VGA_THIS s.vga_mem_updated = 1;
}
break;
case 0x11:
BX_VGA_THIS s.CRTC.write_protect = ((BX_VGA_THIS s.CRTC.reg[0x11] & 0x80) > 0);
break;
case 0x12:
BX_VGA_THIS s.vertical_display_end &= 0x300;
BX_VGA_THIS s.vertical_display_end |= BX_VGA_THIS s.CRTC.reg[0x12];
break;
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_VGA_THIS s.line_offset = BX_VGA_THIS s.CRTC.reg[0x13] << 1;
if (BX_VGA_THIS s.CRTC.reg[0x14] & 0x40) BX_VGA_THIS s.line_offset <<= 2;
else if ((BX_VGA_THIS s.CRTC.reg[0x17] & 0x40) == 0) BX_VGA_THIS s.line_offset <<= 1;
needs_update = 1;
}
break;
case 0x18:
BX_VGA_THIS s.line_compare &= 0x300;
BX_VGA_THIS s.line_compare |= BX_VGA_THIS s.CRTC.reg[0x18];
needs_update = 1;
break;
}
}
break;
case 0x03da: /* Feature Control (color emulation modes) */
BX_DEBUG(("io write: 3da: ignoring: feature ctrl & vert sync"));
break;
case 0x03c1: /* */
default:
BX_ERROR(("unsupported io write to port 0x%04x, val=0x%02x",
(unsigned) address, (unsigned) value));
}
if (charmap_update) {
bx_gui->set_text_charmap(
& BX_VGA_THIS s.memory[0x20000 + BX_VGA_THIS s.charmap_address]);
BX_VGA_THIS s.vga_mem_updated = 1;
}
if (needs_update) {
// Mark all video as updated so the changes will go through
BX_VGA_THIS redraw_area(0, 0, BX_VGA_THIS s.last_xres, BX_VGA_THIS s.last_yres);
}
}
Bit64s bx_vga_c::vga_param_handler(bx_param_c *param, int set, Bit64s val)
{
Bit32u interval;
// handler for runtime parameter 'vga: update_freq'
if (set) {
interval = (Bit32u)(1000000 / val);
BX_INFO(("Changing timer interval to %d", interval));
BX_VGA_THIS timer_handler(theVga);
bx_virt_timer.activate_timer(BX_VGA_THIS timer_id, interval, 1);
if (interval < 300000) {
BX_VGA_THIS s.blink_counter = 300000 / (unsigned)interval;
} else {
BX_VGA_THIS s.blink_counter = 1;
}
}
return val;
}
void bx_vga_c::trigger_timer(void *this_ptr)
{
timer_handler(this_ptr);
}
void bx_vga_c::timer_handler(void *this_ptr)
{
#if BX_USE_VGA_SMF == 0
bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
class_ptr->timer();
}
void bx_vga_c::timer(void)
{
#else
UNUSED(this_ptr);
#endif
update();
bx_gui->flush();
}
Bit8u bx_vga_c::get_vga_pixel(Bit16u x, Bit16u y, Bit16u saddr, Bit16u lc, Bit8u **plane)
{
Bit8u attribute, bit_no, palette_reg_val, DAC_regno;
Bit32u byte_offset;
if (BX_VGA_THIS s.x_dotclockdiv2) x >>= 1;
bit_no = 7 - (x % 8);
if (y > lc) {
byte_offset = x / 8 +
((y - lc - 1) * BX_VGA_THIS s.line_offset);
} else {
byte_offset = saddr + x / 8 +
(y * BX_VGA_THIS s.line_offset);
}
attribute =
(((plane[0][byte_offset] >> bit_no) & 0x01) << 0) |
(((plane[1][byte_offset] >> bit_no) & 0x01) << 1) |
(((plane[2][byte_offset] >> bit_no) & 0x01) << 2) |
(((plane[3][byte_offset] >> bit_no) & 0x01) << 3);
attribute &= BX_VGA_THIS s.attribute_ctrl.color_plane_enable;
// undocumented feature ???: colors 0..7 high intensity, colors 8..15 blinking
// using low/high intensity. Blinking is not implemented yet.
if (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity) attribute ^= 0x08;
palette_reg_val = BX_VGA_THIS s.attribute_ctrl.palette_reg[attribute];
if (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size) {
// use 4 lower bits from palette register
// use 4 higher bits from color select register
// 16 banks of 16-color registers
DAC_regno = (palette_reg_val & 0x0f) |
(BX_VGA_THIS s.attribute_ctrl.color_select << 4);
} else {
// use 6 lower bits from palette register
// use 2 higher bits from color select register
// 4 banks of 64-color registers
DAC_regno = (palette_reg_val & 0x3f) |
((BX_VGA_THIS s.attribute_ctrl.color_select & 0x0c) << 4);
}
// DAC_regno &= video DAC mask register ???
return DAC_regno;
}
void bx_vga_c::update(void)
{
unsigned iHeight, iWidth;
/* 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_pc_system.time_usec() % 13888) < 70)
return;
if ((BX_VGA_THIS vbe.enabled) && (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(&info)) {
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 (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 (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 (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 (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 (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 (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"));
}
// after a vbe display update, don't try to do any 'normal vga' updates anymore
return;
}
// fields that effect the way video memory is serialized into screen output:
// GRAPHICS CONTROLLER:
// BX_VGA_THIS s.graphics_ctrl.shift_reg:
// 0: output data in standard VGA format or CGA-compatible 640x200 2 color
// graphics mode (mode 6)
// 1: output data in CGA-compatible 320x200 4 color graphics mode
// (modes 4 & 5)
// 2: output data 8 bits at a time from the 4 bit planes
// (mode 13 and variants like modeX)
// if (BX_VGA_THIS s.vga_mem_updated==0 || BX_VGA_THIS s.attribute_ctrl.video_enabled == 0)
if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
// Graphics mode
Bit8u color;
unsigned bit_no, r, c, x, y;
unsigned long byte_offset, start_addr;
unsigned xc, yc, xti, yti;
start_addr = (BX_VGA_THIS s.CRTC.reg[0x0c] << 8) | BX_VGA_THIS s.CRTC.reg[0x0d];
//BX_DEBUG(("update: shiftreg=%u, chain4=%u, mapping=%u",
// (unsigned) BX_VGA_THIS s.graphics_ctrl.shift_reg,
// (unsigned) BX_VGA_THIS s.sequencer.chain_four,
// (unsigned) BX_VGA_THIS s.graphics_ctrl.memory_mapping);
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;
}
switch (BX_VGA_THIS s.graphics_ctrl.shift_reg) {
case 0: // interleaved shift
Bit8u attribute, palette_reg_val, DAC_regno;
unsigned long line_compare;
Bit8u *plane[4];
if ((BX_VGA_THIS s.CRTC.reg[0x17] & 1) == 0) { // CGA 640x200x2
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;
/* 0 or 0x2000 */
byte_offset = start_addr + ((y & 1) << 13);
/* to the start of the line */
byte_offset += (320 / 4) * (y / 2);
/* to the byte start */
byte_offset += (x / 8);
bit_no = 7 - (x % 8);
palette_reg_val = (((BX_VGA_THIS s.memory[byte_offset]) >> bit_no) & 1);
DAC_regno = BX_VGA_THIS s.attribute_ctrl.palette_reg[palette_reg_val];
BX_VGA_THIS s.tile[r*X_TILESIZE + c] = DAC_regno;
}
}
SET_TILE_UPDATED (xti, yti, 0);
bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
}
}
}
} else { // output data in serial fashion with each display plane
// output on its associated serial output. Standard EGA/VGA format
if (BX_VGA_THIS vbe.enabled) {
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];
start_addr = BX_VGA_THIS vbe.virtual_start;
line_compare = 0xffff;
} else {
plane[0] = &BX_VGA_THIS s.memory[0<<16];
plane[1] = &BX_VGA_THIS s.memory[1<<16];
plane[2] = &BX_VGA_THIS s.memory[2<<16];
plane[3] = &BX_VGA_THIS s.memory[3<<16];
line_compare = BX_VGA_THIS s.line_compare;
if (BX_VGA_THIS s.y_doublescan) line_compare >>= 1;
}
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, start_addr, line_compare, plane);
}
}
SET_TILE_UPDATED (xti, yti, 0);
bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
}
}
}
}
break; // case 0
case 1: // output the data in a CGA-compatible 320x200 4 color graphics
// mode. (planar shift, modes 4 & 5)
/* CGA 320x200x4 start */
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;
if (BX_VGA_THIS s.x_dotclockdiv2) x >>= 1;
/* 0 or 0x2000 */
byte_offset = start_addr + ((y & 1) << 13);
/* to the start of the line */
byte_offset += (320 / 4) * (y / 2);
/* to the byte start */
byte_offset += (x / 4);
attribute = 6 - 2*(x % 4);
palette_reg_val = (BX_VGA_THIS s.memory[byte_offset]) >> attribute;
palette_reg_val &= 3;
DAC_regno = BX_VGA_THIS s.attribute_ctrl.palette_reg[palette_reg_val];
BX_VGA_THIS s.tile[r*X_TILESIZE + c] = DAC_regno;
}
}
SET_TILE_UPDATED (xti, yti, 0);
bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
}
}
}
/* CGA 320x200x4 end */
break; // case 1
case 2: // output the data eight bits at a time from the 4 bit plane
// (format for VGA mode 13 hex)
case 3: // FIXME: is this really the same ???
if (BX_VGA_THIS s.CRTC.reg[0x14] & 0x40) { // DW set: doubleword mode
unsigned long pixely, pixelx, plane;
if (BX_VGA_THIS s.misc_output.select_high_bank != 1)
BX_PANIC(("update: select_high_bank != 1"));
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++) {
pixely = yc + r;
if (BX_VGA_THIS s.y_doublescan) pixely >>= 1;
for (c=0; c<X_TILESIZE; c++) {
pixelx = (xc + c) >> 1;
plane = (pixelx % 4);
byte_offset = start_addr + (plane * 65536) +
(pixely * BX_VGA_THIS s.line_offset) + (pixelx & ~0x03);
color = BX_VGA_THIS s.memory[byte_offset];
BX_VGA_THIS s.tile[r*X_TILESIZE + c] = color;
}
}
SET_TILE_UPDATED (xti, yti, 0);
bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
}
}
}
} else if (BX_VGA_THIS s.CRTC.reg[0x17] & 0x40) { // B/W set: byte mode, modeX
unsigned long pixely, pixelx, plane;
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++) {
pixely = yc + r;
if (BX_VGA_THIS s.y_doublescan) pixely >>= 1;
for (c=0; c<X_TILESIZE; c++) {
pixelx = (xc + c) >> 1;
plane = (pixelx % 4);
byte_offset = (plane * 65536) +
(pixely * BX_VGA_THIS s.line_offset)
+ (pixelx >> 2);
color = BX_VGA_THIS s.memory[start_addr + byte_offset];
BX_VGA_THIS s.tile[r*X_TILESIZE + c] = color;
}
}
SET_TILE_UPDATED (xti, yti, 0);
bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
}
}
}
} else { // word mode
unsigned long pixely, pixelx, plane;
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++) {
pixely = yc + r;
if (BX_VGA_THIS s.y_doublescan) pixely >>= 1;
for (c=0; c<X_TILESIZE; c++) {
pixelx = (xc + c) >> 1;
plane = (pixelx % 4);
byte_offset = (plane * 65536) +
(pixely * BX_VGA_THIS s.line_offset)
+ ((pixelx >> 1) & ~0x01);
color = BX_VGA_THIS s.memory[start_addr + byte_offset];
BX_VGA_THIS s.tile[r*X_TILESIZE + c] = color;
}
}
SET_TILE_UPDATED (xti, yti, 0);
bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
}
}
}
}
break; // case 2
default:
BX_PANIC(("update: shift_reg == %u", (unsigned)
BX_VGA_THIS s.graphics_ctrl.shift_reg));
}
BX_VGA_THIS s.vga_mem_updated = 0;
return;
}
else { // text mode
unsigned long start_address;
unsigned long cursor_address, cursor_x, cursor_y;
bx_vga_tminfo_t tm_info;
unsigned VDE, MSL, cols, rows, cWidth;
static unsigned cs_counter = 1;
static bx_bool cs_visible = 0;
bx_bool cs_toggle = 0;
cs_counter--;
if ((BX_VGA_THIS s.vga_mem_updated==0) && (cs_counter > 0))
return;
tm_info.start_address = 2*((BX_VGA_THIS s.CRTC.reg[12] << 8) +
BX_VGA_THIS s.CRTC.reg[13]);
tm_info.cs_start = BX_VGA_THIS s.CRTC.reg[0x0a] & 0x3f;
if (cs_counter == 0) {
cs_toggle = 1;
cs_visible = !cs_visible;
cs_counter = BX_VGA_THIS s.blink_counter;
}
if (!cs_visible) {
tm_info.cs_start |= 0x20;
}
tm_info.cs_end = BX_VGA_THIS s.CRTC.reg[0x0b] & 0x1f;
tm_info.line_offset = BX_VGA_THIS s.CRTC.reg[0x13] << 2;
tm_info.line_compare = BX_VGA_THIS s.line_compare;
tm_info.h_panning = BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning & 0x0f;
tm_info.v_panning = BX_VGA_THIS s.CRTC.reg[0x08] & 0x1f;
tm_info.line_graphics = BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics;
tm_info.split_hpanning = BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_panning_compat;
tm_info.blink_flags = 0;
if (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity) {
tm_info.blink_flags |= BX_TEXT_BLINK_MODE;
if (cs_toggle)
tm_info.blink_flags |= BX_TEXT_BLINK_TOGGLE;
if (cs_visible)
tm_info.blink_flags |= BX_TEXT_BLINK_STATE;
}
if ((BX_VGA_THIS s.sequencer.reg1 & 0x01) == 0) {
if (tm_info.h_panning >= 8)
tm_info.h_panning = 0;
else
tm_info.h_panning++;
} else {
tm_info.h_panning &= 0x07;
}
// Verticle Display End: find out how many lines are displayed
VDE = BX_VGA_THIS s.vertical_display_end;
// Maximum Scan Line: height of character cell
MSL = BX_VGA_THIS s.CRTC.reg[0x09] & 0x1f;
cols = BX_VGA_THIS s.CRTC.reg[1] + 1;
// workaround for update() calls before VGABIOS init
if (cols == 1) {
cols = 80;
MSL = 15;
}
if ((MSL == 1) && (VDE == 399)) {
// emulated CGA graphics mode 160x100x16 colors
MSL = 3;
}
rows = (VDE+1)/(MSL+1);
if ((rows * tm_info.line_offset) > (1 << 17)) {
BX_ERROR(("update(): text mode: out of memory"));
return;
}
cWidth = ((BX_VGA_THIS s.sequencer.reg1 & 0x01) == 1) ? 8 : 9;
iWidth = cWidth * cols;
iHeight = VDE+1;
if ((iWidth != BX_VGA_THIS s.last_xres) || (iHeight != BX_VGA_THIS s.last_yres) || (MSL != old_MSL) ||
(BX_VGA_THIS s.last_bpp > 8))
{
bx_gui->dimension_update(iWidth, iHeight, MSL+1, cWidth);
BX_VGA_THIS s.last_xres = iWidth;
BX_VGA_THIS s.last_yres = iHeight;
old_MSL = MSL;
BX_VGA_THIS s.last_bpp = 8;
}
// pass old text snapshot & new VGA memory contents
start_address = tm_info.start_address;
cursor_address = 2*((BX_VGA_THIS s.CRTC.reg[0x0e] << 8) +
BX_VGA_THIS s.CRTC.reg[0x0f]);
if (cursor_address < start_address) {
cursor_x = 0xffff;
cursor_y = 0xffff;
} else {
cursor_x = ((cursor_address - start_address)/2) % (iWidth/cWidth);
cursor_y = ((cursor_address - start_address)/2) / (iWidth/cWidth);
}
bx_gui->text_update(BX_VGA_THIS s.text_snapshot,
&BX_VGA_THIS s.memory[start_address],
cursor_x, cursor_y, tm_info);
if (BX_VGA_THIS s.vga_mem_updated) {
// screen updated, copy new VGA memory contents into text snapshot
memcpy(BX_VGA_THIS s.text_snapshot,
&BX_VGA_THIS s.memory[start_address],
tm_info.line_offset*rows);
BX_VGA_THIS s.vga_mem_updated = 0;
}
}
}
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)
{
Bit32u offset;
Bit8u *plane0, *plane1, *plane2, *plane3;
// 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;
}
switch (BX_VGA_THIS s.graphics_ctrl.memory_mapping) {
case 1: // 0xA0000 .. 0xAFFFF
if (addr > 0xAFFFF) return 0xff;
offset = addr & 0xFFFF;
break;
case 2: // 0xB0000 .. 0xB7FFF
if ((addr < 0xB0000) || (addr > 0xB7FFF)) return 0xff;
offset = addr & 0x7FFF;
break;
case 3: // 0xB8000 .. 0xBFFFF
if (addr < 0xB8000) return 0xff;
offset = addr & 0x7FFF;
break;
default: // 0xA0000 .. 0xBFFFF
offset = addr & 0x1FFFF;
}
if (BX_VGA_THIS s.sequencer.chain_four) {
// Mode 13h: 320 x 200 256 color mode: chained pixel representation
return BX_VGA_THIS s.memory[(offset & ~0x03) + (offset % 4)*65536];
}
if (BX_VGA_THIS vbe.enabled) {
plane0 = &BX_VGA_THIS s.memory[(0<<VBE_DISPI_4BPP_PLANE_SHIFT) + (BX_VGA_THIS vbe.bank<<16)];
plane1 = &BX_VGA_THIS s.memory[(1<<VBE_DISPI_4BPP_PLANE_SHIFT) + (BX_VGA_THIS vbe.bank<<16)];
plane2 = &BX_VGA_THIS s.memory[(2<<VBE_DISPI_4BPP_PLANE_SHIFT) + (BX_VGA_THIS vbe.bank<<16)];
plane3 = &BX_VGA_THIS s.memory[(3<<VBE_DISPI_4BPP_PLANE_SHIFT) + (BX_VGA_THIS vbe.bank<<16)];
} else {
plane0 = &BX_VGA_THIS s.memory[0<<16];
plane1 = &BX_VGA_THIS s.memory[1<<16];
plane2 = &BX_VGA_THIS s.memory[2<<16];
plane3 = &BX_VGA_THIS s.memory[3<<16];
}
/* addr between 0xA0000 and 0xAFFFF */
switch (BX_VGA_THIS s.graphics_ctrl.read_mode) {
case 0: /* read mode 0 */
BX_VGA_THIS s.graphics_ctrl.latch[0] = plane0[offset];
BX_VGA_THIS s.graphics_ctrl.latch[1] = plane1[offset];
BX_VGA_THIS s.graphics_ctrl.latch[2] = plane2[offset];
BX_VGA_THIS s.graphics_ctrl.latch[3] = plane3[offset];
return(BX_VGA_THIS s.graphics_ctrl.latch[BX_VGA_THIS s.graphics_ctrl.read_map_select]);
break;
case 1: /* read mode 1 */
{
Bit8u color_compare, color_dont_care;
Bit8u latch0, latch1, latch2, latch3, retval;
color_compare = BX_VGA_THIS s.graphics_ctrl.color_compare & 0x0f;
color_dont_care = BX_VGA_THIS s.graphics_ctrl.color_dont_care & 0x0f;
latch0 = BX_VGA_THIS s.graphics_ctrl.latch[0] = plane0[offset];
latch1 = BX_VGA_THIS s.graphics_ctrl.latch[1] = plane1[offset];
latch2 = BX_VGA_THIS s.graphics_ctrl.latch[2] = plane2[offset];
latch3 = BX_VGA_THIS s.graphics_ctrl.latch[3] = plane3[offset];
latch0 ^= ccdat[color_compare][0];
latch1 ^= ccdat[color_compare][1];
latch2 ^= ccdat[color_compare][2];
latch3 ^= ccdat[color_compare][3];
latch0 &= ccdat[color_dont_care][0];
latch1 &= ccdat[color_dont_care][1];
latch2 &= ccdat[color_dont_care][2];
latch3 &= ccdat[color_dont_care][3];
retval = ~(latch0 | latch1 | latch2 | latch3);
return retval;
}
break;
default:
return 0;
}
}
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)
{
Bit32u offset;
Bit8u new_val[4] = {0,0,0,0};
unsigned start_addr;
Bit8u *plane0, *plane1, *plane2, *plane3;
// 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;
}
switch (BX_VGA_THIS s.graphics_ctrl.memory_mapping) {
case 1: // 0xA0000 .. 0xAFFFF
if ((addr < 0xA0000) || (addr > 0xAFFFF)) return;
offset = (Bit32u)addr - 0xA0000;
break;
case 2: // 0xB0000 .. 0xB7FFF
if ((addr < 0xB0000) || (addr > 0xB7FFF)) return;
offset = (Bit32u)addr - 0xB0000;
break;
case 3: // 0xB8000 .. 0xBFFFF
if ((addr < 0xB8000) || (addr > 0xBFFFF)) return;
offset = (Bit32u)addr - 0xB8000;
break;
default: // 0xA0000 .. 0xBFFFF
if ((addr < 0xA0000) || (addr > 0xBFFFF)) return;
offset = (Bit32u)addr - 0xA0000;
}
start_addr = (BX_VGA_THIS s.CRTC.reg[0x0c] << 8) | BX_VGA_THIS s.CRTC.reg[0x0d];
if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
if (BX_VGA_THIS s.graphics_ctrl.memory_mapping == 3) { // 0xB8000 .. 0xBFFFF
unsigned x_tileno, x_tileno2, y_tileno;
/* CGA 320x200x4 / 640x200x2 start */
BX_VGA_THIS s.memory[offset] = value;
offset -= start_addr;
if (offset>=0x2000) {
y_tileno = offset - 0x2000;
y_tileno /= (320/4);
y_tileno <<= 1; //2 * y_tileno;
y_tileno++;
x_tileno = (offset - 0x2000) % (320/4);
x_tileno <<= 2; //*= 4;
} else {
y_tileno = offset / (320/4);
y_tileno <<= 1; //2 * y_tileno;
x_tileno = offset % (320/4);
x_tileno <<= 2; //*=4;
}
x_tileno2=x_tileno;
if (BX_VGA_THIS s.graphics_ctrl.shift_reg==0) {
x_tileno*=2;
x_tileno2+=7;
} else {
x_tileno2+=3;
}
if (BX_VGA_THIS s.x_dotclockdiv2) {
x_tileno/=(X_TILESIZE/2);
x_tileno2/=(X_TILESIZE/2);
} else {
x_tileno/=X_TILESIZE;
x_tileno2/=X_TILESIZE;
}
if (BX_VGA_THIS s.y_doublescan) {
y_tileno/=(Y_TILESIZE/2);
} else {
y_tileno/=Y_TILESIZE;
}
BX_VGA_THIS s.vga_mem_updated = 1;
SET_TILE_UPDATED (x_tileno, y_tileno, 1);
if (x_tileno2!=x_tileno) {
SET_TILE_UPDATED (x_tileno2, y_tileno, 1);
}
return;
/* CGA 320x200x4 / 640x200x2 end */
}
/*
else if (BX_VGA_THIS s.graphics_ctrl.memory_mapping != 1) {
BX_PANIC(("mem_write: graphics: mapping = %u",
(unsigned) BX_VGA_THIS s.graphics_ctrl.memory_mapping));
return;
}
*/
if (BX_VGA_THIS s.sequencer.chain_four) {
unsigned x_tileno, y_tileno;
// 320 x 200 256 color mode: chained pixel representation
BX_VGA_THIS s.memory[(offset & ~0x03) + (offset % 4)*65536] = value;
if (BX_VGA_THIS s.line_offset > 0) {
offset -= start_addr;
x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE/2);
if (BX_VGA_THIS s.y_doublescan) {
y_tileno = (offset / BX_VGA_THIS s.line_offset) / (Y_TILESIZE/2);
} else {
y_tileno = (offset / BX_VGA_THIS s.line_offset) / Y_TILESIZE;
}
BX_VGA_THIS s.vga_mem_updated = 1;
SET_TILE_UPDATED (x_tileno, y_tileno, 1);
}
return;
}
}
/* addr between 0xA0000 and 0xAFFFF */
if (BX_VGA_THIS vbe.enabled) {
plane0 = &BX_VGA_THIS s.memory[(0<<VBE_DISPI_4BPP_PLANE_SHIFT) + (BX_VGA_THIS vbe.bank<<16)];
plane1 = &BX_VGA_THIS s.memory[(1<<VBE_DISPI_4BPP_PLANE_SHIFT) + (BX_VGA_THIS vbe.bank<<16)];
plane2 = &BX_VGA_THIS s.memory[(2<<VBE_DISPI_4BPP_PLANE_SHIFT) + (BX_VGA_THIS vbe.bank<<16)];
plane3 = &BX_VGA_THIS s.memory[(3<<VBE_DISPI_4BPP_PLANE_SHIFT) + (BX_VGA_THIS vbe.bank<<16)];
} else {
plane0 = &BX_VGA_THIS s.memory[0<<16];
plane1 = &BX_VGA_THIS s.memory[1<<16];
plane2 = &BX_VGA_THIS s.memory[2<<16];
plane3 = &BX_VGA_THIS s.memory[3<<16];
}
switch (BX_VGA_THIS s.graphics_ctrl.write_mode) {
unsigned i;
case 0: /* write mode 0 */
{
const Bit8u bitmask = BX_VGA_THIS s.graphics_ctrl.bitmask;
const Bit8u set_reset = BX_VGA_THIS s.graphics_ctrl.set_reset;
const Bit8u enable_set_reset = BX_VGA_THIS s.graphics_ctrl.enable_set_reset;
/* perform rotate on CPU data in case its needed */
if (BX_VGA_THIS s.graphics_ctrl.data_rotate) {
value = (value >> BX_VGA_THIS s.graphics_ctrl.data_rotate) |
(value << (8 - BX_VGA_THIS s.graphics_ctrl.data_rotate));
}
new_val[0] = BX_VGA_THIS s.graphics_ctrl.latch[0] & ~bitmask;
new_val[1] = BX_VGA_THIS s.graphics_ctrl.latch[1] & ~bitmask;
new_val[2] = BX_VGA_THIS s.graphics_ctrl.latch[2] & ~bitmask;
new_val[3] = BX_VGA_THIS s.graphics_ctrl.latch[3] & ~bitmask;
switch (BX_VGA_THIS s.graphics_ctrl.raster_op) {
case 0: // replace
new_val[0] |= ((enable_set_reset & 1)
? ((set_reset & 1) ? bitmask : 0)
: (value & bitmask));
new_val[1] |= ((enable_set_reset & 2)
? ((set_reset & 2) ? bitmask : 0)
: (value & bitmask));
new_val[2] |= ((enable_set_reset & 4)
? ((set_reset & 4) ? bitmask : 0)
: (value & bitmask));
new_val[3] |= ((enable_set_reset & 8)
? ((set_reset & 8) ? bitmask : 0)
: (value & bitmask));
break;
case 1: // AND
new_val[0] |= ((enable_set_reset & 1)
? ((set_reset & 1)
? (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask)
: 0)
: (value & BX_VGA_THIS s.graphics_ctrl.latch[0]) & bitmask);
new_val[1] |= ((enable_set_reset & 2)
? ((set_reset & 2)
? (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask)
: 0)
: (value & BX_VGA_THIS s.graphics_ctrl.latch[1]) & bitmask);
new_val[2] |= ((enable_set_reset & 4)
? ((set_reset & 4)
? (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask)
: 0)
: (value & BX_VGA_THIS s.graphics_ctrl.latch[2]) & bitmask);
new_val[3] |= ((enable_set_reset & 8)
? ((set_reset & 8)
? (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask)
: 0)
: (value & BX_VGA_THIS s.graphics_ctrl.latch[3]) & bitmask);
break;
case 2: // OR
new_val[0]
|= ((enable_set_reset & 1)
? ((set_reset & 1)
? bitmask
: (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask))
: ((value | BX_VGA_THIS s.graphics_ctrl.latch[0]) & bitmask));
new_val[1]
|= ((enable_set_reset & 2)
? ((set_reset & 2)
? bitmask
: (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask))
: ((value | BX_VGA_THIS s.graphics_ctrl.latch[1]) & bitmask));
new_val[2]
|= ((enable_set_reset & 4)
? ((set_reset & 4)
? bitmask
: (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask))
: ((value | BX_VGA_THIS s.graphics_ctrl.latch[2]) & bitmask));
new_val[3]
|= ((enable_set_reset & 8)
? ((set_reset & 8)
? bitmask
: (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask))
: ((value | BX_VGA_THIS s.graphics_ctrl.latch[3]) & bitmask));
break;
case 3: // XOR
new_val[0]
|= ((enable_set_reset & 1)
? ((set_reset & 1)
? (~BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask)
: (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask))
: (value ^ BX_VGA_THIS s.graphics_ctrl.latch[0]) & bitmask);
new_val[1]
|= ((enable_set_reset & 2)
? ((set_reset & 2)
? (~BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask)
: (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask))
: (value ^ BX_VGA_THIS s.graphics_ctrl.latch[1]) & bitmask);
new_val[2]
|= ((enable_set_reset & 4)
? ((set_reset & 4)
? (~BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask)
: (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask))
: (value ^ BX_VGA_THIS s.graphics_ctrl.latch[2]) & bitmask);
new_val[3]
|= ((enable_set_reset & 8)
? ((set_reset & 8)
? (~BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask)
: (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask))
: (value ^ BX_VGA_THIS s.graphics_ctrl.latch[3]) & bitmask);
break;
default:
BX_PANIC(("vga_mem_write: write mode 0: op = %u",
(unsigned) BX_VGA_THIS s.graphics_ctrl.raster_op));
}
}
break;
case 1: /* write mode 1 */
for (i=0; i<4; i++) {
new_val[i] = BX_VGA_THIS s.graphics_ctrl.latch[i];
}
break;
case 2: /* write mode 2 */
{
const Bit8u bitmask = BX_VGA_THIS s.graphics_ctrl.bitmask;
new_val[0] = BX_VGA_THIS s.graphics_ctrl.latch[0] & ~bitmask;
new_val[1] = BX_VGA_THIS s.graphics_ctrl.latch[1] & ~bitmask;
new_val[2] = BX_VGA_THIS s.graphics_ctrl.latch[2] & ~bitmask;
new_val[3] = BX_VGA_THIS s.graphics_ctrl.latch[3] & ~bitmask;
switch (BX_VGA_THIS s.graphics_ctrl.raster_op) {
case 0: // write
new_val[0] |= (value & 1) ? bitmask : 0;
new_val[1] |= (value & 2) ? bitmask : 0;
new_val[2] |= (value & 4) ? bitmask : 0;
new_val[3] |= (value & 8) ? bitmask : 0;
break;
case 1: // AND
new_val[0] |= (value & 1)
? (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask)
: 0;
new_val[1] |= (value & 2)
? (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask)
: 0;
new_val[2] |= (value & 4)
? (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask)
: 0;
new_val[3] |= (value & 8)
? (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask)
: 0;
break;
case 2: // OR
new_val[0] |= (value & 1)
? bitmask
: (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask);
new_val[1] |= (value & 2)
? bitmask
: (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask);
new_val[2] |= (value & 4)
? bitmask
: (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask);
new_val[3] |= (value & 8)
? bitmask
: (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask);
break;
case 3: // XOR
new_val[0] |= (value & 1)
? (~BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask)
: (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask);
new_val[1] |= (value & 2)
? (~BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask)
: (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask);
new_val[2] |= (value & 4)
? (~BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask)
: (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask);
new_val[3] |= (value & 8)
? (~BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask)
: (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask);
break;
}
}
break;
case 3: /* write mode 3 */
{
const Bit8u bitmask = BX_VGA_THIS s.graphics_ctrl.bitmask & value;
const Bit8u set_reset = BX_VGA_THIS s.graphics_ctrl.set_reset;
/* perform rotate on CPU data */
if (BX_VGA_THIS s.graphics_ctrl.data_rotate) {
value = (value >> BX_VGA_THIS s.graphics_ctrl.data_rotate) |
(value << (8 - BX_VGA_THIS s.graphics_ctrl.data_rotate));
}
new_val[0] = BX_VGA_THIS s.graphics_ctrl.latch[0] & ~bitmask;
new_val[1] = BX_VGA_THIS s.graphics_ctrl.latch[1] & ~bitmask;
new_val[2] = BX_VGA_THIS s.graphics_ctrl.latch[2] & ~bitmask;
new_val[3] = BX_VGA_THIS s.graphics_ctrl.latch[3] & ~bitmask;
value &= bitmask;
switch (BX_VGA_THIS s.graphics_ctrl.raster_op) {
case 0: // write
new_val[0] |= (set_reset & 1) ? value : 0;
new_val[1] |= (set_reset & 2) ? value : 0;
new_val[2] |= (set_reset & 4) ? value : 0;
new_val[3] |= (set_reset & 8) ? value : 0;
break;
case 1: // AND
new_val[0] |= ((set_reset & 1) ? value : 0)
& BX_VGA_THIS s.graphics_ctrl.latch[0];
new_val[1] |= ((set_reset & 2) ? value : 0)
& BX_VGA_THIS s.graphics_ctrl.latch[1];
new_val[2] |= ((set_reset & 4) ? value : 0)
& BX_VGA_THIS s.graphics_ctrl.latch[2];
new_val[3] |= ((set_reset & 8) ? value : 0)
& BX_VGA_THIS s.graphics_ctrl.latch[3];
break;
case 2: // OR
new_val[0] |= ((set_reset & 1) ? value : 0)
| BX_VGA_THIS s.graphics_ctrl.latch[0];
new_val[1] |= ((set_reset & 2) ? value : 0)
| BX_VGA_THIS s.graphics_ctrl.latch[1];
new_val[2] |= ((set_reset & 4) ? value : 0)
| BX_VGA_THIS s.graphics_ctrl.latch[2];
new_val[3] |= ((set_reset & 8) ? value : 0)
| BX_VGA_THIS s.graphics_ctrl.latch[3];
break;
case 3: // XOR
new_val[0] |= ((set_reset & 1) ? value : 0)
^ BX_VGA_THIS s.graphics_ctrl.latch[0];
new_val[1] |= ((set_reset & 2) ? value : 0)
^ BX_VGA_THIS s.graphics_ctrl.latch[1];
new_val[2] |= ((set_reset & 4) ? value : 0)
^ BX_VGA_THIS s.graphics_ctrl.latch[2];
new_val[3] |= ((set_reset & 8) ? value : 0)
^ BX_VGA_THIS s.graphics_ctrl.latch[3];
break;
}
}
break;
default:
BX_PANIC(("vga_mem_write: write mode %u ?",
(unsigned) BX_VGA_THIS s.graphics_ctrl.write_mode));
}
if (BX_VGA_THIS s.sequencer.map_mask & 0x0f) {
BX_VGA_THIS s.vga_mem_updated = 1;
if (BX_VGA_THIS s.sequencer.map_mask & 0x01)
plane0[offset] = new_val[0];
if (BX_VGA_THIS s.sequencer.map_mask & 0x02)
plane1[offset] = new_val[1];
if (BX_VGA_THIS s.sequencer.map_mask & 0x04) {
if ((offset & 0xe000) == BX_VGA_THIS s.charmap_address) {
bx_gui->set_text_charbyte((offset & 0x1fff), new_val[2]);
}
plane2[offset] = new_val[2];
}
if (BX_VGA_THIS s.sequencer.map_mask & 0x08)
plane3[offset] = new_val[3];
unsigned x_tileno, y_tileno;
if (BX_VGA_THIS s.graphics_ctrl.shift_reg == 2) {
offset -= start_addr;
x_tileno = (offset % BX_VGA_THIS s.line_offset) * 4 / (X_TILESIZE / 2);
if (BX_VGA_THIS s.y_doublescan) {
y_tileno = (offset / BX_VGA_THIS s.line_offset) / (Y_TILESIZE / 2);
} else {
y_tileno = (offset / BX_VGA_THIS s.line_offset) / Y_TILESIZE;
}
SET_TILE_UPDATED (x_tileno, y_tileno, 1);
} else {
if (BX_VGA_THIS s.line_compare < BX_VGA_THIS s.vertical_display_end) {
if (BX_VGA_THIS s.line_offset > 0) {
if (BX_VGA_THIS s.x_dotclockdiv2) {
x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE / 16);
} else {
x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE / 8);
}
if (BX_VGA_THIS s.y_doublescan) {
y_tileno = ((offset / BX_VGA_THIS s.line_offset) * 2 + BX_VGA_THIS s.line_compare + 1) / Y_TILESIZE;
} else {
y_tileno = ((offset / BX_VGA_THIS s.line_offset) + BX_VGA_THIS s.line_compare + 1) / Y_TILESIZE;
}
SET_TILE_UPDATED (x_tileno, y_tileno, 1);
}
}
if (offset >= start_addr) {
offset -= start_addr;
if (BX_VGA_THIS s.line_offset > 0) {
if (BX_VGA_THIS s.x_dotclockdiv2) {
x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE / 16);
} else {
x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE / 8);
}
if (BX_VGA_THIS s.y_doublescan) {
y_tileno = (offset / BX_VGA_THIS s.line_offset) / (Y_TILESIZE / 2);
} else {
y_tileno = (offset / BX_VGA_THIS s.line_offset) / Y_TILESIZE;
}
SET_TILE_UPDATED (x_tileno, y_tileno, 1);
}
}
}
}
}
int bx_vga_c::get_snapshot_mode()
{
if ((BX_VGA_THIS vbe.enabled) && (BX_VGA_THIS vbe.bpp >= 8)) {
return BX_GUI_SNAPSHOT_GFX;
} else if (!BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
return BX_GUI_SNAPSHOT_TXT;
} else if ((BX_VGA_THIS s.graphics_ctrl.shift_reg == 0) &&
((BX_VGA_THIS s.CRTC.reg[0x17] & 1) != 0)) {
return BX_GUI_SNAPSHOT_GFX;
} else if (BX_VGA_THIS s.graphics_ctrl.shift_reg == 2) {
return BX_GUI_SNAPSHOT_GFX;
} else {
return BX_GUI_SNAPSHOT_UNSUP;
}
}
void bx_vga_c::get_text_snapshot(Bit8u **text_snapshot, unsigned *txHeight,
unsigned *txWidth)
{
unsigned VDE, MSL;
if (!BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
*text_snapshot = &BX_VGA_THIS s.text_snapshot[0];
VDE = BX_VGA_THIS s.vertical_display_end;
MSL = BX_VGA_THIS s.CRTC.reg[0x09] & 0x1f;
*txHeight = (VDE+1)/(MSL+1);
*txWidth = BX_VGA_THIS s.CRTC.reg[1] + 1;
} else {
*txHeight = 0;
*txWidth = 0;
}
}
bx_bool bx_vga_c::get_dac_palette(Bit8u **palette_ptr, Bit8u shift)
{
unsigned i;
Bit8u *dst_ptr;
*palette_ptr = (Bit8u*)malloc(256 * 4);
if (palette_ptr == NULL) return 0;
dst_ptr = *palette_ptr;
for (i = 0; i < 256; i++) {
*(dst_ptr++) = (BX_VGA_THIS s.pel.data[i].blue << shift);
*(dst_ptr++) = (BX_VGA_THIS s.pel.data[i].green << shift);
*(dst_ptr++) = (BX_VGA_THIS s.pel.data[i].red << shift);
*(dst_ptr++) = 0;
}
return 1;
}
Bit32u bx_vga_c::get_gfx_snapshot(Bit8u **snapshot_ptr, Bit8u **palette_ptr,
unsigned *iHeight, unsigned *iWidth, unsigned *iDepth)
{
Bit32u len, len1;
unsigned i, line_compare, shift, start_addr, x, y;
unsigned byte_offset, px, py;
Bit8u *dst_ptr, *src_ptr, *plane[4];
if ((BX_VGA_THIS vbe.enabled) && (BX_VGA_THIS vbe.bpp >= 8)) {
*iHeight = BX_VGA_THIS vbe.yres;
*iWidth = BX_VGA_THIS vbe.xres;
*iDepth = BX_VGA_THIS vbe.bpp;
len1 = BX_VGA_THIS vbe.xres * BX_VGA_THIS vbe.bpp_multiplier;
len = len1 * BX_VGA_THIS vbe.yres;
*snapshot_ptr = (Bit8u*)malloc(len);
if (snapshot_ptr == NULL)
return 0;
src_ptr = BX_VGA_THIS s.memory + BX_VGA_THIS vbe.virtual_start;
dst_ptr = *snapshot_ptr;
for (i = 0; i < BX_VGA_THIS vbe.yres; i++) {
memcpy(dst_ptr, src_ptr, len1);
src_ptr += BX_VGA_THIS s.line_offset;
dst_ptr += len1;
}
if (*iDepth == 8) {
if (BX_VGA_THIS vbe.dac_8bit) {
shift = 0;
} else {
shift = 2;
}
BX_VGA_THIS get_dac_palette(palette_ptr, shift);
}
return len;
} else {
*iHeight = BX_VGA_THIS s.last_yres;
*iWidth = BX_VGA_THIS s.last_xres;
*iDepth = 8;
len = (BX_VGA_THIS s.last_xres * BX_VGA_THIS s.last_yres);
*snapshot_ptr = (Bit8u*)malloc(len);
if (snapshot_ptr == NULL)
return 0;
dst_ptr = *snapshot_ptr;
if (BX_VGA_THIS vbe.enabled) {
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];
start_addr = BX_VGA_THIS vbe.virtual_start;
line_compare = 0xffff;
} else {
plane[0] = &BX_VGA_THIS s.memory[0<<16];
plane[1] = &BX_VGA_THIS s.memory[1<<16];
plane[2] = &BX_VGA_THIS s.memory[2<<16];
plane[3] = &BX_VGA_THIS s.memory[3<<16];
start_addr = (BX_VGA_THIS s.CRTC.reg[0x0c] << 8) | BX_VGA_THIS s.CRTC.reg[0x0d];
line_compare = BX_VGA_THIS s.line_compare;
if (BX_VGA_THIS s.y_doublescan) line_compare >>= 1;
}
if ((BX_VGA_THIS s.graphics_ctrl.shift_reg == 0) &&
(BX_VGA_THIS s.graphics_ctrl.memory_mapping != 3)) {
for (y = 0; y < BX_VGA_THIS s.last_yres; y++) {
for (x = 0; x < BX_VGA_THIS s.last_xres; x++) {
*(dst_ptr++) = BX_VGA_THIS get_vga_pixel(x, y, start_addr, line_compare, plane);
}
}
BX_VGA_THIS get_dac_palette(palette_ptr, 2);
return len;
} else if (BX_VGA_THIS s.graphics_ctrl.shift_reg == 2) {
for (y = 0; y < BX_VGA_THIS s.last_yres; y++) {
for (x = 0; x < BX_VGA_THIS s.last_xres; x++) {
px = x >> 1;
py = y >> BX_VGA_THIS s.y_doublescan;
byte_offset = start_addr + py * BX_VGA_THIS s.line_offset;
if (BX_VGA_THIS s.CRTC.reg[0x14] & 0x40) { // DW set: doubleword mode
byte_offset += (px & ~0x03);
} else if (BX_VGA_THIS s.CRTC.reg[0x17] & 0x40) { // B/W set: byte mode, modeX
byte_offset += (px >> 2);
} else {
byte_offset += (px >> 1) & ~0x01;
}
*(dst_ptr++) = plane[px % 4][byte_offset];
}
}
BX_VGA_THIS get_dac_palette(palette_ptr, 2);
return len;
} else {
*iHeight = 0;
*iWidth = 0;
*iDepth = 0;
return 0;
}
}
}
Bit8u bx_vga_c::get_actl_palette_idx(Bit8u index)
{
return BX_VGA_THIS s.attribute_ctrl.palette_reg[index];
}
#if BX_DEBUGGER
void bx_vga_c::debug_dump(void)
{
dbg_printf("s.misc_output.color_emulation = %u\n",
(unsigned) BX_VGA_THIS s.misc_output.color_emulation);
dbg_printf("s.misc_output.enable_ram = %u\n",
(unsigned) BX_VGA_THIS s.misc_output.enable_ram);
dbg_printf("s.misc_output.clock_select = %u ",
(unsigned) BX_VGA_THIS s.misc_output.clock_select);
if (BX_VGA_THIS s.misc_output.clock_select == 0)
dbg_printf("(25Mhz 640 horiz pixel clock)\n");
else
dbg_printf("(28Mhz 720 horiz pixel clock)\n");
dbg_printf("s.misc_output.select_high_bank = %u\n",
(unsigned) BX_VGA_THIS s.misc_output.select_high_bank);
dbg_printf("s.misc_output.horiz_sync_pol = %u\n",
(unsigned) BX_VGA_THIS s.misc_output.horiz_sync_pol);
dbg_printf("s.misc_output.vert_sync_pol = %u ",
(unsigned) BX_VGA_THIS s.misc_output.vert_sync_pol);
switch ((BX_VGA_THIS s.misc_output.vert_sync_pol << 1) |
BX_VGA_THIS s.misc_output.horiz_sync_pol) {
case 1: dbg_printf("(400 lines)\n"); break;
case 2: dbg_printf("(350 lines)\n"); break;
case 3: dbg_printf("(480 lines)\n"); break;
default: dbg_printf("(reserved)\n");
}
dbg_printf("s.graphics_ctrl.odd_even = %u\n",
(unsigned) BX_VGA_THIS s.graphics_ctrl.odd_even);
dbg_printf("s.graphics_ctrl.chain_odd_even = %u\n",
(unsigned) BX_VGA_THIS s.graphics_ctrl.chain_odd_even);
dbg_printf("s.graphics_ctrl.shift_reg = %u\n",
(unsigned) BX_VGA_THIS s.graphics_ctrl.shift_reg);
dbg_printf("s.graphics_ctrl.graphics_alpha = %u\n",
(unsigned) BX_VGA_THIS s.graphics_ctrl.graphics_alpha);
dbg_printf("s.graphics_ctrl.memory_mapping = %u ",
(unsigned) BX_VGA_THIS s.graphics_ctrl.memory_mapping);
switch (BX_VGA_THIS s.graphics_ctrl.memory_mapping) {
case 1: dbg_printf("(A0000-AFFFF)\n"); break;
case 2: dbg_printf("(B0000-B7FFF)\n"); break;
case 3: dbg_printf("(B8000-BFFFF)\n"); break;
default: dbg_printf("(A0000-BFFFF)\n"); break;
}
dbg_printf("s.sequencer.extended_mem = %u\n",
(unsigned) BX_VGA_THIS s.sequencer.extended_mem);
dbg_printf("s.sequencer.odd_even = %u (inverted)\n",
(unsigned) BX_VGA_THIS s.sequencer.odd_even);
dbg_printf("s.sequencer.chain_four = %u\n",
(unsigned) BX_VGA_THIS s.sequencer.chain_four);
dbg_printf("s.attribute_ctrl.video_enabled = %u\n",
(unsigned) BX_VGA_THIS s.attribute_ctrl.video_enabled);
dbg_printf("s.attribute_ctrl.mode_ctrl.graphics_alpha = %u\n",
(unsigned) BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha);
dbg_printf("s.attribute_ctrl.mode_ctrl.display_type = %u\n",
(unsigned) BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type);
dbg_printf("s.attribute_ctrl.mode_ctrl.internal_palette_size = %u\n",
(unsigned) BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size);
dbg_printf("s.attribute_ctrl.mode_ctrl.pixel_clock_select = %u\n",
(unsigned) BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select);
}
#endif
void bx_vga_c::redraw_area(unsigned x0, unsigned y0, unsigned width,
unsigned height)
{
unsigned xti, yti, xt0, xt1, yt0, yt1, xmax, ymax;
if (width == 0 || height == 0) {
return;
}
BX_VGA_THIS s.vga_mem_updated = 1;
if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha || BX_VGA_THIS vbe.enabled) {
// graphics mode
xmax = BX_VGA_THIS s.last_xres;
ymax = BX_VGA_THIS s.last_yres;
if (BX_VGA_THIS vbe.enabled) {
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(xti, yti, 1);
}
}
} else {
// text mode
memset(BX_VGA_THIS s.text_snapshot, 0,
sizeof(BX_VGA_THIS s.text_snapshot));
}
}
bx_bool bx_vga_c::vbe_set_base_addr(Bit32u *addr, Bit8u *pci_conf)
{
if (DEV_pci_set_base_mem(BX_VGA_THIS_PTR, mem_read_handler,
mem_write_handler,
addr, pci_conf, VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES)) {
BX_VGA_THIS vbe.base_address = *addr;
return 1;
}
return 0;
}
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 (BX_VGA_THIS vbe.lfb_enabled)
{
if (addr >= BX_VGA_THIS vbe.base_address) {
// LFB write
offset = (Bit32u)(addr - BX_VGA_THIS vbe.base_address);
}
else {
// banked mode write while in LFB mode -> ignore
return;
}
}
else
{
if (addr < BX_VGA_THIS vbe.base_address) {
// banked mode write
offset = (Bit32u)(BX_VGA_THIS vbe.bank*65536 + (addr - 0xA0000));
}
else {
// LFB write while in banked mode -> ignore
return;
}
}
// 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_NUM_Y_TILES) && (x_tileno < BX_NUM_X_TILES))
{
BX_VGA_THIS s.vga_mem_updated = 1;
SET_TILE_UPDATED (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;
// 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);
default:
BX_PANIC(("VBE unknown data read index 0x%x",BX_VGA_THIS vbe.curindex));
break;
}
}
BX_PANIC(("VBE_read shouldn't reach this"));
return 0; /* keep compiler happy */
}
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))
{
if (!BX_VGA_THIS vbe.lfb_enabled)
{
BX_DEBUG(("VBE set bank to %d", value));
BX_VGA_THIS vbe.bank=value;
}
else
{
BX_ERROR(("VBE set bank in LFB mode ignored"));
}
}
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)
{
BX_VGA_THIS vbe.lfb_enabled=(bx_bool)(value & VBE_DISPI_LFB_ENABLED);
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;
}
}
else if (((value & VBE_DISPI_ENABLED) == 0) && BX_VGA_THIS vbe.enabled)
{
BX_INFO(("VBE disabling"));
BX_VGA_THIS vbe.lfb_enabled=0;
}
BX_VGA_THIS vbe.enabled=(bx_bool)(value & VBE_DISPI_ENABLED);
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;
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
// basicly 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;
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_NUM_X_TILES; xti++) {
for (unsigned yti = 0; yti < BX_NUM_Y_TILES; yti++) {
SET_TILE_UPDATED (xti, yti, 1);
}
}
}
break;
} // end switch address
}