X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fdevices%2Fvga.c;h=de6bc66c6300fb49c37789a6221ad251d1315ff5;hb=7d780533980c895368aa404cbdd54f7bc2d91b40;hp=834f780f0731bd46fc89f8049b1588b240418c6f;hpb=4aaddb894098d739868ac4d6a5e74a8787578f89;p=palacios.git diff --git a/palacios/src/devices/vga.c b/palacios/src/devices/vga.c index 834f780..de6bc66 100644 --- a/palacios/src/devices/vga.c +++ b/palacios/src/devices/vga.c @@ -272,7 +272,7 @@ struct vga_dac_regs { struct vga_internal { - struct vm_device *dev; + struct vm_device *dev; bool passthrough; bool skip_next_passthrough_out; // for word access @@ -320,6 +320,8 @@ struct vga_internal { }; +typedef enum {PLANAR_SHIFT, PACKED_SHIFT, C256_SHIFT} shift_mode_t; + static void find_text_char_dim(struct vga_internal *vga, uint32_t *w, uint32_t *h) { @@ -462,30 +464,26 @@ static void find_graphics_res(struct vga_internal *vga, uint32_t *width, uint32_ } -static void find_graphics_cursor_pos(struct vga_internal *vga, uint32_t *width, uint32_t *height) +static void find_graphics_cursor_pos(struct vga_internal *vga, uint32_t *x, uint32_t *y) { - + // todo + *x=*y=0; } -static void render_graphics(struct vga_internal *vga, void *fb) -{ - PrintDebug("vga: render_graphics is unimplemented\n"); - // Multiuplane 16 - // Packed pixel mono - // packed pixel 4 color - // packed pixel 256 color - - find_graphics_cursor_pos(0,0,0); - -} - -static void render_text_cursor(struct vga_internal *vga, void *fb) +static void find_shift_mode(struct vga_internal *vga, shift_mode_t *mode) { + if (vga->vga_graphics_controller.vga_graphics_mode.c256) { + *mode=C256_SHIFT; + } else { + if (vga->vga_graphics_controller.vga_graphics_mode.shift_reg_mode) { + *mode=PACKED_SHIFT; + } else { + *mode=PLANAR_SHIFT; + } + } } - - static void dac_lookup_24bit_color(struct vga_internal *vga, uint8_t entry, uint8_t *red, @@ -503,6 +501,207 @@ static void dac_lookup_24bit_color(struct vga_internal *vga, } + +/* + Colors work like this: + + 4 bit modes: index is to the internal palette on the attribute controller + that supplies 6 bits, but we need 8 to index the dac + 2 more (the msbs) are supplied from the color select register + we can optionally overwrite bits 5 and 4 from the color + select register as well, depending on a selection bit + in the mode control register. The result of all this is + 8 bit index for the dac + + 8 bit modes: the attribute controller passes the index straight through + to the DAC. + + + The DAC translates from the 8 bit index into 6 bits per color channel + (18 bit color). We mulitply by 4 to get 24 bit color. +*/ + +static void find_24bit_color(struct vga_internal *vga, + uint8_t val, + uint8_t *red, + uint8_t *green, + uint8_t *blue) +{ + uint8_t di; // ultimate dac index + + if (vga->vga_attribute_controller.vga_attribute_mode_control.pixel_width) { + // 8 bit mode does right to the DAC + di=val; + } else { + struct vga_internal_palette_reg pr = vga->vga_attribute_controller.vga_internal_palette[val%16]; + di = pr.palette_data; + + // Fix bits 5-4 if needed + if (vga->vga_attribute_controller.vga_attribute_mode_control.p54_select) { + di &= ~0x30; // clear 5-4 + di |= vga->vga_attribute_controller.vga_color_select.sc4 << 4; + di |= vga->vga_attribute_controller.vga_color_select.sc5 << 5; + } + + // We must always produce bits 6 and 7 + di &= ~0xc0; // clear 7-6 + di |= vga->vga_attribute_controller.vga_color_select.sc6 << 6; + di |= vga->vga_attribute_controller.vga_color_select.sc7 << 7; + } + + dac_lookup_24bit_color(vga,di,red,green,blue); +} + +static void render_graphics(struct vga_internal *vga, void *fb) +{ + + struct v3_frame_buffer_spec *spec = &(vga->target_spec); + + uint32_t gw, gh; // graphics w/h + uint32_t fw, fh; // fb w/h + uint32_t rgw, rgh; // region we can actually show on the frame buffer + + + uint32_t fx, fy; // pixel position within the frame buffer + + uint32_t offset; // offset into the maps + uint8_t m; // map + uint8_t p; // pixel in the current map byte (0..7) + + uint8_t r,g,b; // looked up colors for entry + + void *pixel; // current pixel in the fb + uint8_t *red; // and the channels in the pixel + uint8_t *green; // + uint8_t *blue; // + + uint8_t db[4]; // 4 bytes read at a time + uint8_t pb[8]; // 8 pixels assembled at a time + + shift_mode_t sm; // shift mode + + uint32_t cur_x, cur_y; + + + find_graphics_res(vga,&gw,&gh); + + find_shift_mode(vga,&sm); + + find_graphics_cursor_pos(vga,&cur_x,&cur_y); + + fw = spec->width; + fh = spec->height; + + + PrintDebug("vga: attempting graphics render (%s): graphics_res=(%u,%u), fb_res=(%u,%u), " + "fb=0x%p (16 color mode)\n", + sm == PLANAR_SHIFT ? "planar shift" : + sm == PACKED_SHIFT ? "packed shift" : + sm == C256_SHIFT ? "color256 shift" : "UNKNOWN", + gw,gh,fw,fh, fb); + + // First we need to clip to what we can actually show + rgw = gw < fw ? gw : fw; + rgh = gh < fh ? gh : gw; + + if (gw%8) { + PrintError("vga: warning: graphics width is not a multiple of 8\n"); + } + + offset=0; // do we always start at zero in the map? + + // Now we scan across by row + for (fy=0;fymap[m]+offset)); + } + + // assemble + switch (sm) { + case PLANAR_SHIFT: + for (p=0;p<8;p++) { + pb[p]= + ( db[0] >> 7) | + ( db[1] >> 6) | + ( db[2] >> 5) | + ( db[3] >> 4) ; + + for (m=0;m<4;m++) { + db[m] <<= 1; + } + } + break; + + case PACKED_SHIFT: + // first 4 pixels use planes 0 and 2 + for (p=0;p<4;p++) { + pb[p] = + ( db[2] >> 4) | + ( db[0] >> 6) ; + db[2] <<= 2; + db[0] <<= 2; + } + break; + + // next 4 pixels use planes 1 and 3 + for (p=4;p<8;p++) { + pb[p] = + ( db[3] >> 4) | + ( db[1] >> 6) ; + db[3] <<= 2; + db[1] <<= 2; + } + break; + + case C256_SHIFT: + // this one is either very bizarre or as simple as this + for (p=0;p<4;p++) { + pb[p] = db[p]; + } + break; + } + + // draw each pixel + for (p=0;p< (sm==C256_SHIFT ? 4 : 8);p++) { + + // find its color + find_24bit_color(vga,db[p],&r,&g,&b); + + // find its position in the framebuffer; + pixel = fb + (((fx + p) + (fy*spec->width)) * spec->bytes_per_pixel); + red = pixel + spec->red_offset; + green = pixel + spec->green_offset; + blue = pixel + spec->blue_offset; + + // draw it + *red=r; + *green=g; + *blue=b; + } + } + } + } + + PrintDebug("vga: render done\n"); +} + + +static void render_text_cursor(struct vga_internal *vga, void *fb) +{ +} + + + + // // A variant of this function could render to // a text console interface as well @@ -593,22 +792,22 @@ static void render_text(struct vga_internal *vga, void *fb) // foreground if (!extended_fontset(vga)) { - fg_entry = ((uint8_t)(a.foreground_intensity_or_font_select)) << 3; + fg_entry = a.foreground_intensity_or_font_select << 3; } else { fg_entry = 0; } fg_entry |= a.fore; - dac_lookup_24bit_color(vga,fg_entry,&fgr,&fgg,&fgb); + find_24bit_color(vga,fg_entry,&fgr,&fgg,&fgb); if (!blinking(vga)) { - bg_entry = ((uint8_t)(a.blinking_or_bg_intensity)) << 3; + bg_entry = a.blinking_or_bg_intensity << 3; } else { bg_entry = 0; } bg_entry |= a.back; - dac_lookup_24bit_color(vga,bg_entry,&bgr,&bgg,&bgb); + find_24bit_color(vga,bg_entry,&bgr,&bgg,&bgb); // Draw the character for (l=0; lhost_cons,&(vga->target_spec)); - // Draw some crap for testing for now - if (0) { render_test(vga,fb);} - // Draw the maps for debugging - if (0) { render_maps(vga,fb);} - if (vga->vga_graphics_controller.vga_misc.graphics_mode) { render_graphics(vga,fb); } else { @@ -769,8 +963,9 @@ static int render(struct vga_internal *vga) render_text_cursor(vga,fb); } - render_maps(vga,fb); + if (0) { render_test(vga,fb); } + render_maps(vga,fb); v3_graphics_console_release_frame_buffer_data_rw(vga->host_cons); } @@ -887,10 +1082,6 @@ static int vga_write(struct guest_info * core, /* Write mode determine by Graphics Mode Register (Index 05h).writemode */ - // Probably need to add odd/even mode access here for text - - PrintDebug("vga: write is with odd/even = %u\n", vga->vga_sequencer.vga_mem_mode.odd_even); - switch (vga->vga_graphics_controller.vga_graphics_mode.write_mode) { case 0: { @@ -925,7 +1116,7 @@ static int vga_write(struct guest_info * core, uint8_t bm = vga->vga_graphics_controller.vga_bit_mask; uint8_t mm = find_map_write(vga,guest_addr+i); - PrintDebug("vga: write i=%u, mm=0x%x, offset=0x%x\n",i,(unsigned int)mm,(unsigned int)offset); + //PrintDebug("vga: write i=%u, mm=0x%x, offset=0x%x\n",i,(unsigned int)mm,(unsigned int)offset); for (mapnum=0;mapnum<4;mapnum++, sr>>=1, esr>>=1, bm>>=1, mm>>=1) { vga_map map = vga->map[mapnum];