VOGONS


First post, by dartfrog

User metadata
Rank Newbie
Rank
Newbie

A place for me to post about my card and driver development without spamming other's threads. I have recently made a huge win. Real data from a PicoGus on Windows 10!

---

For those unaware, I've been working on a weird but promising setup: using an IT8888 PCI-to-ISA bridge behind an IT8893 PCIe-to-PCI bridge, under Windows 10, with the goal of eventually supporting ISA DMA / DDMA-style access for things like PicoGUS. Specifically my goal is to support old CNC ISA cards, which is a much bigger task than something like a GUS.

The hardware topology currently looks like this:

Lenovo ThinkCentre M93p / Intel i7-4790 / Chipset Intel Q87
Intel PCIe Root Port
-> ITE IT8893 PCIe-to-PCI bridge (on motherboard)
-> ITE IT8888 PCI-to-ISA bridge (my PCI-ISA card)
-> ISA slot
-> PicoGUS / ISA POST card

The IT8888 is detected by Windows as a PCI device. I wrote a KMDF diagnostic driver and a user-mode tool, "it8888ctl.exe", to poke at PCI config space, IT8888 config registers, port I/O, DDMA registers, traces, and a DMA common buffer.

At first, the IT8888 itself looked alive: PCI config reads worked, the device started, and I could program its positive decode windows. For example, the IT8888 was configured with classic legacy-style I/O decode windows:

cfg58 = e4000220   ; SB-ish 0x220 window
cfg5c = e3000330 ; MPU/GUS-ish 0x330 window
cfg60 = e2000388 ; OPL 0x388 window

But actual ISA I/O reads from "0x220", "0x330", and "0x388" all returned "0xFF". At first I thought maybe the IT8888 was not initialized correctly, or maybe the ISA device was not responding.

The real issue turned out to be upstream bridge forwarding.

I added a "pci-dumpcfg" command to dump arbitrary PCI config space by bus/device/function. That showed the IT8893 bridge and the Intel root port both had their I/O forwarding windows effectively disabled/inverted:

I/O base = 0xf0/f1
I/O limit = 0x00/0x01
decoded as base 0xf000, limit 0x0fff

So even though the IT8888 was configured to decode "0x220", the upstream PCIe/PCI bridge chain was not forwarding those low I/O cycles to it.

I then added raw CF8/CFC PCI config access to the driver, because Windows/HAL config writes were failing for the bridge registers. With that, I could manually open the bridge I/O windows.

For example, opening both bridges to forward "0x8000–0x8FFF" now works:

bridge-iowin 0:28.3 0x8000-0x8fff
command old=0x0404 new=0x0405
io base new=0x80
io limit new=0x80

bridge-iowin 3:0.0 0x8000-0x8fff
command old=0x0407 new=0x0407
io base new=0x80
io limit new=0x80

"pci-dumpcfg" then confirms:

I/O window decoded: 0x00008000-0x00008fff
contains 0x8390: YES

I tried two approaches after that.

First, I tried mapping legacy ISA ports into the high forwarded window:

0x220 -> 0x8220
0x330 -> 0x8330
0x388 -> 0x8788

The IT8888 accepted these high decode values:

cfg58 = e4008220
cfg5c = e3008330
cfg60 = e2008788

Port I/O to those addresses now reaches the driver and is forwarded by the bridges, but plain reads from an ISA POST card naturally just return "0xFF" because a POST card mostly cares about writes to port "0x80".

I also tried opening the bridge windows to "0x0000–0x0FFF" for true legacy I/O. That technically works, but it is dangerous and started causing hangs after some commands. That makes sense: forwarding the whole low legacy I/O page through a PCI bridge can collide with chipset/PIC/PIT/DMA/ACPI/VGA legacy regions. So I am avoiding that except for very short controlled tests.

The big breakthrough was with PicoGUS.

PicoGUS has its own management/control protocol at:

control: 0x1D0
data low: 0x1D1
data high: 0x1D2

So I mapped that into the safe high bridge window: IT8888 cfg60 = e20081d0

Then I opened both upstream bridges to "0x8000–0x8FFF" and talked to PicoGUS at "0x81D0–0x81D2".

This worked.

Protocol read:

out 0x81D0 <- 0xCC
out 0x81D0 <- 0x01
in 0x81D2 -> 0x03

Firmware string read:

