Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Использование ассемблера в MinGW
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
Виктория
Осваиваем инлайновский ассемблер в MinGW.
Текст функции
Код
/******* Вывод байта в порт *******/
void outportb(unsigned addr,        // адрес регистра
                      unsigned char data)    // данные для записи
{
      asm(“mov %%eax, %2; \        // шаблон кода на ассемблере для
               out %1, %%al;”          // вывода байта в порт
               :                    // выходных переменных нет
               : “r” (addr), “r” (data)        // список входных операндов
               : “%%eax”, “%%al”);        // используемые регистры
}


1) Компилятор не желает передавать параметры через короткие регистры, даже для unsigned char (кто-нибудь знает какая, кстати, у него длина в Минималисте?). Поэтому используем eax.

2) Компилятор ругается на строчку с out (неправильный суффикс или операнд?), причём ругается именно на al (т.е. при замене out на mov - одно и тоже сообщение об ошибке). Непонятно sad.gif

3) Тип void тоже почему-то не понимает... Придется вводить фиктивную выходную переменную типа int, например.

Плиз, помогите. Может у кого-нибудь были похожие ситуации и в другом gcc (не обязательно под Windows, для любого МК)? Передать, естеств., хотелось бы байт. Т.к. это для учебной лабы.
alx2
Цитата(Виктория @ Aug 27 2009, 12:52) *
2) Компилятор ругается на строчку с out (неправильный суффикс или операнд?), причём ругается именно на al (т.е. при замене out на mov - одно и тоже сообщение об ошибке). Непонятно sad.gif
У Вас строковый литерал (собственно ассемблерная вставка) распался на две строки.
Кроме этого я вижу тут следующие неприятности:
1. В as для i386 символом начала комментария является '#', а вовсе не точка с запятой (';') как у Вас. Ну еще, кажется, можно использовать /* вот такие */ комментарии, как в C. В вышеприведенном случае ассемблер должен ругаться на "мусор" после команды (начиная с символа ';').
2. Вы поместили сразу две ассемблерные команды в одну строку, поэтому ассемблер будет считать вторую команду продолжением комментария (если Вы исправите предыдущий пункт, заменив '';' на '#'). Перед каждой ассемблерной инструкцией (кроме первой) надо добавлять перевод строки и отступ (обычно ставят табуляцию), чтобы каждая новая инструкция была в новой строке.
3. Нумерация параметров ассемблерной вставки ведется с нуля, а не с единицы, то есть вместо "%1" и "%2" должно быть "%0 и "%1" соответственно.
4. В списке "испорченных" регистров указывается только имя регистра, без символа процентов.
5. Совершенно необязательно (часто даже вредно) выполнять загрузку данных в регистры в ассемблерной вставке. Лучше доверить это компилятору.
6. Адрес порта команд out, насколько я знаю, 16-битный, а не 32-битный.
7. По-моему, вывод 8-битных данных выполняется командой outb, а не out (я ассемблер i386 практически не знаю, так что проверяйте сами).
8. Адрес порта должен загружаться не в любой регистр, а непременно в dx.
9. Перепутаны аргументы команды out.
Вот, как мне кажется, будет более правильно:
Код
#include <stdint.h>
void outportb(uint16_t addr, uint8_t data)
{
    asm("outb %0, %1" :: "a"(data), "d"(addr));
}

Результат компиляции:
Код
outportb:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %edx
        movb    12(%ebp), %al
#APP
        outb %al, %dx
#NO_APP
        leave
        ret

Цитата(Виктория @ Aug 27 2009, 12:52) *
3) Тип void тоже почему-то не понимает... Придется вводить фиктивную выходную переменную типа int, например.
Чтооо??? Это какая версия GCC не понимает тип void? smile.gif Напишите подробнее, что за проблема с void.
Виктория
alx2, спасибо за подсказку по передаче параметров (!!очевидная и простая!!), ассемблеру и за include-файл. С void eщё раз попробую.
Outb нету, ассемблер сам определяет по длине используемого регистра


Функция void со строкой "asm("out %0, %1" :: "a"(data), "d"(addr));" транслируется, но не работает... Похоже надо ещё защищенный режим у Пентиума снимать... Разберемся.

