Справка по преобразованию: __asm__ __volatile__

Я хотел бы перенести функцию outb из C на D.

static __inline void outb (unsigned char value, unsigned short int port)
{
    __asm__ __volatile__ ("outb %b0,%w1"
                          :
                          :
                         "a" (value),
                          "Nd" (port));
}

Это версия D.

extern(C) 
{
    void outb (ubyte value, ushort port)
    {
        // I couldn't figure out this part
   }

}

Это несколько ссылок по теме.

Встроенный ассемблер D

http://dlang.org/iasm.html

GCC-Inline-Assembly-HOWTO

http://ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html < / а>

Но я не знаю ассемблера, поэтому мне нужна помощь. Любая помощь будет оценена. Спасибо.


person Erdem    schedule 23.12.2011    source источник


Ответы (2)


Инструкцию outb следует вызывать только как outb %al, %dx, где %al - значение, а %dx - порт.

D использует синтаксис Intel для x86, в отличие от ассемблера GNU, который по умолчанию использует синтаксис AT&T. Соответствующий синтаксис Intel будет out dx, al, а соответствующий код в D будет выглядеть так:

void outb (ubyte value, ushort port)
{
    asm {
        mov AL, value;
        mov DX, port;
        out DX, AL;
    }
}

Обратите внимание, что вам вообще не нужно писать сборку, потому что druntime имеет функцию core.bitop.outp, которая выполняет то же инструкция.

void outb (ubyte value, ushort port)
{
    import core.bitop;
    outp(port, value);
}
person kennytm    schedule 23.12.2011

Первое, что вас, вероятно, сбивает с толку, это то, что список кодов операций, поддерживаемых компилятором D, не включает outb, как указано в функции C. Покопавшись, я обнаружил, что outb - это более конкретное имя для общего кода операции out. outb указывает, что первый аргумент кода операции будет содержаться в байтовом регистре (в отличие от outw и outl, которые указывают размер первого аргумента, соответственно, слова и двойного слова), однако компилятор D использует код операции out для всех операций и определяет, какой конкретный код операции записывать, в зависимости от размера указанного вами аргумента.

После этого следующее, что нужно сделать, это преобразовать синтаксис GCC в синтаксис D. Согласно GCC-Inline-Assembly-HOWTO, предоставленный вами код использует расширенный синтаксис сборки:

asm ( assembler template 
    : output operands                  /* optional */
    : input operands                   /* optional */
    : list of clobbered registers      /* optional */
    );

Глядя на ваш шаблон, функция определяет одну инструкцию сборки (outb) с двумя аргументами, первый из которых является байтом (%b0), а второй - словом или коротким целым числом (%w0).

Сложность со списком входных аргументов - это строка, которая предшествует каждому из параметров вашей функции. Они, согласно HOWTO, называются ограничениями. По сути, это правила, которым GCC должен следовать при использовании параметров в качестве аргументов предоставленных инструкций по сборке. Ограничение "a", примененное к параметру value, указывает, что содержимое переменной должно быть помещено в регистр eax, ax или al в зависимости от размера переменной. Ограничение на переменную port, "Nd", указывает, во-первых, что значение находится в диапазоне 0-255, а во-вторых, что значение должно быть помещено в регистр edx, dx или dl, опять же, в зависимости от размера Переменная.

Компилятор D не так сильно помогает с переменными в блоках сборки, как GCC; во встроенном ассемблере D вам нужно будет специально переместить значения параметров в соответствующие регистры. Для outb это регистры dx и al. Следуя синтаксису встроенного ассемблера D, вы можете перемещать переменные и вызывать код операции out следующим образом:

asm
{
    MOV AL, value;
    MOV DX, port;
    OUT DX, AL;
}

Обратите внимание: поскольку GCC использует синтаксис ассемблера AT&T, а D использует синтаксис ассемблера Intel, порядок аргументов, предоставленных OUT, меняется на обратный.

person Adam Maras    schedule 23.12.2011