out 0x81D0 <- 0xCC
out 0x81D0 <- 0x02
in 0x81D2 -> 0x70
in 0x81D2 -> 0x69
in 0x81D2 -> 0x63
in 0x81D2 -> 0x6f
in 0x81D2 -> 0x67
in 0x81D2 -> 0x75
in 0x81D2 -> 0x73
in 0x81D2 -> 0x2d

Which decodes to:

picogus-

This text is actually from the PicoGUS, specifically it's part of the "picogus-gus vX.X.X" text where X.X.X is the version number. pgusinit tells you this text and version number when it detects a PicoGUS. The fact we can see this in Win10 is a major step. After 2 years of messing about, I finally got provable real data from an ISA card on Windows 10 on a modern-ish PC (4th gen chipset Q87).

So the full path is proven:

Windows 10 kernel driver
-> Intel PCIe root port
-> IT8893 PCIe-to-PCI bridge
-> IT8888 PCI-to-ISA bridge
-> ISA bus
-> PicoGUS

This is a pretty big milestone. It means the card is reachable through the bridge chain if the bridge I/O windows and IT8888 decode windows are configured carefully.

Current lessons learned:

The IT8888 was not the only problem.
The upstream IT8893/root-port I/O forwarding windows matter.
Windows does not necessarily allocate/enable legacy I/O forwarding for this bridge chain.
Raw PCI config writes via CF8/CFC were needed to force bridge I/O windows open.
Forwarding 0x0000–0x0FFF is risky and can hang the system.
A safer strategy is forwarding 0x8000–0x8FFF and mapping IT8888 decode windows into that range.
PicoGUS management/control protocol works through a high alias, proven by reading the firmware string.

The next step is to add proper PicoGUS helper commands to "it8888ctl", instead of manually doing byte pokes. Something like:

pgus-protocol
pgus-fwstring
pgus-read <cmd> <count>
pgus-write8 <cmd> <value>
pgus-write16 <cmd> <value>
pgus-get-sb
pgus-set-sb 0x220 irq dma type

After that, the next milestone is configuring PicoGUS into SB mode and testing SB DSP reset through an aliased SB window:

IT8888 cfg58 = e4008220   ; SB alias
IT8888 cfg5c = e3008330 ; MPU alias
IT8888 cfg60 = e2008788 ; OPL alias

Then test:

out 0x8226 <- 1
out 0x8226 <- 0
in 0x822E
in 0x822A

The hoped-for result is the classic SB reset response:

0x822A -> 0xAA

There is still a lot left, like supporting real CNC ISA cards, especially real DMA/DDMA behavior. But at this point I have proven that real ISA hardware behind a PCIe-to-PCI-to-ISA chain can be reached from Windows 10, as long as the bridge and IT8888 decode windows are configured manually.

All my hardware, code, docs, and tests are in the repo in my signature, and specifically for this thread, the folder contains the code and driver in "DartFrogTek/PCIe-PCI-ISA/DFT_VMDA8/it8888vdma_win10_predosbox"

What i'm currently working on:

Stop manually poking bytes and add real it8888ctl PicoGUS helpers, including real DMA/DDMA work.

---

Below is a section to talk about why im doing this on Win10, there is method to the madness.

Why Windows 10? wrote:
I'm doing this under Windows 10 first because it is the harshest and most useful test environment for this project. […]
Show full quote

I'm doing this under Windows 10 first because it is the harshest and most useful test environment for this project.

In DOS or Windows 9x, software can usually hit legacy ISA I/O ports directly and the system firmware/chipset may already have some legacy behavior enabled. That makes it easier to get a sound card or POST card to respond, but it also hides which part of the bridge chain is actually working.

Windows 10 is much stricter. It does not automatically make this PCIe -> PCI -> ISA chain behave like a real 1990s ISA bus. The OS did not give the upstream bridges useful legacy I/O forwarding windows, and normal low ISA ports like `0x220`, `0x330`, and `0x388` were not forwarded to the IT8888 at all. I had to prove and manually configure each layer:

PCI config access works
IT8893/root port I/O forwarding works
IT8888 positive decode works
kernel port I/O reaches the bridge
real ISA hardware responds

That is why Windows 10 is useful here: if I can make the chain work from a modern protected OS with manually configured bridge windows, then I have proven the actual hardware path is functional instead of relying on BIOS magic.

It also makes DOS and older Windows easier to reason about later. Once the correct IT8893 bridge window and IT8888 decode settings are known, I can reproduce those settings from a DOS tool, Windows 9x VxD/WDM driver, or even an option-ROM/init utility. The working Windows 10 driver gives me a known-good register recipe.