Возможно завтра задам ещё один вопросик. Нужно будет дописать сохранение/восстановление регистров для функции обработки прерывания. Или мы - опять чайники, и где-то в include есть модификатор interrupt?
ReAl
Фрагмент кода avreal
компилируется (и работает wink.gif ) gcc - linux, freebsd, mingw32
base - это приватное поле класса, базовый адрес LPT
*_offset - enum-ы на разрешённые для операции регистры LPT
Код
uint8_t
lpt_io_t::read(rd_offset offs) const
{
    uint8_t value;
    __asm__ __volatile__(
        "inb %w1, %0"
        : "=a"(value)
        : "Nd"(base_ + offs)
    );
    return value;
}

void
lpt_io_t::write(wr_offset offs, uint8_t value) const
{
    __asm__ __volatile__(
        "outb %b0, %w1"
        :
        : "a"(value), "Nd"(base_ + offs)
    );
}

void
lpt_io_t::write_data(const uint8_t * buf, int len) const
{
    __asm__ __volatile__(
        "cld" "\n\t"
        "rep outsb"
        : "+S"(buf), "+c"(len)
        : "d"(base_)
    );
}

Для нескольких команд команды надо разделять "\n\t", так как и без '\' всё равно всё сольётся в одну длинную строку средствами С-компилятора ещё до передачи в обработку __asm__
Для in/out адрес должен быть именно в dx - в словном, поэтому казывается %w1 а не %1
Виктория
Проблема, что запуск из-под Windows XP. Так что немножко времени необходимо для чтения про корректность постановки задачи. Хотя ключей для запуска приложения в NetBeans штук 5 (тоже надо бы разобраться!).


...

Нет, оказывается из-за запуска из под NetBeans. Нет никакого защищенного режима. При трансляции Минималистом в командной строке и запуска оттуда же всё работает.
Пробую варианты...

Спасибо всем!

А что означают буковки "a" и "Nd"? blush.gif У нас нет никакой литературы по gcc, кроме Артура Гриффитса "GCC. Настольная книга..."
aesok
Цитата(Виктория @ Aug 27 2009, 16:33) *
А что означают буковки "a" и "Nd"? blush.gif У нас нет никакой литературы по gcc, кроме Артура Гриффитса "GCC. Настольная книга..."


Это называеться "Operand Constraints", описание можно найти здесь:
http://gcc.gnu.org/onlinedocs/gccint/Const...tml#Constraints

Анатолий.
ReAl
Цитата(Виктория @ Aug 27 2009, 15:33) *
А что означают буковки "a" и "Nd"? blush.gif У нас нет никакой литературы по gcc, кроме Артура Гриффитса "GCC. Настольная книга..."


http://gcc.gnu.org/onlinedocs/gcc/Constrai...tml#Constraints

a - это для данного аргумента годится только eax
%b0 - это от нулевого аргумента нас интересует байт, т.е. %al

Nd - это для данного аргумента подходит 8-битная константа либо регистр edx

Код
uint16_t base;

inline uint8_t
read(unsigned addr)
{
    uint8_t value;
    __asm__ __volatile__(
        "inb %w1, %0"
        : "=a"(value)
        : "Nd"(addr)
    );
    return value;
}

uint8_t a, b;

void test(void)
{
    a = read(0xB0);   // тут будет непосредственный адрес
    b = read(base);    // тут в DX загрузится значение переменной
    a = read(0x3B0);  // тут в DX загрузится константа, которая не лезет в 8 бит
}

gcc -O2 -fomit-frame-pointer -S
Код
_test:
    inb $176, %al                     <--- это от   a = read(0xB0);
    movzwl    _base, %edx      <--- это от   b = read(base);
    movb    %al, _a              <--- это от   a = read(0xB0);
    inb %dx, %al                      <--- это от   b = read(base);
    movl    $944, %edx                <--- это от   a = read(0x3B0);
    movb    %al, _b              <--- это от   b = read(base);
    inb %dx, %al                      <--- это от   a = read(0x3B0);
    movb    %al, _a              <--- это от   a = read(0x3B0);
    ret
Виктория
Спасибо всем!
ReAl, красота выходного кода и возможностей транслятора лишний раз убеждает в правильности своего выбора профессии ... rolleyes.gif

За указание на сайт http://gcc.gnu.org/ - отдельная благодарность.
klen
в защищенном режиме out и in являются привелегированными и запрнщаются к исполнению пользовательским кодом. Либо в Досе, либо исключительно через драйвер. В драйвере который испольняется в режиме ядра ОС эти команды только и должны использоватся для непосредственного дергания за зелезячки.
Виктория
Klen, Вы в этом абсолютно уверены? Защищенный режим Пентиума? А как же аппаратный сброс и возврат в реальный режим с использованием команды out? Или я опять чего-то путаю?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.