реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Использование ассемблера в MinGW, вопросики...
Виктория
сообщение Aug 27 2009, 07:52
Сообщение #1


инженер
****

Группа: Свой
Сообщений: 520
Регистрация: 19-09-05
Из: Самара
Пользователь №: 8 701



Осваиваем инлайновский ассемблер в 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, для любого МК)? Передать, естеств., хотелось бы байт. Т.к. это для учебной лабы.
Go to the top of the page
 
+Quote Post
alx2
сообщение Aug 27 2009, 10:45
Сообщение #2


Местный
***

Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091



Цитата(Виктория @ 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 - Aug 27 2009, 11:18


--------------------
Всего наилучшего,
Alex Mogilnikov
Go to the top of the page
 
+Quote Post
Виктория
сообщение Aug 27 2009, 11:40
Сообщение #3


инженер
****

Группа: Свой
Сообщений: 520
Регистрация: 19-09-05
Из: Самара
Пользователь №: 8 701



alx2, спасибо за подсказку по передаче параметров (!!очевидная и простая!!), ассемблеру и за include-файл. С void eщё раз попробую.
Outb нету, ассемблер сам определяет по длине используемого регистра


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

Возможно завтра задам ещё один вопросик. Нужно будет дописать сохранение/восстановление регистров для функции обработки прерывания. Или мы - опять чайники, и где-то в include есть модификатор interrupt?
Go to the top of the page
 
+Quote Post
ReAl
сообщение Aug 27 2009, 12:01
Сообщение #4


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Фрагмент кода 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


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
Виктория
сообщение Aug 27 2009, 12:33
Сообщение #5


инженер
****

Группа: Свой
Сообщений: 520
Регистрация: 19-09-05
Из: Самара
Пользователь №: 8 701



Проблема, что запуск из-под Windows XP. Так что немножко времени необходимо для чтения про корректность постановки задачи. Хотя ключей для запуска приложения в NetBeans штук 5 (тоже надо бы разобраться!).


...

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

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

А что означают буковки "a" и "Nd"? blush.gif У нас нет никакой литературы по gcc, кроме Артура Гриффитса "GCC. Настольная книга..."
Go to the top of the page
 
+Quote Post
aesok
сообщение Aug 27 2009, 14:28
Сообщение #6


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



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


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

Анатолий.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Aug 27 2009, 14:42
Сообщение #7


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(Виктория @ 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


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
Виктория
сообщение Aug 28 2009, 04:41
Сообщение #8


инженер
****

Группа: Свой
Сообщений: 520
Регистрация: 19-09-05
Из: Самара
Пользователь №: 8 701



Спасибо всем!
ReAl, красота выходного кода и возможностей транслятора лишний раз убеждает в правильности своего выбора профессии ... rolleyes.gif

За указание на сайт http://gcc.gnu.org/ - отдельная благодарность.
Go to the top of the page
 
+Quote Post
ukpyr
сообщение Aug 28 2009, 05:58
Сообщение #9


Профессионал
*****

Группа: Участник
Сообщений: 1 264
Регистрация: 17-06-08
Из: бандустан
Пользователь №: 38 347



http://www.ibiblio.org/gferg/ldp/GCC-Inlin...mbly-HOWTO.html
http://www.delorie.com/djgpp/doc/brennan/b...line_djgpp.html
http://asm.sourceforge.net//articles/linasm.html

Сообщение отредактировал ukpyr - Aug 28 2009, 05:58
Go to the top of the page
 
+Quote Post
klen
сообщение Aug 29 2009, 08:25
Сообщение #10


бессмертным стать можно тремя способами
*****

Группа: Свой
Сообщений: 1 405
Регистрация: 9-05-06
Из: Москва
Пользователь №: 16 912



в защищенном режиме out и in являются привелегированными и запрнщаются к исполнению пользовательским кодом. Либо в Досе, либо исключительно через драйвер. В драйвере который испольняется в режиме ядра ОС эти команды только и должны использоватся для непосредственного дергания за зелезячки.
Go to the top of the page
 
+Quote Post
Виктория
сообщение Aug 31 2009, 10:10
Сообщение #11


инженер
****

Группа: Свой
Сообщений: 520
Регистрация: 19-09-05
Из: Самара
Пользователь №: 8 701



Klen, Вы в этом абсолютно уверены? Защищенный режим Пентиума? А как же аппаратный сброс и возврат в реальный режим с использованием команды out? Или я опять чего-то путаю?
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 22:56
Рейтинг@Mail.ru


Страница сгенерированна за 0.01469 секунд с 7
ELECTRONIX ©2004-2016