VirtualBox

Changeset 33851 in vbox for trunk/src/VBox/Devices/Graphics


Ignore:
Timestamp:
Nov 8, 2010 2:38:43 PM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
67497
Message:

VGA: Added optional realistic vsync/blank status bit emulation.

Location:
trunk/src/VBox/Devices/Graphics
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Graphics/DevVGA.cpp

    r33676 r33851  
    489489#endif /* IN_RING3 */
    490490
     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 */
     498static 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
     574static 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
     607int 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
    491618static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
    492619{
     
    495622
    496623    /* 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)) {
    499625        val = 0xff;
    500626        Log(("VGA: following read ignored\n"));
     
    562688        case 0x3ba:
    563689        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);
    567691            s->ar_flip_flop = 0;
    568692            break;
     
    584708
    585709    /* 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)) {
    588711        Log(("VGA: previous write ignored\n"));
    589712        return;
     
    625748    case 0x3c2:
    626749        s->msr = val & ~0x10;
     750        if (s->fRealRetrace)
     751            vga_update_retrace_state(s);
    627752        break;
    628753    case 0x3c4:
     
    632757        Log2(("vga: write SR%x = 0x%02x\n", s->sr_index, val));
    633758        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);
    635761#ifndef IN_RC
    636762        /* The VGA region is (could be) affected by this change; reset all aliases we've created. */
     
    698824            return;
    699825        }
    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            }
    713845        }
    714846        break;
     
    39664098static DECLCALLBACK(void) vgaInfoState(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
    39674099{
    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]);
    39744110    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");
    39754112    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);
    39774114    val = s->cr[6] + ((s->cr[7] & 1) << 8) + ((s->cr[7] & 0x20) << 4) + 2;
    39784115    pHlp->pfnPrintf(pHlp, "vtotal: %d px\n", val);
    39794116    val = s->cr[1] + 1;
    3980     w   = val * 8;
     4117    w   = val * char_dots;
    39814118    pHlp->pfnPrintf(pHlp, "hdisp : %d px (%d cclk)\n", w, val);
    39824119    val = s->cr[0x12] + ((s->cr[7] & 2) << 7) + ((s->cr[7] & 0x40) << 4) + 1;
     
    39904127        char_height = val;
    39914128        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);
    39934145    }
    39944146}
     
    52345386    pThis->u64LastLatchedAccess = 0;
    52355387    pThis->iMask                = 0;
     5388
     5389    /* Reset retrace emulation. */
     5390    memset(&pThis->retrace_state, 0, sizeof(pThis->retrace_state));
    52365391}
    52375392
     
    54995654                                          "ShowBootMenu\0"
    55005655                                          "BiosRom\0"
     5656                                          "RealRetrace\0"
    55015657                                          "CustomVideoModes\0"
    55025658                                          "HeightReduction\0"
     
    58866042    if (RT_FAILURE(rc))
    58876043        return rc;
     6044
     6045    /*
     6046     * Initialize the retrace flag.
     6047     */
     6048    rc = CFGMR3QueryBoolDef(pCfg, "RealRetrace", &pThis->fRealRetrace, false);
     6049    AssertLogRelRCReturn(rc, rc);
    58886050
    58896051#ifdef VBE_NEW_DYN_LIST
  • trunk/src/VBox/Devices/Graphics/DevVGA.h

    r33650 r33851  
    138138#define CH_ATTR_SIZE (160 * 100)
    139139#define VGA_MAX_HEIGHT VBE_DISPI_MAX_YRES
     140
     141typedef 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;
    140159
    141160#ifndef VBOX
     
    379398#endif
    380399
     400    /** Retrace emulation state */
     401    bool                        fRealRetrace;
     402    struct vga_retrace          retrace_state;
     403
    381404#ifdef VBE_NEW_DYN_LIST
    382405    /** The VBE BIOS extra data. */
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette