First post, by purple_toupee
This is a weird one. I'm writing a program (in Watcom C/Dos4G/W) that uses mode 0x13. It doesn't do anything fancy, but it only works on SOME of my real hardware.
What it does, in my simplified repro case:
- reprogram the PIT timer channel 0 to use for timing
- Switch to VGA mode 0x13 using int 0x10,0 -- no other VGA setup is done.
- Wait for vsync start, then vsync end (read bytes from port 0x3DA until bit 3 turns on, then off)
- disable interrupts
- record clock time
- again wait for vsync start and end
- record clock time elapsed
- enable interrupts
- printf something (so, bios text output)
- wait for key using a tight kbhit/getch loop
(Basically, I was testing frame time to test the code & assumptions.)
This works fine on DOSBox. It worked fine on my 486 back when I had an 8-bit ATI card in it. Last week, I finally upgraded to a VLB Genoa card. As soon as I change modes, the monitor loses sync. (I am using a VGA->HDMI adapter.) I've tested the new video card with a variety of commercial games; I also used debug to switch modes to 0x13 and everything was fine in DOS.
Here's the wacky thing. If I don't do the whole measurement block -- so I never look at 3da -- then things work fine. What???
I don't THINK it's a hardware issue. I'm betting that EITHER I am messing up the vsync logic, OR I am just failing to understand something about programming the VGA. I'm hoping someone here has guru-level knowledge to point out my error -- or at least suggest a direction of investigation. I'm kind of stumped.
Here's some of the code, in case it's obvious what I did wrong.
extern void DelayInstruction();
#pragma aux DelayInstruction = \
"jmp _label" \
"_label:"
// necessary because of Watcom's stupid 32-bit-wide API
uint8 InPortB(uint16 portNum) { return (uint8)inp(portNum); }
bool IsVerticalRetraceActive()
{
const uint8 vgaStatus = InPortB(0x3DA);
return (vgaStatus & uint8(1 << 3)) != 0;
}
void WaitForVerticalRetraceStart()
{
while (!IsVerticalRetraceActive())
{
DelayInstruction();
}
}
void WaitForVerticalRetraceStop()
{
while (IsVerticalRetraceActive())
{
DelayInstruction();
}
}
void VerticalSync()
{
WaitForVerticalRetraceStart();
WaitForVerticalRetraceStop();
}
//
// main:
//
{
VerticalSync();
_disable();
const uint32 ticks = CHWClock::GetTicks();
VerticalSync();
const uint32 after = CHWClock::GetTicks();
_enable();
const uint32 delta = after - tocks;
// (log the result)
}
printf("ready. hit a key.\n");
while (!kbhit()) {}
while (kbhit()) { getch(); }