VOGONS


CGA on VGA emulation in x86EMU?

Topic actions

Reply 160 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've implemented the reset to allow a maximum of 4 sense interrupts (reporting 0xC1 for valid drives). The sense interrupt results are stopped(start giving normal results) when a command is sent that's not a Sense Interrupt command. When booting from harddisk MS-DOS 5.0 can read the floppy fine (PC-DOS 3.1 floppy), but the BIOS cannot boot from it.

Floppy log when trying to boot from it:

0:00:18:63.5.0929: FLOPPY: Write DOR=1C

0:00:18:63.6.0332: FLOPPY: MSR changed: 80

0:00:18:63.6.0336: FLOPPY: Read MSR=80

0:00:18:63.6.0346: FLOPPY: Command byte sent: 07

0:00:18:63.6.0367: FLOPPY: MSR changed: 90

0:00:18:63.6.0369: FLOPPY: Read MSR=90

0:00:18:63.6.0377: FLOPPY: Parameter sent: 00(#1/1)

0:00:18:63.6.0379: FLOPPY: executing command: 07

0:00:18:63.6.0408: FLOPPY: MSR changed: 80

0:00:18:63.6.0412: FLOPPY: Read MSR=80

0:00:18:63.6.0418: FLOPPY: Command byte sent: 0F

0:00:18:63.6.0428: FLOPPY: MSR changed: 90

0:00:18:63.6.0430: FLOPPY: Read MSR=90

0:00:18:63.6.0437: FLOPPY: Parameter sent: 00(#1/2)

0:00:18:63.6.0447: FLOPPY: Read MSR=90

0:00:18:63.6.0453: FLOPPY: Parameter sent: 00(#2/2)

0:00:18:63.6.0457: FLOPPY: executing command: 0F

0:00:18:63.6.0539: FLOPPY: MSR changed: 80

0:00:18:63.6.0543: FLOPPY: Read MSR=80

0:00:18:63.6.0549: FLOPPY: Command byte sent: 08

0:00:18:63.6.0553: FLOPPY: executing command: 08

0:00:18:63.6.0561: FLOPPY: Sense interrupt: ST0=20, Currentcylinder=00

0:00:18:63.6.0572: FLOPPY: MSR changed: d0

0:00:18:63.6.0574: FLOPPY: Read MSR=D0

0:00:18:63.6.0580: FLOPPY: Reading result byte 1/2=20

0:00:18:63.6.0590: FLOPPY: Read MSR=D0

0:00:18:63.6.0600: FLOPPY: Read MSR=D0

0:00:18:63.6.0607: FLOPPY: Reading result byte 2/2=00

0:00:18:63.6.0617: FLOPPY: MSR changed: 80

0:00:18:63.6.0621: FLOPPY: Read MSR=80

Show last 130 lines
0:00:18:64.6.0324: FLOPPY: Read MSR=80

0:00:18:64.6.0335: FLOPPY: Command byte sent: E6

0:00:18:64.6.0345: FLOPPY: MSR changed: 90

0:00:18:64.6.0349: FLOPPY: Read MSR=90

0:00:18:64.6.0357: FLOPPY: Parameter sent: 00(#1/8)

0:00:18:64.6.0369: FLOPPY: Read MSR=90

0:00:18:64.6.0376: FLOPPY: Parameter sent: 00(#2/8)

0:00:18:64.6.0386: FLOPPY: Read MSR=90

0:00:18:64.6.0394: FLOPPY: Parameter sent: 00(#3/8)

0:00:18:64.6.0404: FLOPPY: Read MSR=90

0:00:18:64.6.0410: FLOPPY: Parameter sent: 01(#4/8)

0:00:18:64.6.0421: FLOPPY: Read MSR=90

0:00:18:64.6.0429: FLOPPY: Parameter sent: 02(#5/8)

0:00:18:64.6.0439: FLOPPY: Read MSR=90

0:00:18:64.6.0445: FLOPPY: Parameter sent: 08(#6/8)

0:00:18:64.6.0455: FLOPPY: Read MSR=90

0:00:18:64.6.0462: FLOPPY: Parameter sent: 2A(#7/8)

0:00:18:64.6.0472: FLOPPY: Read MSR=90

0:00:18:64.6.0480: FLOPPY: Parameter sent: FF(#8/8)

0:00:18:64.6.0482: FLOPPY: executing command: 06

0:00:18:64.6.0486: FLOPPY: Read sector #0

0:00:18:64.6.0488: FLOPPY: Sector size: 512 bytes

0:00:18:64.6.0490: FLOPPY: Requesting transfer for 512 bytes.

0:00:18:64.6.0529: FLOPPY: Start transfer of data (DMA: 1)...

0:00:18:64.6.0748: FLOPPY: Finished transfer of data (1 sectors).

0:00:18:64.6.0771: FLOPPY: MSR changed: d0

0:00:18:64.6.0775: FLOPPY: Read MSR=D0

0:00:18:64.6.0781: FLOPPY: Reading result byte 1/7=20

0:00:18:64.6.0791: FLOPPY: Read MSR=D0

0:00:18:64.6.0804: FLOPPY: Read MSR=D0

0:00:18:64.6.0810: FLOPPY: Reading result byte 2/7=00

0:00:18:64.6.0820: FLOPPY: Read MSR=D0

0:00:18:64.6.0830: FLOPPY: Read MSR=D0

0:00:18:64.6.0836: FLOPPY: Reading result byte 3/7=00

0:00:18:64.6.0849: FLOPPY: Read MSR=D0

0:00:18:64.6.0859: FLOPPY: Read MSR=D0

0:00:18:64.6.0865: FLOPPY: Reading result byte 4/7=00

0:00:18:64.6.0873: FLOPPY: Read MSR=D0

0:00:18:64.6.0885: FLOPPY: Read MSR=D0

0:00:18:64.6.0892: FLOPPY: Reading result byte 5/7=00

0:00:18:64.6.0902: FLOPPY: Read MSR=D0

0:00:18:64.6.0912: FLOPPY: Read MSR=D0

0:00:18:64.6.0918: FLOPPY: Reading result byte 6/7=02

0:00:18:64.6.0928: FLOPPY: Read MSR=D0

0:00:18:64.6.0951: FLOPPY: Read MSR=D0

0:00:18:64.6.0957: FLOPPY: Reading result byte 7/7=00

0:00:18:64.6.0969: FLOPPY: MSR changed: 80

0:00:18:64.6.0971: FLOPPY: Read MSR=80

0:00:18:64.7.0221: FLOPPY: Write DOR=18

0:00:18:64.7.0225: FLOPPY: Reset requested by DOR!

0:00:18:64.7.0230: FLOPPY: Write DOR=1C

0:00:18:64.7.0232: FLOPPY: Activation requested by DOR!

0:00:18:64.7.0252: FLOPPY: Read MSR=80

0:00:18:64.7.0258: FLOPPY: Command byte sent: 08

0:00:18:64.7.0260: FLOPPY: executing command: 08

0:00:18:64.7.0264: FLOPPY: Sense interrupt: ST0=C1, Currentcylinder=00

0:00:18:64.7.0275: FLOPPY: MSR changed: d0

0:00:18:64.7.0277: FLOPPY: Read MSR=D0

0:00:18:64.7.0367: FLOPPY: Reading result byte 1/2=C1

0:00:18:64.7.0391: FLOPPY: Read MSR=D0

0:00:18:64.7.0402: FLOPPY: Read MSR=D0

0:00:18:64.7.0408: FLOPPY: Reading result byte 2/2=00

0:00:18:64.7.0420: FLOPPY: MSR changed: 80

0:00:18:64.7.0422: FLOPPY: Read MSR=80

0:00:19:65.9.0188: FLOPPY: Write DOR=0C

Anyone knows what's happening here? Why won't it boot from it?

Edit: Fixed a bug where it wasn't reporting the result bytes correctly. Although this didn't fix that:

0:00:31:75.8.0114: FLOPPY: Write DOR=1C

0:00:31:75.8.0634: FLOPPY: MSR changed: 80

0:00:31:75.8.0638: FLOPPY: Read MSR=80

0:00:31:75.8.0658: FLOPPY: Command byte sent: 07

0:00:31:75.8.0686: FLOPPY: MSR changed: 90

0:00:31:75.8.0688: FLOPPY: Read MSR=90

0:00:31:75.8.0724: FLOPPY: Parameter sent: 00(#1/1)

0:00:31:75.8.0726: FLOPPY: executing command: 07

0:00:31:75.8.0808: FLOPPY: MSR changed: 80

0:00:31:75.8.0810: FLOPPY: Read MSR=80

0:00:31:75.8.0852: FLOPPY: Command byte sent: 0F

0:00:31:75.8.0914: FLOPPY: MSR changed: 90

0:00:31:75.8.0916: FLOPPY: Read MSR=90

0:00:31:75.8.0946: FLOPPY: Parameter sent: 00(#1/2)

0:00:31:75.8.0970: FLOPPY: Read MSR=90

0:00:31:75.9.0008: FLOPPY: Parameter sent: 00(#2/2)

0:00:31:75.9.0010: FLOPPY: executing command: 0F

0:00:31:75.9.0148: FLOPPY: MSR changed: 80

0:00:31:75.9.0150: FLOPPY: Read MSR=80

0:00:31:75.9.0196: FLOPPY: Command byte sent: 08

0:00:31:75.9.0196: FLOPPY: executing command: 08

0:00:31:75.9.0200: FLOPPY: Sense interrupt: ST0=20, Currentcylinder=00

0:00:31:75.9.0232: FLOPPY: MSR changed: d0

0:00:31:75.9.0234: FLOPPY: Read MSR=D0

0:00:31:75.9.0252: FLOPPY: Reading result byte 1/2=20

0:00:31:75.9.0304: FLOPPY: Read MSR=D0

0:00:31:75.9.0342: FLOPPY: Read MSR=D0

0:00:31:75.9.0362: FLOPPY: Reading result byte 2/2=00

0:00:31:75.9.0410: FLOPPY: MSR changed: 80

0:00:31:75.9.0412: FLOPPY: Read MSR=80

Show last 133 lines
0:00:31:84.8.0686: FLOPPY: Read MSR=80

0:00:31:84.8.0736: FLOPPY: Command byte sent: E6

0:00:31:84.8.0778: FLOPPY: MSR changed: 90

0:00:31:84.8.0782: FLOPPY: Read MSR=90

0:00:31:84.8.0800: FLOPPY: Parameter sent: 00(#1/8)

0:00:31:84.8.0856: FLOPPY: Read MSR=90

0:00:31:84.8.0888: FLOPPY: Parameter sent: 00(#2/8)

0:00:31:84.8.0924: FLOPPY: Read MSR=90

0:00:31:84.8.0938: FLOPPY: Parameter sent: 00(#3/8)

0:00:31:84.9.0030: FLOPPY: Read MSR=90

0:00:31:84.9.0054: FLOPPY: Parameter sent: 01(#4/8)

0:00:31:84.9.0086: FLOPPY: Read MSR=90

0:00:31:84.9.0098: FLOPPY: Parameter sent: 02(#5/8)

0:00:31:84.9.0160: FLOPPY: Read MSR=90

0:00:31:84.9.0188: FLOPPY: Parameter sent: 08(#6/8)

0:00:31:84.9.0218: FLOPPY: Read MSR=90

0:00:31:84.9.0278: FLOPPY: Parameter sent: 2A(#7/8)

0:00:31:84.9.0334: FLOPPY: Read MSR=90

0:00:31:84.9.0354: FLOPPY: Parameter sent: FF(#8/8)

0:00:31:84.9.0356: FLOPPY: executing command: 06

0:00:31:84.9.0360: FLOPPY: Read sector #0

0:00:31:84.9.0360: FLOPPY: Sector size: 512 bytes

0:00:31:84.9.0364: FLOPPY: Requesting transfer for 512 bytes.

0:00:31:84.9.0452: FLOPPY: Start transfer of data (DMA: 1)...

0:03:10:95.2.0720: FLOPPY: Finished transfer of data (1 sectors).

0:03:10:97.3.0936: FLOPPY: MSR changed: d0

0:03:10:97.3.0936: FLOPPY: Read MSR=D0

0:03:10:97.3.0952: FLOPPY: Reading result byte 1/7=20

0:03:10:97.4.0000: FLOPPY: Read MSR=D0

0:03:10:97.4.0048: FLOPPY: Read MSR=D0

0:03:10:97.4.0064: FLOPPY: Reading result byte 2/7=00

0:03:10:97.4.0112: FLOPPY: Read MSR=D0

0:03:10:97.4.0144: FLOPPY: Read MSR=D0

0:03:10:97.4.0192: FLOPPY: Reading result byte 3/7=00

0:03:10:97.4.0224: FLOPPY: Read MSR=D0

0:03:10:97.4.0256: FLOPPY: Read MSR=D0

0:03:10:97.4.0304: FLOPPY: Reading result byte 4/7=00

0:03:10:97.4.0336: FLOPPY: Read MSR=D0

0:03:10:97.4.0368: FLOPPY: Read MSR=D0

0:03:10:97.4.0384: FLOPPY: Reading result byte 5/7=00

0:03:10:97.4.0448: FLOPPY: Read MSR=D0

0:03:10:97.4.0528: FLOPPY: Read MSR=D0

0:03:10:97.4.0544: FLOPPY: Reading result byte 6/7=02

0:03:10:97.4.0624: FLOPPY: Read MSR=D0

0:03:10:97.4.0672: FLOPPY: Read MSR=D0

0:03:10:97.4.0688: FLOPPY: Reading result byte 7/7=02

0:03:10:97.4.0752: FLOPPY: MSR changed: 80

0:03:10:97.4.0752: FLOPPY: Read MSR=80

0:03:10:97.9.0872: FLOPPY: Write DOR=18

0:03:10:97.9.0872: FLOPPY: Reset requested by DOR!

0:03:10:97.9.0888: FLOPPY: Write DOR=1C

0:03:10:97.9.0888: FLOPPY: Activation requested by DOR!

0:03:10:98.0.0000: FLOPPY: Read MSR=80

0:03:10:98.0.0016: FLOPPY: Command byte sent: 08

0:03:10:98.0.0016: FLOPPY: executing command: 08

0:03:10:98.0.0016: FLOPPY: Sense interrupt: ST0=C1, Currentcylinder=00

0:03:10:98.0.0048: FLOPPY: MSR changed: d0

0:03:10:98.0.0048: FLOPPY: Read MSR=D0

0:03:10:98.0.0176: FLOPPY: Reading result byte 1/2=C1

0:03:10:98.0.0208: FLOPPY: Read MSR=D0

0:03:10:98.0.0240: FLOPPY: Read MSR=D0

0:03:10:98.0.0288: FLOPPY: Reading result byte 2/2=00

0:03:10:98.0.0320: FLOPPY: MSR changed: 80

0:03:10:98.0.0320: FLOPPY: Read MSR=80

0:03:17:39.3.0248: FLOPPY: Write DOR=0C

0:04:23:91.7.0296: FLOPPY: Write DOR=0C

0:05:29:29.3.0088: FLOPPY: Write DOR=0C

Looking at the DMA transaction, it sets TC(The DMA transfer is finished, with 1 sector of 512 bytes). Why would it still reset the disk controller and issue a boot failure?
Edit: Fixed it. The problem was in that the controller decreased the counter (which goes from 4 to 0(0 being finished)) before using the value to generate a drive (thus generating drives 1, 2, 3 and 4 instead of 0,1,2,3). This has now been fixed. Also any command which isn't the Sense Interrupt command after reset will set the counter to 0(disabling the reset 0xC* status) and clear the ST0 register to be able to give correct results for the commands being executed. Invalid commands will always give 0x80, so they don't have to check for it(since they don't use the register). This fixes both BIOSes and other drivers etc. which might use some, all or none of those Sense Interrupts(providing what is requested, for up to 4 Sense Interrupts. No Sense Interrupt is also supported now).

So now, the only problem left in the IBM XT BIOS is that it reports a 301 error before the memory check. Anyone knows what might cause this?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 161 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

Looking up the 301 error means that it has problems resetting the keyboard? Anyone knows how exactly it triggers the keyboard reset? How is this different from the 8042 PS/2 keyboard?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 162 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

Looking up the 301 error means that it has problems resetting the keyboard? Anyone knows how exactly it triggers the keyboard reset? How is this different from the 8042 PS/2 keyboard?

There are two bidirectional lines between the XT and the keyboard (clock and data). The XT can force the clock line low by outputting a 0 to bit 6 of PPI port B (IO port address 0x61). Holding it low for 20ms resets the XT keyboard, after which it should respond with scancode 0xAA (once the clock line has gone high again).

Reply 163 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

Strange, as this is already implemented:
Write of 8042 support:

	case 0x61: //PPI keyboard functionality for XT!
if ((value & 0x80) && (EMULATED_CPU<CPU_80286)) //Clear interrupt flag and we're a XT system?
{
Controller8042.status_buffer &= ~0x21; //Clear input buffer full&AUX bits!
fill8042_input_buffer(); //Fill the next byte to use!
}
if ((value & 0x40) && (!(Controller8042.PortB & 0x40))) //Set when unset?
{
resetKeyboard_8042(); //Reset the keyboard manually!
}
Controller8042.PortB = (value&0xC0); //Save values for reference!
return 1;
break;

Read of 8042 support:

	case 0x61: //PPI keyboard functionality for XT!
*result = 0; //We're not having bit 0x80 set!
return 1; //We're processed!
break;

PS/2 keyboard module:

OPTINLINE void resetKeyboard(byte initAA) //Reset the keyboard controller!
{
if (__HW_DISABLED) return; //Abort!
FIFOBUFFER *oldbuffer = Keyboard.buffer; //Old buffer!
memset(&Keyboard,0,sizeof(Keyboard)); //Reset the controller!
Keyboard.keyboard_enabled = 1; //Enable scanning by default!
Keyboard.buffer = oldbuffer; //Restore the buffer!
give_keyboard_input(0xAA); //Give OK status code!
if (initAA) input_lastwrite_keyboard(); //Force to user!
IRQ8042(); //We've got data in our input buffer!
Keyboard.last_send_byte = 0xAA; //Set last send byte!
}

void resetKeyboard_8042()
{
resetKeyboard(1); //Reset us!
}

Or it this problem simply because the high 2 bits of port 0x61 is forced to zero?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 164 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've changed the reset to happen when bit 6 is changed from 1 to 0. Now the error changes into a 101 error(which should means something like "System board failed/unexpected interrupt))? The 8042 does raise an interrupt when resetting? Isn't it supposed to do this?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 165 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

I've changed the reset to happen when bit 6 is changed from 1 to 0. Now the error changes into a 101 error(which should means something like "System board failed/unexpected interrupt))? The 8042 does raise an interrupt when resetting? Isn't it supposed to do this?

Yes, but only if the interrupt is enabled in the IMR.

Reply 166 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

So that would mean there's probably a problem in my PIC emulation?

https://bitbucket.org/superfury/x86emu/src/0a … pic.c?at=master

doirq raises an 'IRQ line' for handling(The CPU will trigger the interrupt if it sees this based in the IMR, ISR etc.).
removeirq lowers the 'IRQ line' (essentially removing the IRQ for triggering an interrupt if it's set by doirq.)
They basically clear/set the corresponding bit in the Interrupt Request Register.

The main routine calls PICInterrupt() to check if an interrupt is available. If it returns TRUE/1, it calls nextintr() for the interrupt number and executes the Interrupt (essentially executes that hardware interrupt) number given.

Edit: It wasn't the interrupt controller at all (both the 301 and 101 error have the same cause: port 0x61 in the 8042 compatibility layer).

This is the fixed method:

		if (EMULATED_CPU<CPU_80286) //XT machine only?
{
if (value & 0x80) //Clear interrupt flag and we're a XT system?
{
Controller8042.status_buffer &= ~0x21; //Clear input buffer full&AUX bits!
fill8042_input_buffer(1); //Fill the next byte to use!
}
if (((value^0x40)==(Controller8042.PortB&0x40)) && ((value)&0x40)) //Set when unset?
{
resetKeyboard_8042(1); //Reset the keyboard manually! Execute an interrupt when reset!
}
Controller8042.PortB = (value&0xC0); //Save values for reference!
return 1;
}

The part saying set when unset was comparing the wrong way. It now doesn't give any errors anymore, nor asks for F1 to be pressed 😀

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 167 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

So that would mean there's probably a problem in my PIC emulation?

I'd expect that would cause the keyboard to not work correctly in other situations.

Put the keyboard reset back to the rising edge of PPI B6 (the keyboard can't send a byte when the clock is being held low). I don't know why you're getting the 301 error, but if you trace through from 0xF000:0xE3B4 you should be able to figure it out. If the IP reaches 0xE3D7 then the keyboard test has failed.

Reply 168 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

Well, since it's handling the rising edge of bit 6 correctly now, it gives no errors anymore. Both the Super PC/Turbo XT BIOS boot without any errors now:)

Next step: Completing the 286&386 CPU (Completing and implementing task switching, interrupts and 286+ instructions(16 bit instructions can be copied from 80(1)86 and adjusted with simple search/replace to apply to 32-bit with 16-bit and 32-bit operand sizes. Address size remains unchanged(Already implemented in the x86 core ModR/M handling))) or getting 8086/88 timing(clock cycle calculations) implemented?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 169 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just managed to fix the overscan problem in both 8088 MPH's Kefrens Bars effect and CGA Compatibility Checker's Horizontal Retrace effect by moving the CGA Scanline drawing routine (which also converts to NTSC/RGB output) to the point before the VGA's horizontal retrace routine increases the scanline on the screen(and starts drawing the next scanline).

Now the effect no longer have the overscan one scanline higher than the content (the drawing was during the next scanline instead of the intended scanline, thus drawing a part of the scanline on the new scanline(the part from horizontal retrace until horizontal total was affectively drawn on the next scanline, shifting the overscan down/up one line, thus the strange effect)).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 170 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie

Superfury, I wonder if you could do me a quick favour. Trixter was recently playing about with some new capture methods and on one of them, two effects from 8088MPH were corrupted (the CGA model identification screen at the beginning, and the vectorballs "IBM" sequence after the Delorean sprite/scrolling part). Is there anything off about the sync pulse timing of those two effects in particular? In particular, I was wondering if either or both were generating less than 262 scanlines. Is that something you can easily check with x86EMU? Just dumping the state of the vsync flag at every hsync would be enough.

Reply 171 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've implemented a simple counter that logs 120 frames of VSync locations(the screen's vertical resolution for 120 frames, as detected when VRetrace starts). Currently starting the log(triggered by a reserved key combination of RALT-F9 in x86EMU)...

Edit: First dump only reports y resolution of 0 pixels. Now applying a filter filtering out 0-height frames...
Edit: Removed the 0-height filter and moved the logging routine to it's correct position (which should give correct results, before it's cleared).

Edit: Here's the log:

Filename
VGA.log
File size
7.97 KiB
Downloads
48 downloads
File comment
CGA logs of those two parts.
File license
Fair use/fair dealing exception

Nothing unusual about it (only 2 resolutions used: 245 and 246 pixels height).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 172 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

Nothing unusual about it (only 2 resolutions used: 245 and 246 pixels height).

Huh, that seems strange to me. I'd have thought that the vsync would appear on scanline 240 if we're counting scanlines the same way the CRTC is. What's the equivalent value for the other effects? In any case, it seems like the CGA model identification screen is a scanline shorter than the vectorballs screen, which is interesting!

What would be even more interesting is the scanline number it reaches right before it gets reset to 0 (i.e. the total number of scanlines in the frame - including active, top and bottom overscan and vertical retrace). This should be 262, if my code isn't buggy!

Reply 173 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

Well, normally that would be 16 scanlines more than what's given, so at 261 with the detection screen and 262 with the vectorballs screen, although this can be earlier depending on register #4(vertical total) and #5:

	if (row>=VGA->registers->CGARegistersMasked[4]) //Past total specified?
{
if ((((VGA->registers->CGARegistersMasked[4]+1)*charheight)+VGA->registers->CGARegistersMasked[5])<=y) //Vertical total adjustment reaced?
{
result |= VGA_SIGNAL_VTOTAL; //End of display: start the next frame!
result |= VGA_SIGNAL_VSYNCRESET; //Reset VSync!
}
//result |= VGA_SIGNAL_VBLANKSTART; //We're blanking always after end of display!
}

The vertical retrace period itself starts at the character clock in register #7 and ends 15 scanlines later (so if it starts at character clock X, 16 scanlines later the retrace ends and the display starts again).

So the actual period is determined by those two factors:
First the character clock it starts.
This will last retrace up to 15 scanlines after the specified clock.
The vertical total(determined by registers #4&#5) WILL terminate the retrace early(so if the effective retrace starts at scanline 140 and ends at 150, but the vertical total would match at 148, the vertical retrace would last from scanline 140-147(scanline 148 will wrap to scanline #0, which will terminate vertical retrace always and start rendering the new frame)).

Full vertical logic used in x86EMU, based on the documentation:

byte CGA_is_vsync(VGA_Type *VGA, word y, byte charheight) //Are we vsync?
{
if ((y>=(VGA->registers->CGARegistersMasked[7]*charheight)) && (y<((VGA->registers->CGARegistersMasked[7]*charheight)+0x10))) //Vertical sync? It's always 16 lines!
{
return 1; //Vertical sync!
}
return 0;
}

word get_display_CGAMDA_y(VGA_Type *VGA, word y)
{
word result=0;
if (!y) result |= VGA_SIGNAL_VRETRACEEND|VGA_SIGNAL_VBLANKEND; //End vertical retrace&blank if still there!
word row;
byte charheight;
charheight = VGA->registers->CGARegistersMasked[9]+1; //Character height!
row = y;
row /= charheight; //The row we're at!
if (row>=VGA->registers->CGARegistersMasked[4]) //Past total specified?
{
if ((((VGA->registers->CGARegistersMasked[4]+1)*charheight)+VGA->registers->CGARegistersMasked[5])<=y) //Vertical total adjustment reaced?
{
result |= VGA_SIGNAL_VTOTAL; //End of display: start the next frame!
result |= VGA_SIGNAL_VSYNCRESET; //Reset VSync!
}
//result |= VGA_SIGNAL_VBLANKSTART; //We're blanking always after end of display!
}

if (row<VGA->registers->CGARegistersMasked[6]) //Active display?
{
result |= VGA_VACTIVEDISPLAY; //We're active display!
}
else
{
result |= VGA_OVERSCAN; //We're overscan by default!
}

if (CGA_is_vsync(VGA,y,charheight)) //Vertical sync?
{
result |= VGA_SIGNAL_VRETRACESTART; //Vertical sync is simply blanking space!
}
else if (y && CGA_is_vsync(VGA,y-1,charheight)) //Previous was vsync?
{
result |= VGA_SIGNAL_VRETRACEEND; //End of retrace period, if any!
}
return result; //Give the signal!
}

Although the scanline number is 0-based, so it's indeed 261 pixels in height(rows 0-260, retrace starts at 261) in the case of the detection screen and 262 pixels in height (rows 0-261, retrace starts at 262) in the case of the vector balls.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 174 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie

Thanks - that's what I wanted to know. That explains why the detection screen could not be captured properly, but the vectorballs effect remains mysterious!

Reply 175 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

Maybe because it's one scanline higher than the detection screen, but the problem lies in that they're both a strange framerate(14MHz clock divided by [vtotal(including register 5) times [htotal*8]]), which results in the camera not being able to use it? I do remember, that during development of x86EMU I saw some odd framerates(non 50/60FPS)?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 176 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie

Well, the standard CGA framerate is (14.318*10^6 pixels per second) / (57*16 pixels per scanline) / (262 scanlines per frame) which is 157500000/(11*912*262) = 4921875/82137 = 59.92Hz. The capture device can capture this just fine. As can most, because it's a pretty standard frame rate for old NTSC computers and consoles which generated non-interlaced video with an integer number of colour carrier cycles per scanline (I think Apple II and TRS-80 have the same timings).

The model identification screen at 261 scanlines total will be 60.15Hz which is likely just slightly too fast for the capture device. But if the vectorballs effect is generating 262 scanlines then I don't know why the capture device is getting confused. The symptom is the same as for the model identification screen - two copies of the image squashed vertically separated by a green band (which is most likely the capture device's replacement for missing data during vsync).

Reply 177 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

Maybe the cause is different horizontal timing? Good vertical timing + Faster/slower horizontal timing = faster/slower framerate? So if the vertical timing is correct, but horizontal timing too fast, the vertical rate will also be too fast(horizontal total times vertical total=Frame time. If this frame time is off because the horizontal retrace or total is incorrect, the framerate will change)?

You assume the horizontal timing is 912 clocks. Is this set correctly in both cases? So 912x262 = ~915.5x261(not the same rate, impossible to reproduce using whole clocks, thus drifts)?

You'll need 114 horizontal character clocks with 262 scanlines(character clocks are 8 pixels. Half(57 character clocks) in 40-column or 320x200 graphics)). Is this set up correctly? Since you need to get ~915.5 pixels with 261 scanlines, this isn't possible on the CGA? Only whole pixels are supported(Even sets if 8 pixels, thinking in chatacter clocks).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 178 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

Maybe the cause is different horizontal timing? Good vertical timing + Faster/slower horizontal timing = faster/slower framerate? So if the vertical timing is correct, but horizontal timing too fast, the vertical rate will also be too fast(horizontal total times vertical total=Frame time. If this frame time is off because the horizontal retrace or total is incorrect, the framerate will change)?

You assume the horizontal timing is 912 clocks. Is this set correctly in both cases? So 912x262 = ~915.5x261(not the same rate, impossible to reproduce using whole clocks, thus drifts)?

I know for sure that the horizontal timing on the vectorballs effect (and indeed on all of 8088MPH) is 912 hdots, because the way I did the capture of the final version actually captures the entire horizontal scanline (including sync and all overscan) so I can see from that that the horizontal timing is correct. Unfortunately my capture card doesn't let me do the same trick for the vertical timing - it misses out part of the data around the vsync on each frame. So it's difficult for me to tell if I'm out by a scanline or two vertically.

Reply 179 of 187, by Scali

User metadata
Rank l33t
Rank
l33t

The sprite part uses two custom modes.
The DeLorean-part uses a 280x174 mode, set like this:

Mode280174 PROC
; Reprogram to 280x174 mode
; Stride is 35*2 bytes instead of 40*2 bytes.
mov dx, 03d8h
mov al, 00ah ; +GRPH | +VIDEO_ENABLE == 2bpp
out dx, al
inc dx
;mov al, 0 ; Black background
;out dx, al
mov dl, 0d4h
mov ax, 03800h ; Horizontal total == 70+1 characters == (280/4)+1
out dx, ax
mov ax, 02301h ; Horizontal displayed == 35 characters
out dx, ax
mov ax, 02A02h ; Horizontal sync position == 45-(40-35)/2 == character 42
out dx, ax
mov ax, 00a03h ; Horizontal sync width == 10 characters
out dx, ax
mov ax, 07f04h ; Vertical total == 127+1 rows
out dx, ax
mov ax, 00605h ; Vertical total adjust == 262-(2*(127+1)) == 6 scanlines
out dx, ax
mov ax, 05706h ; Vertical displayed == 174/2 == 87 rows
out dx, ax
mov ax, 06A07h ; Vertical sync position == 112-(100-87)/2 == row 99
out dx, ax
mov ax, 00208h ; Interlace mode == non-interlaced
out dx, ax
mov ax, 00109h ; One row = 1+1 scanlines
out dx, ax
mov ax, 0060ah ; Cursor start == scanline 6
out dx, ax
mov ax, 0070bh ; Cursor end == scanline 7
out dx, ax
mov ax, 0000dh ; Start address low = 0x00
out dx, ax

ret
Mode280174 ENDP

The 3d vectorbobs use a 224x140 mode, programmed like this:

	
Mode224140 PROC
; Reprogram to 224x140 mode

; Stride is 28*2 bytes instead of 40*2 bytes.
; First page at 0x0000-0x0fff and 0x2000-0x2fff.
; Second page at 0x1000-0x1fff and 0x3000-0x3fff.
mov dx, 03d8h
mov al, 00ah ; +GRPH | +VIDEO_ENABLE == 2bpp
out dx, al
inc dx
;mov al, 0 ; Black background
;out dx, al
mov dl, 0d4h
mov ax, 03800h ; Horizontal total == 56+1 characters
out dx, ax
mov ax, 01c01h ; Horizontal displayed == 28 characters
out dx, ax
mov ax, 02702h ; Horizontal sync position == 45-(40-28)/2 == character 39
out dx, ax
mov ax, 00a03h ; Horizontal sync width == 10 characters
out dx, ax
mov ax, 07f04h ; Vertical total == 127+1 rows
out dx, ax
mov ax, 00605h ; Vertical total adjust == 262-(2*(127+1)) == 6 scanlines
out dx, ax
mov ax, 04606h ; Vertical displayed == 140/2 == 70 rows
out dx, ax
mov ax, 06107h ; Vertical sync position == 112-(100-70)/2 == row 97
out dx, ax
mov ax, 00208h ; Interlace mode == non-interlaced
out dx, ax
mov ax, 00109h ; One row = 1+1 scanlines
out dx, ax
mov ax, 0060ah ; Cursor start == scanline 6
out dx, ax
mov ax, 0070bh ; Cursor end == scanline 7
out dx, ax
mov ax, 0000dh ; Start address low = 0x00
out dx, ax

ret
Mode224140 ENDP

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/