So this is not "Windows 10 because I expect Win10 to be the final ISA gaming environment." It is more like a diagnostic proving ground. If PicoGUS answers through this chain on Windows 10, then the same bridge/decode configuration should be portable to DOS or older Windows, where the software stack is actually more compatible with ISA sound hardware.

The current PicoGUS result is exactly that kind of proof:

Windows 10 driver
-> manually opens root port + IT8893 I/O window
-> programs IT8888 decode window
-> performs port I/O
-> PicoGUS returns firmware string bytes: "picogus-"

That means the electrical and bridge path is real. The next job is packaging the same initialization into a cleaner tool/driver so DOS, Win9x, or other older environments can set the bridges up before using the ISA device normally.

---

A small section about possible address-translation fallback via FPGA incase some legacy ISA devices require the IT8888 or ISA bus to see the original low addresses exactly, an FPGA could translate the address phase of PCI transactions:

Possible FPGA address-translation fallback wrote:
One possible fallback is a small FPGA/CPLD interposer that performs address translation on the PCI side before the IT8888 sees t […]
Show full quote

One possible fallback is a small FPGA/CPLD interposer that performs address translation on the PCI side before the IT8888 sees the cycle.

The current software approach is to keep the upstream bridges forwarding a safe high I/O window, such as:

0x8000–0x8FFF

and then program the IT8888 to decode high aliases like:

0x81D0 for PicoGUS control
0x8220 for Sound Blaster
0x8330 for MPU-401
0x8788 for OPL

This already works for PicoGUS control access, so an FPGA is not needed for that part. However, if some legacy ISA devices require the IT8888 or ISA bus to see the original low addresses exactly, an FPGA could translate the address phase of PCI transactions:

0x8220 -> 0x0220
0x8330 -> 0x0330
0x8788 -> 0x0388

while leaving data phases unchanged.

That would let the host and upstream bridges use a safe high I/O window, while the IT8888/ISA side sees traditional legacy addresses. This is not the first choice because modifying PCI address/data lines in real time is timing-sensitive and should be done with proper glue logic, not a microcontroller bit-bang hack. A small CPLD/FPGA would be the right tool if it becomes necessary.

For now, the better result is that PicoGUS has already responded through a pure software-configured high alias. The FPGA idea remains a fallback only if certain ISA devices cannot tolerate high-address aliasing or if real SB/DMA behavior requires exact low-address presentation.

Potential PCIe-to-PCI-to-ISA pathway repository: https://github.com/DartFrogTek/PCIe-PCI-ISA

Reply 1 of 8, by weedeewee

User metadata
Rank l33t
Rank
l33t

Very nice. Good work.
A question about the bridge window. While setting it from 0x0 to 0xFFF is indeed problematic. Could it be set from 0x200 to 0xFFF ?

Right to repair is fundamental. You own it, you're allowed to fix it.
How To Ask Questions The Smart Way
Do not ask Why !
https://www.vogonswiki.com/index.php/Serial_port

Reply 2 of 8, by rasteri

User metadata
Rank Oldbie
Rank
Oldbie

Wow neat!

As you say DMA may be a challenge, but here's hoping!

Reply 3 of 8, by dartfrog

User metadata
Rank Newbie
Rank
Newbie
weedeewee wrote on Yesterday, 15:52:

Very nice. Good work.
A question about the bridge window. While setting it from 0x0 to 0xFFF is indeed problematic. Could it be set from 0x200 to 0xFFF ?

Thanks! Unfortunately, no, not with the normal Type-1 PCI bridge I/O window. The bridge I/O base/limit registers are 4 KB granular. The register only carries address bits 15:12; the lower 12 bits are implied. Roughly:

base  = (IO_BASE  & 0xF0) << 8;
limit = ((IO_LIMIT & 0xF0) << 8) | 0x0FFF;

So if the window needs to include 0x220, the smallest normal bridge I/O window is: 0x0000-0x0FFF. You can't express 0x0200-0x0FFF with the standard bridge I/O base/limit registers.

Here's a useful reference for PCI configuration space / Type 1 bridge headers for anyone interested.
https://web.archive.org/web/20260412184036/ht … tlk/dd/pci.html

rasteri wrote on Yesterday, 17:43:

Wow neat!

As you say DMA may be a challenge, but here's hoping!

