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

SourceForge.net Logo
Project space on SourceForge.net