c++x86g++inline-assemblyhardware-port

inline asm: operand type mismatch for 'out'


I don't know assembly in depth. Following code is for writing to hardware port.

Compiler gives operand type mismatch error in every line where inline asm is used.When I compile I get these errors:

port.cpp: Assembler messages:  
port.cpp:27: Error: operand type mismatch for 'out'
port.cpp:34: Error: operand type mismatch for 'in' 
port.cpp:51: Error: operand type mismatch for 'out' 
port.cpp:69: Error: operand type mismatch for 'out' 
port.cpp:75: Error: operand type mismatch for 'in' 
port.cpp:94: Error: operand type mismatch for 'out' 
port.cpp:100: Error: operand type mismatch for 'in'

port.h

#ifndef __PORT_H
#define __PORT_H

#include "types.h"


class Port
{
    protected:
        Port(uint16_t portnumber);
        ~Port();
        uint16_t portnumber;
};


class Port8Bit : public Port
{
    public:
        Port8Bit(uint16_t portnumber);
        ~Port8Bit();

        virtual uint8_t Read();
        virtual void Write(uint8_t data);
};



class Port8BitSlow : public Port8Bit
{
    public:
        Port8BitSlow(uint16_t portnumber);
        ~Port8BitSlow();

        virtual void Write(uint8_t data);
};



class Port16Bit : public Port
{
    public:
        Port16Bit(uint16_t portnumber);
        ~Port16Bit();

        virtual uint16_t Read();
        virtual void Write(uint16_t data);
};



class Port32Bit : public Port
{
    public:
        Port32Bit(uint16_t portnumber);
        ~Port32Bit();

        virtual uint32_t Read();
        virtual void Write(uint32_t data);
};

#endif

port.cpp

#include "port.h"


Port::Port(uint16_t portnumber)
{
    this->portnumber = portnumber;
}

Port::~Port()
{
}



Port8Bit::Port8Bit(uint16_t portnumber)
    : Port(portnumber)
{
}

Port8Bit::~Port8Bit()
{
}

void Port8Bit::Write(uint8_t data)
{
    __asm__ volatile("outb %0, %1" :: "a" (data), "Nd" (portnumber));
}

uint8_t Port8Bit::Read()
{
    uint8_t result;
    __asm__ volatile("inb %1, %0" : "=a" (result) : "Nd" (portnumber));   
    return result;
}



Port8BitSlow::Port8BitSlow(uint16_t portnumber)
    : Port8Bit(portnumber)
{
}

Port8BitSlow::~Port8BitSlow()
{
}

void Port8BitSlow::Write(uint8_t data)
{
    __asm__ volatile("outb %0, %1\njmp 1f\n1: jmp 1f\n1:" :: "a" (data),       "Nd" (portnumber));
}





Port16Bit::Port16Bit(uint16_t portnumber)
    : Port(portnumber)
{
}

Port16Bit::~Port16Bit()
{
}

void Port16Bit::Write(uint16_t data)
{
    __asm__ volatile("outw %0, %1" :: "a" (data), "Nd" (portnumber));
}

uint16_t Port16Bit::Read()
{
    uint16_t result;
    __asm__ volatile("inw %1, %0" : "=a" (result) : "Nd" (portnumber));   
    return result;
}





Port32Bit::Port32Bit(uint16_t portnumber)
    : Port(portnumber)
{
}

Port32Bit::~Port32Bit()
{
}

void Port32Bit::Write(uint32_t data)
{
    __asm__ volatile("outl %0, %1" :: "a" (data), "Nd"   (portnumber));
}

uint32_t Port32Bit::Read()
{
    uint32_t result;
    __asm__ volatile("inl %1, %0" : "=a" (result) : "Nd" (portnumber));   
   return result;
}

How can i correct it? Is there anything wrong with structure of program?


Solution

  • The OP never showed types.h but the followup comments only suggested that one real possibility existed and that was uint16_t was not defined as a 16-bit type. On x86/x86-64 such a type can be defined with:

    typedef unsigned short int uint16_t;
    

    The errors come about because in order to choose a register for an extended inline assembly template GCC uses the size of the type passed in the constraint to determine if the register chosen should be a 16/32/64 bit register. If the size is not 16-bits the wrong size register will be chosen and the generated assembly will have an operand mismatch.

    In this case apparently the OP improperly specified a wrong size type when he created his own uint16_t definition. Port commands (in, out etc) only take DX (16-bit) as register operand, not EDX, or RDX or DL. If the register generated was not DX the code would have compiled/assembled with the error the OP was seeing.