Neat indeed! Thanks again for your work. We are so very close now. The encouraging part is the bridge I/O forwarding and PicoGUS control path working. I still need to finish the driver-side DMA/DDMA path and test whether the IT8888/PicoGUS handshake behaves the way we want, but if the industrial motherboards containing IT8888's are any evidence, I would say there's no real unsolved problems left. There is also a possibility that IRQ works differently from I/O and DMA paths, but I don't see either DMA or IRQ paths as major problems, just hurdles to jump now. My current expectation is that normal I/O should keep the IT8888 acting as a PCI target/slave, while DMA/DDMA will require the IT8888/DDMA engine to become a PCI bus master only during the actual transfer. IRQ may also have its own quirks. So I would not call those completely solved yet, but the fact that real ISA hardware is responding is a very good sign.

Potential PCIe-to-PCI-to-ISA pathway repository: https://github.com/DartFrogTek/PCIe-PCI-ISA

Reply 4 of 8, by EduBat

User metadata
Rank Member
Rank
Member
dartfrog wrote on Yesterday, 10:05:

Then I opened both upstream bridges to "0x8000–0x8FFF" and talked to PicoGUS at "0x81D0–0x81D2".

This worked.

Awesome work. This is a great discovery, it means that the sound card is ignoring bit A15 of the I/O access address and responding to accesses to it.
Can't wait for more developments...

Reply 5 of 8, by NeoG_

User metadata
Rank Oldbie
Rank
Oldbie
EduBat wrote on Yesterday, 22:56:

Awesome work. This is a great discovery, it means that the sound card is ignoring bit A15 of the I/O access address and responding to accesses to it.
Can't wait for more developments...

My understanding is that the card interacts on 0x1D0 natively via the ISA bus, the bridge is translating the addresses bi-directionally into and from the 0x8000 range. So only the controller software side (currently being done with primitive reads/writes) needs to be on 0x8000.

98/DOS Rig: BabyAT AladdinV, K6-2+/550, V3 2000, 128MB PC100, 20GB HDD, 128GB SD2IDE, SB Live!, SB16-SCSI, PicoGUS, WP32 McCake, iNFRA CD, ZIP100
XP Rig: Lian Li PC-10 ATX, Gigabyte X38-DQ6, Core2Duo E6850, ATi HD5870, 2GB DDR2, 2TB HDD, X-Fi XtremeGamer

Reply 6 of 8, by EduBat

User metadata
Rank Member
Rank
Member

We are both describing something that is also known as I/O aliasing (see attached, chapter 3.1)

The attachment 318244.pdf is no longer available

Also, I hope this cheat sheet is useful. I did this some time ago as a fun exercise, it may contain errors...

The attachment DMA.txt is no longer available

Reply 7 of 8, by dartfrog

User metadata
Rank Newbie
Rank
Newbie
EduBat wrote on Yesterday, 22:56:

Awesome work. This is a great discovery, it means that the sound card is ignoring bit A15 of the I/O access address and responding to accesses to it.
Can't wait for more developments...

NeoG_ wrote on Yesterday, 23:30:

My understanding is that the card interacts on 0x1D0 natively via the ISA bus, the bridge is translating the addresses bi-directionally into and from the 0x8000 range. So only the controller software side (currently being done with primitive reads/writes) needs to be on 0x8000.

EduBat wrote on Today, 00:55:

We are both describing something that is also known as I/O aliasing (see attached, chapter 3.1)

I think both descriptions are pointing at the same practical effect, but I want to be careful about where the claim for aliasing is happening. What I have proven so far is:

host I/O 0x81D0/0x81D2
-> Intel root port forwards 0x8000-0x8FFF
-> IT8893 forwards 0x8000-0x8FFF
-> IT8888 positive-decodes 0x81D0
-> PicoGUS answers with:
CMD_PROTOCOL -> 0x03
CMD_FWSTRING -> "picogus-"

We know this high window path is working. Whether that means "PicoGUS ignores A15" specifically, or whether the IT8888 is effectively translating/truncating the ISA-side address, I do not want to claim either without probing the ISA address lines with a logic analyzer. However functionally it behaves like I/O aliasing: the Windows side software can talk to a high alias in 0x8000-0x8FFF and still reach the legacy PicoGUS control path.

The Intel paper's section on I/O aliasing is relevant here: many ISA devices only decode a limited number of I/O address bits, so upper address bits become "don't care bits" and the same device can answer at multiple aliases. The practical result is that I do not need to forward the dangerous 0x0000-0x0FFF bridge window for this path. I can keep the bridges forwarding 0x8000-0x8FFF and use IT8888 decode aliases like 0x81D0, 0x8220, 0x8330, 0x8788.

