Виктория 0 27 августа, 2009 Опубликовано 27 августа, 2009 · Жалоба Осваиваем инлайновский ассемблер в 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 - одно и тоже сообщение об ошибке). Непонятно :( 3) Тип void тоже почему-то не понимает... Придется вводить фиктивную выходную переменную типа int, например. Плиз, помогите. Может у кого-нибудь были похожие ситуации и в другом gcc (не обязательно под Windows, для любого МК)? Передать, естеств., хотелось бы байт. Т.к. это для учебной лабы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alx2 0 27 августа, 2009 Опубликовано 27 августа, 2009 (изменено) · Жалоба 2) Компилятор ругается на строчку с out (неправильный суффикс или операнд?), причём ругается именно на al (т.е. при замене out на mov - одно и тоже сообщение об ошибке). Непонятно :(У Вас строковый литерал (собственно ассемблерная вставка) распался на две строки. Кроме этого я вижу тут следующие неприятности: 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 3) Тип void тоже почему-то не понимает... Придется вводить фиктивную выходную переменную типа int, например.Чтооо??? Это какая версия GCC не понимает тип void? :) Напишите подробнее, что за проблема с void. Изменено 27 августа, 2009 пользователем alx2 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Виктория 0 27 августа, 2009 Опубликовано 27 августа, 2009 · Жалоба alx2, спасибо за подсказку по передаче параметров (!!очевидная и простая!!), ассемблеру и за include-файл. С void eщё раз попробую. Outb нету, ассемблер сам определяет по длине используемого регистра Функция void со строкой "asm("out %0, %1" :: "a"(data), "d"(addr));" транслируется, но не работает... Похоже надо ещё защищенный режим у Пентиума снимать... Разберемся. Возможно завтра задам ещё один вопросик. Нужно будет дописать сохранение/восстановление регистров для функции обработки прерывания. Или мы - опять чайники, и где-то в include есть модификатор interrupt? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 27 августа, 2009 Опубликовано 27 августа, 2009 · Жалоба Фрагмент кода avreal компилируется (и работает ;) ) 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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Виктория 0 27 августа, 2009 Опубликовано 27 августа, 2009 · Жалоба Проблема, что запуск из-под Windows XP. Так что немножко времени необходимо для чтения про корректность постановки задачи. Хотя ключей для запуска приложения в NetBeans штук 5 (тоже надо бы разобраться!). ... Нет, оказывается из-за запуска из под NetBeans. Нет никакого защищенного режима. При трансляции Минималистом в командной строке и запуска оттуда же всё работает. Пробую варианты... Спасибо всем! А что означают буковки "a" и "Nd"? У нас нет никакой литературы по gcc, кроме Артура Гриффитса "GCC. Настольная книга..." Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aesok 0 27 августа, 2009 Опубликовано 27 августа, 2009 · Жалоба А что означают буковки "a" и "Nd"? У нас нет никакой литературы по gcc, кроме Артура Гриффитса "GCC. Настольная книга..." Это называеться "Operand Constraints", описание можно найти здесь: http://gcc.gnu.org/onlinedocs/gccint/Const...tml#Constraints Анатолий. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 27 августа, 2009 Опубликовано 27 августа, 2009 · Жалоба А что означают буковки "a" и "Nd"? У нас нет никакой литературы по 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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Виктория 0 28 августа, 2009 Опубликовано 28 августа, 2009 · Жалоба Спасибо всем! ReAl, красота выходного кода и возможностей транслятора лишний раз убеждает в правильности своего выбора профессии ... :rolleyes: За указание на сайт http://gcc.gnu.org/ - отдельная благодарность. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ukpyr 0 28 августа, 2009 Опубликовано 28 августа, 2009 (изменено) · Жалоба 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 Изменено 28 августа, 2009 пользователем ukpyr Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
klen 1 29 августа, 2009 Опубликовано 29 августа, 2009 · Жалоба в защищенном режиме out и in являются привелегированными и запрнщаются к исполнению пользовательским кодом. Либо в Досе, либо исключительно через драйвер. В драйвере который испольняется в режиме ядра ОС эти команды только и должны использоватся для непосредственного дергания за зелезячки. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Виктория 0 31 августа, 2009 Опубликовано 31 августа, 2009 · Жалоба Klen, Вы в этом абсолютно уверены? Защищенный режим Пентиума? А как же аппаратный сброс и возврат в реальный режим с использованием команды out? Или я опять чего-то путаю? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться