VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

When I execute a IN AX,DX or IN EAX,DX what ports are read and what are their sizes?

Is, when DX=100, the ports read:
AX = readportbyte(100) | (readportbyte(101)<<8)
Or is:
AX = readportword(100).

So if I use:
OUT 20h,AX
Is AX written:
AL=>port 20h
AH=>port 21h
Or is AX written:
AX=>20h(word port, if it exists)

Or does this depend on the devices listening to the port? So a VGA would respond like the first case (since it's 8-bits, so 8 bits to port X and 8 bits to port X+1) and a hard disk buffer (port 170/1F0) would accept the whole word on a single port and the port after that (port 1F1) would be ignored?

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

Reply 1 of 10, by Harekiet

User metadata
Rank DOSBox Author
Rank
DOSBox Author

If it's a properly aligned adress the bus logic first tries a word, if that isn't responded on by a device accepting the word bus request, it just does the bytes requests.
Unaligned ones always get split up as far as I know.

Reply 2 of 10, by superfury

User metadata
Rank l33t++
Rank
l33t++

What happens when a dword is read/written to/from an I/O port? Is unaligned access and with no response immediately split up to byte read/writes to the four ports, or is a word in/out performed on port X and X+2, which execute byte I/O when unaligned or no hardware response?

So it's:
Word->byte and byte+1

During 32-bit read/write:
Dword->word and word+2
Or
Dword->byte, byte+1, byte+2 and byte+3?

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

Reply 3 of 10, by Harekiet

User metadata
Rank DOSBox Author
Rank
DOSBox Author

Well considering the ISA bus is only 16 bit you'll only ever get 16 bit access to isa devices but PCI and VLB do allow for direct 32bit transfers

With aligned transfers the cpu will requests a direct 32bit transfer if memory/bus fail to respond it tries for 16/16 bits.
Unaligned transfers will have the cpu split up in 16/16 or 8/16/8 depending on the alignment

The isa bus controller can then split up those 16 bits again if no device on it's bus responds to the 16 bit requests directly.

But either way I doubt you'll see much 32bit i/o access unless you start to play with emulating pci cards.

Reply 4 of 10, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

A 386SX won't be able to do a 32bit transfer with an IN EAX, DX though, it will either be a 16+16 or 4x8. I do wonder though, does it still wait for the memory/bus to fail or does it do it properly from the start?

Vlad.

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 10, by Harekiet

User metadata
Rank DOSBox Author
Rank
DOSBox Author

A 386 SX only has a 16 bit data bus so it won't even try to do any 32bit stuff and immediatly break them up in 16/16 or 8/16/8
A 386 DX has some extra line on the data bus so it can work with 16 or 32bit memory banks. Although I don't think there's any delays involved, it tries to access 32bit and sees in the result phase if it actually got 32bit and if not tries a secondary 16bit access.
I wonder if a 386 would actually try to ask the system for a 32bit IO access and not directly break them up since there wouldn't be any bus capable of providing 32bit IO data.

Reply 6 of 10, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've currently programmed by I/O operations like this:

32-Bit: Try 32-bit. If fails or unaligned, call 16-bit.
16-Bit: Try 16-bit. If fails or unaligned, call 8-bit.
8-Bit: Try 8-bit. If fails, log if enabled.

So the call path with all failing is:
32-Bit->16-Bit->8-Bit->Log.
16-Bit->8-Bit->Log.
8-Bit->Log.

Is this correct?

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

Reply 7 of 10, by kjliew

User metadata
Rank Oldbie
Rank
Oldbie

This is implementation specific. There is no set rules in X86, most would refer to Intel chipsets for standard I/Os. The hardware logics can choose to decode byte-enables and only response to the cycles with correct byte-enables. For eg. the PCI index I/O 0xCF8 can only accept 32-bit I/O while the data I/O 0xCFC can take all per the typical I/O boundary rule. Another example, IDE data port at 0x1F0 or the native BAR+0x0 address, only IDE controller supporting 32-bit PIO can accept 32-bit read/write, otherwise, it should always be 16-bit because the IDE bus is 16-bit. So on 32-bit PIO, the controller will be issuing two 16-bit back-to-back cycles to make up the 32-bit data.

Most of the IBM PC standard I/Os only work for 8-bit I/O, such as PIT, PIC, DMA, RTC etc. The HW should not ACK for non 8-bit cycles. None of the pre-PCI PC legacy I/O can deal with 32-bit operation that I can remember, other than the IDE.

X86 I/O is not memory. Its mapping is entirely orthogonal. It is mostly wrong to assume 16/32-bit I/O breaking down to 8-bit pieces at subsequent I/O address. For example, 16/32-bit access for IDE 0x1F0 is not the same as 8-bit access to 0x1F0...0x1F3.

Reply 8 of 10, by superfury

User metadata
Rank l33t++
Rank
l33t++

My emulator currently acts like the call path with all failing I gave in my last post.

The only 16-bit handled port is the IDE 0x1F0(or the address it's mapped to with the PCI BAR+0 when not 0/1). That port will respond to the 16-bit read/write. My PCI CF8/CFC are 8-bit handlers in my emulation, so they will break up into seperate 8-bit writes to CF8/9/A/B and CFC/D/E/F. This way it should be compatible with 80(1)86 writes in my emulator (32-bit I/O is implemented but not used yet, as I don't have a 286/386/486 processor fully emulated yet. Still working on getting multitasking fully implemented and after that to implement the opcodes themselves (only CPUID is supported atm on the 286+ with 80(1)86 opcodes up to 16-bit(both memory, data and I/O) reads/writes.))

Also what about the VGA CRTC registers? I've seen them being addressed using a single word port out to set the index and data at the same time. I know the CPU breaks it up into two 8-bit writes for the VGA to set the register.

MOV DX,03B4h ;CRTC base address
MOV AX,0102h ;Set register 01h to value 02h.
OUT DX,AX ;Set the register!

will set CRTC register 01h to value 02h. So the instruction should work this way, although the VGA is a 8-bit I/O device.

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

Reply 9 of 10, by Jepael

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:
Also what about the VGA CRTC registers? I've seen them being addressed using a single word port out to set the index and data at […]
Show full quote

Also what about the VGA CRTC registers? I've seen them being addressed using a single word port out to set the index and data at the same time. I know the CPU breaks it up into two 8-bit writes for the VGA to set the register.

MOV DX,03B4h ;CRTC base address
MOV AX,0102h ;Set register 01h to value 02h.
OUT DX,AX ;Set the register!

will set CRTC register 01h to value 02h. So the instruction should work this way, although the VGA is a 8-bit I/O device.

What about VGA registers, what is the exact question?
If the VGA card supports 16-bit bus, and is sitting on a 16-bit ISA slot, it will use word transfer. (Some 16-bit cards are 16-bit only so they cannot be put on 8-bit bus, but maybe some 16-bit cards can work in 8-bit slots as well.)
If the VGA card supports only 8-bit bus, it does not matter if it is in 8 or 16 bit slot and "out dx,ax" will transfer two bytes.

The card is the one that decodes the IO address, and signals to ISA bus if it can support 16 bit transfers at this address or not with IOCS16 signal.
So if CPU wants to transfer a word to an IO address, a bus controller checks the IOCS16 and if it is active then it will enable 16-bit cycle by setting SBHE signal and then the VGA card knows it is a 16-bit cycle.
And if CPU wants to transfer a word but card does not support 16-bit access, IOCS16 is not active so bus controller knows it must be sent as two 8-bit transfers to address+0 and and address+1.
But, what is unclear to me still is that if I want to transfer a byte to non-word aligned odd address so A[0]=1, should the card drive IOCS16 or not, and is the byte sent with SBHE enabled but in D[15..8] so D[7..0] are ignored, or as a regular 8-bit access without SBHE and data on D[7..0].

But I don't know if this matters a lot when you are not physically emulating the ISA bus but a functional emulation, so you can make simplifications how things work. (I know you could emulate a whole CPU and motherboard and video card at the transistor model and electromagnetic wave propagation model if you wanted, but that would not make much sense, unless you are modeling the analog composite output of CGA for example)

Actually, small detail but isn't it the other way around in your example, setting value 01h to register 02h? Byte going to port+0 is low byte, and byte going to port+1 is high byte?

Reply 10 of 10, by superfury

User metadata
Rank l33t++
Rank
l33t++
Jepael wrote:
What about VGA registers, what is the exact question? If the VGA card supports 16-bit bus, and is sitting on a 16-bit ISA slot, […]
Show full quote
superfury wrote:
Also what about the VGA CRTC registers? I've seen them being addressed using a single word port out to set the index and data at […]
Show full quote

Also what about the VGA CRTC registers? I've seen them being addressed using a single word port out to set the index and data at the same time. I know the CPU breaks it up into two 8-bit writes for the VGA to set the register.

MOV DX,03B4h ;CRTC base address
MOV AX,0102h ;Set register 01h to value 02h.
OUT DX,AX ;Set the register!

will set CRTC register 01h to value 02h. So the instruction should work this way, although the VGA is a 8-bit I/O device.

What about VGA registers, what is the exact question?
If the VGA card supports 16-bit bus, and is sitting on a 16-bit ISA slot, it will use word transfer. (Some 16-bit cards are 16-bit only so they cannot be put on 8-bit bus, but maybe some 16-bit cards can work in 8-bit slots as well.)
If the VGA card supports only 8-bit bus, it does not matter if it is in 8 or 16 bit slot and "out dx,ax" will transfer two bytes.

The card is the one that decodes the IO address, and signals to ISA bus if it can support 16 bit transfers at this address or not with IOCS16 signal.
So if CPU wants to transfer a word to an IO address, a bus controller checks the IOCS16 and if it is active then it will enable 16-bit cycle by setting SBHE signal and then the VGA card knows it is a 16-bit cycle.
And if CPU wants to transfer a word but card does not support 16-bit access, IOCS16 is not active so bus controller knows it must be sent as two 8-bit transfers to address+0 and and address+1.
But, what is unclear to me still is that if I want to transfer a byte to non-word aligned odd address so A[0]=1, should the card drive IOCS16 or not, and is the byte sent with SBHE enabled but in D[15..8] so D[7..0] are ignored, or as a regular 8-bit access without SBHE and data on D[7..0].

But I don't know if this matters a lot when you are not physically emulating the ISA bus but a functional emulation, so you can make simplifications how things work. (I know you could emulate a whole CPU and motherboard and video card at the transistor model and electromagnetic wave propagation model if you wanted, but that would not make much sense, unless you are modeling the analog composite output of CGA for example)

Actually, small detail but isn't it the other way around in your example, setting value 01h to register 02h? Byte going to port+0 is low byte, and byte going to port+1 is high byte?

You're right. Got it backwards indeed. It's supposed to be MOV AX,0201h. Was thinking in the order my emulated CPU reads the instruction (first reading the opcode, then low byte, then high byte. But assembly hexdecimal values are reversed (high byte(s) first, low byte(s) last (12345678h in memory is 78563412h is (dis)assembly in the case of x86)).

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