HALICERY

free-time coding, hardware dev, articles

Top
Home 8042 Blogs About
Home IntelEssential 16/32-bit Instructions PORTIO

Last modified: Mon Jun 15 15:23:12 UTC+0200 2026 © A. Tarpai


I/O PORT MOVE

I/O devices existing in the 8086 era (1979) were rather simple: mostly with an 8-bit data bus and a few address lines or just a chip-select. The 8086 was a little bit ahead of its time and utilized 64K I/O address space driving 16 address lines and could transfer not only 8- but 16-bit of word data in one cycle – to interface easily with both 8- and newer 16-bit data transfer capable I/O devices. The 8086 signals I/O transfer by driving bus type onto S2..S0 outputs for I/O access, so the bus controller and I/O devices recognize the I/O-bus transfer (address/data-lines are the same). The I/O space is not segmented and A19..16 is not driven.

The x86 I/O address-bus is 16-bit and this has not changed since.

8086 PORT I/O instructions

Implicit data movement between Accumulator and 8/16-bit data bus (CPU signals I/O access type, that is the difference).

2 x 4 = 8 opcodes:

                Fixed port:                     |   Variable port:
                8-bit PORT address is IMM8      |   16-bit PORT address in DX
                ________________________________|_____________________________
                             |                  |              |
 8-bit data:    IN  AL, imm8 |  OUT imm8, AL    |   IN  AL, DX |  OUT DX, AL
                             |                  |              |
16-bit data:    IN  AX, imm8 |  OUT imm8, AX    |   IN  AX, DX |  OUT DX, AX
                                                |
                                                |
                E4..E7                          |   EC..EF
                _______________   ___________   |   _______________
               |1 1 1 0 0 1 d w| |   IMM8    |  |  |1 1 1 0 1 1 d w|
                ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾   ‾‾‾‾‾‾‾‾‾‾‾   |   ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
                                                |
                d=0 IN    w=0 byte              |   d=0 IN    w=0 byte
                d=1 OUT   w=1 word              |   d=1 OUT   w=1 word

I/O instructions drive the lower 16-bit part of the address bus to transfer byte- or word data. The 16-bit effective address is either driven by the content of DX or an immediate 8-bit value following opcode (setting address high to zero):

 Fixed port:                                      Variable port:

 IMM8                                             DX
+----+                                          +----+
|  0 | -->------------ A0                       |  0 | -->------------ A0
|  1 | -->------------ ..                       |  1 | -->------------ ..
|  2 | -->------------ ..                       |  2 | -->------------ ..
|  3 | -->------------ ..                       |  . | -->------------ ..
|  4 | -->------------ ..                       |  . | -->------------ ..
|  5 | -->------------ ..                       |  . | -->------------ ..
|  6 | -->------------ ..                       |  . | -->------------ ..
|  7 | -->------------ A7                       |  . | -->------------ ..
+----+         0 ----- A8                       |  . | -->------------ ..
               0 ----- ..                       |  . | -->------------ ..
               0 ----- ..                       |  . | -->------------ ..
               0 ----- ..                       |  . | -->------------ ..
               0 ----- ..                       |  . | -->------------ ..
               0 ----- ..                       |  . | -->------------ ..
               0 ----- ..                       |  . | -->------------ ..
               0 ----- ..                       | 15 | -->------------ A15
               0 ----- ..                       +----+         0 ----- A16
               0 ----- ..                                      0 ----- ..
               0 ----- ..                                      0 ----- ..
               0 ----- A19                                     0 ----- A19

 IN/OUT IMM8                                    IN/OUT DX

386 PORT I/O

No new opcodes*. But the 386 can transfer 32-bit data as well to/from accumulator: EAX.

IN/OUT  AL   <--  8-bit I/O port   W=0
IN/OUT  AX   <-- 16-bit I/O port   W=1  operand-size = 16 (D=0 or D=1 and 66h)
IN/OUT EAX   <-- 32-bit I/O port   W=1  operand-size = 32 (D=1 or D=0 and 66h)


                  8-bit PORT address: IMM8      |   16-bit PORT address: DX
                ________________________________|_____________________________
                             |                  |              |
 8-bit data:    IN  AL, imm8 |  OUT imm8, AL    |   IN  AL, DX |  OUT DX, AL
                             |                  |              |
16-bit data:    IN  AX, imm8 |  OUT imm8, AX    |   IN  AX, DX |  OUT DX, AX
                             |                  |              |
32-bit data:    IN EAX, imm8 |  OUT imm8, EAX   |   IN EAX, DX |  OUT DX, EAX

* The 386 address bus is 32-bits, but the I/O-bus has never been extended to 32-bits. PORT ADDRESS is still maximum 16-bit and still driven by DX or IMM8. I/O instructions drive the lower part of the address bus (driving zero onto HIGH lines):

 Fixed port:                                      Variable port:

 IMM8                                             DX
+----+                                          +----+
|  0 | -->------------ A0                       |  0 | -->------------ A0
|  1 | -->------------ ..                       |  1 | -->------------ ..
|  2 | -->------------ ..                       |  2 | -->------------ ..
|  3 | -->------------ ..                       |  . | -->------------ ..
|  4 | -->------------ ..                       |  . | -->------------ ..
|  5 | -->------------ ..                       |  . | -->------------ ..
|  6 | -->------------ ..                       |  . | -->------------ ..
|  7 | -->------------ A7                       |  . | -->------------ ..
+----+         0 ----- A8                       |  . | -->------------ ..
               0 ----- ..                       |  . | -->------------ ..
               0 ----- ..                       |  . | -->------------ ..
               0 ----- ..                       |  . | -->------------ ..
               0 ----- ..                       |  . | -->------------ ..
               0 ----- ..                       |  . | -->------------ ..
               0 ----- ..                       |  . | -->------------ ..
               0 ----- ..                       | 15 | -->------------ A15
               0 ----- ..                       +----+         0 ----- A16
               0 ----- ..                                      0 ----- ..
               0 ----- ..                                      0 ----- ..
               0 ----- ..                                      0 ----- ..
               0 ----- ..                                      0 ----- ..
               0 ----- ..                                      0 ----- ..
               0 ----- ..                                      0 ----- ..
               0 ----- ..                                      0 ----- ..
               0 ----- ..                                      0 ----- ..
               0 ----- ..                                      0 ----- ..
               0 ----- ..                                      0 ----- ..
               0 ----- ..                                      0 ----- ..
               0 ----- ..                                      0 ----- ..
               0 ----- ..                                      0 ----- ..
               0 ----- ..                                      0 ----- ..
               0 ----- A31                                     0 ----- A31

INS/OUTS

For INS/OUTS see REP.html.