I need to read some 16-bit values from the port and save them to the buffer. Tutorial which I'm using suggest using REP INSW instruction, but I don't know how to use it and even how it works...
Is this instruction equivalent to two IN instructions?
The answer is in the Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 1:
Section 18.3 I/O ADDRESS SPACE
Any two consecutive 8-bit ports can be treated as a 16-bit port, and any four consecutive ports can be a 32-bit port. In this manner, the processor can transfer 8, 16, or 32 bits to or from a device in the I/O address space. Like words in memory, 16-bit ports should be aligned to even addresses (0, 2, 4, ...) so that all 16 bits can be transferred in a single bus cycle. Likewise, 32-bit ports should be aligned to addresses that are multiples of four (0, 4, 8, ...). The processor supports data transfers to unaligned ports, but there is a performance penalty because one or more extra bus cycle must be used.
If you review the documentation in the Instruction Set reference in Volume 2A for the INSW
instruction it says this:
INS/INSB/INSW/INSD — Input from Port to String
INS m16, DX Input word from I/O port specified in DX into memory location specified in ES:(E)DI or RDI.
INSW
reads a 16-bit value from IO port space to the specified memory address. INSW
will read a byte starting from the specified PORT specified in DX and an additional byte from PORT+1 and the bytes are stored at ES:E(DI) and ES:E(DI)+1 respectively.
To answer the question about REP INSW
, The REP
will repeat this process for the number of times specified in E(CX). REP INSW
is documented as:
REP/REPE/REPZ/REPNE/REPNZ — Repeat String Operation Prefix
REP INS m16, DX Input (E)CX words from port DX into ES:[(E)DI]
If you useREP INSW
to read 16-bits from port 0x1F0 E(CX) times then effectively you do:
Assuming you are writing 32-bit code then to read 16-bits from port 0x1F0/0x1F1 16 times you would code this in NASM as:
bits 32
; It is assumed that ES is already set and depends on the environment
mov dx, 0x1f0 ; Read words from port 0x1F0 and 0x1F1
mov edi, buffer ; Address of BUFFER
mov ecx, 16 ; Repeat 16 times
rep insw
; Other code and data here
; 16 word buffer (total 32 bytes)
buffer: TIMES 16 dw 0x0000
If writing 16-bit code it would look something like:
bits 16
; It is assumed that ES is already set and depends on the environment
mov dx, 0x1f0 ; Read words from port 0x1F0 and 0x1F1
mov di, buffer ; Address of BUFFER
mov cx, 16 ; Repeat 16 times
rep insw
; Other code and data here
; 16 word buffer (total 32 bytes)
buffer: TIMES 16 dw 0x0000
It is assumed that you are running in an environment where you have the privilege level to use port IO instructions and you have permission to read/write specific IO ports. In real-mode there are no restrictions. In protected-mode, long-mode, and v8086 mode you may or may not have the privilege level to use port instructions or permission to access specific ports. You will have to consult your operating system (OS) documentation, or if you are writing your own OS then you must set the privilege and port access restrictions yourself using privilege levels / IOPL / IOPL bitmaps.
rep insw
can also be used in 64-bit mode using an operand size prefix (NASM will handle the encoding by adding the 0x66 prefix). The count will be in RCX, and the ES segment is not applicable:
REP INS r/m32, DX Input RCX default size from port DX into [RDI].