1 /////////////////////////////////////////////////////////////////////////
2 // $Id: banshee.cc 14310 2021-07-08 14:43:18Z vruppert $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 //  Copyright (C) 2017-2021  The Bochs Project
6 //
7 //  This library is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU Lesser General Public
9 //  License as published by the Free Software Foundation; either
10 //  version 2 of the License, or (at your option) any later version.
11 //
12 //  This library is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 //  Lesser General Public License for more details.
16 //
17 //  You should have received a copy of the GNU Lesser General Public
18 //  License along with this library; if not, write to the Free Software
19 //  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
20 /////////////////////////////////////////////////////////////////////////
21 
22 /*
23  *  Portion of this software comes with the following license
24  */
25 
26 /***************************************************************************
27 
28     Copyright Aaron Giles
29     All rights reserved.
30 
31     Redistribution and use in source and binary forms, with or without
32     modification, are permitted provided that the following conditions are
33     met:
34 
35         * Redistributions of source code must retain the above copyright
36           notice, this list of conditions and the following disclaimer.
37         * Redistributions in binary form must reproduce the above copyright
38           notice, this list of conditions and the following disclaimer in
39           the documentation and/or other materials provided with the
40           distribution.
41         * Neither the name 'MAME' nor the names of its contributors may be
42           used to endorse or promote products derived from this software
43           without specific prior written permission.
44 
45     THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
46     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
47     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
48     DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
49     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
50     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
51     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
53     STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
54     IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
55     POSSIBILITY OF SUCH DAMAGE.
56 
57 ***************************************************************************/
58 
59 // 3dfx Voodoo Banshee / Voodoo3 emulation (partly based on a patch for DOSBox)
60 
61 // TODO:
62 // - 2D host-to-screen stretching support
63 // - 2D screen-to-screen pattern stretching support
64 // - 2D chromaKey support
65 // - 2D reversible line drawing
66 // - pixel format conversion not supported in all cases
67 // - full AGP support
68 
69 // FIXME:
70 // - Display errors in 16 bpp mode after leaving 3D mode
71 // - Display errors in 16 bpp mode with debug messages turned on (timing issue)
72 // - Bochs crashes on Windows host (MSVC in some cases, MSYS2 64-bit build also
73 //   reported, but not yet reproduced)
74 
75 // Define BX_PLUGGABLE in files that can be compiled into plugins.  For
76 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
77 // is used to know when we are exporting symbols and when we are importing.
78 #define BX_PLUGGABLE
79 
80 #include "iodev.h"
81 #if BX_SUPPORT_PCI && BX_SUPPORT_VOODOO
82 
83 #include "pci.h"
84 #include "vgacore.h"
85 #include "ddc.h"
86 #include "voodoo.h"
87 #include "virt_timer.h"
88 #include "bxthread.h"
89 #define BX_USE_TERNARY_ROP
90 #include "bitblt.h"
91 
92 #define LOG_THIS theVoodooDevice->
93 
94 const Bit8u banshee_iomask[256] = {4,0,0,0,7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,
95                                    7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,
96                                    7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,
97                                    7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,
98                                    7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,
99                                    7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,
100                                    7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,
101                                    7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,
102                                    7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,
103                                    7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,
104                                    7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,
105                                    7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1,
106                                    7,1,3,1,7,1,3,1,7,1,3,1,7,1,3,1};
107 
108 const Bit8u pxconv_table[16] = {0x3a,0x02,0x00,0x38,0x38,0x38,0x00,0x00,
109                                 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
110 
111 #include "voodoo_types.h"
112 #include "voodoo_data.h"
113 #include "voodoo_main.h"
114 
115 // Extern and forward declarations
116 extern voodoo_state *v;
117 extern BX_MUTEX(cmdfifo_mutex);
118 extern BX_MUTEX(render_mutex);
119 Bit32u register_r(Bit32u offset);
120 void register_w(Bit32u offset, Bit32u data, bool log);
121 void register_w_common(Bit32u offset, Bit32u data);
122 Bit32u lfb_r(Bit32u offset);
123 Bit32u lfb_w(Bit32u offset, Bit32u data, Bit32u mem_mask);
124 Bit32s texture_w(Bit32u offset, Bit32u data);
125 void cmdfifo_w(cmdfifo_info *f, Bit32u fbi_offset, Bit32u data);
126 
127 // the class bx_banshee_c
128 
bx_banshee_c()129 bx_banshee_c::bx_banshee_c() : bx_voodoo_base_c()
130 {
131 }
132 
~bx_banshee_c()133 bx_banshee_c::~bx_banshee_c()
134 {
135   SIM->get_bochs_root()->remove("voodoo");
136 }
137 
init_model(void)138 void bx_banshee_c::init_model(void)
139 {
140   static char model[40];
141   const char *vgabios_signature;
142 
143   if (theVoodooVga == NULL) {
144     BX_PANIC(("Voodoo Banshee with VGA disabled not supported yet"));
145   }
146   is_agp = SIM->is_agp_device(BX_PLUGIN_VOODOO);
147   if (s.model == VOODOO_BANSHEE) {
148     if (!is_agp) {
149       strcpy(model, "Experimental 3dfx Voodoo Banshee PCI");
150     } else {
151       strcpy(model, "Experimental 3dfx Voodoo Banshee AGP");
152     }
153     DEV_register_pci_handlers2(this, &s.devfunc, BX_PLUGIN_VOODOO, model, is_agp);
154     init_pci_conf(0x121a, 0x0003, 0x01, 0x030000, 0x00, BX_PCI_INTA);
155   } else if (s.model == VOODOO_3) {
156     if (!is_agp) {
157       strcpy(model, "Experimental 3dfx Voodoo 3 PCI");
158     } else {
159       strcpy(model, "Experimental 3dfx Voodoo 3 AGP");
160     }
161     DEV_register_pci_handlers2(this, &s.devfunc, BX_PLUGIN_VOODOO, model, is_agp);
162     init_pci_conf(0x121a, 0x0005, 0x01, 0x030000, 0x00, BX_PCI_INTA);
163   } else {
164     BX_PANIC(("Unknown Voodoo Banshee compatible model"));
165   }
166   pci_conf[0x14] = 0x08;
167   init_bar_mem(0, 0x2000000, mem_read_handler, mem_write_handler);
168   init_bar_mem(1, 0x2000000, mem_read_handler, mem_write_handler);
169   init_bar_io(2, 256, read_handler, write_handler, banshee_iomask);
170   pci_rom_address = 0;
171   pci_rom_read_handler = mem_read_handler;
172   load_pci_rom(SIM->get_param_string(BXPN_VGA_ROM_PATH)->getptr());
173   // Zero out Banshee i/o registers and init strapInfo
174   memset(v->banshee.io, 0, sizeof(v->banshee.io));
175   v->banshee.io[io_strapInfo] = 0x00000060;
176   if (is_agp) {
177     v->banshee.io[io_strapInfo] |= 0x0000000c;
178   }
179   if (pci_rom_size > 0x8000) {
180     v->banshee.io[io_strapInfo] |= 0x00000002;
181   }
182   // Modify device IDs in LGPL'd VGABIOS if required
183   vgabios_signature = (const char*)(pci_rom + 0x22);
184   if (!strncmp(vgabios_signature, "Bochs VGABios (PCI)", 19)) {
185     Bit16u pcir = pci_rom[0x18] | (pci_rom[0x19] << 8); // offset to PCIR data
186     Bit16u pci_vid = pci_rom[pcir + 4] | (pci_rom[pcir + 5] << 8);
187     if (pci_vid == 0x121a) {
188       if (s.model == VOODOO_BANSHEE) {
189         pci_rom[0x7ffa] = is_agp ? 0x03:0x04;
190       } else {
191         pci_rom[pcir + 6] = 0x05;
192         pci_rom[0x7ffa] = is_agp ? 0x52:0x36;
193       }
194       Bit8u checksum = 0;
195       for (int i = 0; i < 0x7fff; i++) {
196         checksum += pci_rom[i];
197       }
198       pci_rom[0x7fff] = -checksum;
199     }
200   }
201 }
202 
reset(unsigned type)203 void bx_banshee_c::reset(unsigned type)
204 {
205   unsigned i;
206 
207   static const struct reset_vals_t {
208     unsigned      addr;
209     unsigned char val;
210   } reset_vals2[] = {
211     { 0x04, 0x00 }, { 0x05, 0x00 }, // command io / memory
212     { 0x06, 0x10 }, { 0x07, 0x00 }, // status
213     // capabilities pointer 0x34 - 0x37
214     { 0x34, 0x60 }, { 0x35, 0x00 },
215     { 0x36, 0x00 }, { 0x37, 0x00 },
216     { 0x3c, 0x00 },                 // IRQ
217     // ACPI capabilities ID 0x60 - 0x63
218     { 0x60, 0x01 }, { 0x61, 0x00 },
219     { 0x62, 0x21 }, { 0x63, 0x00 },
220     // ACPI control/status 0x64 - 0x67
221     { 0x64, 0x00 }, { 0x65, 0x00 },
222     { 0x66, 0x00 }, { 0x67, 0x00 },
223   };
224   for (i = 0; i < sizeof(reset_vals2) / sizeof(*reset_vals2); ++i) {
225     pci_conf[reset_vals2[i].addr] = reset_vals2[i].val;
226   }
227   // AGP reported by PCI status, new capabilities and strapInfo
228   if (is_agp) {
229     pci_conf[0x06] |= 0x20;
230     pci_conf[0x34] = 0x54;
231     pci_conf[0x54] = 0x02;
232     pci_conf[0x55] = 0x60;
233     pci_conf[0x56] = 0x10;
234     pci_conf[0x57] = 0x00;
235     if (s.model == VOODOO_3) {
236       pci_conf[0x58] = 0x23;
237     } else {
238       pci_conf[0x58] = 0x21;
239     }
240     pci_conf[0x59] = 0x02;
241     pci_conf[0x5b] = 0x07;
242   }
243   for (i = 0; i < 4; i++) {
244     pci_conf[0x2c + i] = pci_rom[(pci_rom_size - 8) + i];
245   }
246   v->banshee.io[io_pciInit0] = 0x01800040;
247   v->banshee.io[io_sipMonitor] = 0x40000000;
248   v->banshee.io[io_lfbMemoryConfig] = 0x000a2200;
249   v->banshee.io[io_miscInit1] = ((v->banshee.io[io_strapInfo] & 0x1f) << 24);
250   v->banshee.io[io_dramInit0] = 0x00579d29 | ((v->banshee.io[io_strapInfo] & 0x60) << 21);
251   v->banshee.io[io_dramInit1] = 0x00f02200;
252   v->banshee.io[io_tmuGbeInit] = 0x00000bfb;
253   v->vidclk = 14318180;
254   if (theVoodooVga != NULL) {
255     theVoodooVga->banshee_set_vclk3((Bit32u)v->vidclk);
256   }
257 
258   // Deassert IRQ
259   set_irq_level(0);
260 }
261 
register_state(void)262 void bx_banshee_c::register_state(void)
263 {
264   bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "voodoo", "Voodoo Banshee State");
265   voodoo_register_state(list);
266   bx_list_c *banshee = new bx_list_c(list, "banshee", "Banshee State");
267   new bx_shadow_data_c(banshee, "io", (Bit8u*)v->banshee.io, 256, 1);
268   new bx_shadow_data_c(banshee, "agp", (Bit8u*)v->banshee.agp, 0x80, 1);
269   new bx_shadow_data_c(banshee, "crtc", (Bit8u*)v->banshee.crtc, 0x27, 1);
270   new bx_shadow_num_c(banshee, "disp_bpp", &v->banshee.disp_bpp);
271   BXRS_PARAM_BOOL(banshee, half_mode, v->banshee.half_mode);
272   BXRS_PARAM_BOOL(banshee, dac_8bit, v->banshee.dac_8bit);
273   BXRS_PARAM_BOOL(banshee, desktop_tiled, v->banshee.desktop_tiled);
274   BXRS_PARAM_BOOL(banshee, hwcursor_enabled, v->banshee.hwcursor.enabled);
275   BXRS_PARAM_BOOL(banshee, hwcursor_mode, v->banshee.hwcursor.mode);
276   new bx_shadow_num_c(banshee, "hwcursor_addr", &v->banshee.hwcursor.addr, BASE_HEX);
277   new bx_shadow_num_c(banshee, "hwcursor_x", &v->banshee.hwcursor.x, BASE_HEX);
278   new bx_shadow_num_c(banshee, "hwcursor_y", &v->banshee.hwcursor.y, BASE_HEX);
279   new bx_shadow_num_c(banshee, "hwcursor_color0", &v->banshee.hwcursor.color[0], BASE_HEX);
280   new bx_shadow_num_c(banshee, "hwcursor_color1", &v->banshee.hwcursor.color[1], BASE_HEX);
281   new bx_shadow_data_c(banshee, "blt_reg", (Bit8u*)v->banshee.blt.reg, 0x80, 1);
282   new bx_shadow_data_c(banshee, "blt_cpat", (Bit8u*)v->banshee.blt.cpat, 0x100, 1);
283   BXRS_PARAM_BOOL(banshee, blt_busy, v->banshee.blt.busy);
284   new bx_shadow_num_c(banshee, "blt_cmd", &v->banshee.blt.cmd);
285   BXRS_PARAM_BOOL(banshee, blt_immed, v->banshee.blt.immed);
286   BXRS_PARAM_BOOL(banshee, blt_x_dir, v->banshee.blt.x_dir);
287   BXRS_PARAM_BOOL(banshee, blt_y_dir, v->banshee.blt.y_dir);
288   BXRS_PARAM_BOOL(banshee, blt_transp, v->banshee.blt.transp);
289   new bx_shadow_num_c(banshee, "blt_patsx", &v->banshee.blt.patsx);
290   new bx_shadow_num_c(banshee, "blt_patsy", &v->banshee.blt.patsy);
291   BXRS_PARAM_BOOL(banshee, blt_clip_sel, v->banshee.blt.clip_sel);
292   new bx_shadow_num_c(banshee, "blt_rop0", &v->banshee.blt.rop[0]);
293   new bx_shadow_num_c(banshee, "blt_rop1", &v->banshee.blt.rop[1]);
294   new bx_shadow_num_c(banshee, "blt_rop2", &v->banshee.blt.rop[2]);
295   new bx_shadow_num_c(banshee, "blt_rop3", &v->banshee.blt.rop[3]);
296   new bx_shadow_num_c(banshee, "blt_src_base", &v->banshee.blt.src_base, BASE_HEX);
297   BXRS_PARAM_BOOL(banshee, blt_src_tiled, v->banshee.blt.src_tiled);
298   new bx_shadow_num_c(banshee, "blt_src_fmt", &v->banshee.blt.src_fmt);
299   new bx_shadow_num_c(banshee, "blt_src_pitch", &v->banshee.blt.src_pitch);
300   new bx_shadow_num_c(banshee, "blt_src_swizzle", &v->banshee.blt.src_swizzle);
301   new bx_shadow_num_c(banshee, "blt_src_x", &v->banshee.blt.src_x);
302   new bx_shadow_num_c(banshee, "blt_src_y", &v->banshee.blt.src_y);
303   new bx_shadow_num_c(banshee, "blt_src_w", &v->banshee.blt.src_w);
304   new bx_shadow_num_c(banshee, "blt_src_h", &v->banshee.blt.src_h);
305   new bx_shadow_num_c(banshee, "blt_dst_base", &v->banshee.blt.dst_base, BASE_HEX);
306   BXRS_PARAM_BOOL(banshee, blt_dst_tiled, v->banshee.blt.dst_tiled);
307   new bx_shadow_num_c(banshee, "blt_dst_fmt", &v->banshee.blt.dst_fmt);
308   new bx_shadow_num_c(banshee, "blt_dst_pitch", &v->banshee.blt.dst_pitch);
309   new bx_shadow_num_c(banshee, "blt_dst_x", &v->banshee.blt.dst_x);
310   new bx_shadow_num_c(banshee, "blt_dst_y", &v->banshee.blt.dst_y);
311   new bx_shadow_num_c(banshee, "blt_dst_w", &v->banshee.blt.dst_w);
312   new bx_shadow_num_c(banshee, "blt_dst_h", &v->banshee.blt.dst_h);
313   new bx_shadow_num_c(banshee, "blt_fgcolor", (Bit32u*)&v->banshee.blt.fgcolor, BASE_HEX);
314   new bx_shadow_num_c(banshee, "blt_bgcolor", (Bit32u*)&v->banshee.blt.bgcolor, BASE_HEX);
315   new bx_shadow_num_c(banshee, "blt_clipx0_0", &v->banshee.blt.clipx0[0]);
316   new bx_shadow_num_c(banshee, "blt_clipx0_1", &v->banshee.blt.clipx0[1]);
317   new bx_shadow_num_c(banshee, "blt_clipy0_0", &v->banshee.blt.clipy0[0]);
318   new bx_shadow_num_c(banshee, "blt_clipy0_1", &v->banshee.blt.clipy0[1]);
319   new bx_shadow_num_c(banshee, "blt_clipx1_0", &v->banshee.blt.clipx1[0]);
320   new bx_shadow_num_c(banshee, "blt_clipx1_1", &v->banshee.blt.clipx1[1]);
321   new bx_shadow_num_c(banshee, "blt_clipy1_0", &v->banshee.blt.clipy1[0]);
322   new bx_shadow_num_c(banshee, "blt_clipy1_1", &v->banshee.blt.clipy1[1]);
323   new bx_shadow_num_c(banshee, "blt_h2s_pitch", &v->banshee.blt.h2s_pitch);
324   new bx_shadow_num_c(banshee, "blt_h2s_pxstart", &v->banshee.blt.h2s_pxstart);
325 }
326 
after_restore_state(void)327 void bx_banshee_c::after_restore_state(void)
328 {
329   bx_pci_device_c::after_restore_pci_state(mem_read_handler);
330   if ((v->banshee.io[io_vidProcCfg] & 0x01) && (theVoodooVga != NULL)) {
331     v->fbi.clut_dirty = 1;
332     update_timing();
333     theVoodooVga->banshee_update_mode();
334   }
335   start_fifo_thread();
336 }
337 
update_timing(void)338 bool bx_banshee_c::update_timing(void)
339 {
340   float hfreq;
341   bx_crtc_params_t crtcp;
342   Bit32u vclock = 0;
343 
344   BX_VVGA_THIS get_crtc_params(&crtcp, &vclock);
345   hfreq = vclock / (float)(crtcp.htotal * 8);
346   v->vertfreq = hfreq / (float)crtcp.vtotal;
347   s.vdraw.vtotal_usec = (unsigned)(1000000.0 / v->vertfreq);
348   s.vdraw.width = v->fbi.width;
349   s.vdraw.height = v->fbi.height;
350   vertical_timer_handler(this);
351   bx_virt_timer.activate_timer(s.vertical_timer_id, (Bit32u)s.vdraw.vtotal_usec, 1);
352   return 1;
353 }
354 
set_tile_updated(unsigned xti,unsigned yti,bool flag)355 void bx_banshee_c::set_tile_updated(unsigned xti, unsigned yti, bool flag)
356 {
357   SET_TILE_UPDATED(, xti, yti, flag);
358 }
359 
draw_hwcursor(unsigned xc,unsigned yc,bx_svga_tileinfo_t * info)360 void bx_banshee_c::draw_hwcursor(unsigned xc, unsigned yc, bx_svga_tileinfo_t *info)
361 {
362   unsigned cx, cy, cw, ch, px, py, w, h, x, y;
363   Bit8u *cpat0, *cpat1, *tile_ptr, *tile_ptr2, *vid_ptr;
364   Bit8u ccode, pbits, pval0, pval1;
365   Bit32u colour = 0, start;
366   Bit16u index, pitch;
367   int i;
368 
369   if ((xc <= v->banshee.hwcursor.x) &&
370       ((int)(xc + X_TILESIZE) > (v->banshee.hwcursor.x - 63)) &&
371       (yc <= v->banshee.hwcursor.y) &&
372       ((int)(yc + Y_TILESIZE) > (v->banshee.hwcursor.y - 63))) {
373 
374     if ((v->banshee.io[io_vidProcCfg] & 0x181) == 0x81) {
375       start = v->banshee.io[io_vidDesktopStartAddr];
376       pitch = v->banshee.io[io_vidDesktopOverlayStride] & 0x7fff;
377     } else {
378       start = v->fbi.rgboffs[0];
379       pitch = (v->banshee.io[io_vidDesktopOverlayStride] >> 16) & 0x7fff;
380     }
381     Bit8u *disp_ptr = &v->fbi.ram[start & v->fbi.mask];
382     if (v->banshee.desktop_tiled) {
383       pitch *= 128;
384     }
385     tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
386 
387     if ((v->banshee.hwcursor.x - 63) < (int)xc) {
388       cx = xc;
389       if ((v->banshee.hwcursor.x - xc + 1) > w) {
390         cw = w;
391       } else {
392         cw = v->banshee.hwcursor.x - xc + 1;
393       }
394       px = 63 - (v->banshee.hwcursor.x - xc);
395     } else {
396       cx = v->banshee.hwcursor.x - 63;
397       cw = w - (v->banshee.hwcursor.x - 63 - xc);
398       px = 0;
399     }
400     if ((v->banshee.hwcursor.y - 63) < (int)yc) {
401       cy = yc;
402       if ((v->banshee.hwcursor.y - yc + 1) > h) {
403         ch = h;
404       } else {
405         ch = v->banshee.hwcursor.y - yc + 1;
406       }
407       py = 63 - (v->banshee.hwcursor.y - yc);
408     } else {
409       cy = v->banshee.hwcursor.y - 63;
410       ch = h - (v->banshee.hwcursor.y - 63 - yc);
411       py = 0;
412     }
413     tile_ptr += ((cy - yc) * info->pitch);
414     tile_ptr += ((cx - xc) * (info->bpp >> 3));
415     cpat0 = &v->fbi.ram[v->banshee.hwcursor.addr] + (py * 16);
416     for (y = cy; y < (cy + ch); y++) {
417       cpat1 = cpat0 + (px >> 3);
418       pbits = 8 - (px & 7);
419       tile_ptr2 = tile_ptr;
420       for (x = cx; x < (cx + cw); x++) {
421         pval0 = (*cpat1 >> (pbits - 1)) & 1;
422         pval1 = (*(cpat1 + 8) >> (pbits - 1)) & 1;
423         ccode = pval0 + (pval1 << 1) + (v->banshee.hwcursor.mode << 2);
424         if ((ccode == 0) || (ccode == 5)) {
425           colour = v->banshee.hwcursor.color[0];
426         } else if ((ccode == 2) || (ccode == 7)) {
427           colour = v->banshee.hwcursor.color[1];
428         } else {
429           vid_ptr = disp_ptr + y * pitch + x * (v->banshee.disp_bpp >> 3);
430           switch (v->banshee.disp_bpp) {
431             case 8:
432               if (info->is_indexed) {
433                 colour = *vid_ptr;
434               } else {
435                 colour = v->fbi.clut[*vid_ptr];
436               }
437               break;
438             case 16:
439               index = *(vid_ptr++);
440               index |= *(vid_ptr++) << 8;
441               colour = v->fbi.pen[index];
442               break;
443             case 24:
444             case 32:
445               colour = *vid_ptr;
446               colour |= (*(vid_ptr + 1)) << 8;
447               colour |= (*(vid_ptr + 2)) << 16;
448               break;
449           }
450           if (ccode == 3) colour ^= 0xffffff;
451         }
452         if (!info->is_indexed) {
453           colour = MAKE_COLOUR(
454             colour, 24, info->red_shift, info->red_mask,
455             colour, 16, info->green_shift, info->green_mask,
456             colour, 8, info->blue_shift, info->blue_mask);
457           if (info->is_little_endian) {
458             for (i=0; i<info->bpp; i+=8) {
459               *(tile_ptr2++) = (Bit8u)(colour >> i);
460             }
461           } else {
462             for (i=info->bpp-8; i>-8; i-=8) {
463               *(tile_ptr2++) = (Bit8u)(colour >> i);
464             }
465           }
466         } else {
467           *(tile_ptr2++) = (Bit8u)colour;
468         }
469         if (--pbits == 0) {
470           cpat1++;
471           pbits = 8;
472         }
473       }
474       cpat0 += 16;
475       tile_ptr += info->pitch;
476     }
477   }
478 }
479 
get_retrace(bool hv)480 Bit32u bx_banshee_c::get_retrace(bool hv)
481 {
482   return theVoodooVga->get_retrace();
483 }
484 
reg_write(Bit32u reg,Bit32u value)485 void bx_banshee_c::reg_write(Bit32u reg, Bit32u value)
486 {
487   if ((reg >> 11) & 1) {
488     blt_reg_write(reg & 0xff, value);
489   } else {
490     register_w(reg, value, 1);
491   }
492 }
493 
494 // pci configuration space write handler
pci_write_handler(Bit8u address,Bit32u value,unsigned io_len)495 void bx_banshee_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
496 {
497   Bit8u value8, oldval;
498 
499   if ((address >= 0x1c) && (address < 0x2c))
500     return;
501 
502   BX_DEBUG_PCI_WRITE(address, value, io_len);
503   for (unsigned i=0; i<io_len; i++) {
504     value8 = (value >> (i*8)) & 0xFF;
505     oldval = pci_conf[address+i];
506     switch (address+i) {
507       case 0x04:
508         value8 &= 0x23;
509         break;
510       case 0x2c:
511       case 0x2d:
512       case 0x2e:
513       case 0x2f:
514         if ((v->banshee.io[io_miscInit1] & 0x08) == 0) {
515           value8 = oldval;
516         }
517         break;
518       case 0x06:
519       case 0x07:
520         value8 = oldval;
521         break;
522       default:
523         if (address >= 0x54) {
524           value8 = oldval;
525         }
526     }
527     pci_conf[address+i] = value8;
528   }
529 }
530 
read_handler(void * this_ptr,Bit32u address,unsigned io_len)531 Bit32u bx_banshee_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
532 {
533   bx_banshee_c *class_ptr = (bx_banshee_c*)this_ptr;
534   return class_ptr->read(address, io_len);
535 }
536 
read(Bit32u address,unsigned io_len)537 Bit32u bx_banshee_c::read(Bit32u address, unsigned io_len)
538 {
539   static Bit8u lastreg = 0xff;
540   Bit32u result;
541 
542   Bit8u offset = (Bit8u)(address & 0xff);
543   Bit8u reg = (offset >> 2);
544   switch (reg) {
545     case io_status:
546       result = register_r(0);
547       break;
548 
549     case io_dacData:
550       result = v->fbi.clut[v->banshee.io[io_dacAddr] & 0x1ff] = v->banshee.io[reg];
551       break;
552 
553     case io_vgab0:  case io_vgab4:  case io_vgab8:  case io_vgabc:
554     case io_vgac0:  case io_vgac4:  case io_vgac8:  case io_vgacc:
555     case io_vgad0:  case io_vgad4:  case io_vgad8:  case io_vgadc:
556       result = 0;
557       // i/o read only, not memory mapped
558       if ((theVoodooVga != NULL) && (address & 0xff00)) {
559         for (unsigned i=0; i<io_len; i++) {
560           result |= (theVoodooVga->banshee_vga_read_handler(theVoodooVga, 0x300+offset+i, 1) << (i*8));
561         }
562       }
563       break;
564 
565     case io_vidSerialParallelPort:
566       result = v->banshee.io[reg] & 0xf387ffff;
567       if ((v->banshee.io[reg] >> 18) & 1) {
568         result |= ((Bit32u)ddc.read() << 19);
569       } else {
570         result |= 0x00780000;
571       }
572       if ((v->banshee.io[reg] >> 23) & 1) {
573         result |= ((v->banshee.io[reg] & 0x03000000) << 2);
574       } else {
575         result |= 0x0f000000;
576       }
577       break;
578 
579     default:
580       result = v->banshee.io[reg];
581       break;
582   }
583   if ((reg < io_vgab0) || (reg > io_vgadc)) {
584     if ((offset & 3) != 0) {
585       result >>= ((offset & 3) * 8);
586     }
587   }
588   if ((reg != io_status) || (lastreg != io_status)) {
589     BX_DEBUG(("banshee read from offset 0x%02x (%s) result = 0x%08x", offset,
590               banshee_io_reg_name[reg], result));
591   }
592   lastreg = reg;
593   return result;
594 }
595 
write_handler(void * this_ptr,Bit32u address,Bit32u value,unsigned io_len)596 void bx_banshee_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
597 {
598   bx_banshee_c *class_ptr = (bx_banshee_c*)this_ptr;
599   return class_ptr->write(address, value, io_len);
600 }
601 
write(Bit32u address,Bit32u value,unsigned io_len)602 void bx_banshee_c::write(Bit32u address, Bit32u value, unsigned io_len)
603 {
604   Bit8u offset = (Bit8u)(address & 0xff);
605   Bit8u reg = (offset>>2), dac_idx, k, m, n, shift;
606   Bit32u old = v->banshee.io[reg], mask;
607   bool prev_hwce = v->banshee.hwcursor.enabled;
608   Bit16u prev_hwcx = v->banshee.hwcursor.x;
609   Bit16u prev_hwcy = v->banshee.hwcursor.y;
610   bool mode_change = 0;
611 
612   BX_DEBUG(("banshee write to offset 0x%02x: value = 0x%08x len=%d (%s)", offset, value,
613             io_len, banshee_io_reg_name[reg]));
614   if ((reg < io_vgab0) || (reg > io_vgadc)) {
615     if (io_len == 1) {
616       shift = ((offset & 3) * 8);
617       mask = ~(0xff << shift);
618       value = (old & mask) | (value << shift);
619     } else if (io_len == 2) {
620       shift = ((offset & 2) * 8);
621       mask = ~(0xffff << shift);
622       value = (old & mask) | (value << shift);
623     }
624   }
625   switch (reg) {
626     case io_lfbMemoryConfig:
627       v->banshee.io[reg] = value;
628       v->fbi.lfb_base = (value & 0x1fff) << 12;
629       v->fbi.lfb_stride = ((value >> 13) & 7) + 10;
630       break;
631 
632     case io_miscInit0:
633       v->banshee.io[reg] = value;
634       v->fbi.yorigin = (value >> 18) & 0xfff;
635       break;
636 
637     case io_miscInit1:
638       v->banshee.io[reg] = value & 0xffffff;
639       v->banshee.io[reg] |= ((v->banshee.io[io_strapInfo] & 0x1f) << 24);
640       break;
641 
642     case io_vgaInit0:
643       v->banshee.io[reg] = value;
644       if (theVoodooVga != NULL) {
645         theVoodooVga->banshee_set_dac_mode((v->banshee.io[reg] & 0x04) != 0);
646       }
647       break;
648 
649     case io_dramCommand:
650       blt_reg_write(0x1c, value);
651       break;
652 
653     case io_dramData:
654       blt_reg_write(0x19, value);
655       break;
656 
657     case io_strapInfo:
658       break;
659 
660     case io_pllCtrl0:
661       if (value != v->banshee.io[reg]) {
662         v->banshee.io[reg] = value;
663         k = (Bit8u)(value & 0x03);
664         m = (Bit8u)((value >> 2) & 0x3f);
665         n = (Bit8u)((value >> 8) & 0xff);
666         v->vidclk = (float)(14318180.0f * ((double)n + 2.0f) / ((double)m + 2.0f) / (double)(1 << k));
667         BX_INFO(("Setting VCLK #3 (pllCtrl0) = %.3f MHz", v->vidclk / 1000000.0f));
668         if (theVoodooVga != NULL) {
669           theVoodooVga->banshee_set_vclk3((Bit32u)v->vidclk);
670         }
671       }
672       break;
673 
674     case io_dacData:
675       v->banshee.io[reg] = value;
676       if (v->banshee.io[reg] != v->fbi.clut[v->banshee.io[io_dacAddr] & 0x1ff]) {
677         v->fbi.clut[v->banshee.io[io_dacAddr] & 0x1ff] = v->banshee.io[reg];
678         v->fbi.clut_dirty = 1;
679         if (v->banshee.io[io_dacAddr] <= 0xff) {
680           dac_idx = v->banshee.io[io_dacAddr] & 0xff;
681           bx_gui->palette_change_common(dac_idx, (v->fbi.clut[dac_idx] >> 16) & 0xff,
682                                         (v->fbi.clut[dac_idx] >> 8) & 0xff,
683                                         v->fbi.clut[dac_idx] & 0xff);
684         }
685       }
686       break;
687 
688     case io_vidProcCfg:
689       v->banshee.io[reg] = value;
690       if ((v->banshee.io[reg] ^ old) & 0x3c00)
691         v->fbi.clut_dirty = 1;
692       if ((v->banshee.io[reg] & 0x01) && ((old & 0x01) == 0x00)) {
693         update_timing();
694         if (theVoodooVga != NULL) {
695           theVoodooVga->banshee_update_mode();
696         }
697         mode_change = 1;
698       } else if (!(v->banshee.io[reg] & 0x01) && ((old & 0x01) == 0x01)) {
699         bx_virt_timer.deactivate_timer(s.vertical_timer_id);
700         v->vtimer_running = 0;
701       }
702       if ((v->banshee.io[reg] & 0x01) && ((v->banshee.io[reg] & 0x180) != (old & 0x180))) {
703         mode_change = 1;
704       }
705       if (mode_change) {
706         if ((v->banshee.io[reg] & 0x180) == 0x080) {
707           BX_INFO(("2D desktop mode enabled"));
708         } else if ((old & 0x100) == 0) {
709           BX_INFO(("3D overlay mode enabled"));
710           v->vtimer_running = 1;
711         }
712       }
713       v->banshee.hwcursor.enabled = ((v->banshee.io[reg] >> 27) & 1);
714       v->banshee.hwcursor.mode = ((v->banshee.io[reg] >> 1) & 1);
715       if (v->banshee.hwcursor.enabled != prev_hwce) {
716         theVoodooVga->redraw_area(v->banshee.hwcursor.x - 63, v->banshee.hwcursor.y - 63,
717                                   v->banshee.hwcursor.x, v->banshee.hwcursor.y);
718       }
719       if ((v->banshee.io[reg] >> 2) & 1) {
720         BX_ERROR(("vidProcCfg: overlay stereo mode not supported yet"));
721       }
722       if ((v->banshee.io[reg] >> 5) & 1) {
723         BX_ERROR(("vidProcCfg: chromaKey mode not supported yet"));
724       }
725       if ((v->banshee.io[reg] >> 16) & 3) {
726         BX_ERROR(("vidProcCfg: overlay filter mode not supported yet"));
727       }
728       v->banshee.desktop_tiled = ((v->banshee.io[reg] >> 24) & 1);
729       break;
730 
731     case io_hwCurPatAddr:
732       v->banshee.io[reg] = value;
733       v->banshee.hwcursor.addr = v->banshee.io[reg] & 0xffffff;
734       if (v->banshee.hwcursor.enabled && (value != old)) {
735         theVoodooVga->redraw_area(v->banshee.hwcursor.x - 63, v->banshee.hwcursor.y - 63,
736                                   v->banshee.hwcursor.x, v->banshee.hwcursor.y);
737       }
738       break;
739 
740     case io_hwCurLoc:
741       v->banshee.io[reg] = value;
742       v->banshee.hwcursor.x = v->banshee.io[reg] & 0x7ff;
743       v->banshee.hwcursor.y = (v->banshee.io[reg] >> 16) & 0x7ff;
744       if (v->banshee.hwcursor.enabled && (value != old)) {
745         theVoodooVga->redraw_area(prev_hwcx - 63, prev_hwcy - 63, prev_hwcx, prev_hwcy);
746         theVoodooVga->redraw_area(v->banshee.hwcursor.x - 63, v->banshee.hwcursor.y - 63,
747                                   v->banshee.hwcursor.x, v->banshee.hwcursor.y);
748       }
749       break;
750 
751     case io_hwCurC0:
752       v->banshee.io[reg] = value;
753       v->banshee.hwcursor.color[0] = v->banshee.io[reg] & 0xffffff;
754       break;
755 
756     case io_hwCurC1:
757       v->banshee.io[reg] = value;
758       v->banshee.hwcursor.color[1] = v->banshee.io[reg] & 0xffffff;
759       break;
760 
761     case io_vidSerialParallelPort:
762       v->banshee.io[reg] = value;
763       if ((v->banshee.io[reg] >> 18) & 1) {
764         ddc.write((v->banshee.io[reg] >> 19) & 1, (v->banshee.io[reg] >> 20) & 1);
765       }
766       break;
767 
768     case io_vidScreenSize:
769       v->banshee.io[reg] = value;
770       v->fbi.width = (value & 0xfff);
771       v->fbi.height = (value >> 12) & 0xfff;
772       break;
773 
774     case io_vgab0:  case io_vgab4:  case io_vgab8:  case io_vgabc:
775     case io_vgac0:  case io_vgac4:  case io_vgac8:  case io_vgacc:
776     case io_vgad0:  case io_vgad4:  case io_vgad8:  case io_vgadc:
777       // i/o write only, not memory mapped
778       if ((theVoodooVga != NULL) && (address & 0xff00)) {
779         for (unsigned i=0; i<io_len; i++) {
780           Bit8u value8 = (value >> (i*8)) & 0xff;
781           theVoodooVga->banshee_vga_write_handler(theVoodooVga, 0x300+offset+i, value8, 1);
782         }
783       }
784       break;
785 
786     case io_vidDesktopStartAddr:
787     case io_vidDesktopOverlayStride:
788       if ((v->banshee.io[io_vidProcCfg] & 0x01) && (v->banshee.io[reg] != value)) {
789         v->fbi.video_changed = 1;
790       }
791       v->banshee.io[reg] = value;
792       break;
793 
794     default:
795       v->banshee.io[reg] = value;
796       break;
797   }
798 }
799 
mem_read_handler(bx_phy_address addr,unsigned len,void * data,void * param)800 bool bx_banshee_c::mem_read_handler(bx_phy_address addr, unsigned len,
801                                     void *data, void *param)
802 {
803   bx_banshee_c *class_ptr = (bx_banshee_c*)param;
804   class_ptr->mem_read(addr, len, data);
805   return 1;
806 }
807 
mem_write_handler(bx_phy_address addr,unsigned len,void * data,void * param)808 bool bx_banshee_c::mem_write_handler(bx_phy_address addr, unsigned len,
809                                      void *data, void *param)
810 {
811   bx_banshee_c *class_ptr = (bx_banshee_c*)param;
812   class_ptr->mem_write(addr, len, data);
813   return 1;
814 }
815 
mem_read(bx_phy_address addr,unsigned len,void * data)816 void bx_banshee_c::mem_read(bx_phy_address addr, unsigned len, void *data)
817 {
818   Bit64u value = BX_MAX_BIT64U;
819   Bit32u offset = (addr & 0x1ffffff);
820   Bit32u pitch = v->banshee.io[io_vidDesktopOverlayStride] & 0x7fff;
821   unsigned i, x, y;
822 
823   if (pci_rom_size > 0) {
824     Bit32u mask = (pci_rom_size - 1);
825     if (((Bit32u)addr & ~mask) == pci_rom_address) {
826       if (pci_conf[0x30] & 0x01) {
827         value = 0;
828         for (unsigned i = 0; i < len; i++) {
829           value |= (pci_rom[(addr & mask) + i] << (i * 8));
830         }
831       }
832       switch (len) {
833         case 1:
834           *((Bit8u*)data) = (Bit8u)value;
835           break;
836         case 2:
837           *((Bit16u*)data) = (Bit16u)value;
838           break;
839         default:
840           *((Bit32u*)data) = (Bit32u)value;
841       }
842       return;
843     }
844   }
845   if ((addr & ~0x1ffffff) == pci_bar[0].addr) {
846     if (offset < 0x80000) {
847       value = read(offset, len);
848     } else if (offset < 0x100000) {
849       value = agp_reg_read((offset >> 2) & 0x7f);
850     } else if (offset < 0x200000) {
851       value = blt_reg_read((offset >> 2) & 0x7f);
852     } else if (offset < 0x600000) {
853       value = register_r((offset - 0x200000) >> 2);
854     } else if (offset < 0xc00000) {
855       BX_DEBUG(("reserved read from offset 0x%08x", offset));
856     } else if (offset < 0x1000000) {
857       BX_ERROR(("TODO: YUV planar space read from offset 0x%08x", offset));
858     } else {
859       Bit8u temp = v->fbi.lfb_stride;
860       v->fbi.lfb_stride = 11;
861       value = lfb_r((offset & v->fbi.mask) >> 2);
862       v->fbi.lfb_stride = temp;
863     }
864   } else if ((addr & ~0x1ffffff) == pci_bar[1].addr) {
865     if (offset >= v->fbi.lfb_base) {
866       offset -= v->fbi.lfb_base;
867       pitch *= 128;
868       x = (offset << 0) & ((1 << v->fbi.lfb_stride) - 1);
869       y = (offset >> v->fbi.lfb_stride) & 0x1fff;
870       offset = (v->fbi.lfb_base + y * pitch + x) & v->fbi.mask;
871     } else {
872       offset &= v->fbi.mask;
873     }
874     value = 0;
875     for (i = 0; i < len; i++) {
876       value |= ((Bit64u)v->fbi.ram[offset + i] << (i*8));
877     }
878   }
879   switch (len) {
880     case 1:
881       *((Bit8u*)data) = (Bit8u)value;
882       break;
883     case 2:
884       *((Bit16u*)data) = (Bit16u)value;
885       break;
886     case 4:
887       *((Bit32u*)data) = (Bit32u)value;
888       break;
889     default:
890       *((Bit64u*)data) = value;
891   }
892 }
893 
mem_write(bx_phy_address addr,unsigned len,void * data)894 void bx_banshee_c::mem_write(bx_phy_address addr, unsigned len, void *data)
895 {
896   Bit32u offset = (addr & 0x1ffffff);
897   Bit32u value;
898   Bit32u mask = 0xffffffff;
899 
900   switch (len) {
901     case 1:
902       value = *(Bit8u*)data;
903       break;
904     case 2:
905       value = *(Bit16u*)data;
906       break;
907     default:
908       value = *(Bit32u*)data;
909   }
910   if ((addr & ~0x1ffffff) == pci_bar[0].addr) {
911     if (offset < 0x80000) {
912       write(offset, value, len);
913     } else if (offset < 0x100000) {
914       agp_reg_write((offset >> 2) & 0x7f, value);
915     } else if (offset < 0x200000) {
916       blt_reg_write((offset >> 2) & 0x7f, value);
917     } else if (offset < 0x600000) {
918       register_w_common((offset - 0x200000) >> 2, value);
919     } else if (offset < 0x800000) {
920       texture_w((offset & 0x1fffff) >> 2, value);
921     } else if ((offset < 0xa00000) && (s.model == VOODOO_3)) {
922       texture_w((1 << 19) | ((offset & 0x1fffff) >> 2), value);
923     } else if (offset < 0xc00000) {
924       BX_DEBUG(("reserved write to offset 0x%08x", offset));
925     } else if (offset < 0x1000000) {
926       BX_ERROR(("TODO: YUV planar space write to offset 0x%08x", offset));
927     } else {
928       Bit8u temp = v->fbi.lfb_stride;
929       v->fbi.lfb_stride = 11;
930       if (len == 2) {
931         if ((offset & 3) == 0) {
932           mask = 0x0000ffff;
933         } else {
934           mask = 0xffff0000;
935         }
936       }
937       lfb_w((offset & v->fbi.mask) >> 2, value, mask);
938       v->fbi.lfb_stride = temp;
939     }
940   } else if ((addr & ~0x1ffffff) == pci_bar[1].addr) {
941     if (v->fbi.cmdfifo[0].enabled && (offset >= v->fbi.cmdfifo[0].base) &&
942         (offset < v->fbi.cmdfifo[0].end)) {
943       if (len == 4) {
944         cmdfifo_w(&v->fbi.cmdfifo[0], offset, value);
945       } else {
946         BX_ERROR(("CMDFIFO #0 write with len = %d redirected to LFB", len));
947         mem_write_linear(offset, value, len);
948       }
949     } else if (v->fbi.cmdfifo[1].enabled && (offset >= v->fbi.cmdfifo[1].base) &&
950                (offset < v->fbi.cmdfifo[1].end)) {
951       if (len == 4) {
952         cmdfifo_w(&v->fbi.cmdfifo[1], offset, value);
953       } else  {
954         BX_ERROR(("CMDFIFO #1 write with len = %d redirected to LFB", len));
955         mem_write_linear(offset, value, len);
956       }
957     } else {
958       mem_write_linear(offset, value, len);
959     }
960   }
961 }
962 
mem_write_linear(Bit32u offset,Bit32u value,unsigned len)963 void bx_banshee_c::mem_write_linear(Bit32u offset, Bit32u value, unsigned len)
964 {
965   Bit8u value8;
966   Bit32u start = v->banshee.io[io_vidDesktopStartAddr];
967   Bit32u pitch = v->banshee.io[io_vidDesktopOverlayStride] & 0x7fff;
968   unsigned i, w, x, y;
969 
970   if (offset >= v->fbi.lfb_base) {
971     offset -= v->fbi.lfb_base;
972     pitch *= 128;
973     x = (offset << 0) & ((1 << v->fbi.lfb_stride) - 1);
974     y = (offset >> v->fbi.lfb_stride) & 0x1fff;
975     offset = (v->fbi.lfb_base + y * pitch + x) & v->fbi.mask;
976   } else {
977     offset &= v->fbi.mask;
978   }
979   BX_LOCK(render_mutex);
980   for (i = 0; i < len; i++) {
981     value8 = (value >> (i*8)) & 0xff;
982     v->fbi.ram[offset + i] = value8;
983   }
984   if (offset >= start) {
985     offset -= start;
986     x = (offset % pitch) / (v->banshee.disp_bpp >> 3);
987     y = offset / pitch;
988     w = len / (v->banshee.disp_bpp >> 3);
989     if (w == 0) w = 1;
990     theVoodooVga->redraw_area(x, y, w, 1);
991   }
992   BX_UNLOCK(render_mutex);
993 }
994 
agp_reg_read(Bit8u reg)995 Bit32u bx_banshee_c::agp_reg_read(Bit8u reg)
996 {
997   Bit32u result = 0;
998   Bit8u fifo_idx = (reg >= cmdBaseAddr1);
999 
1000   switch (reg) {
1001     case cmdBaseAddr0:
1002     case cmdBaseAddr1:
1003       result = (v->fbi.cmdfifo[fifo_idx].base >> 12);
1004       break;
1005     case cmdBump0:
1006     case cmdBump1:
1007       break;
1008     case cmdRdPtrL0:
1009     case cmdRdPtrL1:
1010       result = v->fbi.cmdfifo[fifo_idx].rdptr;
1011       break;
1012     case cmdFifoDepth0:
1013     case cmdFifoDepth1:
1014       result = v->fbi.cmdfifo[fifo_idx].depth;
1015       break;
1016     case cmdHoleCnt0:
1017     case cmdHoleCnt1:
1018       result = v->fbi.cmdfifo[fifo_idx].holes;
1019       break;
1020     case cmdStatus0:
1021     case cmdStatus1:
1022       BX_ERROR(("cmdStatus%d not implemented yet", fifo_idx));
1023     default:
1024       result = v->banshee.agp[reg];
1025   }
1026   BX_DEBUG(("AGP read register 0x%03x (%s) result = 0x%08x", reg<<2,
1027             banshee_agp_reg_name[reg], result));
1028   return result;
1029 }
1030 
agp_reg_write(Bit8u reg,Bit32u value)1031 void bx_banshee_c::agp_reg_write(Bit8u reg, Bit32u value)
1032 {
1033   Bit8u fifo_idx = (reg >= cmdBaseAddr1);
1034 
1035   BX_DEBUG(("AGP write register 0x%03x (%s) value = 0x%08x", reg<<2,
1036             banshee_agp_reg_name[reg], value));
1037   switch (reg) {
1038     case cmdBaseAddr0:
1039     case cmdBaseAddr1:
1040       BX_LOCK(cmdfifo_mutex);
1041       v->fbi.cmdfifo[fifo_idx].base = (value << 12);
1042       if (fifo_idx == 0) {
1043         v->fbi.cmdfifo[0].end = v->fbi.cmdfifo[0].base +
1044           (((v->banshee.agp[cmdBaseSize0] & 0xff) + 1) << 12);
1045       } else {
1046         v->fbi.cmdfifo[1].end = v->fbi.cmdfifo[1].base +
1047           (((v->banshee.agp[cmdBaseSize1] & 0xff) + 1) << 12);
1048       }
1049       BX_UNLOCK(cmdfifo_mutex);
1050       break;
1051     case cmdBaseSize0:
1052     case cmdBaseSize1:
1053       BX_LOCK(cmdfifo_mutex);
1054       if (fifo_idx == 0) {
1055         v->fbi.cmdfifo[0].end = v->fbi.cmdfifo[0].base + (((value & 0xff) + 1) << 12);
1056       } else {
1057         v->fbi.cmdfifo[1].end = v->fbi.cmdfifo[1].base + (((value & 0xff) + 1) << 12);
1058       }
1059       v->fbi.cmdfifo[fifo_idx].count_holes = (((value >> 10) & 1) == 0);
1060       if ((value >> 9) & 1) {
1061         BX_ERROR(("CMDFIFO in AGP memory not supported yet"));
1062       }
1063       if (v->fbi.cmdfifo[fifo_idx].enabled != ((value >> 8) & 1)) {
1064         v->fbi.cmdfifo[fifo_idx].enabled = ((value >> 8) & 1);
1065         BX_INFO(("CMDFIFO #%d now %sabled", fifo_idx,
1066                  v->fbi.cmdfifo[fifo_idx].enabled ? "en" : "dis"));
1067       }
1068       BX_UNLOCK(cmdfifo_mutex);
1069       break;
1070     case cmdBump0:
1071     case cmdBump1:
1072       if (value > 0) {
1073         BX_ERROR(("cmdBump%d not implemented (value = 0x%04x)", fifo_idx, (Bit16u)value));
1074       }
1075       break;
1076     case cmdRdPtrL0:
1077     case cmdRdPtrL1:
1078       BX_LOCK(cmdfifo_mutex);
1079       v->fbi.cmdfifo[fifo_idx].rdptr = value;
1080       BX_UNLOCK(cmdfifo_mutex);
1081       break;
1082     case cmdRdPtrH0:
1083     case cmdRdPtrH1:
1084       if (value > 0) {
1085         BX_ERROR(("cmdRdPtrH%d not supported yet", fifo_idx));
1086       }
1087       break;
1088     case cmdAMin0:
1089     case cmdAMin1:
1090       BX_LOCK(cmdfifo_mutex);
1091       v->fbi.cmdfifo[fifo_idx].amin = value;
1092       BX_UNLOCK(cmdfifo_mutex);
1093       break;
1094     case cmdAMax0:
1095     case cmdAMax1:
1096       BX_LOCK(cmdfifo_mutex);
1097       v->fbi.cmdfifo[fifo_idx].amax = value;
1098       BX_UNLOCK(cmdfifo_mutex);
1099       break;
1100     case cmdFifoDepth0:
1101     case cmdFifoDepth1:
1102       BX_LOCK(cmdfifo_mutex);
1103       v->fbi.cmdfifo[fifo_idx].depth = value & 0xfffff;
1104       BX_UNLOCK(cmdfifo_mutex);
1105       break;
1106     case cmdHoleCnt0:
1107     case cmdHoleCnt1:
1108       if (value > 0) {
1109         BX_ERROR(("cmdHoleCnt%d not supported yet", fifo_idx));
1110       }
1111       break;
1112   }
1113   v->banshee.agp[reg] = value;
1114 }
1115 
1116 #define BLT v->banshee.blt
1117 
blt_reg_read(Bit8u reg)1118 Bit32u bx_banshee_c::blt_reg_read(Bit8u reg)
1119 {
1120   Bit32u result = 0;
1121 
1122   switch (reg) {
1123     case blt_status:
1124       result = register_r(0);
1125       break;
1126     case blt_intrCtrl:
1127       result = register_r(1);
1128       break;
1129     default:
1130       if (reg < 0x20) {
1131         result = BLT.reg[reg];
1132       }
1133   }
1134   if (reg < 0x20) {
1135     BX_DEBUG(("2D read register 0x%03x (%s) result = 0x%08x", reg<<2,
1136               banshee_blt_reg_name[reg], result));
1137   }
1138   return result;
1139 }
1140 
blt_reg_write(Bit8u reg,Bit32u value)1141 void bx_banshee_c::blt_reg_write(Bit8u reg, Bit32u value)
1142 {
1143   Bit8u old_cmd;
1144   Bit8u colorkey_en = BLT.reg[blt_commandExtra] & 3;
1145 
1146   if (reg < 0x20) {
1147     BLT.reg[reg] = value;
1148     BX_DEBUG(("2D write register 0x%03x (%s) value = 0x%08x", reg<<2,
1149               banshee_blt_reg_name[reg], value));
1150   }
1151   switch (reg) {
1152     case blt_intrCtrl:
1153       register_w_common(1, value);
1154       break;
1155     case blt_clip0Min:
1156       BLT.clipx0[0] = BLT.reg[reg] & 0xfff;
1157       BLT.clipy0[0] = (BLT.reg[reg] >> 16) & 0x1fff;
1158       break;
1159     case blt_clip0Max:
1160       BLT.clipx1[0] = BLT.reg[reg] & 0xfff;
1161       BLT.clipy1[0] = (BLT.reg[reg] >> 16) & 0x1fff;
1162       break;
1163     case blt_dstBaseAddr:
1164       BLT.dst_base = BLT.reg[reg] & v->fbi.mask;
1165       BLT.dst_tiled = BLT.reg[reg] >> 31;
1166       if (BLT.dst_tiled) {
1167         BLT.dst_pitch = (BLT.reg[blt_dstFormat] & 0x7f) << 7;
1168       } else {
1169         BLT.dst_pitch = BLT.reg[blt_dstFormat] & 0x3fff;
1170       }
1171       break;
1172     case blt_dstFormat:
1173       BLT.dst_fmt = (BLT.reg[reg] >> 16) & 0x07;
1174       if (BLT.dst_tiled) {
1175         BLT.dst_pitch = (BLT.reg[reg] & 0x7f) << 7;
1176       } else {
1177         BLT.dst_pitch = BLT.reg[reg] & 0x3fff;
1178       }
1179       break;
1180     case blt_srcBaseAddr:
1181       BLT.src_base = BLT.reg[reg] & v->fbi.mask;
1182       BLT.src_tiled = BLT.reg[reg] >> 31;
1183       if (BLT.src_tiled) {
1184         BLT.src_pitch = (BLT.reg[blt_srcFormat] & 0x7f) << 7;
1185       } else {
1186         BLT.src_pitch = BLT.reg[blt_srcFormat] & 0x3fff;
1187       }
1188       break;
1189     case blt_srcFormat:
1190       BLT.src_fmt = (BLT.reg[reg] >> 16) & 0x0f;
1191       BLT.src_swizzle = (BLT.reg[reg] >> 20) & 0x03;
1192       if (BLT.src_tiled) {
1193         BLT.src_pitch = (BLT.reg[reg] & 0x7f) << 7;
1194       } else {
1195         BLT.src_pitch = BLT.reg[reg] & 0x3fff;
1196       }
1197       break;
1198     case blt_pattern0Alias:
1199       BLT.cpat[0][0] = value & 0xff;
1200       BLT.cpat[0][1] = (value >> 8) & 0xff;
1201       BLT.cpat[0][2] = (value >> 16) & 0xff;
1202       BLT.cpat[0][3] = (value >> 24) & 0xff;
1203       break;
1204     case blt_pattern1Alias:
1205       BLT.cpat[1][0] = value & 0xff;
1206       BLT.cpat[1][1] = (value >> 8) & 0xff;
1207       BLT.cpat[1][2] = (value >> 16) & 0xff;
1208       BLT.cpat[1][3] = (value >> 24) & 0xff;
1209       break;
1210     case blt_clip1Min:
1211       BLT.clipx0[1] = BLT.reg[reg] & 0xfff;
1212       BLT.clipy0[1] = (BLT.reg[reg] >> 16) & 0x1fff;
1213       break;
1214     case blt_clip1Max:
1215       BLT.clipx1[1] = BLT.reg[reg] & 0xfff;
1216       BLT.clipy1[1] = (BLT.reg[reg] >> 16) & 0x1fff;
1217       break;
1218     case blt_srcSize:
1219       BLT.src_w = BLT.reg[reg] & 0x1fff;
1220       BLT.src_h = (BLT.reg[reg] >> 16) & 0x1fff;
1221       break;
1222     case blt_srcXY:
1223       BLT.src_x = BLT.reg[reg] & 0x1fff;
1224       BLT.src_y = (BLT.reg[reg] >> 16) & 0x1fff;
1225       break;
1226     case blt_colorBack:
1227       BLT.bgcolor[0] = BLT.reg[reg] & 0xff;
1228       BLT.bgcolor[1] = (BLT.reg[reg] >> 8) & 0xff;
1229       BLT.bgcolor[2] = (BLT.reg[reg] >> 16) & 0xff;
1230       BLT.bgcolor[3] = (BLT.reg[reg] >> 24) & 0xff;
1231       break;
1232     case blt_colorFore:
1233       BLT.fgcolor[0] = BLT.reg[reg] & 0xff;
1234       BLT.fgcolor[1] = (BLT.reg[reg] >> 8) & 0xff;
1235       BLT.fgcolor[2] = (BLT.reg[reg] >> 16) & 0xff;
1236       BLT.fgcolor[3] = (BLT.reg[reg] >> 24) & 0xff;
1237       break;
1238     case blt_dstSize:
1239       BLT.dst_w = BLT.reg[reg] & 0x1fff;
1240       BLT.dst_h = (BLT.reg[reg] >> 16) & 0x1fff;
1241       break;
1242     case blt_dstXY:
1243       if ((BLT.reg[reg] >> 15) & 1) {
1244         BLT.dst_x = (Bit16s)(BLT.reg[reg] & 0xffff);
1245       } else {
1246         BLT.dst_x = BLT.reg[reg] & 0x1fff;
1247       }
1248       if (BLT.reg[reg] >> 31) {
1249         BLT.dst_y = (Bit16s)(BLT.reg[reg] >> 16);
1250       } else {
1251         BLT.dst_y = (BLT.reg[reg] >> 16) & 0x1fff;
1252       }
1253       break;
1254     case blt_command:
1255       old_cmd = BLT.cmd;
1256       BLT.cmd = (value & 0x0f);
1257       BLT.immed = (value >> 8) & 1;
1258       BLT.x_dir = (value >> 14) & 1;
1259       BLT.y_dir = (value >> 15) & 1;
1260       BLT.transp = (value >> 16) & 1;
1261       BLT.patsx = (value >> 17) & 7;
1262       BLT.patsy = (value >> 20) & 7;
1263       BLT.clip_sel = (value >> 23) & 1;
1264       BLT.rop[0] = (value >> 24);
1265       BLT.rop[1] = BLT.reg[blt_rop] & 0xff;
1266       BLT.rop[2] = (BLT.reg[blt_rop] >> 8) & 0xff;
1267       BLT.rop[3] = (BLT.reg[blt_rop] >> 16) & 0xff;
1268       BLT.pattern_blt = (BLT.rop_flags[BLT.rop[0]] & BX_ROP_PATTERN);
1269       if (colorkey_en & 1) {
1270         BLT.pattern_blt |= (BLT.rop_flags[BLT.rop[2]] & BX_ROP_PATTERN);
1271       }
1272       if (colorkey_en & 2) {
1273         BLT.pattern_blt |= (BLT.rop_flags[BLT.rop[1]] & BX_ROP_PATTERN);
1274       }
1275       if (colorkey_en == 3) {
1276         BLT.pattern_blt |= (BLT.rop_flags[BLT.rop[3]] & BX_ROP_PATTERN);
1277       }
1278       if (BLT.x_dir) {
1279         BLT.rop_fn[0] = BLT.rop_handler[1][BLT.rop[0]];
1280         BLT.rop_fn[1] = BLT.rop_handler[1][BLT.rop[1]];
1281         BLT.rop_fn[2] = BLT.rop_handler[1][BLT.rop[2]];
1282         BLT.rop_fn[3] = BLT.rop_handler[1][BLT.rop[3]];
1283       } else {
1284         BLT.rop_fn[0] = BLT.rop_handler[0][BLT.rop[0]];
1285         BLT.rop_fn[1] = BLT.rop_handler[0][BLT.rop[1]];
1286         BLT.rop_fn[2] = BLT.rop_handler[0][BLT.rop[2]];
1287         BLT.rop_fn[3] = BLT.rop_handler[0][BLT.rop[3]];
1288       }
1289       if (BLT.lamem != NULL) {
1290         BX_ERROR(("Writing new command while another one is still pending"));
1291         delete [] BLT.lamem;
1292         BLT.lamem = NULL;
1293       }
1294       if (old_cmd == 8) {
1295         blt_polygon_fill(1);
1296       }
1297       if (BLT.cmd == 8) {
1298         BLT.pgn_init = 0;
1299       }
1300       if (BLT.immed) {
1301         blt_execute();
1302       } else {
1303         blt_launch_area_setup();
1304       }
1305       break;
1306     case blt_commandExtra:
1307       if ((value & 0x04) != 0) {
1308         BX_ERROR(("wait for vsync not supported yet"));
1309       }
1310       break;
1311     default:
1312       if ((reg >= 0x20) && (reg < 0x40)) {
1313         blt_launch_area_write(value);
1314       } else if ((reg >= 0x40) && (reg < 0x80)) {
1315         reg -= 0x40;
1316         BX_DEBUG(("colorPattern write reg 0x%02x: value = 0x%08x", reg, value));
1317         BLT.cpat[reg][0] = value & 0xff;
1318         BLT.cpat[reg][1] = (value >> 8) & 0xff;
1319         BLT.cpat[reg][2] = (value >> 16) & 0xff;
1320         BLT.cpat[reg][3] = (value >> 24) & 0xff;
1321       }
1322   }
1323 }
1324 
blt_launch_area_setup()1325 void bx_banshee_c::blt_launch_area_setup()
1326 {
1327   Bit32u pbytes;
1328   Bit8u pxpack, pxsize = 0, pxstart;
1329 
1330   BLT.lacnt = 0;
1331   BLT.laidx = 0;
1332   switch (BLT.cmd) {
1333     case 1:
1334     case 2:
1335     case 5:
1336     case 6:
1337     case 7:
1338     case 8:
1339       BLT.lacnt = 1;
1340       break;
1341     case 3:
1342     case 4:
1343       pxpack = (BLT.reg[blt_srcFormat] >> 22) & 3;
1344       if (BLT.src_fmt == 0) {
1345         BLT.h2s_pxstart = BLT.reg[blt_srcXY] & 0x1f;
1346         pbytes = (BLT.dst_w + BLT.h2s_pxstart + 7) >> 3;
1347       } else {
1348         BLT.h2s_pxstart = BLT.reg[blt_srcXY] & 0x03;
1349         if (BLT.src_fmt == 1) {
1350           pxsize = 1;
1351         } else if ((BLT.src_fmt >= 3) && (BLT.src_fmt <= 5))  {
1352           pxsize = BLT.src_fmt - 1;
1353         } else {
1354           BX_ERROR(("Source format %d not handled yet", BLT.src_fmt));
1355         }
1356         pbytes = BLT.dst_w * pxsize + BLT.h2s_pxstart;
1357       }
1358       switch (pxpack) {
1359         case 1:
1360           BLT.h2s_pitch = pbytes;
1361           break;
1362         case 2:
1363           BLT.h2s_pitch = (pbytes + 1) & ~1;
1364           break;
1365         case 3:
1366           BLT.h2s_pitch = (pbytes + 3) & ~3;
1367           break;
1368         default:
1369           BLT.h2s_pitch = (pbytes + 3) & ~3;
1370           pbytes = 0;
1371           pxstart = BLT.h2s_pxstart;
1372           if (BLT.src_fmt == 0) {
1373             for (int i = 0; i < BLT.dst_h; i++) {
1374               pbytes += ((((BLT.dst_w + pxstart + 7) >> 3) + 3) & ~3);
1375               pxstart += (Bit8u)(BLT.reg[blt_srcFormat] << 3);
1376               pxstart &= 0x1f;
1377             }
1378           } else {
1379             for (int i = 0; i < BLT.dst_h; i++) {
1380               pbytes += ((BLT.dst_w * pxsize + pxstart + 3) & ~3);
1381               pxstart += (Bit8u)BLT.reg[blt_srcFormat];
1382               pxstart &= 0x03;
1383             }
1384           }
1385           BLT.lacnt = pbytes >> 2;
1386       }
1387       if (pxpack != 0) {
1388         BLT.lacnt = (BLT.h2s_pitch * BLT.dst_h + 3) >> 2;
1389       }
1390       BLT.lamem = new Bit8u[BLT.lacnt * 4];
1391       break;
1392     default:
1393       BX_ERROR(("launchArea setup: command %d not handled yet", BLT.cmd));
1394   }
1395 }
1396 
blt_launch_area_write(Bit32u value)1397 void bx_banshee_c::blt_launch_area_write(Bit32u value)
1398 {
1399   if (BLT.lacnt > 0) {
1400     BX_DEBUG(("launchArea write: value = 0x%08x", value));
1401     if (BLT.lamem != NULL) {
1402       if (BLT.src_swizzle & 1) {
1403         value = bx_bswap32(value);
1404       }
1405       if (BLT.src_swizzle & 2) {
1406         value = (value >> 16) | (value << 16);
1407       }
1408       BLT.lamem[BLT.laidx++] = (value & 0xff);
1409       BLT.lamem[BLT.laidx++] = ((value >> 8) & 0xff);
1410       BLT.lamem[BLT.laidx++] = ((value >> 16) & 0xff);
1411       BLT.lamem[BLT.laidx++] = ((value >> 24) & 0xff);
1412     } else if ((BLT.cmd == 1) || (BLT.cmd == 2)) {
1413       BLT.reg[blt_srcXY] = value;
1414       BLT.src_x = value & 0x1fff;
1415       BLT.src_y = (value >> 16) & 0x1fff;
1416     } if ((BLT.cmd >= 5) && (BLT.cmd <= 7)) {
1417       BLT.reg[blt_dstXY] = value;
1418       if ((value >> 15) & 1) {
1419         BLT.dst_x = (Bit16s)(value & 0xffff);
1420       } else {
1421         BLT.dst_x = value & 0x1fff;
1422       }
1423       if (value >> 31) {
1424         BLT.dst_y = (Bit16s)(value >> 16);
1425       } else {
1426         BLT.dst_y = (value >> 16) & 0x1fff;
1427       }
1428     } if (BLT.cmd == 8) {
1429       BLT.pgn_val = value;
1430     }
1431     if (--BLT.lacnt == 0) {
1432       blt_execute();
1433     }
1434   } else {
1435     BX_ERROR(("launchArea write: ignoring extra data"));
1436   }
1437 }
1438 
blt_execute()1439 void bx_banshee_c::blt_execute()
1440 {
1441   Bit16u x, y;
1442 
1443   switch (BLT.cmd) {
1444     case 0: // NOP
1445       break;
1446     case 1:
1447       BLT.busy = 1;
1448       if (BLT.pattern_blt) {
1449         blt_screen_to_screen_pattern();
1450       } else {
1451         blt_screen_to_screen();
1452       }
1453       if (!BLT.immed) {
1454         BLT.lacnt = 1;
1455       }
1456       break;
1457     case 2:
1458       if (BLT.pattern_blt) {
1459         BX_ERROR(("TODO: 2D Screen to screen stretch pattern blt"));
1460       } else {
1461         BLT.busy = 1;
1462         blt_screen_to_screen_stretch();
1463       }
1464       break;
1465     case 3:
1466     case 4:
1467       if (!BLT.immed) {
1468         if (BLT.cmd == 3) {
1469           BLT.busy = 1;
1470           if (BLT.pattern_blt) {
1471             blt_host_to_screen_pattern();
1472           } else {
1473             blt_host_to_screen();
1474           }
1475         } else {
1476           BX_ERROR(("TODO: 2D Host to screen stretch blt"));
1477         }
1478         delete [] BLT.lamem;
1479         BLT.lamem = NULL;
1480       } else {
1481         BX_ERROR(("Host to screen blt: immediate execution not supported"));
1482       }
1483       break;
1484     case 5:
1485       BLT.busy = 1;
1486       if (BLT.pattern_blt) {
1487         if ((BLT.reg[blt_command] >> 13) & 1) {
1488           blt_pattern_fill_mono();
1489         } else {
1490           blt_pattern_fill_color();
1491         }
1492       } else {
1493         blt_rectangle_fill();
1494       }
1495       if (!BLT.immed) {
1496         BLT.lacnt = 1;
1497       }
1498       break;
1499     case 6:
1500     case 7:
1501       BLT.busy = 1;
1502       blt_line(BLT.cmd == 7);
1503       if (!BLT.immed) {
1504         BLT.lacnt = 1;
1505       }
1506       break;
1507     case 8:
1508       if (!BLT.immed) {
1509         if (!BLT.pgn_init) {
1510           BLT.pgn_l0x = BLT.pgn_l1x = BLT.src_x;
1511           BLT.pgn_l0y = BLT.pgn_l1y = BLT.src_y;
1512           BLT.pgn_r0x = BLT.pgn_r1x = BLT.dst_x;
1513           BLT.pgn_r0y = BLT.pgn_r1y = BLT.dst_y;
1514           BLT.pgn_init = 1;
1515         }
1516         x = (Bit16u)BLT.pgn_val;
1517         y = (Bit16u)(BLT.pgn_val >> 16);
1518         if (BLT.pgn_r1y >= BLT.pgn_l1y) {
1519           BLT.pgn_l1x = x;
1520           BLT.pgn_l1y = y;
1521           if (y == BLT.pgn_l0y) {
1522             BLT.pgn_l0x = x;
1523           }
1524         } else {
1525           BLT.pgn_r1x = x;
1526           BLT.pgn_r1y = y;
1527           if (y == BLT.pgn_r0y) {
1528             BLT.pgn_r0x = x;
1529           }
1530         }
1531         blt_polygon_fill(0);
1532       } else {
1533         BLT.reg[blt_dstXY] = BLT.reg[blt_srcXY];
1534         BLT.immed = 0;
1535       }
1536       BLT.lacnt = 1;
1537       break;
1538     case 13:
1539       BX_ERROR(("TODO: 2D Write Sgram Mode register"));
1540       break;
1541     case 14:
1542       BX_ERROR(("TODO: 2D Write Sgram Mask register"));
1543       break;
1544     case 15:
1545       BX_ERROR(("TODO: 2D Write Sgram Color register"));
1546       break;
1547     default:
1548       BX_ERROR(("Unknown BitBlt command"));
1549   }
1550 }
1551 
blt_complete()1552 void bx_banshee_c::blt_complete()
1553 {
1554   Bit32u vstart = v->banshee.io[io_vidDesktopStartAddr] & v->fbi.mask;
1555   Bit16u vpitch = v->banshee.io[io_vidDesktopOverlayStride] & 0x7fff;
1556   Bit8u vpxsize = (v->banshee.disp_bpp >> 3);
1557   Bit32u dstart = BLT.dst_base;
1558   Bit16u dpitch = BLT.dst_pitch;
1559   Bit8u dpxsize = (BLT.dst_fmt > 1) ? (BLT.dst_fmt - 1) : 1;
1560   Bit32u cmd = BLT.reg[blt_command];
1561   bool xinc = (cmd >> 10) & 1;
1562   bool yinc = (cmd >> 11) & 1;
1563   int x, y, w, h;
1564 
1565   if (v->banshee.desktop_tiled) {
1566     vpitch *= 128;
1567   }
1568   if ((dstart == vstart) && (dpitch == vpitch) && (dpxsize == vpxsize)) {
1569     if (BLT.cmd < 6) {
1570       if (BLT.x_dir) {
1571         x = BLT.dst_x + 1 - BLT.dst_w;
1572       } else {
1573         x = BLT.dst_x;
1574       }
1575       if (BLT.y_dir) {
1576         y = BLT.dst_y + 1 - BLT.dst_h;
1577       } else {
1578         y = BLT.dst_y;
1579       }
1580       w = BLT.dst_w;
1581       h = BLT.dst_h;
1582     } else {
1583       if (BLT.src_x < BLT.dst_x) {
1584         x = BLT.src_x;
1585         w = BLT.dst_x - BLT.src_x + 1;
1586       } else {
1587         x = BLT.dst_x;
1588         w = BLT.src_x - BLT.dst_x + 1;
1589       }
1590       if (BLT.src_y < BLT.dst_y) {
1591         y = BLT.src_y;
1592         h = BLT.dst_y - BLT.src_y + 1;
1593       } else {
1594         y = BLT.dst_y;
1595         h = BLT.src_y - BLT.dst_y + 1;
1596       }
1597     }
1598     theVoodooVga->redraw_area(x, y, w, h);
1599   }
1600   if (xinc) {
1601     BLT.dst_x += BLT.dst_w;
1602     BLT.reg[blt_dstXY] &= ~0xffff;
1603     BLT.reg[blt_dstXY] |= BLT.dst_x;
1604   }
1605   if (yinc) {
1606     BLT.dst_y += BLT.dst_h;
1607     BLT.reg[blt_dstXY] &= 0xffff;
1608     BLT.reg[blt_dstXY] |= (BLT.dst_y << 16);
1609   }
1610   BLT.busy = 0;
1611 }
1612 
blt_apply_clipwindow(int * x0,int * y0,int * x1,int * y1,int * w,int * h)1613 bool bx_banshee_c::blt_apply_clipwindow(int *x0, int *y0, int *x1, int *y1, int *w, int *h)
1614 {
1615   int cx0, cx1, cy0, cy1, xd, yd;
1616 
1617   cx0 = BLT.clipx0[BLT.clip_sel];
1618   cy0 = BLT.clipy0[BLT.clip_sel];
1619   cx1 = BLT.clipx1[BLT.clip_sel];
1620   cy1 = BLT.clipy1[BLT.clip_sel];
1621   if (BLT.x_dir) {
1622     xd = *x1 - cx1 + 1;
1623     if (xd > 0) {
1624       *w -= xd;
1625       *x1 = cx1 - 1;
1626       if (x0 != NULL) *x0 -= xd;
1627     }
1628     xd = cx0 - (*x1 - *w + 1);
1629     if (xd > 0) {
1630       *w -= xd;
1631     }
1632   } else {
1633     xd = cx0 - *x1;
1634     if (xd > 0) {
1635       *w -= xd;
1636       *x1 = cx0;
1637       if (x0 != NULL) *x0 += xd;
1638     }
1639     xd = *x1 + *w - cx1;
1640     if (xd > 0) {
1641       *w -= xd;
1642     }
1643   }
1644   if (BLT.y_dir) {
1645     yd = *y1 - cy1 + 1;
1646     if (yd > 0) {
1647       *h -= yd;
1648       *y1 = cy1 - 1;
1649       if (y0 != NULL) *y0 -= xd;
1650     }
1651     yd = cy0 - (*y1 - *h + 1);
1652     if (yd > 0) {
1653       *h -= xd;
1654     }
1655   } else {
1656     yd = cy0 - *y1;
1657     if (yd > 0) {
1658       *h -= yd;
1659       *y1 = cy0;
1660       if (y0 != NULL) *y0 += yd;
1661     }
1662     yd = *y1 + *h - cy1;
1663     if (yd > 0) {
1664       *h -= yd;
1665     }
1666   }
1667   return ((*w > 0) && (*h > 0));
1668 }
1669 
blt_clip_check(int x,int y)1670 bool bx_banshee_c::blt_clip_check(int x, int y)
1671 {
1672   if ((x >= BLT.clipx0[BLT.clip_sel]) && (x < BLT.clipx1[BLT.clip_sel]) &&
1673       (y >= BLT.clipy0[BLT.clip_sel]) && (y < BLT.clipy1[BLT.clip_sel])) {
1674     return true;
1675   }
1676   return false;
1677 }
1678 
blt_colorkey_check(Bit8u * ptr,Bit8u pxsize,bool dst)1679 Bit8u bx_banshee_c::blt_colorkey_check(Bit8u *ptr, Bit8u pxsize, bool dst)
1680 {
1681   Bit8u pass = 0;
1682   Bit32u color, cmin, cmax;
1683   Bit8u r, g, b, rmin, rmax, gmin, gmax, bmin, bmax;
1684 
1685   if (!dst) {
1686     cmin = BLT.reg[blt_srcColorkeyMin];
1687     cmax = BLT.reg[blt_srcColorkeyMax];
1688   } else {
1689     cmin = BLT.reg[blt_dstColorkeyMin];
1690     cmax = BLT.reg[blt_dstColorkeyMax];
1691   }
1692   if (pxsize == 1) {
1693     pass = ((*ptr >= (Bit8u)cmin) && (*ptr <= (Bit8u)cmax));
1694   } else {
1695     if (pxsize == 2) {
1696       color = *ptr;
1697       color |= *(ptr + 1) << 8;
1698       r = (color >> 11);
1699       g = (color >> 5) & 0x3f;
1700       b = color & 0x1f;
1701       rmin = (cmin >> 11) & 0x1f;
1702       rmax = (cmax >> 11) & 0x1f;
1703       gmin = (cmin >> 5) & 0x3f;
1704       gmax = (cmax >> 5) & 0x3f;
1705       bmin = cmin & 0x1f;
1706       bmax = cmax & 0x1f;
1707     } else {
1708       color = *ptr;
1709       color |= *(ptr + 1) << 8;
1710       color |= *(ptr + 2) << 16;
1711       r = (color >> 16);
1712       g = (color >> 8) & 0xff;
1713       b = color & 0xff;
1714       rmin = (cmin >> 16) & 0xff;
1715       rmax = (cmax >> 16) & 0xff;
1716       gmin = (cmin >> 8) & 0xff;
1717       gmax = (cmax >> 8) & 0xff;
1718       bmin = cmin & 0xff;
1719       bmax = cmax & 0xff;
1720     }
1721     pass = ((r >= rmin) && (r <= rmax) && (g >= gmin) && (g <= gmax) &&
1722             (b >= bmin) && (b <= bmax));
1723   }
1724   if (!dst) pass <<= 1;
1725   return pass;
1726 }
1727 
blt_rectangle_fill()1728 void bx_banshee_c::blt_rectangle_fill()
1729 {
1730   Bit32u dpitch = BLT.dst_pitch;
1731   Bit8u dpxsize = (BLT.dst_fmt > 1) ? (BLT.dst_fmt - 1) : 1;
1732   Bit8u *dst_ptr, *dst_ptr1;
1733   Bit8u colorkey_en = BLT.reg[blt_commandExtra] & 3;
1734   Bit8u rop = 0;
1735   int dx, dy, w, h, x, y;
1736 
1737   dx = BLT.dst_x;
1738   dy = BLT.dst_y;
1739   w = BLT.dst_w;
1740   h = BLT.dst_h;
1741   BX_DEBUG(("Rectangle fill: %d x %d  ROP0 %02X", w, h, BLT.rop[0]));
1742   if (!blt_apply_clipwindow(NULL, NULL, &dx, &dy, &w, &h)) {
1743     BLT.busy = 0;
1744     return;
1745   }
1746   BX_LOCK(render_mutex);
1747   dst_ptr = &v->fbi.ram[BLT.dst_base + dy * dpitch + dx * dpxsize];
1748   for (y = 0; y < h; y++) {
1749     dst_ptr1 = dst_ptr;
1750     for (x = 0; x < w; x++) {
1751       if (colorkey_en & 2) {
1752         rop = blt_colorkey_check(dst_ptr1, dpxsize, 1);
1753       }
1754       BLT.rop_fn[rop](dst_ptr1, BLT.fgcolor, dpitch, dpxsize, dpxsize, 1);
1755       dst_ptr1 += dpxsize;
1756     }
1757     dst_ptr += dpitch;
1758   }
1759   blt_complete();
1760   BX_UNLOCK(render_mutex);
1761 }
1762 
blt_pattern_fill_mono()1763 void bx_banshee_c::blt_pattern_fill_mono()
1764 {
1765   Bit32u dpitch = BLT.dst_pitch;
1766   Bit8u dpxsize = (BLT.dst_fmt > 1) ? (BLT.dst_fmt - 1) : 1;
1767   Bit8u *pat_ptr = &BLT.cpat[0][0];
1768   Bit8u *dst_ptr, *dst_ptr1, *pat_ptr1;
1769   bool patrow0 = (BLT.reg[blt_commandExtra] & 0x08) > 0;
1770   Bit8u colorkey_en = BLT.reg[blt_commandExtra] & 3;
1771   Bit8u rop = 0;
1772   Bit8u *color;
1773   int dx, dy, w, h, x, y;
1774   Bit8u mask;
1775   bool set;
1776 
1777   dx = BLT.dst_x;
1778   dy = BLT.dst_y;
1779   w = BLT.dst_w;
1780   h = BLT.dst_h;
1781   BX_DEBUG(("Pattern fill mono: %d x %d  ROP0 %02X", w, h, BLT.rop[0]));
1782   if (!blt_apply_clipwindow(NULL, NULL, &dx, &dy, &w, &h)) {
1783     BLT.busy = 0;
1784     return;
1785   }
1786   BX_LOCK(render_mutex);
1787   dst_ptr = &v->fbi.ram[BLT.dst_base + dy * dpitch + dx * dpxsize];
1788   for (y = dy; y < (dy + h); y++) {
1789     dst_ptr1 = dst_ptr;
1790     if (!patrow0) {
1791       pat_ptr1 = pat_ptr + ((y + BLT.patsy) & 7);
1792     } else {
1793       pat_ptr1 = pat_ptr;
1794     }
1795     for (x = dx; x < (dx + w); x++) {
1796       mask = 0x80 >> ((x + BLT.patsx) & 7);
1797       set = (*pat_ptr1 & mask) > 0;
1798       if (set) {
1799         color = &BLT.fgcolor[0];
1800       } else {
1801         color = &BLT.bgcolor[0];
1802       }
1803       if ((set) || !BLT.transp) {
1804         if (colorkey_en & 2) {
1805           rop = blt_colorkey_check(dst_ptr1, dpxsize, 1);
1806         }
1807         BLT.rop_fn[rop](dst_ptr1, color, dpitch, dpxsize, dpxsize, 1);
1808       }
1809       dst_ptr1 += dpxsize;
1810     }
1811     dst_ptr += dpitch;
1812   }
1813   blt_complete();
1814   BX_UNLOCK(render_mutex);
1815 }
1816 
blt_pattern_fill_color()1817 void bx_banshee_c::blt_pattern_fill_color()
1818 {
1819   Bit32u dpitch = BLT.dst_pitch;
1820   Bit8u dpxsize = (BLT.dst_fmt > 1) ? (BLT.dst_fmt - 1) : 1;
1821   Bit8u *pat_ptr = &BLT.cpat[0][0];
1822   Bit8u *dst_ptr, *dst_ptr1, *pat_ptr1, *pat_ptr2;
1823   bool patrow0 = (BLT.reg[blt_commandExtra] & 0x08) > 0;
1824   Bit8u colorkey_en = BLT.reg[blt_commandExtra] & 3;
1825   Bit8u rop = 0;
1826   int dx, dy, w, h, x, y;
1827 
1828   dx = BLT.dst_x;
1829   dy = BLT.dst_y;
1830   w = BLT.dst_w;
1831   h = BLT.dst_h;
1832   BX_DEBUG(("Pattern fill color: %d x %d  ROP0 %02X", w, h, BLT.rop[0]));
1833   if (!blt_apply_clipwindow(NULL, NULL, &dx, &dy, &w, &h)) {
1834     BLT.busy = 0;
1835     return;
1836   }
1837   BX_LOCK(render_mutex);
1838   dst_ptr = &v->fbi.ram[BLT.dst_base + dy * dpitch + dx * dpxsize];
1839   for (y = dy; y < (dy + h); y++) {
1840     dst_ptr1 = dst_ptr;
1841     if (!patrow0) {
1842       pat_ptr1 = pat_ptr + ((y + BLT.patsy) & 7) * dpxsize * 8;
1843     } else {
1844       pat_ptr1 = pat_ptr;
1845     }
1846     for (x = dx; x < (dx + w); x++) {
1847       pat_ptr2 = pat_ptr1 + ((x + BLT.patsx) & 7) * dpxsize;
1848       if (colorkey_en & 2) {
1849         rop = blt_colorkey_check(dst_ptr1, dpxsize, 1);
1850       }
1851       BLT.rop_fn[rop](dst_ptr1, pat_ptr2, dpitch, dpxsize, dpxsize, 1);
1852       dst_ptr1 += dpxsize;
1853     }
1854     dst_ptr += dpitch;
1855   }
1856   blt_complete();
1857   BX_UNLOCK(render_mutex);
1858 }
1859 
blt_screen_to_screen()1860 void bx_banshee_c::blt_screen_to_screen()
1861 {
1862   Bit8u *src_ptr = &v->fbi.ram[BLT.src_base];
1863   Bit8u *dst_ptr, *dst_ptr1, *src_ptr1;
1864   Bit8u pxpack = (BLT.reg[blt_srcFormat] >> 22) & 3;
1865   int dpxsize = (BLT.dst_fmt > 1) ? (BLT.dst_fmt - 1) : 1;
1866   Bit8u *color;
1867   Bit8u colorkey_en = BLT.reg[blt_commandExtra] & 3;
1868   int spitch;
1869   int dpitch = BLT.dst_pitch;
1870   int ncols, nrows, dx, dy, sx, sy, w, h;
1871   Bit8u smask, rop = 0;
1872   bool set;
1873 
1874   sx = BLT.src_x;
1875   sy = BLT.src_y;
1876   dx = BLT.dst_x;
1877   dy = BLT.dst_y;
1878   w = BLT.dst_w;
1879   h = BLT.dst_h;
1880   BX_DEBUG(("Screen to screen blt: %d x %d  ROP0 %02X", w, h, BLT.rop[0]));
1881   if ((BLT.src_fmt != 0) && (BLT.dst_fmt != BLT.src_fmt)) {
1882     BX_ERROR(("Pixel format conversion not supported yet"));
1883   }
1884   if (!blt_apply_clipwindow(&sx, &sy, &dx, &dy, &w, &h)) {
1885     BLT.busy = 0;
1886     return;
1887   }
1888   BX_LOCK(render_mutex);
1889   if ((BLT.src_fmt == 0) && (pxpack == 1)) {
1890     spitch = (BLT.dst_w + 7) / 8;
1891   } else {
1892     spitch = BLT.src_pitch;
1893   }
1894   dst_ptr = &v->fbi.ram[BLT.dst_base + dy * dpitch + dx * dpxsize];
1895   if (BLT.x_dir) {
1896     dpxsize *= -1;
1897   }
1898   if (BLT.y_dir) {
1899     spitch *= -1;
1900     dpitch *= -1;
1901   }
1902   if ((BLT.src_fmt == 0) && (pxpack == 1)) {
1903     src_ptr += (sy * abs(spitch) + sx / 8);
1904     nrows = h;
1905     do {
1906       src_ptr1 = src_ptr;
1907       dst_ptr1 = dst_ptr;
1908       smask = 0x80 >> (sx & 7);
1909       ncols = w;
1910       do {
1911         set = (*src_ptr1 & smask) > 0;
1912         if (set) {
1913           color = &BLT.fgcolor[0];
1914         } else {
1915           color = &BLT.bgcolor[0];
1916         }
1917         if (set || !BLT.transp) {
1918           if (colorkey_en & 2) {
1919             rop = blt_colorkey_check(dst_ptr1, abs(dpxsize), 1);
1920           }
1921           BLT.rop_fn[rop](dst_ptr1, color, dpitch, dpxsize, abs(dpxsize), 1);
1922         }
1923         smask >>= 1;
1924         if (smask == 0) {
1925           src_ptr1++;
1926           smask = 0x80;
1927         }
1928         dst_ptr1 += dpxsize;
1929       } while (--ncols);
1930       src_ptr += spitch;
1931       dst_ptr += dpitch;
1932     } while (--nrows);
1933   } else if (colorkey_en > 0) {
1934     src_ptr += (sy * abs(spitch) + sx * abs(dpxsize));
1935     nrows = h;
1936     do {
1937       src_ptr1 = src_ptr;
1938       dst_ptr1 = dst_ptr;
1939       ncols = w;
1940       do {
1941         if (colorkey_en & 1) {
1942           rop = blt_colorkey_check(src_ptr1, abs(dpxsize), 0);
1943         }
1944         if (colorkey_en & 2) {
1945           rop |= blt_colorkey_check(dst_ptr1, abs(dpxsize), 1);
1946         }
1947         BLT.rop_fn[rop](dst_ptr1, src_ptr1, dpitch, spitch, abs(dpxsize), 1);
1948         src_ptr1 += dpxsize;
1949         dst_ptr1 += dpxsize;
1950       } while (--ncols);
1951       src_ptr += spitch;
1952       dst_ptr += dpitch;
1953     } while (--nrows);
1954   } else {
1955     src_ptr += (sy * abs(spitch) + sx * abs(dpxsize));
1956     BLT.rop_fn[0](dst_ptr, src_ptr, dpitch, spitch, w * abs(dpxsize), h);
1957   }
1958   blt_complete();
1959   BX_UNLOCK(render_mutex);
1960 }
1961 
blt_screen_to_screen_pattern()1962 void bx_banshee_c::blt_screen_to_screen_pattern()
1963 {
1964   Bit8u *dst_ptr, *dst_ptr1, *src_ptr, *src_ptr1;
1965   Bit8u *pat_ptr = &BLT.cpat[0][0], *pat_ptr1, *pat_ptr2 = NULL;
1966   int dpxsize = (BLT.dst_fmt > 1) ? (BLT.dst_fmt - 1) : 1;
1967   int spitch = BLT.src_pitch;
1968   int dpitch = BLT.dst_pitch;
1969   bool patmono = (BLT.reg[blt_command] >> 13) & 1;
1970   bool patrow0 = (BLT.reg[blt_commandExtra] & 0x08) > 0;
1971   Bit8u colorkey_en = BLT.reg[blt_commandExtra] & 3;
1972   Bit8u *patcolor;
1973   int ncols, nrows, dx, dy, x, sx, sy, w, h;
1974   Bit8u pmask = 0, rop = 0, patline;
1975   bool set;
1976 
1977   sx = BLT.src_x;
1978   sy = BLT.src_y;
1979   dx = BLT.dst_x;
1980   dy = BLT.dst_y;
1981   w = BLT.dst_w;
1982   h = BLT.dst_h;
1983   BX_DEBUG(("Screen to screen pattern blt: %d x %d  ROP0 %02X", w, h, BLT.rop[0]));
1984   if (BLT.dst_fmt != BLT.src_fmt) {
1985     BX_ERROR(("Pixel format conversion not supported yet"));
1986   }
1987   if (!blt_apply_clipwindow(&sx, &sy, &dx, &dy, &w, &h)) {
1988     BLT.busy = 0;
1989     return;
1990   }
1991   BX_LOCK(render_mutex);
1992   src_ptr = &v->fbi.ram[BLT.src_base + sy * spitch + sx * dpxsize];
1993   dst_ptr = &v->fbi.ram[BLT.dst_base + dy * dpitch + dx * dpxsize];
1994   if (BLT.x_dir) {
1995     dpxsize *= -1;
1996   }
1997   if (BLT.y_dir) {
1998     spitch *= -1;
1999     dpitch *= -1;
2000   }
2001   nrows = h;
2002   do {
2003     src_ptr1 = src_ptr;
2004     dst_ptr1 = dst_ptr;
2005     if (!patrow0) {
2006       patline = (dy + BLT.patsy) & 7;
2007       if (patmono) {
2008         pat_ptr1 = pat_ptr + patline;
2009       } else {
2010         pat_ptr1 = pat_ptr + patline * dpxsize * 8;
2011       }
2012     } else {
2013       pat_ptr1 = pat_ptr;
2014     }
2015     x = dx;
2016     ncols = w;
2017     do {
2018       if (patmono) {
2019         pmask = 0x80 >> ((x + BLT.patsx) & 7);
2020         set = (*pat_ptr & pmask) > 0;
2021         if (set) {
2022           patcolor = &BLT.fgcolor[0];
2023         } else {
2024           patcolor = &BLT.bgcolor[0];
2025         }
2026         if (set || !BLT.transp) {
2027           if (colorkey_en & 2) {
2028             rop = blt_colorkey_check(dst_ptr1, abs(dpxsize), 1);
2029           }
2030           bx_ternary_rop(BLT.rop[rop], dst_ptr1, src_ptr1, patcolor, abs(dpxsize));
2031         }
2032       } else {
2033         pat_ptr2 = pat_ptr1 + ((x + BLT.patsx) & 7) * dpxsize;
2034         patcolor = pat_ptr2;
2035         if (colorkey_en & 1) {
2036           rop = blt_colorkey_check(src_ptr1, abs(dpxsize), 0);
2037         }
2038         if (colorkey_en & 2) {
2039           rop |= blt_colorkey_check(dst_ptr1, abs(dpxsize), 1);
2040         }
2041         bx_ternary_rop(BLT.rop[rop], dst_ptr1, src_ptr1, patcolor, abs(dpxsize));
2042       }
2043       src_ptr1 += dpxsize;
2044       dst_ptr1 += dpxsize;
2045       x++;
2046     } while (--ncols);
2047     src_ptr += spitch;
2048     dst_ptr += dpitch;
2049     if (BLT.y_dir) {
2050       dy--;
2051     } else {
2052       dy++;
2053     }
2054   } while (--nrows);
2055   blt_complete();
2056   BX_UNLOCK(render_mutex);
2057 }
2058 
blt_screen_to_screen_stretch()2059 void bx_banshee_c::blt_screen_to_screen_stretch()
2060 {
2061   Bit8u *dst_ptr, *dst_ptr1, *src_ptr, *src_ptr1;
2062   Bit8u dpxsize = (BLT.dst_fmt > 1) ? (BLT.dst_fmt - 1) : 1;
2063   int spitch = BLT.src_pitch;
2064   int dpitch = BLT.dst_pitch;
2065   Bit8u colorkey_en = BLT.reg[blt_commandExtra] & 3;
2066   Bit8u rop = 0;
2067   int nrows, stepy;
2068   int dx, dy, x2, x3, y2, y3, w0, h0, w1, h1;
2069   double fx, fy;
2070 
2071   w0 = BLT.src_w;
2072   h0 = BLT.src_h;
2073   w1 = BLT.dst_w;
2074   h1 = BLT.dst_h;
2075   BX_DEBUG(("Screen to screen stretch blt: : %d x %d -> %d x %d  ROP0 %02X",
2076             w0, h0, w1, h1, BLT.rop[0]));
2077   if (BLT.dst_fmt != BLT.src_fmt) {
2078     BX_ERROR(("Pixel format conversion not supported yet"));
2079   }
2080   BX_LOCK(render_mutex);
2081   dy = BLT.dst_y;
2082   dst_ptr = &v->fbi.ram[BLT.dst_base + dy * dpitch + BLT.dst_x * dpxsize];
2083   src_ptr = &v->fbi.ram[BLT.src_base + BLT.src_y * spitch + BLT.src_x * dpxsize];
2084   if (BLT.y_dir) {
2085     spitch *= -1;
2086     dpitch *= -1;
2087     stepy = -1;
2088   } else {
2089     stepy = 1;
2090   }
2091   fx = (double)w1 / (double)w0;
2092   fy = (double)h1 / (double)h0;
2093   y2 = 0;
2094   nrows = h1;
2095   do {
2096     dst_ptr1 = dst_ptr;
2097     x2 = 0;
2098     for (dx = BLT.dst_x; dx < (BLT.dst_x + w1); dx++) {
2099       if (blt_clip_check(dx, dy)) {
2100         x3 = (int)((double)x2 / fx + 0.49f);
2101         y3 = (int)((double)y2 / fy + 0.49f);
2102         src_ptr1 = src_ptr + (y3 * spitch + x3 * dpxsize);
2103         if (colorkey_en & 1) {
2104           rop = blt_colorkey_check(src_ptr1, dpxsize, 0);
2105         }
2106         if (colorkey_en & 2) {
2107           rop |= blt_colorkey_check(dst_ptr1, dpxsize, 1);
2108         }
2109         BLT.rop_fn[rop](dst_ptr1, src_ptr1, dpitch, dpxsize, dpxsize, 1);
2110       }
2111       dst_ptr1 += dpxsize;
2112       x2++;
2113     }
2114     dst_ptr += dpitch;
2115     dy += stepy;
2116     y2++;
2117   } while (--nrows);
2118   blt_complete();
2119   BX_UNLOCK(render_mutex);
2120 }
2121 
blt_host_to_screen()2122 void bx_banshee_c::blt_host_to_screen()
2123 {
2124   Bit32u dpitch = BLT.dst_pitch;
2125   Bit8u dpxsize = (BLT.dst_fmt > 1) ? (BLT.dst_fmt - 1) : 1;
2126   Bit8u colorkey_en = BLT.reg[blt_commandExtra] & 3;
2127   Bit8u rop = 0;
2128   Bit8u *src_ptr = &BLT.lamem[0];
2129   Bit8u *dst_ptr, *dst_ptr1, *src_ptr1;
2130   Bit16u spitch = BLT.h2s_pitch;
2131   Bit8u srcfmt = BLT.src_fmt;
2132   Bit8u pxpack = (BLT.reg[blt_srcFormat] >> 22) & 3;
2133   Bit8u spxsize = 0, r = 0, g = 0, b = 0;
2134   Bit8u scolor[4];
2135   Bit8u *color;
2136   int nrows, x, y, w, h, xs;
2137   Bit8u smask = 0;
2138   bool set;
2139 
2140   w = BLT.dst_w;
2141   h = BLT.dst_h;
2142   BX_DEBUG(("Host to screen blt: %d x %d  ROP0 %02X", w, h, BLT.rop[0]));
2143   if ((pxconv_table[srcfmt] & (1 << BLT.dst_fmt)) == 0) {
2144     BX_ERROR(("Pixel format conversion not supported"));
2145   }
2146   BX_LOCK(render_mutex);
2147   if (srcfmt > 0) {
2148     if (srcfmt == 1) {
2149       spxsize = 1;
2150     } else if ((srcfmt >= 3) && (srcfmt <= 5)) {
2151       spxsize = srcfmt - 1;
2152     } else {
2153       spxsize = 4;
2154     }
2155   }
2156   y = BLT.dst_y;
2157   xs = BLT.h2s_pxstart;
2158   dst_ptr = &v->fbi.ram[BLT.dst_base + y * dpitch + BLT.dst_x * dpxsize];
2159   nrows = h;
2160   do {
2161     if (srcfmt == 0) {
2162       src_ptr1 = src_ptr + (xs >> 3);
2163       smask = 0x80 >> (xs & 7);
2164     } else {
2165       src_ptr1 = src_ptr + xs;
2166     }
2167     dst_ptr1 = dst_ptr;
2168     for (x = BLT.dst_x; x < (BLT.dst_x + w); x++) {
2169       if (blt_clip_check(x, y)) {
2170         if (srcfmt == 0) {
2171           set = (*src_ptr1 & smask) > 0;
2172           if (set) {
2173             color = &BLT.fgcolor[0];
2174           } else {
2175             color = &BLT.bgcolor[0];
2176           }
2177           if (set || !BLT.transp) {
2178             if (colorkey_en & 2) {
2179               rop = blt_colorkey_check(dst_ptr1, dpxsize, 1);
2180             }
2181             BLT.rop_fn[rop](dst_ptr1, color, dpitch, dpxsize, dpxsize, 1);
2182           }
2183         } else {
2184           if (colorkey_en & 1) {
2185             rop = blt_colorkey_check(src_ptr1, spxsize, 0);
2186           }
2187           if (BLT.dst_fmt != srcfmt) {
2188             if ((srcfmt == 4) || (srcfmt == 5)) {
2189               b = src_ptr1[0];
2190               g = src_ptr1[1];
2191               r = src_ptr1[2];
2192             } else if (srcfmt == 3) {
2193               b = src_ptr1[0] << 3;
2194               g = ((src_ptr1[1] & 0x07) << 5) | ((src_ptr1[0] & 0xe0) >> 3);
2195               r = src_ptr1[1] & 0xf8;
2196             }
2197             if (dpxsize == 2) {
2198               scolor[0] = (b >> 3) | ((g & 0x1c) << 3);
2199               scolor[1] = (g >> 5) | (r & 0xf8);
2200               if (colorkey_en & 2) {
2201                 rop |= blt_colorkey_check(dst_ptr1, dpxsize, 1);
2202               }
2203               BLT.rop_fn[rop](dst_ptr1, scolor, dpitch, dpxsize, dpxsize, 1);
2204             } else if ((dpxsize == 3) || (dpxsize == 4)) {
2205               scolor[0] = b;
2206               scolor[1] = g;
2207               scolor[2] = r;
2208               scolor[3] = 0;
2209               if (colorkey_en & 2) {
2210                 rop |= blt_colorkey_check(dst_ptr1, dpxsize, 1);
2211               }
2212               BLT.rop_fn[rop](dst_ptr1, scolor, dpitch, dpxsize, dpxsize, 1);
2213             }
2214           } else {
2215             if (colorkey_en & 2) {
2216               rop |= blt_colorkey_check(dst_ptr1, dpxsize, 1);
2217             }
2218             BLT.rop_fn[rop](dst_ptr1, src_ptr1, dpitch, dpxsize, dpxsize, 1);
2219           }
2220         }
2221       }
2222       if (srcfmt == 0) {
2223         smask >>= 1;
2224         if (smask == 0) {
2225           src_ptr1++;
2226           smask = 0x80;
2227         }
2228       } else {
2229         src_ptr1 += spxsize;
2230       }
2231       dst_ptr1 += dpxsize;
2232     }
2233     src_ptr += spitch;
2234     if (pxpack == 0) {
2235       if (srcfmt == 0) {
2236         xs += (Bit8u)(BLT.reg[blt_srcFormat] << 3);
2237         xs &= 0x1f;
2238         spitch = ((((w + xs + 7) >> 3) + 3) & ~3);
2239       } else {
2240         xs += (Bit8u)BLT.reg[blt_srcFormat];
2241         xs &= 0x03;
2242         spitch = ((w * spxsize + xs + 3) & ~3);
2243       }
2244     }
2245     if (BLT.y_dir) {
2246       dst_ptr -= dpitch;
2247       y--;
2248     } else {
2249       dst_ptr += dpitch;
2250       y++;
2251     }
2252   } while (--nrows);
2253   blt_complete();
2254   BX_UNLOCK(render_mutex);
2255 }
2256 
blt_host_to_screen_pattern()2257 void bx_banshee_c::blt_host_to_screen_pattern()
2258 {
2259   Bit32u dpitch = BLT.dst_pitch;
2260   Bit8u dpxsize = (BLT.dst_fmt > 1) ? (BLT.dst_fmt - 1) : 1;
2261   Bit8u *src_ptr = &BLT.lamem[0];
2262   Bit8u *dst_ptr, *dst_ptr1, *src_ptr1, *pat_ptr1, *pat_ptr2;
2263   Bit8u *pat_ptr = &BLT.cpat[0][0];
2264   Bit16u spitch = BLT.h2s_pitch;
2265   Bit8u srcfmt = BLT.src_fmt;
2266   Bit8u pxpack = (BLT.reg[blt_srcFormat] >> 22) & 3;
2267   bool patmono = (BLT.reg[blt_command] >> 13) & 1;
2268   bool patrow0 = (BLT.reg[blt_commandExtra] & 0x08) > 0;
2269   Bit8u colorkey_en = BLT.reg[blt_commandExtra] & 3;
2270   Bit8u spxsize = 0;
2271   Bit8u *srccolor, *patcolor;
2272   int nrows, dx, dy, w, h, xs;
2273   Bit8u smask = 0, pmask = 0, rop = 0, patline;
2274   bool set;
2275 
2276   w = BLT.dst_w;
2277   h = BLT.dst_h;
2278   BX_DEBUG(("Host to screen pattern blt: %d x %d  ROP0 %02X", w, h, BLT.rop[0]));
2279   if ((srcfmt != 0) && (BLT.dst_fmt != srcfmt)) {
2280     BX_ERROR(("Pixel format conversion not supported yet"));
2281   }
2282   BX_LOCK(render_mutex);
2283   if (srcfmt > 0) {
2284     if (srcfmt == 1) {
2285       spxsize = 1;
2286     } else if ((srcfmt >= 3) && (srcfmt <= 5)) {
2287       spxsize = srcfmt - 1;
2288     } else {
2289       spxsize = 4;
2290     }
2291   }
2292   dy = BLT.dst_y;
2293   xs = BLT.h2s_pxstart;
2294   dst_ptr = &v->fbi.ram[BLT.dst_base + dy * dpitch + BLT.dst_x * dpxsize];
2295   nrows = h;
2296   do {
2297     if (srcfmt == 0) {
2298       src_ptr1 = src_ptr + (xs >> 3);
2299       smask = 0x80 >> (xs & 7);
2300     } else {
2301       src_ptr1 = src_ptr + xs;
2302     }
2303     if (!patrow0) {
2304       patline = (dy + BLT.patsy) & 7;
2305       if (patmono) {
2306         pat_ptr1 = pat_ptr + patline;
2307       } else {
2308         pat_ptr1 = pat_ptr + patline * dpxsize * 8;
2309       }
2310     } else {
2311       pat_ptr1 = pat_ptr;
2312     }
2313     dst_ptr1 = dst_ptr;
2314     for (dx = BLT.dst_x; dx < (BLT.dst_x + w); dx++) {
2315       if (blt_clip_check(dx, dy)) {
2316         if (srcfmt == 0) {
2317           set = (*src_ptr1 & smask) > 0;
2318           if (set) {
2319             srccolor = &BLT.fgcolor[0];
2320           } else {
2321             srccolor = &BLT.bgcolor[0];
2322           }
2323         } else {
2324           srccolor = src_ptr1;
2325         }
2326         if (patmono) {
2327           pmask = 0x80 >> ((dx + BLT.patsx) & 7);
2328           set = (*pat_ptr1 & pmask) > 0;
2329           if (set) {
2330             patcolor = &BLT.fgcolor[0];
2331           } else {
2332             patcolor = &BLT.bgcolor[0];
2333           }
2334           if (set || !BLT.transp) {
2335             if (colorkey_en & 1) {
2336               rop = blt_colorkey_check(srccolor, dpxsize, 0);
2337             }
2338             if (colorkey_en & 2) {
2339               rop |= blt_colorkey_check(dst_ptr1, dpxsize, 1);
2340             }
2341             bx_ternary_rop(BLT.rop[rop], dst_ptr1, srccolor, patcolor, dpxsize);
2342           }
2343         } else {
2344           pat_ptr2 = pat_ptr1 + ((dx + BLT.patsx) & 7) * dpxsize;
2345           patcolor = pat_ptr2;
2346           if (colorkey_en & 1) {
2347             rop = blt_colorkey_check(srccolor, dpxsize, 0);
2348           }
2349           if (colorkey_en & 2) {
2350             rop |= blt_colorkey_check(dst_ptr1, dpxsize, 1);
2351           }
2352           bx_ternary_rop(BLT.rop[rop], dst_ptr1, srccolor, patcolor, dpxsize);
2353         }
2354       }
2355       if (srcfmt == 0) {
2356         smask >>= 1;
2357         if (smask == 0) {
2358           src_ptr1++;
2359           smask = 0x80;
2360         }
2361       } else {
2362         src_ptr1 += spxsize;
2363       }
2364       dst_ptr1 += dpxsize;
2365     }
2366     src_ptr += spitch;
2367     if (pxpack == 0) {
2368       if (srcfmt == 0) {
2369         xs += (Bit8u)(BLT.reg[blt_srcFormat] << 3);
2370         xs &= 0x1f;
2371         spitch = ((((w + xs + 7) >> 3) + 3) & ~3);
2372       } else {
2373         xs += (Bit8u)BLT.reg[blt_srcFormat];
2374         xs &= 0x03;
2375         spitch = ((w * spxsize + xs + 3) & ~3);
2376       }
2377     }
2378     if (BLT.y_dir) {
2379       dst_ptr -= dpitch;
2380       dy--;
2381     } else {
2382       dst_ptr += dpitch;
2383       dy++;
2384     }
2385   } while (--nrows);
2386   blt_complete();
2387   BX_UNLOCK(render_mutex);
2388 }
2389 
blt_line(bool pline)2390 void bx_banshee_c::blt_line(bool pline)
2391 {
2392   Bit32u dpitch = BLT.dst_pitch;
2393   Bit8u dpxsize = (BLT.dst_fmt > 1) ? (BLT.dst_fmt - 1) : 1;
2394   Bit8u colorkey_en = BLT.reg[blt_commandExtra] & 3;
2395   Bit8u rop = 0;
2396   Bit8u *dst_ptr = &v->fbi.ram[BLT.dst_base];
2397   Bit8u *dst_ptr1;
2398   int i, deltax, deltay, numpixels, d, dinc1, dinc2;
2399   int x, xinc1, xinc2, y, yinc1, yinc2;
2400   int x0, y0, x1, y1;
2401   bool lstipple = ((BLT.reg[blt_command] >> 12) & 1);
2402   Bit8u lpattern = BLT.reg[blt_lineStipple];
2403   Bit8u lrepeat = (BLT.reg[blt_lineStyle] & 0xff);
2404   Bit8u lpat_max = ((BLT.reg[blt_lineStyle] >> 8) & 0x1f);
2405   Bit8u lrep_cnt = lrepeat - ((BLT.reg[blt_lineStyle] >> 16) & 0xff);
2406   Bit8u lpat_idx = ((BLT.reg[blt_lineStyle] >> 24) & 0x1f);
2407 
2408   BX_LOCK(render_mutex);
2409   x0 = BLT.src_x;
2410   y0 = BLT.src_y;
2411   x1 = BLT.dst_x;
2412   y1 = BLT.dst_y;
2413   if (pline) {
2414     BX_DEBUG(("Polyline: %d/%d  -> %d/%d  ROP0 %02X", x0, y0, x1, y1, BLT.rop[0]));
2415   } else {
2416     BX_DEBUG(("Line: %d/%d  -> %d/%d  ROP0 %02X", x0, y0, x1, y1, BLT.rop[0]));
2417   }
2418   deltax = abs(x1 - x0);
2419   deltay = abs(y1 - y0);
2420   if (deltax >= deltay) {
2421     numpixels = deltax + 1;
2422     d = (deltay << 1) - deltax;
2423     dinc1 = deltay << 1;
2424     dinc2 = (deltay - deltax) << 1;
2425     xinc1 = 1;
2426     xinc2 = 1;
2427     yinc1 = 0;
2428     yinc2 = 1;
2429   } else {
2430     numpixels = deltay + 1;
2431     d = (deltax << 1) - deltay;
2432     dinc1 = deltax << 1;
2433     dinc2 = (deltax - deltay) << 1;
2434     xinc1 = 0;
2435     xinc2 = 1;
2436     yinc1 = 1;
2437     yinc2 = 1;
2438   }
2439 
2440   if (x0 > x1) {
2441     xinc1 = -xinc1;
2442     xinc2 = -xinc2;
2443   }
2444   if (y0 > y1) {
2445     yinc1 = -yinc1;
2446     yinc2 = -yinc2;
2447   }
2448   x = x0;
2449   y = y0;
2450 
2451   for (i = 0; i < (numpixels - 1); i++) {
2452     if (blt_clip_check(x, y)) {
2453       dst_ptr1 = dst_ptr + y * dpitch + x * dpxsize;
2454       if (colorkey_en & 2) {
2455         rop = blt_colorkey_check(dst_ptr1, dpxsize, 1);
2456       }
2457       if (!lstipple) {
2458         BLT.rop_fn[rop](dst_ptr1, BLT.fgcolor, dpitch, dpxsize, dpxsize, 1);
2459       } else {
2460         if ((lpattern & (1 << lpat_idx)) != 0) {
2461           BLT.rop_fn[rop](dst_ptr1, BLT.fgcolor, dpitch, dpxsize, dpxsize, 1);
2462         } else if (!BLT.transp) {
2463           BLT.rop_fn[rop](dst_ptr1, BLT.bgcolor, dpitch, dpxsize, dpxsize, 1);
2464         }
2465       }
2466     }
2467     if (lrep_cnt == 0) {
2468       if (++lpat_idx > lpat_max) {
2469         lpat_idx = 0;
2470       }
2471       lrep_cnt = lrepeat;
2472     } else {
2473       lrep_cnt--;
2474     }
2475     if (d < 0) {
2476       d = d + dinc1;
2477       x = x + xinc1;
2478       y = y + yinc1;
2479     } else {
2480       d = d + dinc2;
2481       x = x + xinc2;
2482       y = y + yinc2;
2483     }
2484   }
2485 
2486   if (!pline) {
2487     dst_ptr1 = dst_ptr + y1 * dpitch + x1 * dpxsize;
2488     if (colorkey_en & 2) {
2489       rop = blt_colorkey_check(dst_ptr1, dpxsize, 1);
2490     }
2491     BLT.rop_fn[rop](dst_ptr1, BLT.fgcolor, dpitch, dpxsize, dpxsize, 1);
2492   }
2493   blt_complete();
2494   BLT.reg[blt_srcXY] = BLT.reg[blt_dstXY];
2495   BLT.src_x = BLT.dst_x;
2496   BLT.src_y = BLT.dst_y;
2497   BX_UNLOCK(render_mutex);
2498 }
2499 
calc_line_xpos(int x1,int y1,int x2,int y2,int yc,bool r)2500 int calc_line_xpos(int x1, int y1, int x2, int y2, int yc, bool r)
2501 {
2502   int i, deltax, deltay, numpixels,
2503       d, dinc1, dinc2,
2504       x, xinc1, xinc2,
2505       y, yinc1, yinc2;
2506   int xl = -1, xr = -1;
2507 
2508   if (x1 == x2) {
2509     xl = xr = x1;
2510   } else {
2511     deltax = abs(x2 - x1);
2512     deltay = abs(y2 - y1);
2513     if (deltax >= deltay) {
2514       numpixels = deltax + 1;
2515       d = (deltay << 1) - deltax;
2516       dinc1 = deltay << 1;
2517       dinc2 = (deltay - deltax) << 1;
2518       xinc1 = 1;
2519       xinc2 = 1;
2520       yinc1 = 0;
2521       yinc2 = 1;
2522     } else {
2523       numpixels = deltay + 1;
2524       d = (deltax << 1) - deltay;
2525       dinc1 = deltax << 1;
2526       dinc2 = (deltax - deltay) << 1;
2527       xinc1 = 0;
2528       xinc2 = 1;
2529       yinc1 = 1;
2530       yinc2 = 1;
2531     }
2532 
2533     if (x1 > x2) {
2534       xinc1 = - xinc1;
2535       xinc2 = - xinc2;
2536     }
2537     if (y1 > y2) {
2538       yinc1 = - yinc1;
2539       yinc2 = - yinc2;
2540     }
2541     x = x1;
2542     y = y1;
2543 
2544     for (i = 0; i < numpixels; i++) {
2545       if (y == yc) {
2546         if (xl == -1) {
2547           xl = xr = x;
2548         } else {
2549           if (x < xl) xl = x;
2550           if (x > xr) xr = x;
2551         }
2552       }
2553       if (d < 0) {
2554         d = d + dinc1;
2555         x = x + xinc1;
2556         y = y + yinc1;
2557       } else {
2558         d = d + dinc2;
2559         x = x + xinc2;
2560         y = y + yinc2;
2561       }
2562     }
2563   }
2564   return (r ? xr : xl);
2565 }
2566 
blt_polygon_fill(bool force)2567 void bx_banshee_c::blt_polygon_fill(bool force)
2568 {
2569   Bit32u dpitch = BLT.dst_pitch;
2570   Bit8u dpxsize = (BLT.dst_fmt > 1) ? (BLT.dst_fmt - 1) : 1;
2571   Bit8u *dst_ptr = &v->fbi.ram[BLT.dst_base];
2572   Bit8u *pat_ptr = &BLT.cpat[0][0];
2573   Bit8u *dst_ptr1, *pat_ptr1 = NULL;
2574   bool patmono = (BLT.reg[blt_command] >> 13) & 1;
2575   bool patrow0 = (BLT.reg[blt_commandExtra] & 0x08) > 0;
2576   bool set;
2577   Bit8u colorkey_en = BLT.reg[blt_commandExtra] & 3;
2578   Bit8u rop = 0, mask, patline;
2579   Bit8u *color;
2580   Bit16u x, y, x0, x1, y0, y1;
2581 
2582   if (force) {
2583     if (BLT.pgn_l1y == BLT.pgn_r1y) {
2584       return;
2585     } else if (BLT.pgn_l1y < BLT.pgn_r1y) {
2586       BLT.pgn_l1x = BLT.pgn_r1x;
2587       BLT.pgn_l1y = BLT.pgn_r1y;
2588     } else {
2589       BLT.pgn_r1x = BLT.pgn_l1x;
2590       BLT.pgn_r1y = BLT.pgn_l1y;
2591     }
2592   }
2593   if ((BLT.pgn_l1y > BLT.pgn_l0y) && (BLT.pgn_r1y > BLT.pgn_r0y)) {
2594     BLT.busy = 1;
2595     BX_LOCK(render_mutex);
2596     y0 = BLT.pgn_l0y;
2597     if (BLT.pgn_l1y < BLT.pgn_r1y) {
2598       y1 = BLT.pgn_l1y;
2599     } else {
2600       y1 = BLT.pgn_r1y;
2601     }
2602     for (y = y0; y < y1; y++) {
2603       x0 = calc_line_xpos(BLT.pgn_l0x, BLT.pgn_l0y, BLT.pgn_l1x, BLT.pgn_l1y, y, 0);
2604       if (y <= BLT.pgn_r0y) {
2605         x1 = calc_line_xpos(BLT.pgn_l0x, BLT.pgn_l0y, BLT.pgn_r0x, BLT.pgn_r0y, y, 1);
2606       } else {
2607         x1 = calc_line_xpos(BLT.pgn_r0x, BLT.pgn_r0y, BLT.pgn_r1x, BLT.pgn_r1y, y, 1);
2608       }
2609       if (BLT.pattern_blt) {
2610         if (!patrow0) {
2611           patline = (y + BLT.patsy) & 7;
2612           if (patmono) {
2613             pat_ptr1 = pat_ptr + patline;
2614           } else {
2615             pat_ptr1 = pat_ptr + patline * dpxsize * 8;
2616           }
2617         } else {
2618           pat_ptr1 = pat_ptr;
2619         }
2620       }
2621       dst_ptr1 = dst_ptr + y * dpitch + x0 * dpxsize;
2622       if (blt_clip_check(x0, y)) {
2623         if (colorkey_en & 2) {
2624           rop = blt_colorkey_check(dst_ptr1, dpxsize, 1);
2625         }
2626         if (BLT.pattern_blt) {
2627           if (patmono) {
2628             mask = 0x80 >> ((x0 + BLT.patsx) & 7);
2629             set = (*pat_ptr1 & mask) > 0;
2630             if (set) {
2631               color = &BLT.fgcolor[0];
2632             } else {
2633               color = &BLT.bgcolor[0];
2634             }
2635             if ((set) || !BLT.transp) {
2636               BLT.rop_fn[rop](dst_ptr1, color, dpitch, dpxsize, dpxsize, 1);
2637             }
2638           } else {
2639             color = (pat_ptr1 + ((x0 + BLT.patsx) & 7) * dpxsize);
2640             BLT.rop_fn[rop](dst_ptr1, color, dpitch, dpxsize, dpxsize, 1);
2641           }
2642         } else {
2643           BLT.rop_fn[rop](dst_ptr1, BLT.fgcolor, dpitch, dpxsize, dpxsize, 1);
2644         }
2645       }
2646       dst_ptr1 += dpxsize;
2647       for (x = x0 + 1; x < x1; x++) {
2648         if (blt_clip_check(x, y)) {
2649           if (colorkey_en & 2) {
2650             rop = blt_colorkey_check(dst_ptr1, dpxsize, 1);
2651           }
2652           if (BLT.pattern_blt) {
2653             if (patmono) {
2654               mask = 0x80 >> ((x + BLT.patsx) & 7);
2655               set = (*pat_ptr1 & mask) > 0;
2656               if (set) {
2657                 color = &BLT.fgcolor[0];
2658               } else {
2659                 color = &BLT.bgcolor[0];
2660               }
2661               if ((set) || !BLT.transp) {
2662                 BLT.rop_fn[rop](dst_ptr1, color, dpitch, dpxsize, dpxsize, 1);
2663               }
2664             } else {
2665               color = (pat_ptr1 + ((x + BLT.patsx) & 7) * dpxsize);
2666               BLT.rop_fn[rop](dst_ptr1, color, dpitch, dpxsize, dpxsize, 1);
2667             }
2668           } else {
2669             BLT.rop_fn[rop](dst_ptr1, BLT.fgcolor, dpitch, dpxsize, dpxsize, 1);
2670           }
2671         }
2672         dst_ptr1 += dpxsize;
2673       }
2674     }
2675     BX_DEBUG(("Polygon fill: L0=(%d,%d) L1=(%d,%d) R0=(%d,%d) R1=(%d,%d) ROP0 %02X",
2676               BLT.pgn_l0x, BLT.pgn_l0y, BLT.pgn_l1x, BLT.pgn_l1y,
2677               BLT.pgn_r0x, BLT.pgn_r0y, BLT.pgn_r1x, BLT.pgn_r1y, BLT.rop[0]));
2678     if (y1 == BLT.pgn_l1y) {
2679       BLT.pgn_l0x = BLT.pgn_l1x;
2680       BLT.pgn_l0y = BLT.pgn_l1y;
2681     }
2682     if (y1 == BLT.pgn_r1y) {
2683       BLT.pgn_r0x = BLT.pgn_r1x;
2684       BLT.pgn_r0y = BLT.pgn_r1y;
2685     }
2686     blt_complete();
2687     BX_UNLOCK(render_mutex);
2688   }
2689 }
2690 
2691 #if BX_DEBUGGER
debug_dump(int argc,char ** argv)2692 void bx_banshee_c::debug_dump(int argc, char **argv)
2693 {
2694   bool is_agp = SIM->is_agp_device(BX_PLUGIN_VOODOO);
2695   if (v->banshee.io[io_vidProcCfg] & 0x01) {
2696     if (s.model == VOODOO_BANSHEE) {
2697       dbg_printf("Voodoo Banshee %s adapter\n\n", is_agp ? "AGP":"PCI");
2698     } else {
2699       dbg_printf("Voodoo3 %s adapter\n\n", is_agp ? "AGP":"PCI");
2700     }
2701     dbg_printf("current mode : %u x %u x %u ", v->fbi.width,
2702                v->fbi.height, v->banshee.disp_bpp);
2703     if ((v->banshee.io[io_vidProcCfg] & 0x180) == 0x080) {
2704       dbg_printf("(2D desktop mode)\n");
2705     } else if ((v->banshee.io[io_vidProcCfg] & 0x180) == 0x100) {
2706       dbg_printf("(3D overlay mode)\n");
2707     } else {
2708       dbg_printf("\n");
2709     }
2710     if (argc > 0) {
2711       dbg_printf("\nAdditional options not supported\n");
2712     }
2713   } else {
2714     theVoodooVga->debug_dump(argc, argv);
2715   }
2716 }
2717 #endif
2718 
2719 #undef BLT
2720 
2721 #undef LOG_THIS
2722 #define LOG_THIS theVoodooVga->
2723 
bx_voodoo_vga_c()2724 bx_voodoo_vga_c::bx_voodoo_vga_c() : bx_vgacore_c()
2725 {
2726   put("VVGA");
2727 }
2728 
~bx_voodoo_vga_c()2729 bx_voodoo_vga_c::~bx_voodoo_vga_c()
2730 {
2731   s.memory = NULL;
2732 }
2733 
init_vga_extension(void)2734 bool bx_voodoo_vga_c::init_vga_extension(void)
2735 {
2736   bool ret = 0;
2737 
2738   Bit8u model = (Bit8u)SIM->get_param_enum("model", (bx_list_c*)SIM->get_param(BXPN_VOODOO))->get();
2739   if (model < VOODOO_BANSHEE) {
2740     theVoodooDevice = new bx_voodoo_1_2_c();
2741     theVoodooDevice->init();
2742     init_iohandlers(read_handler, write_handler);
2743   } else {
2744     theVoodooDevice = new bx_banshee_c();
2745     theVoodooDevice->init();
2746     BX_VVGA_THIS s.memory = v->fbi.ram;
2747     BX_VVGA_THIS s.memsize = v->fbi.mask + 1;
2748     init_iohandlers(banshee_vga_read_handler, banshee_vga_write_handler);
2749     DEV_register_iowrite_handler(this, banshee_vga_write_handler, 0x0102, "banshee", 1);
2750     DEV_register_iowrite_handler(this, banshee_vga_write_handler, 0x46e8, "banshee", 1);
2751     BX_VVGA_THIS s.max_xres = 1600;
2752     BX_VVGA_THIS s.max_yres = 1280;
2753     v->banshee.disp_bpp = 8;
2754     BX_VVGA_THIS s.vclk[0] = 25175000;
2755     BX_VVGA_THIS s.vclk[1] = 28322000;
2756     BX_VVGA_THIS s.vclk[2] = 50000000;
2757     BX_VVGA_THIS s.vclk[3] = 25175000;
2758     BX_VVGA_THIS pci_enabled = 1;
2759     ret = 1;
2760   }
2761 #if BX_DEBUGGER
2762   // register device for the 'info device' command (calls debug_dump())
2763   bx_dbg_register_debug_info("voodoo", theVoodooDevice);
2764 #endif
2765   return ret;
2766 }
2767 
reset(unsigned type)2768 void bx_voodoo_vga_c::reset(unsigned type)
2769 {
2770   theVoodooDevice->reset(type);
2771 }
2772 
register_state(void)2773 void bx_voodoo_vga_c::register_state(void)
2774 {
2775   bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "voodoo_vga", "Voodoo VGA State");
2776   BX_VVGA_THIS vgacore_register_state(list);
2777   theVoodooDevice->register_state();
2778 }
2779 
after_restore_state(void)2780 void bx_voodoo_vga_c::after_restore_state(void)
2781 {
2782   bx_vgacore_c::after_restore_state();
2783   theVoodooDevice->after_restore_state();
2784 }
2785 
redraw_area(unsigned x0,unsigned y0,unsigned width,unsigned height)2786 void bx_voodoo_vga_c::redraw_area(unsigned x0, unsigned y0, unsigned width,
2787                                   unsigned height)
2788 {
2789   if (v->banshee.io[io_vidProcCfg] & 0x01) {
2790     theVoodooDevice->redraw_area(x0, y0, width, height);
2791   } else {
2792     bx_vgacore_c::redraw_area(x0, y0, width, height);
2793   }
2794 }
2795 
banshee_update_mode(void)2796 void bx_voodoo_vga_c::banshee_update_mode(void)
2797 {
2798   Bit8u format = (v->banshee.io[io_vidProcCfg] >> 18) & 0x07;
2799 
2800   if (format < 4) {
2801     v->banshee.disp_bpp = (format + 1) << 3;
2802   } else {
2803     BX_ERROR(("Ignoring reserved pixel format"));
2804     return;
2805   }
2806   v->banshee.half_mode = (v->banshee.io[io_vidProcCfg] >> 4) & 1;
2807   BX_INFO(("switched to %d x %d x %d @ %d Hz", v->fbi.width, v->fbi.height,
2808            v->banshee.disp_bpp, (unsigned)v->vertfreq));
2809   bx_gui->dimension_update(v->fbi.width, v->fbi.height, 0, 0, v->banshee.disp_bpp);
2810   // compatibilty settings for VGA core
2811   BX_VVGA_THIS s.last_xres = v->fbi.width;
2812   BX_VVGA_THIS s.last_yres = v->fbi.height;
2813   BX_VVGA_THIS s.last_bpp = v->banshee.disp_bpp;
2814   BX_VVGA_THIS s.last_fh = 0;
2815 }
2816 
banshee_set_dac_mode(bool mode)2817 void bx_voodoo_vga_c::banshee_set_dac_mode(bool mode)
2818 {
2819   unsigned i;
2820 
2821   if (mode != v->banshee.dac_8bit) {
2822     if (mode) {
2823       for (i=0; i<256; i++) {
2824         s.pel.data[i].red <<= 2;
2825         s.pel.data[i].green <<= 2;
2826         s.pel.data[i].blue <<= 2;
2827       }
2828       BX_INFO(("DAC in 8 bit mode"));
2829     } else {
2830       for (i=0; i<256; i++) {
2831         s.pel.data[i].red >>= 2;
2832         s.pel.data[i].green >>= 2;
2833         s.pel.data[i].blue >>= 2;
2834       }
2835       BX_INFO(("DAC in standard mode"));
2836     }
2837     v->banshee.dac_8bit = mode;
2838     s.dac_shift = mode ? 0 : 2;
2839   }
2840 }
2841 
banshee_set_vclk3(Bit32u value)2842 void bx_voodoo_vga_c::banshee_set_vclk3(Bit32u value)
2843 {
2844   BX_VVGA_THIS s.vclk[3] = value;
2845   if (BX_VVGA_THIS s.misc_output.clock_select == 3) {
2846     calculate_retrace_timing();
2847   }
2848 }
2849 
get_retrace()2850 Bit32u bx_voodoo_vga_c::get_retrace()
2851 {
2852   Bit32u retval = 1;
2853   Bit64u display_usec =
2854     bx_virt_timer.time_usec(BX_VVGA_THIS vsync_realtime) % BX_VVGA_THIS s.vtotal_usec;
2855   if ((display_usec >= BX_VVGA_THIS s.vrstart_usec) &&
2856       (display_usec <= BX_VVGA_THIS s.vrend_usec)) {
2857     retval = 0;
2858   }
2859   return retval;
2860 }
2861 
get_crtc_params(bx_crtc_params_t * crtcp,Bit32u * vclock)2862 void bx_voodoo_vga_c::get_crtc_params(bx_crtc_params_t *crtcp, Bit32u *vclock)
2863 {
2864   *vclock = BX_VVGA_THIS s.vclk[BX_VVGA_THIS s.misc_output.clock_select];
2865   crtcp->htotal = BX_VVGA_THIS s.CRTC.reg[0] + ((v->banshee.crtc[0x1a] & 0x01) << 8) + 5;
2866   crtcp->vtotal = BX_VVGA_THIS s.CRTC.reg[6] + ((BX_VVGA_THIS s.CRTC.reg[7] & 0x01) << 8) +
2867                   ((BX_VVGA_THIS s.CRTC.reg[7] & 0x20) << 4) +
2868                   ((v->banshee.crtc[0x1b] & 0x01) << 10) + 2;
2869   crtcp->vrstart = BX_VVGA_THIS s.CRTC.reg[16] +
2870                    ((BX_VVGA_THIS s.CRTC.reg[7] & 0x04) << 6) +
2871                    ((BX_VVGA_THIS s.CRTC.reg[7] & 0x80) << 2) +
2872                    ((v->banshee.crtc[0x1b] & 0x40) << 4);
2873 }
2874 
update(void)2875 void bx_voodoo_vga_c::update(void)
2876 {
2877   if (v->banshee.io[io_vidProcCfg] & 0x01) {
2878     theVoodooDevice->update();
2879   } else if (!((v->banshee.io[io_vgaInit0] >> 12) & 1)) {
2880     BX_VVGA_THIS bx_vgacore_c::update();
2881   }
2882 }
2883 
banshee_vga_read_handler(void * this_ptr,Bit32u address,unsigned io_len)2884 Bit32u bx_voodoo_vga_c::banshee_vga_read_handler(void *this_ptr, Bit32u address, unsigned io_len)
2885 {
2886   UNUSED(this_ptr);
2887   Bit32u value;
2888 
2889   if ((io_len == 2) && ((address & 1) == 0)) {
2890     value = banshee_vga_read_handler(theVoodooVga,address,1);
2891     value |= (banshee_vga_read_handler(theVoodooVga,address+1,1) << 8);
2892     return value;
2893   }
2894 
2895   if (BX_VVGA_THIS s.misc_output.color_emulation && (address == 0x03b5))
2896     return 0xff;
2897   if (!BX_VVGA_THIS s.misc_output.color_emulation && (address == 0x03d5))
2898     return 0xff;
2899 
2900   switch (address) {
2901     case 0x03b5:
2902     case 0x03d5:
2903       if (BX_VVGA_THIS s.CRTC.address > 0x18) {
2904         if (BX_VVGA_THIS s.CRTC.address == 0x22) {
2905           value = bx_vgacore_c::read_handler(BX_VVGA_THIS_PTR, address, io_len);
2906         } else if (BX_VVGA_THIS s.CRTC.address <= 0x26) {
2907           if ((v->banshee.io[io_vgaInit0] & 0x440) == 0x040) {
2908             value = v->banshee.crtc[BX_VVGA_THIS s.CRTC.address];
2909             BX_DEBUG(("read from banshee CRTC address 0x%02x value 0x%02x",
2910                       BX_VVGA_THIS s.CRTC.address, value));
2911           } else {
2912             value = 0xff;
2913           }
2914         } else {
2915           value = 0xff;
2916         }
2917         break;
2918       }
2919     default:
2920       value = bx_vgacore_c::read_handler(BX_VVGA_THIS_PTR, address, io_len);
2921   }
2922   return value;
2923 
2924 }
2925 
banshee_vga_write_handler(void * this_ptr,Bit32u address,Bit32u value,unsigned io_len)2926 void bx_voodoo_vga_c::banshee_vga_write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
2927 {
2928   UNUSED(this_ptr);
2929   Bit8u value8;
2930 
2931   if ((io_len == 2) && ((address & 1) == 0)) {
2932     banshee_vga_write_handler(theVoodooVga,address,value & 0xff,1);
2933     banshee_vga_write_handler(theVoodooVga,address+1,value >> 8,1);
2934     return;
2935   }
2936 
2937   if (BX_VVGA_THIS s.misc_output.color_emulation && (address == 0x03b5))
2938     return;
2939   if (!BX_VVGA_THIS s.misc_output.color_emulation && (address == 0x03d5))
2940     return;
2941 
2942   switch (address) {
2943     case 0x0102:
2944     case 0x46e8:
2945       // TODO
2946       return;
2947 
2948     case 0x03c9:
2949       value8 = (Bit8u)value;
2950       if (!v->banshee.dac_8bit) value8 <<= 2;
2951       switch (BX_VVGA_THIS s.pel.write_data_cycle) {
2952         case 0:
2953           v->fbi.clut[BX_VVGA_THIS s.pel.write_data_register] &= 0x00ffff;
2954           v->fbi.clut[BX_VVGA_THIS s.pel.write_data_register] |= (value8 << 16);
2955           break;
2956         case 1:
2957           v->fbi.clut[BX_VVGA_THIS s.pel.write_data_register] &= 0xff00ff;
2958           v->fbi.clut[BX_VVGA_THIS s.pel.write_data_register] |= (value8 << 8);
2959           break;
2960         case 2:
2961           v->fbi.clut[BX_VVGA_THIS s.pel.write_data_register] &= 0xffff00;
2962           v->fbi.clut[BX_VVGA_THIS s.pel.write_data_register] |= value8;
2963           break;
2964       }
2965       break;
2966 
2967     case 0x03b5:
2968     case 0x03d5:
2969       if (BX_VVGA_THIS s.CRTC.address > 0x18) {
2970         if (BX_VVGA_THIS s.CRTC.address <= 0x26) {
2971           if ((v->banshee.io[io_vgaInit0] & 0x440) == 0x040) {
2972             BX_DEBUG(("write to banshee CRTC address 0x%02x value 0x%02x",
2973                       BX_VVGA_THIS s.CRTC.address, value));
2974             v->banshee.crtc[BX_VVGA_THIS s.CRTC.address] = (Bit8u)value;
2975           }
2976         }
2977         return;
2978       }
2979       break;
2980   }
2981   bx_vgacore_c::write_handler(theVoodooVga, address, value, io_len);
2982 }
2983 
mem_read(bx_phy_address addr)2984 Bit8u bx_voodoo_vga_c::mem_read(bx_phy_address addr)
2985 {
2986   Bit32u offset = ((v->banshee.io[io_vgaInit1] & 0xffc00) << 5) + (addr & 0x1ffff);
2987   bool chain4 = ((v->banshee.io[io_vgaInit1] >> 20) & 1);
2988 
2989   if (chain4) {
2990     return v->fbi.ram[offset & v->fbi.mask];
2991   } else {
2992     return bx_vgacore_c::mem_read(addr);
2993   }
2994 }
2995 
mem_write(bx_phy_address addr,Bit8u value)2996 void bx_voodoo_vga_c::mem_write(bx_phy_address addr, Bit8u value)
2997 {
2998   bool chain4 = ((v->banshee.io[io_vgaInit1] >> 20) & 1);
2999   Bit32u offset, start, end, pitch;
3000   unsigned xti, yti;
3001 
3002   if (chain4) {
3003     offset = (((v->banshee.io[io_vgaInit1] & 0x3ff) << 15) + (addr & 0x1ffff)) & v->fbi.mask;
3004     v->fbi.ram[offset] = value;
3005     start = v->banshee.io[io_vidDesktopStartAddr] & v->fbi.mask;
3006     pitch = v->banshee.io[io_vidDesktopOverlayStride] & 0x7fff;
3007     end = start + pitch * v->fbi.height;
3008     if ((offset >= start) && (offset < end)) {
3009       offset -= start;
3010       if (v->banshee.half_mode) {
3011         yti = (offset / pitch) / (Y_TILESIZE / 2);
3012       } else {
3013         yti = (offset / pitch) / Y_TILESIZE;
3014       }
3015       xti = ((offset % pitch) / (v->banshee.disp_bpp >> 3)) / X_TILESIZE;
3016       theVoodooDevice->set_tile_updated(xti, yti, 1);
3017     }
3018   } else {
3019     bx_vgacore_c::mem_write(addr, value);
3020   }
3021 }
3022 
3023 #endif // BX_SUPPORT_PCI && BX_SUPPORT_VOODOO
3024