Справка по конвертации: __asm__ __volatile__ - PullRequest
9 голосов
/ 23 декабря 2011

Я бы хотел перенести функцию 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-Инлайн-сборочно-HOWTO

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

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

Ответы [ 2 ]

9 голосов
/ 23 декабря 2011

Инструкция 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);
}
5 голосов
/ 23 декабря 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 или * 1027. * опять же, исходя из размера переменной.

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

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

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

...