Changeset 33851 in vbox for trunk/src/VBox/Devices/Graphics
- Timestamp:
- Nov 8, 2010 2:38:43 PM (14 years ago)
- svn:sync-xref-src-repo-rev:
- 67497
- Location:
- trunk/src/VBox/Devices/Graphics
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Graphics/DevVGA.cpp
r33676 r33851 489 489 #endif /* IN_RING3 */ 490 490 491 /* Update the values needed for calculating Vertical Retrace and 492 * Display Enable status bits more or less accurately. The Display Enable 493 * bit is set (indicating *disabled* display signal) when either the 494 * horizontal (hblank) or vertical (vblank) blanking is active. The 495 * Vertical Retrace bit is set when vertical retrace (vsync) is active. 496 * Unless the CRTC is horribly misprogrammed, vsync implies vblank. 497 */ 498 static void vga_update_retrace_state(VGAState *s) 499 { 500 unsigned htotal_cclks, vtotal_lines, chars_per_sec; 501 unsigned hblank_start_cclk, hblank_end_cclk, hblank_width, hblank_skew_cclks; 502 unsigned vsync_start_line, vsync_end, vsync_width; 503 unsigned vblank_start_line, vblank_end, vblank_width; 504 unsigned char_dots, clock_doubled, clock_index; 505 const int clocks[] = {25175000, 28322000, 25175000, 25175000}; 506 vga_retrace_s *r = &s->retrace_state; 507 508 /* For horizontal timings, we only care about the blanking start/end. */ 509 htotal_cclks = s->cr[0x00] + 5; 510 hblank_start_cclk = s->cr[0x02]; 511 hblank_end_cclk = (s->cr[0x03] & 0x1f) + ((s->cr[0x05] & 0x80) >> 2); 512 hblank_skew_cclks = (s->cr[0x03] >> 5) & 3; 513 514 /* For vertical timings, we need both the blanking start/end... */ 515 vtotal_lines = s->cr[0x06] + ((s->cr[0x07] & 1) << 8) + ((s->cr[0x07] & 0x20) << 4) + 2; 516 vblank_start_line = s->cr[0x15] + ((s->cr[0x07] & 8) << 5) + ((s->cr[0x09] & 0x20) << 4); 517 vblank_end = s->cr[0x16]; 518 /* ... and the vertical retrace (vsync) start/end. */ 519 vsync_start_line = s->cr[0x10] + ((s->cr[0x07] & 4) << 6) + ((s->cr[0x07] & 0x80) << 2); 520 vsync_end = s->cr[0x11] & 0xf; 521 522 /* Calculate the blanking and sync widths. The way it's implemented in 523 * the VGA with limited-width compare counters is quite a piece of work. 524 */ 525 hblank_width = (hblank_end_cclk - hblank_start_cclk) & 0x3f;/* 6 bits */ 526 vblank_width = (vblank_end - vblank_start_line) & 0xff; /* 8 bits */ 527 vsync_width = (vsync_end - vsync_start_line) & 0xf; /* 4 bits */ 528 529 /* Calculate the dot and character clock rates. */ 530 clock_doubled = (s->sr[0x01] >> 3) & 1; /* Clock doubling bit. */ 531 clock_index = (s->msr >> 2) & 3; 532 char_dots = (s->sr[0x01] & 1) ? 8 : 9; /* 8 or 9 dots per cclk. */ 533 534 chars_per_sec = clocks[clock_index] / char_dots; 535 Assert(chars_per_sec); /* Can't possibly be zero. */ 536 537 htotal_cclks <<= clock_doubled; 538 539 /* Calculate the number of cclks per entire frame. */ 540 r->frame_cclks = vtotal_lines * htotal_cclks; 541 Assert(r->frame_cclks); /* Can't possibly be zero. */ 542 543 if (r->v_freq_hz) { /* Could be set to emulate a specific rate. */ 544 r->cclk_ns = 1000000000 / (r->frame_cclks * r->v_freq_hz); 545 } else { 546 r->cclk_ns = 1000000000 / chars_per_sec; 547 } 548 Assert(r->cclk_ns); 549 r->frame_ns = r->frame_cclks * r->cclk_ns; 550 551 /* Calculate timings in cclks/lines. Stored but not directly used. */ 552 r->hb_start = hblank_start_cclk + hblank_skew_cclks; 553 r->hb_end = hblank_start_cclk + hblank_width + hblank_skew_cclks; 554 r->h_total = htotal_cclks; 555 Assert(r->h_total); /* Can't possibly be zero. */ 556 557 r->vb_start = vblank_start_line; 558 r->vb_end = vblank_start_line + vblank_width + 1; 559 r->vs_start = vsync_start_line; 560 r->vs_end = vsync_start_line + vsync_width + 1; 561 562 /* Calculate timings in nanoseconds. For easier comparisons, the frame 563 * is considered to start at the beginning of the vertical and horizontal 564 * blanking period. 565 */ 566 r->h_total_ns = htotal_cclks * r->cclk_ns; 567 r->hb_end_ns = hblank_width * r->cclk_ns; 568 r->vb_end_ns = vblank_width * r->h_total_ns; 569 r->vs_start_ns = (r->vs_start - r->vb_start) * r->h_total_ns; 570 r->vs_end_ns = (r->vs_end - r->vb_start) * r->h_total_ns; 571 Assert(r->h_total_ns); /* See h_total. */ 572 } 573 574 static uint8_t vga_retrace(VGAState *s) 575 { 576 vga_retrace_s *r = &s->retrace_state; 577 578 if (r->frame_ns) { 579 uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE); 580 unsigned cur_frame_ns, cur_line_ns; 581 int64_t time_ns; 582 583 time_ns = PDMDevHlpTMTimeVirtGetNano(VGASTATE2DEVINS(s)); 584 585 /* Determine the time within the frame. */ 586 cur_frame_ns = time_ns % r->frame_ns; 587 588 /* See if we're in the vertical blanking period... */ 589 if (cur_frame_ns < r->vb_end_ns) { 590 val |= ST01_DISP_ENABLE; 591 /* ... and additionally in the vertical sync period. */ 592 if (cur_frame_ns >= r->vs_start_ns && cur_frame_ns <= r->vs_end_ns) 593 val |= ST01_V_RETRACE; 594 } else { 595 /* Determine the time within the current scanline. */ 596 cur_line_ns = cur_frame_ns % r->h_total_ns; 597 /* See if we're in the horizontal blanking period. */ 598 if (cur_line_ns < r->hb_end_ns) 599 val |= ST01_DISP_ENABLE; 600 } 601 return val; 602 } else { 603 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE); 604 } 605 } 606 607 int vga_ioport_invalid(VGAState *s, uint32_t addr) 608 { 609 if (s->msr & MSR_COLOR_EMULATION) { 610 /* Color */ 611 return (addr >= 0x3b0 && addr <= 0x3bf); 612 } else { 613 /* Monochrome */ 614 return (addr >= 0x3d0 && addr <= 0x3df); 615 } 616 } 617 491 618 static uint32_t vga_ioport_read(void *opaque, uint32_t addr) 492 619 { … … 495 622 496 623 /* check port range access depending on color/monochrome mode */ 497 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) || 498 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) { 624 if (vga_ioport_invalid(s, addr)) { 499 625 val = 0xff; 500 626 Log(("VGA: following read ignored\n")); … … 562 688 case 0x3ba: 563 689 case 0x3da: 564 /* just toggle to fool polling */ 565 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE; 566 val = s->st01; 690 val = s->st01 = vga_retrace(s); 567 691 s->ar_flip_flop = 0; 568 692 break; … … 584 708 585 709 /* check port range access depending on color/monochrome mode */ 586 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) || 587 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) { 710 if (vga_ioport_invalid(s, addr)) { 588 711 Log(("VGA: previous write ignored\n")); 589 712 return; … … 625 748 case 0x3c2: 626 749 s->msr = val & ~0x10; 750 if (s->fRealRetrace) 751 vga_update_retrace_state(s); 627 752 break; 628 753 case 0x3c4: … … 632 757 Log2(("vga: write SR%x = 0x%02x\n", s->sr_index, val)); 633 758 s->sr[s->sr_index] = val & sr_mask[s->sr_index]; 634 759 if (s->fRealRetrace && s->sr_index == 0x01) 760 vga_update_retrace_state(s); 635 761 #ifndef IN_RC 636 762 /* The VGA region is (could be) affected by this change; reset all aliases we've created. */ … … 698 824 return; 699 825 } 700 switch(s->cr_index) { 701 case 0x01: /* horizontal display end */ 702 case 0x07: 703 case 0x09: 704 case 0x0c: 705 case 0x0d: 706 case 0x12: /* vertical display end */ 707 s->cr[s->cr_index] = val; 708 break; 709 710 default: 711 s->cr[s->cr_index] = val; 712 break; 826 s->cr[s->cr_index] = val; 827 828 if (s->fRealRetrace) { 829 /* The following registers are only updated during a mode set. */ 830 switch(s->cr_index) { 831 case 0x00: 832 case 0x02: 833 case 0x03: 834 case 0x05: 835 case 0x06: 836 case 0x07: 837 case 0x09: 838 case 0x10: 839 case 0x11: 840 case 0x15: 841 case 0x16: 842 vga_update_retrace_state(s); 843 break; 844 } 713 845 } 714 846 break; … … 3966 4098 static DECLCALLBACK(void) vgaInfoState(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) 3967 4099 { 3968 PVGASTATE s = PDMINS_2_DATA(pDevIns, PVGASTATE); 3969 int is_graph; 3970 int w, h, char_height; 3971 int val; 3972 3973 is_graph = s->gr[6] & 1; 4100 PVGASTATE s = PDMINS_2_DATA(pDevIns, PVGASTATE); 4101 int is_graph; 4102 int w, h, char_height, char_dots; 4103 int val, vfreq_hz, hfreq_hz; 4104 vga_retrace_s *r = &s->retrace_state; 4105 const char *clocks[] = { "25.175 MHz", "28.322 MHz", "External", "Reserved?!" }; 4106 4107 is_graph = s->gr[6] & 1; 4108 char_dots = (s->sr[0x01] & 1) ? 8 : 9; 4109 pHlp->pfnPrintf(pHlp, "pixel clock: %s\n", clocks[(s->msr >> 2) & 3]); 3974 4110 pHlp->pfnPrintf(pHlp, "double scanning %s\n", s->cr[9] & 0x80 ? "on" : "off"); 4111 pHlp->pfnPrintf(pHlp, "double clocking %s\n", s->sr[1] & 0x08 ? "on" : "off"); 3975 4112 val = s->cr[0] + 5; 3976 pHlp->pfnPrintf(pHlp, "htotal: %d px (%d cclk)\n", val * 8, val);4113 pHlp->pfnPrintf(pHlp, "htotal: %d px (%d cclk)\n", val * char_dots, val); 3977 4114 val = s->cr[6] + ((s->cr[7] & 1) << 8) + ((s->cr[7] & 0x20) << 4) + 2; 3978 4115 pHlp->pfnPrintf(pHlp, "vtotal: %d px\n", val); 3979 4116 val = s->cr[1] + 1; 3980 w = val * 8;4117 w = val * char_dots; 3981 4118 pHlp->pfnPrintf(pHlp, "hdisp : %d px (%d cclk)\n", w, val); 3982 4119 val = s->cr[0x12] + ((s->cr[7] & 2) << 7) + ((s->cr[7] & 0x40) << 4) + 1; … … 3990 4127 char_height = val; 3991 4128 pHlp->pfnPrintf(pHlp, "char height %d\n", val); 3992 pHlp->pfnPrintf(pHlp, "text mode %dx%d\n", w / 8, h / char_height); 4129 pHlp->pfnPrintf(pHlp, "text mode %dx%d\n", w / char_dots, h / char_height); 4130 } 4131 if (s->fRealRetrace) 4132 { 4133 val = r->hb_start; 4134 pHlp->pfnPrintf(pHlp, "hblank start: %d px (%d cclk)\n", val * char_dots, val); 4135 val = r->hb_end; 4136 pHlp->pfnPrintf(pHlp, "hblank end : %d px (%d cclk)\n", val * char_dots, val); 4137 pHlp->pfnPrintf(pHlp, "vblank start: %d px, end: %d px\n", r->vb_start, r->vb_end); 4138 pHlp->pfnPrintf(pHlp, "vsync start : %d px, end: %d px\n", r->vs_start, r->vs_end); 4139 pHlp->pfnPrintf(pHlp, "cclks per frame: %d\n", r->frame_cclks); 4140 pHlp->pfnPrintf(pHlp, "cclk time (ns) : %d\n", r->cclk_ns); 4141 vfreq_hz = 1000000000 / r->frame_ns; 4142 hfreq_hz = 1000000000 / r->h_total_ns; 4143 pHlp->pfnPrintf(pHlp, "vfreq: %d Hz, hfreq: %d.%03d kHz\n", 4144 vfreq_hz, hfreq_hz / 1000, hfreq_hz % 1000); 3993 4145 } 3994 4146 } … … 5234 5386 pThis->u64LastLatchedAccess = 0; 5235 5387 pThis->iMask = 0; 5388 5389 /* Reset retrace emulation. */ 5390 memset(&pThis->retrace_state, 0, sizeof(pThis->retrace_state)); 5236 5391 } 5237 5392 … … 5499 5654 "ShowBootMenu\0" 5500 5655 "BiosRom\0" 5656 "RealRetrace\0" 5501 5657 "CustomVideoModes\0" 5502 5658 "HeightReduction\0" … … 5886 6042 if (RT_FAILURE(rc)) 5887 6043 return rc; 6044 6045 /* 6046 * Initialize the retrace flag. 6047 */ 6048 rc = CFGMR3QueryBoolDef(pCfg, "RealRetrace", &pThis->fRealRetrace, false); 6049 AssertLogRelRCReturn(rc, rc); 5888 6050 5889 6051 #ifdef VBE_NEW_DYN_LIST -
trunk/src/VBox/Devices/Graphics/DevVGA.h
r33650 r33851 138 138 #define CH_ATTR_SIZE (160 * 100) 139 139 #define VGA_MAX_HEIGHT VBE_DISPI_MAX_YRES 140 141 typedef struct vga_retrace { 142 unsigned frame_cclks; /* Character clocks per frame. */ 143 unsigned frame_ns; /* Frame duration in ns. */ 144 unsigned cclk_ns; /* Character clock duration in ns. */ 145 unsigned vb_start; /* Vertical blanking start (scanline). */ 146 unsigned vb_end; /* Vertical blanking end (scanline). */ 147 unsigned vb_end_ns; /* Vertical blanking end time (length) in ns. */ 148 unsigned vs_start; /* Vertical sync start (scanline). */ 149 unsigned vs_end; /* Vertical sync end (scanline). */ 150 unsigned vs_start_ns; /* Vertical sync start time in ns. */ 151 unsigned vs_end_ns; /* Vertical sync end time in ns. */ 152 unsigned h_total; /* Horizontal total (cclks per scanline). */ 153 unsigned h_total_ns; /* Scanline duration in ns. */ 154 unsigned hb_start; /* Horizontal blanking start (cclk). */ 155 unsigned hb_end; /* Horizontal blanking end (cclk). */ 156 unsigned hb_end_ns; /* Horizontal blanking end time (length) in ns. */ 157 unsigned v_freq_hz; /* Vertical refresh rate to emulate. */ 158 } vga_retrace_s; 140 159 141 160 #ifndef VBOX … … 379 398 #endif 380 399 400 /** Retrace emulation state */ 401 bool fRealRetrace; 402 struct vga_retrace retrace_state; 403 381 404 #ifdef VBE_NEW_DYN_LIST 382 405 /** The VBE BIOS extra data. */
Note:
See TracChangeset
for help on using the changeset viewer.