First post, by vladstamate
- Rank
- Oldbie
(This could be under Release Announcements however not yet as I am not yet releasing it as such until I figure out something about the sourcecode. This is more of a technical annoucement for now).
It all started with this (from Scali) a bit more than 6 months ago:
wrote:Ok, Scali, that is it, challenge accepted! :) […]
wrote:I think the world of PC emulation just has an attitude problem. They don't know how to build proper emulators, and they don't know that they don't know how to build proper emulators.
wrote:It is simply inexcusable that for the most popular personal/home computer platform out there, nobody seems to be capable of delivering a proper emulator. The C64/Amiga people apparently have much higher standards/skills.
Ok, Scali, that is it, challenge accepted! 😀
I am going to fork my emulator code, and have it just emulate the IBM PC. No PCJr, 186, 286, 386, AdLib, etc. Just the IBM PC. My code already emulates the bus , the prefetch queue (on bus idle cycles), memory wait states, CGA memory vs conventional ram speed, 8bit bus, instruction cycle timing (including accurate EA calculation timing). There are still quite a few things which I do not do at the moment, and lack support for (like CGA per pixel timing emulation and better instruction timing). I will work on fixing those.
So here it is. I finally did it. You can check more details at https://sites.google.com/site/capex86/home. It supports almost all SW/games I threw at it that should run on an IBM PC XT.
Basically this is an x86/x88 emulator that at the core is not an instruction emulator but rather a cycle emulator. Notice I am not saying mine is better just different. That means there is no such thing as the traditional loop:
1) fetch instruction (from prefetch or otherwise)
2) big switch statement (or function pointer table) to execute said instruction (and write out to memory or registers)
3) increment CS:IP
4) delay enough cycle to make it timing accurate
5) go to 1
Instead at the processor level it emulates the BIU and the EU (and EA) at the cycle level and it will do required action each cycle same as a real processor does. In other words only the work required for that cycle for a given instruction is done in a given cycle (now that is not true for the actual execution say a-b, as that I do instant when execution needs to happen but no results are written out of course until it is time). Also things like HW interrupts or NMI are also emulated in the cycle fashion which is not something I've ever seen done.
A little bit of its log explains a bit more:
Cycle 4654501 T1 [ 0xb4 xxxx xxxx xxxx ] EA calculation { ea read execute delay }
Cycle 4654502 T2 [ 0xb4 xxxx xxxx xxxx ] EA calculation { ea read execute delay }
Cycle 4654503 T3 [ 0xb4 xxxx xxxx xxxx ] EA calculation { ea read execute delay }
Cycle 4654504 T4 0xff675 0x a >P [ 0xb4 0x0a xxxx xxxx ] EA calculation { ea read execute delay }
Cycle 4654505 T1 [ 0xb4 0x0a xxxx xxxx ] EA calculation { ea read execute delay }
Cycle 4654506 T2 [ 0xb4 0x0a xxxx xxxx ] EA calculation { ea read execute delay }
Cycle 4654507 T3 [ 0xb4 0x0a xxxx xxxx ] { read execute delay }
Cycle 4654508 T4 0x003e2 0x 7 <M [ 0xb4 0x0a xxxx xxxx ] { execute delay }
Cycle 4654509 T1 [ 0xb4 0x0a xxxx xxxx ] executing { delay }
Cycle 4654510 T2 [ 0xb4 0x0a xxxx xxxx ] { decode }
Cycle 4654511 T3 <P [ 0x0a xxxx xxxx xxxx ] new opcode 0xb4 { imm execute delay }
Cycle 4654512 T4 0xff676 0xb9 <P >P [ 0xb9 xxxx xxxx xxxx ] { execute delay }
Cycle 4654513 T1 [ 0xb9 xxxx xxxx xxxx ] executing { delay }
Cycle 4654514 T2 [ 0xb9 xxxx xxxx xxxx ] executing delay { decode }
Cycle 4654515 T3 <P [ xxxx xxxx xxxx xxxx ] new opcode 0xb9 { imm execute delay }
Cycle 4654516 T4 0xff677 0x 1 >P [ 0x01 xxxx xxxx xxxx ] waiting for data { imm execute delay }
Cycle 4654517 T1 <P [ xxxx xxxx xxxx xxxx ] waiting for data { imm execute delay }
Cycle 4654518 T2 [ xxxx xxxx xxxx xxxx ] waiting for data { imm execute delay }
Cycle 4654519 T3 [ xxxx xxxx xxxx xxxx ] waiting for data { imm execute delay }
Cycle 4654520 T4 0xff678 0x 0 >P [ 0x00 xxxx xxxx xxxx ] waiting for data { imm execute delay }
Cycle 4654521 T1 <P [ xxxx xxxx xxxx xxxx ] { execute delay }
Cycle 4654522 T2 [ xxxx xxxx xxxx xxxx ] executing { delay }
Format is
cycle number / cycle type / memory address / memory data / data action (>P read into prefetch, >M write to memory,etc) / prefetch buffer contents / CPU state / next CPU stages
It is written in a nice and clean C++ with a very good inheritance hierarchy so that I can build processors by putting together a certain class of BIU and certain class of EU (or EA).
There is a lot more information on the website about features that I will not mention here.
I just want to say thank you to all who helped me and without him I could not have done this (in no particular order): Jepael, reenigne, superfury, Scali, gdjacobs and all others (you know who you are).
But all this does not really matter because what I really want to do is have 8088MPH running perfectly which it is not 🙁. There are still some visual issues due to a) some cycle timings not being 100% accurate and b) my CGA emulation still not being 100% there in terms of timing.
I am trying to figure out how to push my code on github and not upset my employer. So for now, if anyone would like to see the code, just drop me a note as a personal message and I will provide it to you.
Enjoy the cycles!
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/