VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

I'm thinking about making the UniPCemu Paging lookups(from CR3 etc.), descriptor fetching(from GDTR/IDTR) and Task switching cycle-accurate, but am a bit unsure how to handle the different stages and how a real CPU handles it. I'm thinking about the lines of dynamic handling using handlers, which run little scripts(being able to wait for the BIU to fetch data that way) in some kind of parallel processing way(like DMA does with the CPU, except the CPU stays active while doing so, instead of DMA working in parallel).

Anyone got some ideas on what kind of handlers to create(which are little scripts that run one at a time, which interact with the BIU in an EU kind of way)? Vladstamate? Jepael?

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

Reply 1 of 7, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

You can look at my code, 286 task switching should be cycle-accurate to the extent of my knowledge. I've extrapolated from the 286 Intel document. You can look at processor_80286_EU.cpp (line 129 and below). I basically have sub-phases for the task switching instructions (CALL, JMP FAR etc).

Things like interrupts I treat the same. Ping pong between EU and BIU for data read and write (as well as wait for the prefetch buffer if necessary).

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 2 of 7, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

The main cycle accurate task switch function is "CAPEProcessor80286EU::switchTaskCycle". In there you will see the whole script EU is executing and all the BIU transactions it waits for. And how a task switch is broken in individual parts.

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 3 of 7, by superfury

User metadata
Rank l33t++
Rank
l33t++

Some things:
1. I don't see any error handling of the loading of segment descriptors?
2. Shouldn't the whole task switch thing be about the same with IRET and normal task switches? Just some extra steps in between that activate wih IRET only?
3. Shouldn't checks be made before/after the task switch (look at the 80386 manual chapter on task switching)?
4. Step 3 also applies to protected mode interrupts? Also, real mode interrupts also use the IDTR(it can be loaded with an abitrary address to change the IVT address to a non-zero base address, breaking 8086 compatibility). Otherwise, it's easily implemented in UniPCemu(it can handle the ping-pong dynamically, with the function being called for each entry to be loaded from memory, when implemented at the EU-overriding level). Also, how are the segments loaded? They should load descriptors as well? Also, shoudn't those(looking at the 80286 EU unit of CAPE) be loaded cycle-accurate as well? I see it's directly returning the data from RAM(64-bit entry from RAM is read directly, uninterruptable, by the call itself)?

CAPE_PROCESSOR_DESCRIPTOR* CAPEProcessor80286::getGDTEntry(uint32_t index)
{
return (CAPE_PROCESSOR_DESCRIPTOR*)(m_pComputer->m_pMMU->getPointerToData(m_kGDTR.address + index * 8));
}

CAPE_PROCESSOR_DESCRIPTOR* CAPEProcessor80286::getLDTEntry(uint32_t index)
{
return (CAPE_PROCESSOR_DESCRIPTOR*)(m_pComputer->m_pMMU->getPointerToData(m_kLDTR.address + index * 8));
}

CAPE_PROCESSOR_IDT* CAPEProcessor80286::getIDTEntry(uint32_t index)
{
return (CAPE_PROCESSOR_IDT*)(m_pComputer->m_pMMU->getPointerToData(m_kIDTR.address + index * 8));
}

Shouldn't that be done in a cycle-accurate way as well? Also, paging on the 80386(when you start to implement that) makes this pretty much unworkable.

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

Reply 4 of 7, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

Some things:
1. I don't see any error handling of the loading of segment descriptors?

That is currently missing.

superfury wrote:

2. Shouldn't the whole task switch thing be about the same with IRET and normal task switches? Just some extra steps in between that activate wih IRET only?

I treat that in "void CAPEProcessor80286EU::switchTaskIRETCycle()"

superfury wrote:

3. Shouldn't checks be made before/after the task switch (look at the 80386 manual chapter on task switching)?

They should, like I said I am missing some checks and errors. It is on my todo list: bugs.txt bug number 69.

superfury wrote:
4. Step 3 also applies to protected mode interrupts? Also, real mode interrupts also use the IDTR(it can be loaded with an abitr […]
Show full quote

4. Step 3 also applies to protected mode interrupts? Also, real mode interrupts also use the IDTR(it can be loaded with an abitrary address to change the IVT address to a non-zero base address, breaking 8086 compatibility). Otherwise, it's easily implemented in UniPCemu(it can handle the ping-pong dynamically, with the function being called for each entry to be loaded from memory, when implemented at the EU-overriding level). Also, how are the segments loaded? They should load descriptors as well? Also, shoudn't those(looking at the 80286 EU unit of CAPE) be loaded cycle-accurate as well? I see it's directly returning the data from RAM(64-bit entry from RAM is read directly, uninterruptable, by the call itself)?

CAPE_PROCESSOR_DESCRIPTOR* CAPEProcessor80286::getGDTEntry(uint32_t index)
{
return (CAPE_PROCESSOR_DESCRIPTOR*)(m_pComputer->m_pMMU->getPointerToData(m_kGDTR.address + index * 8));
}

CAPE_PROCESSOR_DESCRIPTOR* CAPEProcessor80286::getLDTEntry(uint32_t index)
{
return (CAPE_PROCESSOR_DESCRIPTOR*)(m_pComputer->m_pMMU->getPointerToData(m_kLDTR.address + index * 8));
}

CAPE_PROCESSOR_IDT* CAPEProcessor80286::getIDTEntry(uint32_t index)
{
return (CAPE_PROCESSOR_IDT*)(m_pComputer->m_pMMU->getPointerToData(m_kIDTR.address + index * 8));
}

Shouldn't that be done in a cycle-accurate way as well? Also, paging on the 80386(when you start to implement that) makes this pretty much unworkable.

It is done in cycle accurate. All that function does is a pointer retrieval. It does not dereference anything.
For 386 those functions will be virtual and the 386 implementation will be different.

In CAPE each processor or piece of hardware (like a video card or even 8255) is uniquely implemented. I use inheritance and virtual functions to cover similarities. So a 386 will be its own processor with its own EU/processor implementation derived from a 286 and will override all virtual functions that are different.

I do the same for video cards. I have each card CGA, MDA, Hercules, EGA implemented separately and I do not run just EGA and run it in CGA mode when I want CGA. I even have 2 versions of Intel 8255 because the PCJr one is quite different so rather than cram 2 implementation in 1 single cpp file I have 2 implementations.

Hope that makes sense.

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 5 of 7, by kazblox

User metadata
Rank Newbie
Rank
Newbie
vladstamate wrote:

I even have 2 versions of Intel 8255 because the PCJr one is quite different so rather than cram 2 implementation in 1 single cpp file I have 2 implementations.

The PCjr motherboard uses a regular 8255 IC though. Perhaps the pins are hooked up to a different interface?

Reply 6 of 7, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

It seems to expect to behave differently. PCEm also has a special 8255 emulation for PCJr. Port 62h seems to return different values and it works a bit different than on an PC XT.

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 7 of 7, by crazyc

User metadata
Rank Member
Rank
Member
vladstamate wrote:

It seems to expect to behave differently. PCEm also has a special 8255 emulation for PCJr. Port 62h seems to return different values and it works a bit different than on an PC XT.

The PCJR has a real 8255. It's wired up almost entirely differently than a 5150.