Cirrus.cpp

Go to the documentation of this file.
00001 /* ES40 emulator.
00002  * Copyright (C) 2007-2008 by the ES40 Emulator Project
00003  *
00004  * WWW    : http://sourceforge.net/projects/es40
00005  * E-mail : camiel@camicom.com
00006  * 
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  * 
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00020  * 
00021  * Although this is not required, the author would appreciate being notified of, 
00022  * and receiving any modifications you may make to the source code that might serve
00023  * the general public.
00024  */
00025 
00097 #include "StdAfx.h"
00098 #include "Cirrus.h"
00099 #include "System.h"
00100 #include "AliM1543C.h"
00101 #include "gui/gui.h"
00102 
00103 static unsigned old_iHeight = 0, old_iWidth = 0, old_MSL = 0;
00104 
00105 static const u8 ccdat[16][4] = {
00106   {0x00, 0x00, 0x00, 0x00},
00107   {0xff, 0x00, 0x00, 0x00},
00108   {0x00, 0xff, 0x00, 0x00},
00109   {0xff, 0xff, 0x00, 0x00},
00110   {0x00, 0x00, 0xff, 0x00},
00111   {0xff, 0x00, 0xff, 0x00},
00112   {0x00, 0xff, 0xff, 0x00},
00113   {0xff, 0xff, 0xff, 0x00},
00114   {0x00, 0x00, 0x00, 0xff},
00115   {0xff, 0x00, 0x00, 0xff},
00116   {0x00, 0xff, 0x00, 0xff},
00117   {0xff, 0xff, 0x00, 0xff},
00118   {0x00, 0x00, 0xff, 0xff},
00119   {0xff, 0x00, 0xff, 0xff},
00120   {0x00, 0xff, 0xff, 0xff},
00121   {0xff, 0xff, 0xff, 0xff},
00122 };
00123 
00130 #define SET_TILE_UPDATED(xtile, ytile, value)                    \
00131   do                                                             \
00132   {                                                              \
00133     if(((xtile) < BX_NUM_X_TILES) && ((ytile) < BX_NUM_Y_TILES)) \
00134       state.vga_tile_updated[(xtile)][(ytile)] = value;          \
00135   } while(0)
00136 
00143 #define GET_TILE_UPDATED(xtile, ytile) \
00144     ((((xtile) < BX_NUM_X_TILES) && ((ytile) < BX_NUM_Y_TILES)) ? state.vga_tile_updated[(xtile)][(ytile)] : 0)
00145 
00156 void CCirrus::run()
00157 {
00158   try
00159   {
00160     // initialize the GUI (and let it know our tilesize)
00161     bx_gui->init(state.x_tilesize, state.y_tilesize);
00162     for(;;)
00163     {
00164       // Terminate thread if StopThread is set to true
00165       if(StopThread)
00166         return;
00167       // Handle GUI events (100 times per second)
00168       for (int i=0;i<10;i++)
00169       {
00170         bx_gui->lock();
00171         bx_gui->handle_events();
00172         bx_gui->unlock();
00173         Poco::Thread::sleep(10);
00174       }
00175       //Update the screen (10 times per second)
00176       bx_gui->lock();
00177       update();
00178       bx_gui->flush();
00179       bx_gui->unlock();
00180     }
00181   }
00182 
00183   catch(Poco::Exception & e)
00184   {
00185     printf("Exception in Cirrus thread: %s.\n", e.displayText().c_str());
00186 
00187     // Let the thread die...
00188   }
00189 }
00190 
00192 static unsigned int rom_max;
00193 
00195 static u8           option_rom[65536];
00196 
00198 static u32          cirrus_cfg_data[64] = {
00199   /*00*/ 0x00a81013,            // CFID: vendor + device
00200   /*04*/ 0x011f0000,            // CFCS: command + status
00201   /*08*/ 0x03000002,            // CFRV: class + revision
00202   /*0c*/ 0x00000000,            // CFLT: latency timer + cache line size
00203   /*10*/ 0xf8000000,            // BAR0: FB
00204   /*14*/ 0x00000000,            // BAR1:
00205   /*18*/ 0x00000000,            // BAR2:
00206   /*1c*/ 0x00000000,            // BAR3:
00207   /*20*/ 0x00000000,            // BAR4:
00208   /*24*/ 0x00000000,            // BAR5:
00209   /*28*/ 0x00000000,            // CCIC: CardBus
00210   /*2c*/ 0x00000000,            // CSID: subsystem + vendor
00211   /*30*/ 0x00000000,            // BAR6: expansion rom base
00212   /*34*/ 0x00000000,            // CCAP: capabilities pointer
00213   /*38*/ 0x00000000,
00214   /*3c*/ 0x281401ff,            // CFIT: interrupt configuration
00215   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00216   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00217   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
00218 };
00219 
00221 static u32          cirrus_cfg_mask[64] = {
00222   /*00*/ 0x00000000,            // CFID: vendor + device
00223   /*04*/ 0x0000ffff,            // CFCS: command + status
00224   /*08*/ 0x00000000,            // CFRV: class + revision
00225   /*0c*/ 0x0000ffff,            // CFLT: latency timer + cache line size
00226   /*10*/ 0xfc000000,            // BAR0: FB
00227   /*14*/ 0x00000000,            // BAR1:
00228   /*18*/ 0x00000000,            // BAR2:
00229   /*1c*/ 0x00000000,            // BAR3:
00230   /*20*/ 0x00000000,            // BAR4:
00231   /*24*/ 0x00000000,            // BAR5:
00232   /*28*/ 0x00000000,            // CCIC: CardBus
00233   /*2c*/ 0x00000000,            // CSID: subsystem + vendor
00234   /*30*/ 0x00000000,            // BAR6: expansion rom base
00235   /*34*/ 0x00000000,            // CCAP: capabilities pointer
00236   /*38*/ 0x00000000,
00237   /*3c*/ 0x000000ff,            // CFIT: interrupt configuration
00238   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00239   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00240   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
00241 };
00242 
00248 CCirrus::CCirrus(CConfigurator* cfg, CSystem* c, int pcibus, int pcidev) : CVGA(cfg, c, pcibus, pcidev)
00249 { }
00250 
00254 void CCirrus::init()
00255 {
00256   // Register PCI device
00257   add_function(0, cirrus_cfg_data, cirrus_cfg_mask);
00258 
00259   int i;
00260 
00261   // Initialize all state variables to 0
00262   memset((void*) &state, 0, sizeof(state));
00263 
00264   // Register VGA I/O ports at 3b4, 3b5, 3ba, 3c0..cf, 3d4, 3d5, 3da
00265   add_legacy_io(1, 0x3b4, 2);
00266   add_legacy_io(3, 0x3ba, 2);
00267   add_legacy_io(2, 0x3c0, 16);
00268   add_legacy_io(8, 0x3d4, 2);
00269   add_legacy_io(9, 0x3da, 1);
00270 
00271   /* The VGA BIOS we use sends text messages to port 0x500.
00272      We listen for these messages at port 500. */
00273   add_legacy_io(7, 0x500, 1);
00274   bios_message_size = 0;
00275   bios_message[0] = '\0';
00276 
00277   // Legacy video address space: A0000 -> bffff
00278   add_legacy_mem(4, 0xa0000, 128 * 1024);
00279 
00280   // Reset the base PCI device
00281   ResetPCI();
00282 
00283   /* The configuration file variable "rom" should point to a VGA BIOS
00284      image. If not, try "vgabios.bin". */
00285   FILE*   rom = fopen(myCfg->get_text_value("rom", "vgabios.bin"), "rb");
00286   if(!rom)
00287   {
00288     FAILURE_1(FileNotFound, "cirrus rom file %s not found.",
00289               myCfg->get_text_value("rom", "vgabios.bin"));
00290   }
00291 
00292   rom_max = (unsigned) fread(option_rom, 1, 65536, rom);
00293   fclose(rom);
00294 
00295   // Option ROM address space: C0000
00296   add_legacy_mem(5, 0xc0000, rom_max);
00297 
00298   state.vga_enabled = 1;
00299   state.misc_output.color_emulation = 1;
00300   state.misc_output.enable_ram = 1;
00301   state.misc_output.horiz_sync_pol = 1;
00302   state.misc_output.vert_sync_pol = 1;
00303 
00304   state.attribute_ctrl.mode_ctrl.enable_line_graphics = 1;
00305 
00306   state.line_offset = 80;
00307   state.line_compare = 1023;
00308   state.vertical_display_end = 399;
00309 
00310   state.attribute_ctrl.video_enabled = 1;
00311   state.attribute_ctrl.color_plane_enable = 0x0f;
00312 
00313   state.pel.dac_state = 0x01;
00314   state.pel.mask = 0xff;
00315 
00316   state.graphics_ctrl.memory_mapping = 2; // monochrome text mode
00317 
00318   state.sequencer.reset1 = 1;
00319   state.sequencer.reset2 = 1;
00320   state.sequencer.extended_mem = 1;       // display mem greater than 64K
00321   state.sequencer.odd_even = 1;           // use sequential addressing mode
00322 
00323   state.memsize = 0x40000;
00324   state.memory = new u8[state.memsize];
00325   memset(state.memory, 0, state.memsize);
00326 
00327   state.last_bpp = 8;
00328 
00329   state.CRTC.reg[0x09] = 16;
00330   state.graphics_ctrl.memory_mapping = 3; // color text mode
00331   state.vga_mem_updated = 1;
00332 
00333   myThread = 0;
00334   printf("%s: $Id: Cirrus.cpp,v 1.21 2008/03/25 08:41:32 iamcamiel Exp $\n",
00335          devid_string);
00336 }
00337 
00341 void CCirrus::start_threads()
00342 {
00343   if(!myThread)
00344   {
00345     myThread = new Poco::Thread("cirrus");
00346     printf(" %s", myThread->getName().c_str());
00347     StopThread = false;
00348     myThread->start(*this);
00349   }
00350 }
00351 
00355 void CCirrus::stop_threads()
00356 {
00357   // Signal the thread to stop
00358   StopThread = true;
00359   if(myThread)
00360   {
00361     printf(" %s", myThread->getName().c_str());
00362     // Wait for the thread to end execution
00363     myThread->join();
00364     // And delete the Thread object
00365     delete myThread;
00366     myThread = 0;
00367   }
00368 }
00369 
00373 CCirrus::~CCirrus()
00374 {
00375   stop_threads();
00376 }
00377 
00381 u32 CCirrus::ReadMem_Legacy(int index, u32 address, int dsize)
00382 {
00383   u32 data = 0;
00384   switch(index)
00385   {
00386   // IO Port 0x3b4
00387   case 1: 
00388     data = io_read(address + 0x3b4, dsize);
00389     break;
00390   
00391   // IO Port 0x3c0..0x3cf
00392   case 2: 
00393     data = io_read(address + 0x3c0, dsize);
00394     break;
00395   
00396   // IO Port 0x3ba
00397   case 3: 
00398     data = io_read(address + 0x3ba, dsize);
00399     break;
00400 
00401   // VGA Memory
00402   case 4: 
00403     data = legacy_read(address, dsize);
00404     break;
00405 
00406   // ROM
00407   case 5: 
00408     data = rom_read(address, dsize);
00409     break;
00410 
00411   // IO Port 0x3d4
00412   case 8:
00413     data = io_read(address + 0x3d4, dsize);
00414     break;
00415 
00416   // IO Port 0x3da
00417   case 9:
00418     data = io_read(address + 0x3da, dsize);
00419     break;
00420   }
00421 
00422   return data;
00423 }
00424 
00428 void CCirrus::WriteMem_Legacy(int index, u32 address, int dsize, u32 data)
00429 {
00430   switch(index)
00431   {
00432   // IO Port 0x3b4
00433   case 1:
00434     io_write(address + 0x3b4, dsize, data);
00435     return;
00436 
00437   // IO Port 0x3c0..0x3cf
00438   case 2:
00439     io_write(address + 0x3c0, dsize, data);
00440     return;
00441 
00442   // IO Port 0x3ba
00443   case 3:
00444     io_write(address + 0x3ba, dsize, data);
00445     return;
00446 
00447   // VGA Memory
00448   case 4:
00449     legacy_write(address, dsize, data);
00450     return;
00451 
00452   // BIOS Message IO Port (0x500)
00453   case 7:
00454     bios_message[bios_message_size++] = (char) data & 0xff;
00455     if(((data & 0xff) == 0x0a) || ((data & 0xff) == 0x0d))
00456     {
00457       if(bios_message_size > 1)
00458       {
00459         bios_message[bios_message_size - 1] = '\0';
00460         printf("cirrus: %s\n", bios_message);
00461       }
00462 
00463       bios_message_size = 0;
00464     }
00465 
00466     return;
00467 
00468   // IO Port 0x3d4
00469   case 8: /* io port */
00470     io_write(address + 0x3d4, dsize, data);
00471     return;
00472 
00473   // IO Port 0x3da
00474   case 9:
00475     io_write(address + 0x3da, dsize, data);
00476     return;
00477   }
00478 }
00479 
00483 u32 CCirrus::ReadMem_Bar(int func, int bar, u32 address, int dsize)
00484 {
00485   switch(bar)
00486   {
00487   // PCI memory range
00488   case 0: 
00489     return mem_read(address, dsize);
00490   }
00491 
00492   return 0;
00493 }
00494 
00498 void CCirrus::WriteMem_Bar(int func, int bar, u32 address, int dsize, u32 data)
00499 {
00500   switch(bar)
00501   {
00502   // PCI Memory range
00503   case 0: 
00504     mem_write(address, dsize, data); 
00505     return;
00506   }
00507 }
00508 
00512 void CCirrus::check_state()
00513 {
00514   if(myThread && !myThread->isRunning())
00515     FAILURE(Thread, "Cirrus thread has died");
00516 }
00517 
00518 static u32  cirrus_magic1 = 0xC1AA4500;
00519 static u32  cirrus_magic2 = 0x0054AA1C;
00520 
00524 int CCirrus::SaveState(FILE* f)
00525 {
00526   long  ss = sizeof(state);
00527   int   res;
00528 
00529   if(res = CPCIDevice::SaveState(f))
00530     return res;
00531 
00532   fwrite(&cirrus_magic1, sizeof(u32), 1, f);
00533   fwrite(&ss, sizeof(long), 1, f);
00534   fwrite(&state, sizeof(state), 1, f);
00535   fwrite(&cirrus_magic2, sizeof(u32), 1, f);
00536   printf("%s: %d bytes saved.\n", devid_string, (int) ss);
00537   return 0;
00538 }
00539 
00543 int CCirrus::RestoreState(FILE* f)
00544 {
00545   long    ss;
00546   u32     m1;
00547   u32     m2;
00548   int     res;
00549   size_t  r;
00550 
00551   if(res = CPCIDevice::RestoreState(f))
00552     return res;
00553 
00554   r = fread(&m1, sizeof(u32), 1, f);
00555   if(r != 1)
00556   {
00557     printf("%s: unexpected end of file!\n", devid_string);
00558     return -1;
00559   }
00560 
00561   if(m1 != cirrus_magic1)
00562   {
00563     printf("%s: MAGIC 1 does not match!\n", devid_string);
00564     return -1;
00565   }
00566 
00567   fread(&ss, sizeof(long), 1, f);
00568   if(r != 1)
00569   {
00570     printf("%s: unexpected end of file!\n", devid_string);
00571     return -1;
00572   }
00573 
00574   if(ss != sizeof(state))
00575   {
00576     printf("%s: STRUCT SIZE does not match!\n", devid_string);
00577     return -1;
00578   }
00579 
00580   fread(&state, sizeof(state), 1, f);
00581   if(r != 1)
00582   {
00583     printf("%s: unexpected end of file!\n", devid_string);
00584     return -1;
00585   }
00586 
00587   r = fread(&m2, sizeof(u32), 1, f);
00588   if(r != 1)
00589   {
00590     printf("%s: unexpected end of file!\n", devid_string);
00591     return -1;
00592   }
00593 
00594   if(m2 != cirrus_magic2)
00595   {
00596     printf("%s: MAGIC 1 does not match!\n", devid_string);
00597     return -1;
00598   }
00599 
00600   printf("%s: %d bytes restored.\n", devid_string, (int) ss);
00601   return 0;
00602 }
00603 
00609 u32 CCirrus::mem_read(u32 address, int dsize)
00610 {
00611   u32 data = 0;
00612 
00613   //printf("cirrus: mem read: %" LL "x, %d, %" LL "x   \n", address, dsize, data);
00614   return data;
00615 }
00616 
00622 void CCirrus::mem_write(u32 address, int dsize, u32 data)
00623 {
00624 
00625   //printf("cirrus: mem write: %" LL "x, %d, %" LL "x   \n", address, dsize, data);
00626   switch(dsize)
00627   {
00628   case 8:
00629   case 16:
00630   case 32:
00631     break;
00632   }
00633 }
00634 
00640 u32 CCirrus::legacy_read(u32 address, int dsize)
00641 {
00642   u32 data = 0;
00643   switch(dsize)
00644   {
00645   case 32:
00646     data |= (u64) vga_mem_read((u32) address + 0xA0003) << 24;
00647     data |= (u64) vga_mem_read((u32) address + 0xA0002) << 16;
00648 
00649   case 16:
00650     data |= (u64) vga_mem_read((u32) address + 0xA0001) << 8;
00651 
00652   case 8:
00653     data |= (u64) vga_mem_read((u32) address + 0xA0000);
00654   }
00655 
00656   //  //printf("cirrus: legacy read: %" LL "x, %d, %" LL "x   \n", address, dsize, data);
00657   return data;
00658 }
00659 
00665 void CCirrus::legacy_write(u32 address, int dsize, u32 data)
00666 {
00667 
00668   //  //printf("cirrus: legacy write: %" LL "x, %d, %" LL "x   \n", address, dsize, data);
00669   switch(dsize)
00670   {
00671   case 32:
00672     vga_mem_write((u32) address + 0xA0002, (u8) (data >> 16));
00673     vga_mem_write((u32) address + 0xA0003, (u8) (data >> 24));
00674 
00675   case 16:
00676     vga_mem_write((u32) address + 0xA0001, (u8) (data >> 8));
00677 
00678   case 8:
00679     vga_mem_write((u32) address + 0xA0000, (u8) (data));
00680   }
00681 }
00682 
00686 u32 CCirrus::rom_read(u32 address, int dsize)
00687 {
00688   u32   data = 0x00;
00689   u8*   x = (u8*) option_rom;
00690   if(address <= rom_max)
00691   {
00692     x += address;
00693     switch(dsize)
00694     {
00695     case 8:   data = (u32) endian_8((*((u8*) x)) & 0xff); break;
00696     case 16:  data = (u32) endian_16((*((u16*) x)) & 0xffff); break;
00697     case 32:  data = (u32) endian_32((*((u32*) x)) & 0xffffffff); break;
00698     }
00699 
00700     //printf("cirrus: rom read: %" LL "x, %d, %" LL "x\n", address, dsize,data);
00701   }
00702   else
00703   {
00704     printf("cirrus: (BAD) rom read: %"LL "x, %d, %"LL "x\n", address, dsize,
00705            data);
00706   }
00707 
00708   return data;
00709 }
00710 
00714 u32 CCirrus::io_read(u32 address, int dsize)
00715 {
00716   u32 data = 0;
00717   if(dsize != 8)
00718     FAILURE(InvalidArgument, "Unsupported dsize!\n");
00719 
00720   switch(address)
00721   {
00722   case 0x3c0:
00723     data = read_b_3c0();
00724     break;
00725 
00726   case 0x3c1:
00727     data = read_b_3c1();
00728     break;
00729 
00730   case 0x3c2:
00731     data = read_b_3c2();
00732     break;
00733 
00734   case 0x3c3:
00735     data = read_b_3c3();
00736     break;
00737 
00738   case 0x3c4:
00739     data = read_b_3c4();
00740     break;
00741 
00742   case 0x3c5:
00743     data = read_b_3c5();
00744     break;
00745 
00746   case 0x3c9:
00747     data = read_b_3c9();
00748     break;
00749 
00750   case 0x3ca:
00751     data = read_b_3ca();
00752     break;
00753 
00754   case 0x3cc:
00755     data = read_b_3cc();
00756     break;
00757 
00758   case 0x3cf:
00759     data = read_b_3cf();
00760     break;
00761 
00762   case 0x3b4:
00763   case 0x3d4:
00764     data = read_b_3d4();
00765     break;
00766 
00767   case 0x3b5:
00768   case 0x3d5:
00769     data = read_b_3d5();
00770     break;
00771 
00772   case 0x3ba:
00773   case 0x3da:
00774     data = read_b_3da();
00775     break;
00776 
00777   default:
00778     FAILURE_1(NotImplemented, "Unhandled port %x read", address);
00779   }
00780 
00781   //printf("cirrus: io read: %" LL "x, %d, %" LL "x   \n", address+VGA_BASE, dsize, data);
00782   return data;
00783 }
00784 
00790 void CCirrus::io_write(u32 address, int dsize, u32 data)
00791 {
00792 
00793   //  printf("cirrus: io write: %" LL "x, %d, %" LL "x   \n", address+VGA_BASE, dsize, data);
00794   switch(dsize)
00795   {
00796   case 8:
00797     io_write_b(address, (u8) data);
00798     break;
00799 
00800   case 16:
00801     io_write_b(address, (u8) data);
00802     io_write_b(address + 1, (u8) (data >> 8));
00803     break;
00804 
00805   default:
00806     FAILURE(InvalidArgument, "Weird IO size!");
00807   }
00808 }
00809 
00813 void CCirrus::io_write_b(u32 address, u8 data)
00814 {
00815   switch(address)
00816   {
00817   case 0x3c0:
00818     write_b_3c0(data);
00819     break;
00820 
00821   case 0x3c2:
00822     write_b_3c2(data);
00823     break;
00824 
00825   case 0x3c4:
00826     write_b_3c4(data);
00827     break;
00828 
00829   case 0x3c5:
00830     write_b_3c5(data);
00831     break;
00832 
00833   case 0x3c6:
00834     write_b_3c6(data);
00835     break;
00836 
00837   case 0x3c7:
00838     write_b_3c7(data);
00839     break;
00840 
00841   case 0x3c8:
00842     write_b_3c8(data);
00843     break;
00844 
00845   case 0x3c9:
00846     write_b_3c9(data);
00847     break;
00848 
00849   case 0x3ce:
00850     write_b_3ce(data);
00851     break;
00852 
00853   case 0x3cf:
00854     write_b_3cf(data);
00855     break;
00856 
00857   case 0x3b4:
00858   case 0x3d4:
00859     write_b_3d4(data);
00860     break;
00861 
00862   case 0x3b5:
00863   case 0x3d5:
00864     write_b_3d5(data);
00865     break;
00866 
00867   default:
00868     FAILURE_1(NotImplemented, "Unhandled port %x write", address);
00869   }
00870 }
00871 
01002 void CCirrus::write_b_3c0(u8 value)
01003 {
01004   // Variables to save old state (to detect transitions)
01005   bool  prev_video_enabled;
01006   bool  prev_line_graphics;
01007   bool  prev_int_pal_size;
01008 
01009   /* The flip-flop determines whether the write goes to the index-register
01010      (address) or the data-register. */
01011   if(state.attribute_ctrl.flip_flop == 0)
01012   { 
01013     // Write goes to the index-register.
01014 
01015     /* The index register also has a bit that controls whether video
01016        output is enabled or not.
01017        We check this bit, and compare it to it's previous state, to 
01018        determine whether we need to perform an enable or disable 
01019        transition. */
01020     prev_video_enabled = state.attribute_ctrl.video_enabled;
01021     state.attribute_ctrl.video_enabled = (value >> 5) & 0x01;
01022 #if defined(DEBUG_VGA)
01023     printf("io write 3c0: video_enabled = %u   \n",
01024            (unsigned) state.attribute_ctrl.video_enabled);
01025 #endif
01026     if(state.attribute_ctrl.video_enabled == 0)
01027     {
01028       if (prev_video_enabled)
01029       {
01030 #if defined(DEBUG_VGA)
01031         printf("found disable transition   \n");
01032 #endif
01033         // Video output has been disabled. Clear the screen.
01034         bx_gui->lock();
01035         bx_gui->clear_screen();
01036         bx_gui->unlock();
01037       }
01038     }
01039     else if(!prev_video_enabled)
01040     {
01041 #if defined(DEBUG_VGA)
01042       printf("found enable transition   \n");
01043 #endif
01044       // Video output has been enabled. Draw the screen.
01045       redraw_area(0, 0, old_iWidth, old_iHeight);
01046     }
01047 
01048     // Determine what register should be addressed.
01049     value &= 0x1f;  /* address = bits 0..4 */
01050     state.attribute_ctrl.address = value;
01051 
01052     /* Registers 0x00..0x0f are palette selection registers. 
01053        Write a debugging message for all other registers. */
01054 #if defined(DEBUG_VGA)
01055     if (value>0x0f)
01056       printf("io write 3c0: address mode reg=%u   \n", (unsigned) value);
01057 #endif
01058   }
01059   else
01060   { 
01061     // Write should go to the data-register.
01062 
01063     // Registers 0x00..0x0f are palette selection registers.
01064     if (state.attribute_ctrl.address<=0x0f)
01065     {
01066       // Update palette selection only of there is a change.
01067       if(value != state.attribute_ctrl.palette_reg[state.attribute_ctrl.
01068            address])
01069       {
01070         // Update the palette selection.
01071         state.attribute_ctrl.palette_reg[state.attribute_ctrl.address] = value;
01072         // Requires redrawing the screen.
01073         redraw_area(0, 0, old_iWidth, old_iHeight);
01074       }
01075     }
01076     else
01077     {
01078       switch(state.attribute_ctrl.address)
01079       {
01080       // Mode control register
01081       case 0x10:
01082         prev_line_graphics = state.attribute_ctrl.mode_ctrl.enable_line_graphics;
01083         prev_int_pal_size = state.attribute_ctrl.mode_ctrl.internal_palette_size;
01084         state.attribute_ctrl.mode_ctrl.graphics_alpha = (value >> 0) & 0x01;
01085         state.attribute_ctrl.mode_ctrl.display_type = (value >> 1) & 0x01;
01086         state.attribute_ctrl.mode_ctrl.enable_line_graphics = (value >> 2) & 0x01;
01087         state.attribute_ctrl.mode_ctrl.blink_intensity = (value >> 3) & 0x01;
01088         state.attribute_ctrl.mode_ctrl.pixel_panning_compat = (value >> 5) & 0x01;
01089         state.attribute_ctrl.mode_ctrl.pixel_clock_select = (value >> 6) & 0x01;
01090         state.attribute_ctrl.mode_ctrl.internal_palette_size = (value >> 7) & 0x01;
01091         if(((value >> 2) & 0x01) != prev_line_graphics)
01092         {
01093           bx_gui->lock();
01094           bx_gui->set_text_charmap(&state.memory[0x20000 + state.charmap_address]);
01095           bx_gui->unlock();
01096           state.vga_mem_updated = 1;
01097         }
01098 
01099         if(((value >> 7) & 0x01) != prev_int_pal_size)
01100         {
01101           redraw_area(0, 0, old_iWidth, old_iHeight);
01102         }
01103 
01104 #if defined(DEBUG_VGA)
01105         printf("io write 3c0: mode control: %02x h   \n", (unsigned) value);
01106 #endif
01107         break;
01108 
01109       // Overscan Color Register
01110       case 0x11:
01111         /* We don't do anything with this. Our display doesn't
01112            show the overscan part of the normal monitor. */
01113         state.attribute_ctrl.overscan_color = (value & 0x3f);
01114 #if defined(DEBUG_VGA)
01115         printf("io write 3c0: overscan color = %02x   \n", (unsigned) value);
01116 #endif
01117         break;
01118 
01119       // Color Plane Enable Register
01120       case 0x12:
01121         state.attribute_ctrl.color_plane_enable = (value & 0x0f);
01122         redraw_area(0, 0, old_iWidth, old_iHeight);
01123 #if defined(DEBUG_VGA)
01124         printf("io write 3c0: color plane enable = %02x   \n", (unsigned) value);
01125 #endif
01126         break;
01127 
01128       // Horizontal Pixel Panning Register
01129       case 0x13:
01130         state.attribute_ctrl.horiz_pel_panning = (value & 0x0f);
01131         redraw_area(0, 0, old_iWidth, old_iHeight);
01132 #if defined(DEBUG_VGA)
01133         printf("io write 3c0: horiz pel panning = %02x   \n", (unsigned) value);
01134 #endif
01135         break;
01136 
01137       // Color Select Register
01138       case 0x14:
01139         state.attribute_ctrl.color_select = (value & 0x0f);
01140         redraw_area(0, 0, old_iWidth, old_iHeight);
01141 #if defined(DEBUG_VGA)
01142         printf("io write 3c0: color select = %02x   \n",
01143                (unsigned) state.attribute_ctrl.color_select);
01144 #endif
01145         break;
01146 
01147       default:
01148         FAILURE_1(NotImplemented, "io write 3c0: data-write mode %02x h",
01149                   (unsigned) state.attribute_ctrl.address);
01150       }
01151     }
01152   }
01153 
01154   // Flip the flip-flop
01155   state.attribute_ctrl.flip_flop = !state.attribute_ctrl.flip_flop;
01156 }
01157 
01193 void CCirrus::write_b_3c2(u8 value)
01194 {
01195   state.misc_output.color_emulation = (value >> 0) & 0x01;
01196   state.misc_output.enable_ram = (value >> 1) & 0x01;
01197   state.misc_output.clock_select = (value >> 2) & 0x03;
01198   state.misc_output.select_high_bank = (value >> 5) & 0x01;
01199   state.misc_output.horiz_sync_pol = (value >> 6) & 0x01;
01200   state.misc_output.vert_sync_pol = (value >> 7) & 0x01;
01201 #if defined(DEBUG_VGA)
01202   printf("io write 3c2:   \n");
01203   printf("  color_emulation = %u   \n",
01204          (unsigned) state.misc_output.color_emulation);
01205   printf("  enable_ram = %u   \n", (unsigned) state.misc_output.enable_ram);
01206   printf("  clock_select = %u   \n", (unsigned) state.misc_output.clock_select);
01207   printf("  select_high_bank = %u   \n",
01208          (unsigned) state.misc_output.select_high_bank);
01209   printf("  horiz_sync_pol = %u   \n",
01210          (unsigned) state.misc_output.horiz_sync_pol);
01211   printf("  vert_sync_pol = %u   \n", (unsigned) state.misc_output.vert_sync_pol);
01212 #endif
01213 }
01214 
01357 void CCirrus::write_b_3c4(u8 value)
01358 {
01359   state.sequencer.index = value;
01360 }
01361 
01367 void CCirrus::write_b_3c5(u8 value)
01368 {
01369   unsigned  i;
01370   u8        charmap1;
01371   u8        charmap2;
01372 
01373   switch(state.sequencer.index)
01374   {
01375   // Sequencer: reset register
01376   case 0:
01377 #if defined(DEBUG_VGA)
01378     printf("write 0x3c5: sequencer reset: value=0x%02x   \n", (unsigned) value);
01379 #endif
01380     if(state.sequencer.reset1 && ((value & 0x01) == 0))
01381     {
01382       state.sequencer.char_map_select = 0;
01383       state.charmap_address = 0;
01384       bx_gui->lock();
01385       bx_gui->set_text_charmap(&state.memory[0x20000 + state.charmap_address]);
01386       bx_gui->unlock();
01387       state.vga_mem_updated = 1;
01388     }
01389 
01390     state.sequencer.reset1 = (value >> 0) & 0x01;
01391     state.sequencer.reset2 = (value >> 1) & 0x01;
01392     break;
01393 
01394   // Sequencer: clocking mode register
01395   case 1:
01396 #if defined(DEBUG_VGA)
01397     printf("io write 3c5=%02x: clocking mode reg: ignoring   \n",
01398            (unsigned) value);
01399 #endif
01400     state.sequencer.reg1 = value & 0x3f;
01401     state.x_dotclockdiv2 = ((value & 0x08) > 0);
01402     break;
01403 
01404   // Sequencer: map mask register
01405   case 2:
01406     state.sequencer.map_mask = (value & 0x0f);
01407     for(i = 0; i < 4; i++)
01408       state.sequencer.map_mask_bit[i] = (value >> i) & 0x01;
01409     break;
01410 
01411   // Sequencer: character map select register
01412   case 3:
01413     state.sequencer.char_map_select = value;
01414     charmap1 = value & 0x13;
01415     if(charmap1 > 3)
01416       charmap1 = (charmap1 & 3) + 4;
01417     charmap2 = (value & 0x2C) >> 2;
01418     if(charmap2 > 3)
01419       charmap2 = (charmap2 & 3) + 4;
01420     if(state.CRTC.reg[0x09] > 0)
01421     {
01422       state.charmap_address = (charmap1 << 13);
01423       bx_gui->lock();
01424       bx_gui->set_text_charmap(&state.memory[0x20000 + state.charmap_address]);
01425       bx_gui->unlock();
01426       state.vga_mem_updated = 1;
01427     }
01428 
01429     if(charmap2 != charmap1)
01430       printf("char map select: #2=%d (unused)   \n", charmap2);
01431     break;
01432 
01433   // Sequencer: memory mode register
01434   case 4:
01435     state.sequencer.extended_mem = (value >> 1) & 0x01;
01436     state.sequencer.odd_even = (value >> 2) & 0x01;
01437     state.sequencer.chain_four = (value >> 3) & 0x01;
01438 
01439 #if defined(DEBUG_VGA)
01440     printf("io write 3c5: index 4:   \n");
01441     printf("  extended_mem %u   \n", (unsigned) state.sequencer.extended_mem);
01442     printf("  odd_even %u   \n", (unsigned) state.sequencer.odd_even);
01443     printf("  chain_four %u   \n", (unsigned) state.sequencer.chain_four);
01444 #endif
01445     break;
01446 
01447   default:
01448     FAILURE_1(NotImplemented, "io write 3c5: index %u unhandled",
01449               (unsigned) state.sequencer.index);
01450   }
01451 }
01452 
01459 void CCirrus::write_b_3c6(u8 value)
01460 {
01461   state.pel.mask = value;
01462 #if defined(DEBUG_VGA)
01463   if(state.pel.mask != 0xff)
01464     printf("io write 3c6: PEL mask=0x%02x != 0xFF   \n", value);
01465 #endif
01466 
01467   // state.pel.mask should be and'd with final value before
01468   // indexing into color register state.pel.data[]
01469 }
01470 
01499 void CCirrus::write_b_3c7(u8 value)
01500 {
01501   state.pel.read_data_register = value;
01502   state.pel.read_data_cycle = 0;
01503   state.pel.dac_state = 0x03;
01504 }
01505 
01511 void CCirrus::write_b_3c8(u8 value)
01512 {
01513   state.pel.write_data_register = value;
01514   state.pel.write_data_cycle = 0;
01515   state.pel.dac_state = 0x00;
01516 }
01517 
01523 void CCirrus::write_b_3c9(u8 value)
01524 {
01525   switch(state.pel.write_data_cycle)
01526   {
01527   case 0:
01528     state.pel.data[state.pel.write_data_register].red = value;
01529     break;
01530 
01531   case 1:
01532     state.pel.data[state.pel.write_data_register].green = value;
01533     break;
01534 
01535   case 2:
01536     {
01537       state.pel.data[state.pel.write_data_register].blue = value;
01538       // Palette write complete. Check if value has changed
01539       bx_gui->lock();
01540       bool  changed = bx_gui->palette_change(state.pel.write_data_register,
01541                                              state.pel.data[state.pel.write_data_register].red << 2,
01542                                              state.pel.data[state.pel.write_data_register].green << 2,
01543                                              state.pel.data[state.pel.write_data_register].blue << 2);
01544       bx_gui->unlock();
01545       // If palette value has changed, redraw the screen.
01546       if(changed)
01547         redraw_area(0, 0, old_iWidth, old_iHeight);
01548     }
01549     break;
01550   }
01551 
01552   // Move on to next RGB component
01553   state.pel.write_data_cycle++;
01554 
01555   // palette entry complete, move on to next one
01556   if(state.pel.write_data_cycle >= 3)
01557   {
01558 
01559     //BX_INFO(("state.pel.data[%u] {r=%u, g=%u, b=%u}",
01560     //  (unsigned) state.pel.write_data_register,
01561     //  (unsigned) state.pel.data[state.pel.write_data_register].red,
01562     //  (unsigned) state.pel.data[state.pel.write_data_register].green,
01563     //  (unsigned) state.pel.data[state.pel.write_data_register].blue);
01564     state.pel.write_data_cycle = 0;
01565     state.pel.write_data_register++;
01566   }
01567 }
01568 
01801 void CCirrus::write_b_3ce(u8 value)
01802 {
01803 #if defined(DEBUG_VGA)
01804   if(value > 0x08)  /* ??? */
01805     printf("io write: 3ce: value > 8   \n");
01806 #endif
01807   state.graphics_ctrl.index = value;
01808 }
01809 
01815 void CCirrus::write_b_3cf(u8 value)
01816 {
01817   u8    prev_memory_mapping;
01818   bool  prev_graphics_alpha;
01819   bool  prev_chain_odd_even;
01820 
01821   /* Graphics Controller Registers 00..08 */
01822   switch(state.graphics_ctrl.index)
01823   {
01824   case 0:           /* Set/Reset */
01825     state.graphics_ctrl.set_reset = value & 0x0f;
01826     break;
01827 
01828   case 1:           /* Enable Set/Reset */
01829     state.graphics_ctrl.enable_set_reset = value & 0x0f;
01830     break;
01831 
01832   case 2:           /* Color Compare */
01833     state.graphics_ctrl.color_compare = value & 0x0f;
01834     break;
01835 
01836   case 3:           /* Data Rotate */
01837     state.graphics_ctrl.data_rotate = value & 0x07;
01838 
01839     /* ??? is this bits 3..4 or 4..5 */
01840     state.graphics_ctrl.raster_op = (value >> 3) & 0x03;  /* ??? */
01841     break;
01842 
01843   case 4:     /* Read Map Select */
01844     state.graphics_ctrl.read_map_select = value & 0x03;
01845 #if defined(DEBUG_VGA)
01846     printf("io write to 03cf = %02x (RMS)   \n", (unsigned) value);
01847 #endif
01848     break;
01849 
01850   case 5:     /* Mode */
01851     state.graphics_ctrl.write_mode = value & 0x03;
01852     state.graphics_ctrl.read_mode = (value >> 3) & 0x01;
01853     state.graphics_ctrl.odd_even = (value >> 4) & 0x01;
01854     state.graphics_ctrl.shift_reg = (value >> 5) & 0x03;
01855 
01856 #if defined(DEBUG_VGA)
01857     if(state.graphics_ctrl.odd_even)
01858       printf("io write: 3cf: reg 05: value = %02xh   \n", (unsigned) value);
01859     if(state.graphics_ctrl.shift_reg)
01860       printf("io write: 3cf: reg 05: value = %02xh   \n", (unsigned) value);
01861 #endif
01862     break;
01863 
01864   case 6:     /* Miscellaneous */
01865     prev_graphics_alpha = state.graphics_ctrl.graphics_alpha;
01866     prev_chain_odd_even = state.graphics_ctrl.chain_odd_even;
01867     prev_memory_mapping = state.graphics_ctrl.memory_mapping;
01868 
01869     state.graphics_ctrl.graphics_alpha = value & 0x01;
01870     state.graphics_ctrl.chain_odd_even = (value >> 1) & 0x01;
01871     state.graphics_ctrl.memory_mapping = (value >> 2) & 0x03;
01872 #if defined(DEBUG_VGA)
01873     printf("memory_mapping set to %u   \n",
01874            (unsigned) state.graphics_ctrl.memory_mapping);
01875     printf("graphics mode set to %u   \n",
01876            (unsigned) state.graphics_ctrl.graphics_alpha);
01877     printf("odd_even mode set to %u   \n",
01878            (unsigned) state.graphics_ctrl.odd_even);
01879     printf("io write: 3cf: reg 06: value = %02xh   \n", (unsigned) value);
01880 #endif
01881     if(prev_memory_mapping != state.graphics_ctrl.memory_mapping)
01882     {
01883       redraw_area(0, 0, old_iWidth, old_iHeight);
01884     }
01885 
01886     if(prev_graphics_alpha != state.graphics_ctrl.graphics_alpha)
01887     {
01888       redraw_area(0, 0, old_iWidth, old_iHeight);
01889       old_iHeight = 0;
01890     }
01891     break;
01892 
01893   case 7:     /* Color Don't Care */
01894     state.graphics_ctrl.color_dont_care = value & 0x0f;
01895     break;
01896 
01897   case 8:     /* Bit Mask */
01898     state.graphics_ctrl.bitmask = value;
01899     break;
01900 
01901   default:
01902 
01903     /* ??? */
01904     FAILURE_1(NotImplemented, "io write: 3cf: index %u unhandled",
01905               (unsigned) state.graphics_ctrl.index);
01906   }
01907 }
01908 
02431 void CCirrus::write_b_3d4(u8 value)
02432 {
02433   state.CRTC.address = value & 0x7f;
02434 #if defined(DEBUG_VGA)
02435   if(state.CRTC.address > 0x18)
02436     printf("write: invalid CRTC register 0x%02x selected",
02437            (unsigned) state.CRTC.address);
02438 #endif
02439 }
02440 
02446 void CCirrus::write_b_3d5(u8 value)
02447 {
02448 
02449   /* CRTC Registers */
02450   if(state.CRTC.address > 0x18)
02451   {
02452 #if defined(DEBUG_VGA)
02453     printf("write: invalid CRTC register 0x%02x ignored",
02454            (unsigned) state.CRTC.address);
02455 #endif
02456     return;
02457   }
02458 
02459   if(state.CRTC.write_protect && (state.CRTC.address < 0x08))
02460   {
02461     if(state.CRTC.address == 0x07)
02462     {
02463       state.CRTC.reg[state.CRTC.address] &= ~0x10;
02464       state.CRTC.reg[state.CRTC.address] |= (value & 0x10);
02465       state.line_compare &= 0x2ff;
02466       if(state.CRTC.reg[0x07] & 0x10)
02467         state.line_compare |= 0x100;
02468       redraw_area(0, 0, old_iWidth, old_iHeight);
02469       return;
02470     }
02471     else
02472     {
02473       return;
02474     }
02475   }
02476 
02477   if(value != state.CRTC.reg[state.CRTC.address])
02478   {
02479     state.CRTC.reg[state.CRTC.address] = value;
02480     switch(state.CRTC.address)
02481     {
02482     case 0x07:
02483       state.vertical_display_end &= 0xff;
02484       if(state.CRTC.reg[0x07] & 0x02)
02485         state.vertical_display_end |= 0x100;
02486       if(state.CRTC.reg[0x07] & 0x40)
02487         state.vertical_display_end |= 0x200;
02488       state.line_compare &= 0x2ff;
02489       if(state.CRTC.reg[0x07] & 0x10)
02490         state.line_compare |= 0x100;
02491       redraw_area(0, 0, old_iWidth, old_iHeight);
02492       break;
02493 
02494     case 0x08:
02495 
02496       // Vertical pel panning change
02497       redraw_area(0, 0, old_iWidth, old_iHeight);
02498       break;
02499 
02500     case 0x09:
02501       state.y_doublescan = ((value & 0x9f) > 0);
02502       state.line_compare &= 0x1ff;
02503       if(state.CRTC.reg[0x09] & 0x40)
02504         state.line_compare |= 0x200;
02505       redraw_area(0, 0, old_iWidth, old_iHeight);
02506       break;
02507 
02508     case 0x0A:
02509     case 0x0B:
02510     case 0x0E:
02511     case 0x0F:
02512 
02513       // Cursor size / location change
02514       state.vga_mem_updated = 1;
02515       break;
02516 
02517     case 0x0C:
02518     case 0x0D:
02519 
02520       // Start address change
02521       if(state.graphics_ctrl.graphics_alpha)
02522       {
02523         redraw_area(0, 0, old_iWidth, old_iHeight);
02524       }
02525       else
02526       {
02527         state.vga_mem_updated = 1;
02528       }
02529       break;
02530 
02531     case 0x12:
02532       state.vertical_display_end &= 0x300;
02533       state.vertical_display_end |= state.CRTC.reg[0x12];
02534       break;
02535 
02536     case 0x13:
02537     case 0x14:
02538     case 0x17:
02539 
02540       // Line offset change
02541       state.line_offset = state.CRTC.reg[0x13] << 1;
02542       if(state.CRTC.reg[0x14] & 0x40)
02543         state.line_offset <<= 2;
02544       else if((state.CRTC.reg[0x17] & 0x40) == 0)
02545         state.line_offset <<= 1;
02546       redraw_area(0, 0, old_iWidth, old_iHeight);
02547       break;
02548 
02549     case 0x18:
02550       state.line_compare &= 0x300;
02551       state.line_compare |= state.CRTC.reg[0x18];
02552       redraw_area(0, 0, old_iWidth, old_iHeight);
02553       break;
02554     }
02555   }
02556 }
02557 
02563 u8 CCirrus::read_b_3c0()
02564 {
02565   if(state.attribute_ctrl.flip_flop == 0)
02566   {
02567 
02568     //BX_INFO(("io read: 0x3c0: flip_flop = 0"));
02569     return(state.attribute_ctrl.video_enabled << 5) | state.attribute_ctrl.address;
02570   }
02571   else
02572   {
02573     FAILURE(NotImplemented, "io read: 0x3c0: flip_flop != 0");
02574   }
02575 }
02576 
02582 u8 CCirrus::read_b_3c1()
02583 {
02584   u8  retval;
02585   switch(state.attribute_ctrl.address)
02586   {
02587   case 0x00:
02588   case 0x01:
02589   case 0x02:
02590   case 0x03:
02591   case 0x04:
02592   case 0x05:
02593   case 0x06:
02594   case 0x07:
02595   case 0x08:
02596   case 0x09:
02597   case 0x0a:
02598   case 0x0b:
02599   case 0x0c:
02600   case 0x0d:
02601   case 0x0e:
02602   case 0x0f:
02603     retval = state.attribute_ctrl.palette_reg[state.attribute_ctrl.address];
02604     return(retval);
02605     break;
02606 
02607   case 0x10:  /* mode control register */
02608     retval = (state.attribute_ctrl.mode_ctrl.graphics_alpha << 0) |
02609       (state.attribute_ctrl.mode_ctrl.display_type << 1) |
02610         (state.attribute_ctrl.mode_ctrl.enable_line_graphics << 2) |
02611           (state.attribute_ctrl.mode_ctrl.blink_intensity << 3) |
02612             (state.attribute_ctrl.mode_ctrl.pixel_panning_compat << 5) |
02613               (state.attribute_ctrl.mode_ctrl.pixel_clock_select << 6) |
02614                 (state.attribute_ctrl.mode_ctrl.internal_palette_size << 7);
02615     return(retval);
02616     break;
02617 
02618   case 0x11:  /* overscan color register */
02619     return(state.attribute_ctrl.overscan_color);
02620     break;
02621 
02622   case 0x12:  /* color plane enable */
02623     return(state.attribute_ctrl.color_plane_enable);
02624     break;
02625 
02626   case 0x13:  /* horizontal PEL panning register */
02627     return(state.attribute_ctrl.horiz_pel_panning);
02628     break;
02629 
02630   case 0x14:  /* color select register */
02631     return(state.attribute_ctrl.color_select);
02632     break;
02633 
02634   default:
02635     FAILURE_1(NotImplemented, "io read: 0x3c1: unknown register 0x%02x",
02636               (unsigned) state.attribute_ctrl.address);
02637   }
02638 }
02639 
02654 u8 CCirrus::read_b_3c2()
02655 {
02656   return 0;   // input status register
02657 }
02658 
02664 u8 CCirrus::read_b_3c3()
02665 {
02666   return state.vga_enabled;
02667 }
02668 
02674 u8 CCirrus::read_b_3c4()
02675 {
02676   return state.sequencer.index;
02677 }
02678 
02684 u8 CCirrus::read_b_3c5()
02685 {
02686   switch(state.sequencer.index)
02687   {
02688   case 0:     /* sequencer: reset */
02689 #if defined(DEBUG_VGA)
02690     BX_DEBUG(("io read 0x3c5: sequencer reset"));
02691 #endif
02692     return(state.sequencer.reset1 ? 1 : 0) | (state.sequencer.reset2 ? 2 : 0);
02693     break;
02694 
02695   case 1:     /* sequencer: clocking mode */
02696 #if defined(DEBUG_VGA)
02697     BX_DEBUG(("io read 0x3c5: sequencer clocking mode"));
02698 #endif
02699     return state.sequencer.reg1;
02700     break;
02701 
02702   case 2:     /* sequencer: map mask register */
02703     return state.sequencer.map_mask;
02704     break;
02705 
02706   case 3:     /* sequencer: character map select register */
02707     return state.sequencer.char_map_select;
02708     break;
02709 
02710   case 4:     /* sequencer: memory mode register */
02711     return(state.sequencer.extended_mem << 1) |
02712       (state.sequencer.odd_even << 2) |
02713       (state.sequencer.chain_four << 3);
02714     break;
02715 
02716   default:
02717     FAILURE_1(NotImplemented, "io read 0x3c5: index %u unhandled",
02718               (unsigned) state.sequencer.index);
02719   }
02720 }
02721 
02727 u8 CCirrus::read_b_3c9()
02728 {
02729   u8  retval;
02730   if(state.pel.dac_state == 0x03)
02731   {
02732     switch(state.pel.read_data_cycle)
02733     {
02734     case 0:   retval = state.pel.data[state.pel.read_data_register].red; break;
02735     case 1:   retval = state.pel.data[state.pel.read_data_register].green; break;
02736     case 2:   retval = state.pel.data[state.pel.read_data_register].blue; break;
02737     default:  retval = 0; // keep compiler happy
02738     }
02739 
02740     state.pel.read_data_cycle++;
02741     if(state.pel.read_data_cycle >= 3)
02742     {
02743       state.pel.read_data_cycle = 0;
02744       state.pel.read_data_register++;
02745     }
02746   }
02747   else
02748   {
02749     retval = 0x3f;
02750   }
02751 
02752   return retval;
02753 }
02766 u8 CCirrus::read_b_3ca()
02767 {
02768   return 0;
02769 }
02770 
02776 u8 CCirrus::read_b_3cc()
02777 {
02778 
02779   /* Miscellaneous Output / Graphics 1 Position ??? */
02780   return((state.misc_output.color_emulation & 0x01) << 0) |
02781     ((state.misc_output.enable_ram & 0x01) << 1) |
02782       ((state.misc_output.clock_select & 0x03) << 2) |
02783         ((state.misc_output.select_high_bank & 0x01) << 5) |
02784           ((state.misc_output.horiz_sync_pol & 0x01) << 6) |
02785             ((state.misc_output.vert_sync_pol & 0x01) << 7);
02786 }
02787 
02793 u8 CCirrus::read_b_3cf()
02794 {
02795   u8  retval;
02796   switch(state.graphics_ctrl.index)
02797   {
02798   case 0:               /* Set/Reset */
02799     return(state.graphics_ctrl.set_reset);
02800     break;
02801 
02802   case 1:               /* Enable Set/Reset */
02803     return(state.graphics_ctrl.enable_set_reset);
02804     break;
02805 
02806   case 2:               /* Color Compare */
02807     return(state.graphics_ctrl.color_compare);
02808     break;
02809 
02810   case 3:               /* Data Rotate */
02811     retval = ((state.graphics_ctrl.raster_op & 0x03) << 3) | ((state.graphics_ctrl.data_rotate & 0x07) << 0);
02812     return(retval);
02813     break;
02814 
02815   case 4:               /* Read Map Select */
02816     return(state.graphics_ctrl.read_map_select);
02817     break;
02818 
02819   case 5:               /* Mode */
02820     retval = ((state.graphics_ctrl.shift_reg & 0x03) << 5) |
02821       ((state.graphics_ctrl.odd_even & 0x01) << 4) |
02822         ((state.graphics_ctrl.read_mode & 0x01) << 3) |
02823           ((state.graphics_ctrl.write_mode & 0x03) << 0);
02824 
02825 #if defined(DEBUG_VGA)
02826     if(state.graphics_ctrl.odd_even || state.graphics_ctrl.shift_reg)
02827       BX_DEBUG(("io read 0x3cf: reg 05 = 0x%02x", (unsigned) retval));
02828 #endif
02829     return(retval);
02830     break;
02831 
02832   case 6:               /* Miscellaneous */
02833     return((state.graphics_ctrl.memory_mapping & 0x03) << 2) |
02834       ((state.graphics_ctrl.odd_even & 0x01) << 1) |
02835         ((state.graphics_ctrl.graphics_alpha & 0x01) << 0);
02836     break;
02837 
02838   case 7:               /* Color Don't Care */
02839     return(state.graphics_ctrl.color_dont_care);
02840     break;
02841 
02842   case 8:               /* Bit Mask */
02843     return(state.graphics_ctrl.bitmask);
02844     break;
02845 
02846   default:
02847     FAILURE_1(NotImplemented, "io read: 0x3cf: index %u unhandled",
02848               (unsigned) state.graphics_ctrl.index);
02849   }
02850 }
02851 
02857 u8 CCirrus::read_b_3d4()
02858 {
02859   return state.CRTC.address;
02860 }
02861 
02867 u8 CCirrus::read_b_3d5()
02868 {
02869   if(state.CRTC.address > 0x18)
02870   {
02871     FAILURE_1(NotImplemented, "io read: invalid CRTC register 0x%02x   \n",
02872               (unsigned) state.CRTC.address);
02873   }
02874 
02875   return state.CRTC.reg[state.CRTC.address];
02876 }
02877 
02901 u8 CCirrus::read_b_3da()
02902 {
02903 
02904   /* Input Status 1 (color emulation modes) */
02905   u8  retval = 0;
02906 
02907   // bit3: Vertical Retrace
02908   //       0 = display is in the display mode
02909   //       1 = display is in the vertical retrace mode
02910   // bit0: Display Enable
02911   //       0 = display is in the display mode
02912   //       1 = display is not in the display mode; either the
02913   //           horizontal or vertical retrace period is active
02914   // using 72 Hz vertical frequency
02915 
02916   /*** TO DO ??? ***
02917        usec = bx_pc_system.time_usec();
02918        switch ( ( state.misc_output.vert_sync_pol << 1) | state.misc_output.horiz_sync_pol )
02919        {
02920          case 0: vertres = 200; break;
02921          case 1: vertres = 400; break;
02922          case 2: vertres = 350; break;
02923          default: vertres = 480; break;
02924        }
02925        if ((usec % 13888) < 70) {
02926          vert_retrace = 1;
02927        }
02928        if ((usec % (13888 / vertres)) == 0) {
02929          horiz_retrace = 1;
02930        }
02931  
02932        if (horiz_retrace || vert_retrace)
02933          retval = 0x01;
02934        if (vert_retrace)
02935          retval |= 0x08;
02936  
02937        *** TO DO ??? ***/
02938 
02939   /* reading this port resets the flip-flop to address mode */
02940   state.attribute_ctrl.flip_flop = 0;
02941   return retval;
02942 }
02943 
02944 u8 CCirrus::get_actl_palette_idx(u8 index)
02945 {
02946   return state.attribute_ctrl.palette_reg[index];
02947 }
02948 
02949 void CCirrus::redraw_area(unsigned x0, unsigned y0, unsigned width,
02950                           unsigned height)
02951 {
02952   unsigned  xti;
02953 
02954   unsigned  yti;
02955 
02956   unsigned  xt0;
02957 
02958   unsigned  xt1;
02959 
02960   unsigned  yt0;
02961 
02962   unsigned  yt1;
02963 
02964   unsigned  xmax;
02965 
02966   unsigned  ymax;
02967 
02968   if((width == 0) || (height == 0))
02969   {
02970     return;
02971   }
02972 
02973   state.vga_mem_updated = 1;
02974 
02975   if(state.graphics_ctrl.graphics_alpha)
02976   {
02977 
02978     // graphics mode
02979     xmax = old_iWidth;
02980     ymax = old_iHeight;
02981     xt0 = x0 / X_TILESIZE;
02982     yt0 = y0 / Y_TILESIZE;
02983     if(x0 < xmax)
02984     {
02985       xt1 = (x0 + width - 1) / X_TILESIZE;
02986     }
02987     else
02988     {
02989       xt1 = (xmax - 1) / X_TILESIZE;
02990     }
02991 
02992     if(y0 < ymax)
02993     {
02994       yt1 = (y0 + height - 1) / Y_TILESIZE;
02995     }
02996     else
02997     {
02998       yt1 = (ymax - 1) / Y_TILESIZE;
02999     }
03000 
03001     for(yti = yt0; yti <= yt1; yti++)
03002     {
03003       for(xti = xt0; xti <= xt1; xti++)
03004       {
03005         SET_TILE_UPDATED(xti, yti, 1);
03006       }
03007     }
03008   }
03009   else
03010   {
03011 
03012     // text mode
03013     memset(state.text_snapshot, 0, sizeof(state.text_snapshot));
03014   }
03015 }
03016 
03017 void CCirrus::update(void)
03018 {
03019   unsigned  iHeight;
03020 
03021   unsigned  iWidth;
03022 
03023   /* no screen update necessary */
03024   if(state.vga_mem_updated == 0)
03025     return;
03026 
03027   /* skip screen update when vga/video is disabled or the sequencer is in reset mode */
03028   if(!state.vga_enabled || !state.attribute_ctrl.video_enabled
03029    || !state.sequencer.reset2 || !state.sequencer.reset1) return;
03030 
03031   // fields that effect the way video memory is serialized into screen output:
03032   // GRAPHICS CONTROLLER:
03033   //   state.graphics_ctrl.shift_reg:
03034   //     0: output data in standard VGA format or CGA-compatible 640x200 2 color
03035   //        graphics mode (mode 6)
03036   //     1: output data in CGA-compatible 320x200 4 color graphics mode
03037   //        (modes 4 & 5)
03038   //     2: output data 8 bits at a time from the 4 bit planes
03039   //        (mode 13 and variants like modeX)
03040   // if (state.vga_mem_updated==0 || state.attribute_ctrl.video_enabled == 0)
03041   if(state.graphics_ctrl.graphics_alpha)
03042   {
03043     u8            color;
03044     unsigned      bit_no;
03045     unsigned      r;
03046     unsigned      c;
03047     unsigned      x;
03048     unsigned      y;
03049     unsigned long byte_offset;
03050     unsigned long start_addr;
03051     unsigned      xc;
03052     unsigned      yc;
03053     unsigned      xti;
03054     unsigned      yti;
03055 
03056     start_addr = (state.CRTC.reg[0x0c] << 8) | state.CRTC.reg[0x0d];
03057 
03058     //BX_DEBUG(("update: shiftreg=%u, chain4=%u, mapping=%u",
03059     //  (unsigned) state.graphics_ctrl.shift_reg,
03060     //  (unsigned) state.sequencer.chain_four,
03061     //  (unsigned) state.graphics_ctrl.memory_mapping);
03062     determine_screen_dimensions(&iHeight, &iWidth);
03063     if((iWidth != old_iWidth) || (iHeight != old_iHeight) || (state.last_bpp > 8))
03064     {
03065       bx_gui->dimension_update(iWidth, iHeight);
03066       old_iWidth = iWidth;
03067       old_iHeight = iHeight;
03068       state.last_bpp = 8;
03069     }
03070 
03071     switch(state.graphics_ctrl.shift_reg)
03072     {
03073     case 0:
03074       u8 attribute, palette_reg_val, DAC_regno;
03075 
03076       unsigned long line_compare;
03077       u8*           plane0;
03078       u8 *plane1;
03079       u8 *plane2;
03080       u8 *plane3;
03081 
03082       if(state.graphics_ctrl.memory_mapping == 3)
03083       {                 // CGA 640x200x2
03084         for(yc = 0, yti = 0; yc < iHeight; yc += Y_TILESIZE, yti++)
03085         {
03086           for(xc = 0, xti = 0; xc < iWidth; xc += X_TILESIZE, xti++)
03087           {
03088             if(GET_TILE_UPDATED(xti, yti))
03089             {
03090               for(r = 0; r < Y_TILESIZE; r++)
03091               {
03092                 y = yc + r;
03093                 if(state.y_doublescan)
03094                   y >>= 1;
03095                 for(c = 0; c < X_TILESIZE; c++)
03096                 {
03097                   x = xc + c;
03098 
03099                   /* 0 or 0x2000 */
03100                   byte_offset = start_addr + ((y & 1) << 13);
03101 
03102                   /* to the start of the line */
03103                   byte_offset += (320 / 4) * (y / 2);
03104 
03105                   /* to the byte start */
03106                   byte_offset += (x / 8);
03107 
03108                   bit_no = 7 - (x % 8);
03109                   palette_reg_val = (((state.memory[byte_offset]) >> bit_no) & 1);
03110                   DAC_regno = state.attribute_ctrl.palette_reg[palette_reg_val];
03111                   state.tile[r * X_TILESIZE + c] = DAC_regno;
03112                 }
03113               }
03114 
03115               SET_TILE_UPDATED(xti, yti, 0);
03116               bx_gui->graphics_tile_update(state.tile, xc, yc);
03117             }
03118           }
03119         }
03120       }
03121       else
03122       {                 // output data in serial fashion with each display plane
03123         // output on its associated serial output.  Standard EGA/VGA format
03124         plane0 = &state.memory[0 << 16];
03125         plane1 = &state.memory[1 << 16];
03126         plane2 = &state.memory[2 << 16];
03127         plane3 = &state.memory[3 << 16];
03128         line_compare = state.line_compare;
03129         if(state.y_doublescan)
03130           line_compare >>= 1;
03131 
03132         for(yc = 0, yti = 0; yc < iHeight; yc += Y_TILESIZE, yti++)
03133         {
03134           for(xc = 0, xti = 0; xc < iWidth; xc += X_TILESIZE, xti++)
03135           {
03136             if(GET_TILE_UPDATED(xti, yti))
03137             {
03138               for(r = 0; r < Y_TILESIZE; r++)
03139               {
03140                 y = yc + r;
03141                 if(state.y_doublescan)
03142                   y >>= 1;
03143                 for(c = 0; c < X_TILESIZE; c++)
03144                 {
03145                   x = xc + c;
03146                   if(state.x_dotclockdiv2)
03147                     x >>= 1;
03148                   bit_no = 7 - (x % 8);
03149                   if(y > line_compare)
03150                   {
03151                     byte_offset = x / 8 + ((y - line_compare - 1) * state.line_offset);
03152                   }
03153                   else
03154                   {
03155                     byte_offset = start_addr + x / 8 + (y * state.line_offset);
03156                   }
03157 
03158                   attribute = (((plane0[byte_offset] >> bit_no) & 0x01) << 0) |
03159                     (((plane1[byte_offset] >> bit_no) & 0x01) << 1) |
03160                       (((plane2[byte_offset] >> bit_no) & 0x01) << 2) |
03161                         (((plane3[byte_offset] >> bit_no) & 0x01) << 3);
03162 
03163                   attribute &= state.attribute_ctrl.color_plane_enable;
03164 
03165                   // undocumented feature ???: colors 0..7 high intensity, colors 8..15 blinking
03166                   // using low/high intensity. Blinking is not implemented yet.
03167                   if(state.attribute_ctrl.mode_ctrl.blink_intensity)
03168                     attribute ^= 0x08;
03169                   palette_reg_val = state.attribute_ctrl.palette_reg[attribute];
03170                   if(state.attribute_ctrl.mode_ctrl.internal_palette_size)
03171                   {
03172 
03173                     // use 4 lower bits from palette register
03174                     // use 4 higher bits from color select register
03175                     // 16 banks of 16-color registers
03176                     DAC_regno = (palette_reg_val & 0x0f) | (state.attribute_ctrl.color_select << 4);
03177                   }
03178                   else
03179                   {
03180 
03181                     // use 6 lower bits from palette register
03182                     // use 2 higher bits from color select register
03183                     // 4 banks of 64-color registers
03184                     DAC_regno = (palette_reg_val & 0x3f) | ((state.attribute_ctrl.color_select & 0x0c) << 4);
03185                   }
03186 
03187                   // DAC_regno &= video DAC mask register ???
03188                   state.tile[r * X_TILESIZE + c] = DAC_regno;
03189                 }
03190               }
03191 
03192               SET_TILE_UPDATED(xti, yti, 0);
03193               bx_gui->graphics_tile_update(state.tile, xc, yc);
03194             }
03195           }
03196         }
03197       }
03198       break;            // case 0
03199 
03200     case 1:             // output the data in a CGA-compatible 320x200 4 color graphics
03201       // mode.  (modes 4 & 5)
03202 
03203       /* CGA 320x200x4 start */
03204       for(yc = 0, yti = 0; yc < iHeight; yc += Y_TILESIZE, yti++)
03205       {
03206         for(xc = 0, xti = 0; xc < iWidth; xc += X_TILESIZE, xti++)
03207         {
03208           if(GET_TILE_UPDATED(xti, yti))
03209           {
03210             for(r = 0; r < Y_TILESIZE; r++)
03211             {
03212               y = yc + r;
03213               if(state.y_doublescan)
03214                 y >>= 1;
03215               for(c = 0; c < X_TILESIZE; c++)
03216               {
03217                 x = xc + c;
03218                 if(state.x_dotclockdiv2)
03219                   x >>= 1;
03220 
03221                 /* 0 or 0x2000 */
03222                 byte_offset = start_addr + ((y & 1) << 13);
03223 
03224                 /* to the start of the line */
03225                 byte_offset += (320 / 4) * (y / 2);
03226 
03227                 /* to the byte start */
03228                 byte_offset += (x / 4);
03229 
03230                 attribute = 6 - 2 * (x % 4);
03231                 palette_reg_val = (state.memory[byte_offset]) >> attribute;
03232                 palette_reg_val &= 3;
03233                 DAC_regno = state.attribute_ctrl.palette_reg[palette_reg_val];
03234                 state.tile[r * X_TILESIZE + c] = DAC_regno;
03235               }
03236             }
03237 
03238             SET_TILE_UPDATED(xti, yti, 0);
03239             bx_gui->graphics_tile_update(state.tile, xc, yc);
03240           }
03241         }
03242       }
03243 
03244       /* CGA 320x200x4 end */
03245       break;            // case 1
03246 
03247     case 2:             // output the data eight bits at a time from the 4 bit plane
03248 
03249     // (format for VGA mode 13 hex)
03250     case 3:             // FIXME: is this really the same ???
03251       if(state.sequencer.chain_four)
03252       {
03253         unsigned long pixely;
03254 
03255         unsigned long pixelx;
03256 
03257         unsigned long plane;
03258 
03259         if(state.misc_output.select_high_bank != 1)
03260         {
03261           FAILURE(NotImplemented, "update: select_high_bank != 1   \n");
03262         }
03263 
03264         for(yc = 0, yti = 0; yc < iHeight; yc += Y_TILESIZE, yti++)
03265         {
03266           for(xc = 0, xti = 0; xc < iWidth; xc += X_TILESIZE, xti++)
03267           {
03268             if(GET_TILE_UPDATED(xti, yti))
03269             {
03270               for(r = 0; r < Y_TILESIZE; r++)
03271               {
03272                 pixely = yc + r;
03273                 if(state.y_doublescan)
03274                   pixely >>= 1;
03275                 for(c = 0; c < X_TILESIZE; c++)
03276                 {
03277                   pixelx = (xc + c) >> 1;
03278                   plane = (pixelx % 4);
03279                   byte_offset = start_addr + (plane * 65536) + (pixely * state.line_offset) + (pixelx &~0x03);
03280                   color = state.memory[byte_offset];
03281                   state.tile[r * X_TILESIZE + c] = color;
03282                 }
03283               }
03284 
03285               SET_TILE_UPDATED(xti, yti, 0);
03286               bx_gui->graphics_tile_update(state.tile, xc, yc);
03287             }
03288           }
03289         }
03290       }
03291       else
03292       {                 // chain_four == 0, modeX
03293         unsigned long pixely;
03294 
03295         // chain_four == 0, modeX
03296         unsigned long pixelx;
03297 
03298         // chain_four == 0, modeX
03299         unsigned long plane;
03300 
03301         for(yc = 0, yti = 0; yc < iHeight; yc += Y_TILESIZE, yti++)
03302         {
03303           for(xc = 0, xti = 0; xc < iWidth; xc += X_TILESIZE, xti++)
03304           {
03305             if(GET_TILE_UPDATED(xti, yti))
03306             {
03307               for(r = 0; r < Y_TILESIZE; r++)
03308               {
03309                 pixely = yc + r;
03310                 if(state.y_doublescan)
03311                   pixely >>= 1;
03312                 for(c = 0; c < X_TILESIZE; c++)
03313                 {
03314                   pixelx = (xc + c) >> 1;
03315                   plane = (pixelx % 4);
03316                   byte_offset = (plane * 65536) + (pixely * state.line_offset) + (pixelx >> 2);
03317                   color = state.memory[start_addr + byte_offset];
03318                   state.tile[r * X_TILESIZE + c] = color;
03319                 }
03320               }
03321 
03322               SET_TILE_UPDATED(xti, yti, 0);
03323               bx_gui->graphics_tile_update(state.tile, xc, yc);
03324             }
03325           }
03326         }
03327       }
03328       break;            // case 2
03329 
03330     default:
03331       FAILURE_1(NotImplemented, "update: shift_reg == %u   \n",
03332                 (unsigned) state.graphics_ctrl.shift_reg);
03333     }
03334 
03335     state.vga_mem_updated = 0;
03336     return;
03337   }
03338   else
03339   {                     // text mode
03340     unsigned long   start_address;
03341     unsigned long   cursor_address;
03342     unsigned long   cursor_x;
03343     unsigned long   cursor_y;
03344     bx_vga_tminfo_t tm_info;
03345     unsigned        VDE;
03346     unsigned        MSL;
03347     unsigned        cols;
03348     unsigned        rows;
03349     unsigned        cWidth;
03350 
03351     tm_info.start_address = 2 * ((state.CRTC.reg[12] << 8) + state.CRTC.reg[13]);
03352     tm_info.cs_start = state.CRTC.reg[0x0a] & 0x3f;
03353     tm_info.cs_end = state.CRTC.reg[0x0b] & 0x1f;
03354     tm_info.line_offset = state.CRTC.reg[0x13] << 2;
03355     tm_info.line_compare = state.line_compare;
03356     tm_info.h_panning = state.attribute_ctrl.horiz_pel_panning & 0x0f;
03357     tm_info.v_panning = state.CRTC.reg[0x08] & 0x1f;
03358     tm_info.line_graphics = state.attribute_ctrl.mode_ctrl.enable_line_graphics;
03359     tm_info.split_hpanning = state.attribute_ctrl.mode_ctrl.pixel_panning_compat;
03360     if((state.sequencer.reg1 & 0x01) == 0)
03361     {
03362       if(tm_info.h_panning >= 8)
03363         tm_info.h_panning = 0;
03364       else
03365         tm_info.h_panning++;
03366     }
03367     else
03368     {
03369       tm_info.h_panning &= 0x07;
03370     }
03371 
03372     // Verticle Display End: find out how many lines are displayed
03373     VDE = state.vertical_display_end;
03374 
03375     // Maximum Scan Line: height of character cell
03376     MSL = state.CRTC.reg[0x09] & 0x1f;
03377     if(MSL == 0)
03378     {
03379 #if defined(DEBUG_VGA)
03380       BX_ERROR(("character height = 1, skipping text update"));
03381 #endif
03382       return;
03383     }
03384 
03385     cols = state.CRTC.reg[1] + 1;
03386     if((MSL == 1) && (VDE == 399))
03387     {
03388 
03389       // emulated CGA graphics mode 160x100x16 colors
03390       MSL = 3;
03391     }
03392 
03393     rows = (VDE + 1) / (MSL + 1);
03394     if(rows > BX_MAX_TEXT_LINES)
03395     {
03396       BX_PANIC(("text rows>%d: %d", BX_MAX_TEXT_LINES, rows));
03397       return;
03398     }
03399 
03400     cWidth = ((state.sequencer.reg1 & 0x01) == 1) ? 8 : 9;
03401     iWidth = cWidth * cols;
03402     iHeight = VDE + 1;
03403     if((iWidth != old_iWidth) || (iHeight != old_iHeight) || (MSL != old_MSL)
03404      || (state.last_bpp > 8))
03405     {
03406       bx_gui->dimension_update(iWidth, iHeight, MSL + 1, cWidth);
03407       old_iWidth = iWidth;
03408       old_iHeight = iHeight;
03409       old_MSL = MSL;
03410       state.last_bpp = 8;
03411     }
03412 
03413     // pass old text snapshot & new VGA memory contents
03414     start_address = 2 * ((state.CRTC.reg[12] << 8) + state.CRTC.reg[13]);
03415     cursor_address = 2 * ((state.CRTC.reg[0x0e] << 8) + state.CRTC.reg[0x0f]);
03416     if(cursor_address < start_address)
03417     {
03418       cursor_x = 0xffff;
03419       cursor_y = 0xffff;
03420     }
03421     else
03422     {
03423       cursor_x = ((cursor_address - start_address) / 2) % (iWidth / cWidth);
03424       cursor_y = ((cursor_address - start_address) / 2) / (iWidth / cWidth);
03425     }
03426 
03427     bx_gui->text_update(state.text_snapshot, &state.memory[start_address],
03428                         cursor_x, cursor_y, tm_info, rows);
03429 
03430     // screen updated, copy new VGA memory contents into text snapshot
03431     memcpy(state.text_snapshot, &state.memory[start_address], 2 * cols * rows);
03432     state.vga_mem_updated = 0;
03433   }
03434 }
03435 
03436 void CCirrus::determine_screen_dimensions(unsigned* piHeight, unsigned* piWidth)
03437 {
03438   int ai[0x20];
03439   int i;
03440   int h;
03441   int v;
03442   for(i = 0; i < 0x20; i++)
03443     ai[i] = state.CRTC.reg[i];
03444 
03445   h = (ai[1] + 1) * 8;
03446   v = (ai[18] | ((ai[7] & 0x02) << 7) | ((ai[7] & 0x40) << 3)) + 1;
03447 
03448   if(state.graphics_ctrl.shift_reg == 0)
03449   {
03450     *piWidth = 640;
03451     *piHeight = 480;
03452 
03453     if(state.CRTC.reg[6] == 0xBF)
03454     {
03455       if(state.CRTC.reg[23] == 0xA3 && state.CRTC.reg[20] == 0x40
03456        && state.CRTC.reg[9] == 0x41)
03457       {
03458         *piWidth = 320;
03459         *piHeight = 240;
03460       }
03461       else
03462       {
03463         if(state.x_dotclockdiv2)
03464           h <<= 1;
03465         *piWidth = h;
03466         *piHeight = v;
03467       }
03468     }
03469     else if((h >= 640) && (v >= 480))
03470     {
03471       *piWidth = h;
03472       *piHeight = v;
03473     }
03474   }
03475   else if(state.graphics_ctrl.shift_reg == 2)
03476   {
03477     if(state.sequencer.chain_four)
03478     {
03479       *piWidth = h;
03480       *piHeight = v;
03481     }
03482     else
03483     {
03484       *piWidth = h;
03485       *piHeight = v;
03486     }
03487   }
03488   else
03489   {
03490     if(state.x_dotclockdiv2)
03491       h <<= 1;
03492     *piWidth = h;
03493     *piHeight = v;
03494   }
03495 }
03496 
03497 u8 CCirrus::vga_mem_read(u32 addr)
03498 {
03499   u32   offset;
03500   u8*   plane0;
03501   u8 *plane1;
03502   u8 *plane2;
03503   u8 *plane3;
03504   u8    retval = 0;
03505 
03506   switch(state.graphics_ctrl.memory_mapping)
03507   {
03508   case 1:               // 0xA0000 .. 0xAFFFF
03509     if(addr > 0xAFFFF)
03510       return 0xff;
03511     offset = addr & 0xFFFF;
03512     break;
03513 
03514   case 2:               // 0xB0000 .. 0xB7FFF
03515     if((addr < 0xB0000) || (addr > 0xB7FFF))
03516       return 0xff;
03517     offset = addr & 0x7FFF;
03518     break;
03519 
03520   case 3:               // 0xB8000 .. 0xBFFFF
03521     if(addr < 0xB8000)
03522       return 0xff;
03523     offset = addr & 0x7FFF;
03524     break;
03525 
03526   default:              // 0xA0000 .. 0xBFFFF
03527     offset = addr & 0x1FFFF;
03528   }
03529 
03530   if(state.sequencer.chain_four)
03531   {
03532 
03533     // Mode 13h: 320 x 200 256 color mode: chained pixel representation
03534     return state.memory[(offset &~0x03) + (offset % 4) * 65536];
03535   }
03536 
03537   plane0 = &state.memory[0 << 16];
03538   plane1 = &state.memory[1 << 16];
03539   plane2 = &state.memory[2 << 16];
03540   plane3 = &state.memory[3 << 16];
03541 
03542   /* addr between 0xA0000 and 0xAFFFF */
03543   switch(state.graphics_ctrl.read_mode)
03544   {
03545   case 0:               /* read mode 0 */
03546     state.graphics_ctrl.latch[0] = plane0[offset];
03547     state.graphics_ctrl.latch[1] = plane1[offset];
03548     state.graphics_ctrl.latch[2] = plane2[offset];
03549     state.graphics_ctrl.latch[3] = plane3[offset];
03550     retval = state.graphics_ctrl.latch[state.graphics_ctrl.read_map_select];
03551     break;
03552 
03553   case 1:               /* read mode 1 */
03554     {
03555       u8  color_compare;
03556 
03557       u8  color_dont_care;
03558       u8  latch0;
03559       u8  latch1;
03560       u8  latch2;
03561       u8  latch3;
03562 
03563       color_compare = state.graphics_ctrl.color_compare & 0x0f;
03564       color_dont_care = state.graphics_ctrl.color_dont_care & 0x0f;
03565       latch0 = state.graphics_ctrl.latch[0] = plane0[offset];
03566       latch1 = state.graphics_ctrl.latch[1] = plane1[offset];
03567       latch2 = state.graphics_ctrl.latch[2] = plane2[offset];
03568       latch3 = state.graphics_ctrl.latch[3] = plane3[offset];
03569 
03570       latch0 ^= ccdat[color_compare][0];
03571       latch1 ^= ccdat[color_compare][1];
03572       latch2 ^= ccdat[color_compare][2];
03573       latch3 ^= ccdat[color_compare][3];
03574 
03575       latch0 &= ccdat[color_dont_care][0];
03576       latch1 &= ccdat[color_dont_care][1];
03577       latch2 &= ccdat[color_dont_care][2];
03578       latch3 &= ccdat[color_dont_care][3];
03579 
03580       retval = ~(latch0 | latch1 | latch2 | latch3);
03581     }
03582     break;
03583   }
03584 
03585   return retval;
03586 }
03587 
03592 void CCirrus::vga_mem_write(u32 addr, u8 value)
03593 {
03594   u32       offset;
03595   u8        new_val[4];
03596   unsigned  start_addr;
03597   u8*       plane0;
03598   u8 *plane1;
03599   u8 *plane2;
03600   u8 *plane3;
03601 
03602   /* The memory_mapping bits of the graphics controller determine 
03603    * what window of VGA memory is available.
03604    *
03605    *  00: 0xA0000 .. 0xBFFFF (128K)
03606    *  01: 0xA0000 .. 0xAFFFF (64K) (also used for VGA text mode)
03607    *  02: 0xB0000 .. 0xB7FFF (32K)
03608    *  03: 0xB8000 .. 0xBFFFF (32K) (also used for CGA text mode)
03609    */
03610   switch(state.graphics_ctrl.memory_mapping)
03611   {
03612   // 0xA0000 .. 0xAFFFF
03613   case 1:
03614     if(addr > 0xAFFFF)
03615       return;
03616     offset = addr - 0xA0000;
03617     break;
03618 
03619   // 0xB0000 .. 0xB7FFF
03620   case 2:
03621     if((addr < 0xB0000) || (addr > 0xB7FFF))
03622       return;
03623     offset = addr - 0xB0000;
03624     break;
03625 
03626   // 0xB8000 .. 0xBFFFF
03627   case 3:
03628     if(addr < 0xB8000)
03629       return;
03630     offset = addr - 0xB8000;
03631     break;
03632 
03633   // 0xA0000 .. 0xBFFFF
03634   default:
03635     offset = addr - 0xA0000;
03636   }
03637 
03638   start_addr = (state.CRTC.reg[0x0c] << 8) | state.CRTC.reg[0x0d];
03639 
03640   if(state.graphics_ctrl.graphics_alpha)
03641   {
03642     if(state.graphics_ctrl.memory_mapping == 3)
03643     {                   
03644       // Text mode, and memory 0xB8000 .. 0xBFFFF selected => CGA text mode
03645       unsigned  x_tileno;
03646       unsigned  x_tileno2;
03647       unsigned  y_tileno;
03648 
03649       /* CGA 320x200x4 / 640x200x2 start */
03650       state.memory[offset] = value;
03651       offset -= start_addr;
03652       if(offset >= 0x2000)
03653       {
03654         y_tileno = offset - 0x2000;
03655         y_tileno /= (320 / 4);
03656         y_tileno <<= 1; //2 * y_tileno;
03657         y_tileno++;
03658         x_tileno = (offset - 0x2000) % (320 / 4);
03659         x_tileno <<= 2; //*= 4;
03660       }
03661       else
03662       {
03663         y_tileno = offset / (320 / 4);
03664         y_tileno <<= 1; //2 * y_tileno;
03665         x_tileno = offset % (320 / 4);
03666         x_tileno <<= 2; //*=4;
03667       }
03668 
03669       x_tileno2 = x_tileno;
03670       if(state.graphics_ctrl.shift_reg == 0)
03671       {
03672         x_tileno *= 2;
03673         x_tileno2 += 7;
03674       }
03675       else
03676       {
03677         x_tileno2 += 3;
03678       }
03679 
03680       if(state.x_dotclockdiv2)
03681       {
03682         x_tileno /= (X_TILESIZE / 2);
03683         x_tileno2 /= (X_TILESIZE / 2);
03684       }
03685       else
03686       {
03687         x_tileno /= X_TILESIZE;
03688         x_tileno2 /= X_TILESIZE;
03689       }
03690 
03691       if(state.y_doublescan)
03692       {
03693         y_tileno /= (Y_TILESIZE / 2);
03694       }
03695       else
03696       {
03697         y_tileno /= Y_TILESIZE;
03698       }
03699 
03700       state.vga_mem_updated = 1;
03701       SET_TILE_UPDATED(x_tileno, y_tileno, 1);
03702       if(x_tileno2 != x_tileno)
03703       {
03704         SET_TILE_UPDATED(x_tileno2, y_tileno, 1);
03705       }
03706 
03707       return;
03708 
03709       /* CGA 320x200x4 / 640x200x2 end */
03710     }
03711     
03712     if(state.graphics_ctrl.memory_mapping != 1)
03713     {
03714       FAILURE_1(NotImplemented, "mem_write: graphics: mapping = %u  \n",
03715                 (unsigned) state.graphics_ctrl.memory_mapping);
03716     }
03717 
03718     if(state.sequencer.chain_four)
03719     {
03720       unsigned  x_tileno;
03721 
03722       unsigned  y_tileno;
03723 
03724       // 320 x 200 256 color mode: chained pixel representation
03725       state.memory[(offset &~0x03) + (offset % 4) * 65536] = value;
03726       if(state.line_offset > 0)
03727       {
03728         offset -= start_addr;
03729         x_tileno = (offset % state.line_offset) / (X_TILESIZE / 2);
03730         if(state.y_doublescan)
03731         {
03732           y_tileno = (offset / state.line_offset) / (Y_TILESIZE / 2);
03733         }
03734         else
03735         {
03736           y_tileno = (offset / state.line_offset) / Y_TILESIZE;
03737         }
03738 
03739         state.vga_mem_updated = 1;
03740         SET_TILE_UPDATED(x_tileno, y_tileno, 1);
03741       }
03742 
03743       return;
03744     }
03745   }
03746 
03747   /* addr between 0xA0000 and 0xAFFFF */
03748   plane0 = &state.memory[0 << 16];
03749   plane1 = &state.memory[1 << 16];
03750   plane2 = &state.memory[2 << 16];
03751   plane3 = &state.memory[3 << 16];
03752 
03753   switch(state.graphics_ctrl.write_mode)
03754   {
03755     unsigned  i;
03756   // Write mode 0
03757   case 0:
03758     {
03759       /* Write Mode 0 is the standard and most general write mode. 
03760        * While the other write modes are designed to perform a specific 
03761        * task, this mode can be used to perform most tasks as all five 
03762        * operations are performed on the data:
03763        *   - The data byte from the host is first rotated as specified
03764        *     by the Rotate Count field, then is replicated across all
03765        *     four planes.
03766        *   - Then the Enable Set/Reset field selects which planes will
03767        *     receive their values from the host data and which will
03768        *     receive their data from that plane's Set/Reset field
03769        *     location.
03770        *   - Then the operation specified by the Logical Operation
03771        *     field is performed on the resulting data and the data in
03772        *     the read latches.
03773        *   - The Bit Mask field is then used to select between the
03774        *     resulting data and data from the latch register. 
03775        *   - Finally, the resulting data is written to the display
03776        *     memory planes enabled in the Memory Plane Write Enable
03777        *     field. 
03778        *   .
03779        */
03780       const u8  bitmask = state.graphics_ctrl.bitmask;
03781       const u8  set_reset = state.graphics_ctrl.set_reset;
03782       const u8  enable_set_reset = state.graphics_ctrl.enable_set_reset;
03783 
03784       /* perform rotate on CPU data in case its needed */
03785       if(state.graphics_ctrl.data_rotate)
03786       {
03787         value = (value >> state.graphics_ctrl.data_rotate) | (value << (8 - state.graphics_ctrl.data_rotate));
03788       }
03789 
03790       new_val[0] = state.graphics_ctrl.latch[0] &~bitmask;
03791       new_val[1] = state.graphics_ctrl.latch[1] &~bitmask;
03792       new_val[2] = state.graphics_ctrl.latch[2] &~bitmask;
03793       new_val[3] = state.graphics_ctrl.latch[3] &~bitmask;
03794       switch(state.graphics_ctrl.raster_op)
03795       {
03796       case 0: // replace
03797         new_val[0] |=
03798           (
03799             (enable_set_reset & 1) ? ((set_reset & 1) ? bitmask : 0) :
03800               (value & bitmask)
03801           );
03802         new_val[1] |=
03803           (
03804             (enable_set_reset & 2) ? ((set_reset & 2) ? bitmask : 0) :
03805               (value & bitmask)
03806           );
03807         new_val[2] |=
03808           (
03809             (enable_set_reset & 4) ? ((set_reset & 4) ? bitmask : 0) :
03810               (value & bitmask)
03811           );
03812         new_val[3] |=
03813           (
03814             (enable_set_reset & 8) ? ((set_reset & 8) ? bitmask : 0) :
03815               (value & bitmask)
03816           );
03817         break;
03818 
03819       case 1: // AND
03820         new_val[0] |=
03821           (
03822             (enable_set_reset & 1) ?
03823               ((set_reset & 1) ? (state.graphics_ctrl.latch[0] & bitmask) : 0) :
03824                 (value & state.graphics_ctrl.latch[0]) & bitmask
03825           );
03826         new_val[1] |=
03827           (
03828             (enable_set_reset & 2) ?
03829               ((set_reset & 2) ? (state.graphics_ctrl.latch[1] & bitmask) : 0) :
03830                 (value & state.graphics_ctrl.latch[1]) & bitmask
03831           );
03832         new_val[2] |=
03833           (
03834             (enable_set_reset & 4) ?
03835               ((set_reset & 4) ? (state.graphics_ctrl.latch[2] & bitmask) : 0) :
03836                 (value & state.graphics_ctrl.latch[2]) & bitmask
03837           );
03838         new_val[3] |=
03839           (
03840             (enable_set_reset & 8) ?
03841               ((set_reset & 8) ? (state.graphics_ctrl.latch[3] & bitmask) : 0) :
03842                 (value & state.graphics_ctrl.latch[3]) & bitmask
03843           );
03844         break;
03845 
03846       case 2: // OR
03847         new_val[0] |=
03848           (
03849             (enable_set_reset & 1) ?
03850               (
03851                 (set_reset & 1) ? bitmask :
03852                   (state.graphics_ctrl.latch[0] & bitmask)
03853               ) : ((value | state.graphics_ctrl.latch[0]) & bitmask)
03854           );
03855         new_val[1] |=
03856           (
03857             (enable_set_reset & 2) ?
03858               (
03859                 (set_reset & 2) ? bitmask :
03860                   (state.graphics_ctrl.latch[1] & bitmask)
03861               ) : ((value | state.graphics_ctrl.latch[1]) & bitmask)
03862           );
03863         new_val[2] |=
03864           (
03865             (enable_set_reset & 4) ?
03866               (
03867                 (set_reset & 4) ? bitmask :
03868                   (state.graphics_ctrl.latch[2] & bitmask)
03869               ) : ((value | state.graphics_ctrl.latch[2]) & bitmask)
03870           );
03871         new_val[3] |=
03872           (
03873             (enable_set_reset & 8) ?
03874               (
03875                 (set_reset & 8) ? bitmask :
03876                   (state.graphics_ctrl.latch[3] & bitmask)
03877               ) : ((value | state.graphics_ctrl.latch[3]) & bitmask)
03878           );
03879         break;
03880 
03881       case 3: // XOR
03882         new_val[0] |=
03883           (
03884             (enable_set_reset & 1) ?
03885               (
03886                 (set_reset & 1) ? (~state.graphics_ctrl.latch[0] & bitmask) :
03887                   (state.graphics_ctrl.latch[0] & bitmask)
03888               ) : (value ^ state.graphics_ctrl.latch[0]) & bitmask
03889           );
03890         new_val[1] |=
03891           (
03892             (enable_set_reset & 2) ?
03893               (
03894                 (set_reset & 2) ? (~state.graphics_ctrl.latch[1] & bitmask) :
03895                   (state.graphics_ctrl.latch[1] & bitmask)
03896               ) : (value ^ state.graphics_ctrl.latch[1]) & bitmask
03897           );
03898         new_val[2] |=
03899           (
03900             (enable_set_reset & 4) ?
03901               (
03902                 (set_reset & 4) ? (~state.graphics_ctrl.latch[2] & bitmask) :
03903                   (state.graphics_ctrl.latch[2] & bitmask)
03904               ) : (value ^ state.graphics_ctrl.latch[2]) & bitmask
03905           );
03906         new_val[3] |=
03907           (
03908             (enable_set_reset & 8) ?
03909               (
03910                 (set_reset & 8) ? (~state.graphics_ctrl.latch[3] & bitmask) :
03911                   (state.graphics_ctrl.latch[3] & bitmask)
03912               ) : (value ^ state.graphics_ctrl.latch[3]) & bitmask
03913           );
03914         break;
03915 
03916       default:
03917         FAILURE_1(NotImplemented, "vga_mem_write: write mode 0: op = %u",
03918                   (unsigned) state.graphics_ctrl.raster_op);
03919       }
03920     }
03921     break;
03922 
03923   // Write mode 1
03924   case 1:
03925     /* Write Mode 1 is used to transfer the data in the latches
03926      * register directly to the screen, affected only by the
03927      * Memory Plane Write Enable field. This can facilitate
03928      * rapid transfer of data on byte boundaries from one area
03929      * of video memory to another or filling areas of the
03930      * display with a pattern of 8 pixels. 
03931      * When Write Mode 0 is used with the Bit Mask field set to 
03932      * 00000000b the operation of the hardware is identical to 
03933      * this mode.
03934      */
03935     for(i = 0; i < 4; i++)
03936     {
03937       new_val[i] = state.graphics_ctrl.latch[i];
03938     }
03939     break;
03940 
03941   // Write mode 2
03942   case 2:
03943     {
03944       /* Write Mode 2 is used to unpack a pixel value packed into
03945        * the lower 4 bits of the host data byte into the 4 display
03946        * planes:
03947        *   - In the byte from the host, the bit representing each
03948        *     plane will be replicated across all 8 bits of the
03949        *     corresponding planes.
03950        *   - Then the operation specified by the Logical Operation
03951        *     field is performed on the resulting data and the data
03952        *     in the read latches.
03953        *   - The Bit Mask field is then used to select between the
03954        *     resulting data and data from the latch register. 
03955        *   - Finally, the resulting data is written to the display
03956        *     memory planes enabled in the Memory Plane Write Enable
03957        *     field.
03958        *   .
03959        */
03960       const u8  bitmask = state.graphics_ctrl.bitmask;
03961 
03962       new_val[0] = state.graphics_ctrl.latch[0] &~bitmask;
03963       new_val[1] = state.graphics_ctrl.latch[1] &~bitmask;
03964       new_val[2] = state.graphics_ctrl.latch[2] &~bitmask;
03965       new_val[3] = state.graphics_ctrl.latch[3] &~bitmask;
03966       switch(state.graphics_ctrl.raster_op)
03967       {
03968       case 0: // write
03969         new_val[0] |= (value & 1) ? bitmask : 0;
03970         new_val[1] |= (value & 2) ? bitmask : 0;
03971         new_val[2] |= (value & 4) ? bitmask : 0;
03972         new_val[3] |= (value & 8) ? bitmask : 0;
03973         break;
03974 
03975       case 1: // AND
03976         new_val[0] |= (value & 1) ? (state.graphics_ctrl.latch[0] & bitmask) : 0;
03977         new_val[1] |= (value & 2) ? (state.graphics_ctrl.latch[1] & bitmask) : 0;
03978         new_val[2] |= (value & 4) ? (state.graphics_ctrl.latch[2] & bitmask) : 0;
03979         new_val[3] |= (value & 8) ? (state.graphics_ctrl.latch[3] & bitmask) : 0;
03980         break;
03981 
03982       case 2: // OR
03983         new_val[0] |= (value & 1) ? bitmask : (state.graphics_ctrl.latch[0] & bitmask);
03984         new_val[1] |= (value & 2) ? bitmask : (state.graphics_ctrl.latch[1] & bitmask);
03985         new_val[2] |= (value & 4) ? bitmask : (state.graphics_ctrl.latch[2] & bitmask);
03986         new_val[3] |= (value & 8) ? bitmask : (state.graphics_ctrl.latch[3] & bitmask);
03987         break;
03988 
03989       case 3: // XOR
03990         new_val[0] |= (value & 1) ? (~state.graphics_ctrl.latch[0] & bitmask) : (state.graphics_ctrl.latch[0] & bitmask);
03991         new_val[1] |= (value & 2) ? (~state.graphics_ctrl.latch[1] & bitmask) : (state.graphics_ctrl.latch[1] & bitmask);
03992         new_val[2] |= (value & 4) ? (~state.graphics_ctrl.latch[2] & bitmask) : (state.graphics_ctrl.latch[2] & bitmask);
03993         new_val[3] |= (value & 8) ? (~state.graphics_ctrl.latch[3] & bitmask) : (state.graphics_ctrl.latch[3] & bitmask);
03994         break;
03995       }
03996     }
03997     break;
03998 
03999   // Write mode 3
04000   case 3:
04001     {
04002       /* Write Mode 3 is used when the color written is fairly
04003        * constant but the Bit Mask field needs to be changed
04004        * frequently, such as when drawing single color lines or
04005        * text: 
04006        *   - The value of the Set/Reset field is expanded as if
04007        *     the Enable Set/Reset field were set to 1111b,
04008        *     regardless of its actual value.
04009        *   - The host data is first rotated as specified by the
04010        *     Rotate Count field, then is ANDed with the Bit
04011        *     Mask field.
04012        *   - The resulting value is used where the Bit Mask
04013        *     field normally would be used, selecting data from
04014        *     either the expansion of the Set/Reset field or the
04015        *     latch register.
04016        *   - Finally, the resulting data is written to the
04017        *     display memory planes enabled in the Memory Plane
04018        *     Write Enable field.
04019        *   .
04020        */
04021       const u8  bitmask = state.graphics_ctrl.bitmask & value;
04022       const u8  set_reset = state.graphics_ctrl.set_reset;
04023 
04024       /* perform rotate on CPU data */
04025       if(state.graphics_ctrl.data_rotate)
04026       {
04027         value = (value >> state.graphics_ctrl.data_rotate) | (value << (8 - state.graphics_ctrl.data_rotate));
04028       }
04029 
04030       new_val[0] = state.graphics_ctrl.latch[0] &~bitmask;
04031       new_val[1] = state.graphics_ctrl.latch[1] &~bitmask;
04032       new_val[2] = state.graphics_ctrl.latch[2] &~bitmask;
04033       new_val[3] = state.graphics_ctrl.latch[3] &~bitmask;
04034 
04035       value &= bitmask;
04036 
04037       switch(state.graphics_ctrl.raster_op)
04038       {
04039       case 0: // write
04040         new_val[0] |= (set_reset & 1) ? value : 0;
04041         new_val[1] |= (set_reset & 2) ? value : 0;
04042         new_val[2] |= (set_reset & 4) ? value : 0;
04043         new_val[3] |= (set_reset & 8) ? value : 0;
04044         break;
04045 
04046       case 1: // AND
04047         new_val[0] |= ((set_reset & 1) ? value : 0) & state.graphics_ctrl.latch[0];
04048         new_val[1] |= ((set_reset & 2) ? value : 0) & state.graphics_ctrl.latch[1];
04049         new_val[2] |= ((set_reset & 4) ? value : 0) & state.graphics_ctrl.latch[2];
04050         new_val[3] |= ((set_reset & 8) ? value : 0) & state.graphics_ctrl.latch[3];
04051         break;
04052 
04053       case 2: // OR
04054         new_val[0] |= ((set_reset & 1) ? value : 0) | state.graphics_ctrl.latch[0];
04055         new_val[1] |= ((set_reset & 2) ? value : 0) | state.graphics_ctrl.latch[1];
04056         new_val[2] |= ((set_reset & 4) ? value : 0) | state.graphics_ctrl.latch[2];
04057         new_val[3] |= ((set_reset & 8) ? value : 0) | state.graphics_ctrl.latch[3];
04058         break;
04059 
04060       case 3: // XOR
04061         new_val[0] |= ((set_reset & 1) ? value : 0) ^ state.graphics_ctrl.latch[0];
04062         new_val[1] |= ((set_reset & 2) ? value : 0) ^ state.graphics_ctrl.latch[1];
04063         new_val[2] |= ((set_reset & 4) ? value : 0) ^ state.graphics_ctrl.latch[2];
04064         new_val[3] |= ((set_reset & 8) ? value : 0) ^ state.graphics_ctrl.latch[3];
04065         break;
04066       }
04067     }
04068     break;
04069 
04070   default:
04071     FAILURE_1(NotImplemented, "vga_mem_write: write mode %u ?",
04072               (unsigned) state.graphics_ctrl.write_mode);
04073   }
04074 
04075   // state.sequencer.map_mask determines which bitplanes the write should actually go to
04076   if(state.sequencer.map_mask & 0x0f)
04077   {
04078     state.vga_mem_updated = 1;
04079     if(state.sequencer.map_mask & 0x01)
04080       plane0[offset] = new_val[0];
04081     if(state.sequencer.map_mask & 0x02)
04082       plane1[offset] = new_val[1];
04083     if(state.sequencer.map_mask & 0x04)
04084     {
04085       // Plane 2 contains the character map
04086       if((offset & 0xe000) == state.charmap_address)
04087       {
04088 
04089         //printf("Updating character map %04x with %02x...\n  ", (offset & 0x1fff), new_val[2]);
04090         bx_gui->lock();
04091         bx_gui->set_text_charbyte((u16) (offset & 0x1fff), new_val[2]);
04092         bx_gui->unlock();
04093       }
04094 
04095       plane2[offset] = new_val[2];
04096     }
04097 
04098     if(state.sequencer.map_mask & 0x08)
04099       plane3[offset] = new_val[3];
04100 
04101     unsigned  x_tileno;
04102 
04103     unsigned  y_tileno;
04104 
04105     if(state.graphics_ctrl.shift_reg == 2)
04106     {
04107       offset -= start_addr;
04108       x_tileno = (offset % state.line_offset) * 4 / (X_TILESIZE / 2);
04109       if(state.y_doublescan)
04110       {
04111         y_tileno = (offset / state.line_offset) / (Y_TILESIZE / 2);
04112       }
04113       else
04114       {
04115         y_tileno = (offset / state.line_offset) / Y_TILESIZE;
04116       }
04117 
04118       SET_TILE_UPDATED(x_tileno, y_tileno, 1);
04119     }
04120     else
04121     {
04122       if(state.line_compare < state.vertical_display_end)
04123       {
04124         if(state.line_offset > 0)
04125         {
04126           if(state.x_dotclockdiv2)
04127           {
04128             x_tileno = (offset % state.line_offset) / (X_TILESIZE / 16);
04129           }
04130           else
04131           {
04132             x_tileno = (offset % state.line_offset) / (X_TILESIZE / 8);
04133           }
04134 
04135           if(state.y_doublescan)
04136           {
04137             y_tileno =
04138               (
04139                 (offset / state.line_offset) *
04140                 2 +
04141                 state.line_compare +
04142                 1
04143               ) /
04144               Y_TILESIZE;
04145           }
04146           else
04147           {
04148             y_tileno = ((offset / state.line_offset) + state.line_compare + 1) / Y_TILESIZE;
04149           }
04150 
04151           SET_TILE_UPDATED(x_tileno, y_tileno, 1);
04152         }
04153       }
04154 
04155       if(offset >= start_addr)
04156       {
04157         offset -= start_addr;
04158         if(state.line_offset > 0)
04159         {
04160           if(state.x_dotclockdiv2)
04161           {
04162             x_tileno = (offset % state.line_offset) / (X_TILESIZE / 16);
04163           }
04164           else
04165           {
04166             x_tileno = (offset % state.line_offset) / (X_TILESIZE / 8);
04167           }
04168 
04169           if(state.y_doublescan)
04170           {
04171             y_tileno = (offset / state.line_offset) / (Y_TILESIZE / 2);
04172           }
04173           else
04174           {
04175             y_tileno = (offset / state.line_offset) / Y_TILESIZE;
04176           }
04177 
04178           SET_TILE_UPDATED(x_tileno, y_tileno, 1);
04179         }
04180       }
04181     }
04182   }
04183 }

SourceForge.net Logo
Project space on SourceForge.net