Personally I'd avoid saying "the bridge is translating bidirectionally into and from the 0x8000 range" unless by "bridge" you mean the whole root port/IT8893/IT8888 chain. A normal PCI to PCI bridge is not translating the port number, it is forwarding a window. The main take away is that the IT8888 decode plus ISA side aliasing is what makes the high address useful.

There might be some problems with I/O aliasing though, if an ISA device does actually decode upper address bits, then that FPGA workaround might be needed for that kind of card. I suspect some devices might behave differently than what is the letter of the spec and datasheets actually say

---

Some more info on the IRQ and DMA side, we are seemingly covered by some of the most common PCIe-PCI bridges and the IT8888 PCI -> ISA bridge

IRQ:
mostly yes, translated up through PCI INTx -> PCIe INTx messages, assuming IT8888 IRQ routing is configured.

DMA/DDMA:
yes in principle, but only after IT8888 DDMA is explicitly armed and a real ISA side DRQ/DACK transaction happens. Specifically IT8893 can forward the resulting PCI bus-master traffic. This is also true for other PCIe-PCI bridges, but i have no idea about all of them, just the ones I read their docs for seem to agree it's possible, so that's a good sign.

The bridge chip is designed to carry downstream PCI master transactions upstream. That is exactly the kind of mechanism DDMA needs. The part that is not automatic is IT8888 DDMA. We still have to configure/arm the IT8888 DDMA windows and channel behavior. My current driver already has the IT8888 command register, I/O, memory, and bus-master enable set (cmd/status 0x02800007), and the DDMA base windows are programmed at 0x8380, 0x8390, 0x83a0, etc. But bus-master enable just gives permission; it does not start a transfer by itself.

This is what I'm working on atm, get/force the ISA side to initiate a transfer. I'm optimistic it will just work because the glue/configuration layer is all done in my kernel level driver and it8888ctl.exe. Which is why KYA's whole idea on VirtualDMA was such a ground breaking idea for me. By both using something like VDMA and keeping normal I/O target/slave based, while only enabling bus mastering for DDMA if/when the DDMA engine needs it. It's allowed me to rebuild the missing machinery virtually. I vaguely remember us talking about something similar to VDMA/kernel driver in rasteri's thread, but IIRC I dismissed it too early because I had not yet discovered/accounted for the I/O aliasing effect and also misunderstanding the nature of master/slave on the IT8888. You both are right to focus on the aliasing effect, because without it I am now certain the high window approach would not be possible without the extra FPGA hardware. Keeping the FPGA out of the chain is a real desirable goal as any timing addition might make issues and a soundcard will be first to sound the problems, pun intended.

---

One minor note: I have gotten a question in my email about what the folder name "it8888vdma_win10_predosbox" means, specifically what does "predosbox" mean in the repo. Well, if this approach works fully, I will move on to try and patch DOSBOX to use real ISA hardware through my driver. Which is what will be required for my goal of actually supporting old CNC ISA cards on a modern OS, since most drivers/software do not exist past DOS. Obviously this would mean you too could use your ISA cards with DOSBOX. That's my end goal: Real ISA hardware communicating with DOSBOX on Win10+.

---

Anyways I'll get back to work, as I'm sure some of you are just screaming at your monitor: "GOSH DARN IT, DF! JUST TELL ME ALREADY! DOES THE GUS PLAY DOOM MUSIC YET??!?!"

I will try my best making this work. I have not and will not rest until every possible avenue is explored.

Potential PCIe-to-PCI-to-ISA pathway repository: https://github.com/DartFrogTek/PCIe-PCI-ISA

Reply 8 of 8, by NeoG_

User metadata
Rank Oldbie
Rank
Oldbie
dartfrog wrote on 29 minutes ago:

Personally I'd avoid saying "the bridge is translating bidirectionally into and from the 0x8000 range" unless by "bridge" you mean the whole root port/IT8893/IT8888 chain.

Yes I was inaccurately referring to the steps in between as the bridge - Logically truncation can only work in one direction, once the data has to return via the same path the alias needs to be added. So something in the chain is actively managing the process of going between 0x8000 and the original addresses on the ISA bus side which is why I would lean on calling it translation.

98/DOS Rig: BabyAT AladdinV, K6-2+/550, V3 2000, 128MB PC100, 20GB HDD, 128GB SD2IDE, SB Live!, SB16-SCSI, PicoGUS, WP32 McCake, iNFRA CD, ZIP100
XP Rig: Lian Li PC-10 ATX, Gigabyte X38-DQ6, Core2Duo E6850, ATi HD5870, 2GB DDR2, 2TB HDD, X-Fi XtremeGamer