Как передать параметры ассемблерной вставке?

Обсуждаем контроллеры компании Atmel.
Аватара пользователя
zebrox
Встал на лапы
Сообщения: 117
Зарегистрирован: Вс апр 12, 2009 22:40:37

Как передать параметры ассемблерной вставке?

Сообщение zebrox »

Всем добрый день.
Есть функция на "си" cvavr. Скажем int SUM(int a, int b).
Сложение необходимо сделать на ассемблере, как можно этой вставке передать два двухбайтных параметра, и как потом вернуть результат из вставки обратно в функцию?

Подскажите, как это можно реализовать?

Спасибо!
Реклама
sasha2011
Открыл глаза
Сообщения: 49
Зарегистрирован: Вс апр 17, 2011 11:33:26

Re: Как передать параметры ассемблерной вставке?

Сообщение sasha2011 »

eсли это СVAVR, то может быть использовать переменные типа register unsigned char
Реклама
Аватара пользователя
pyzhman
Друг Кота
Сообщения: 7016
Зарегистрирован: Вс июл 12, 2009 19:15:29
Откуда: Ижевск
Контактная информация:

Re: Как передать параметры ассемблерной вставке?

Сообщение pyzhman »

Жмякаем F1 и ищем Calling Assembly Functions from C
Docendo discimus
Аватара пользователя
zebrox
Встал на лапы
Сообщения: 117
Зарегистрирован: Вс апр 12, 2009 22:40:37

Re: Как передать параметры ассемблерной вставке?

Сообщение zebrox »

Как вариант конечно можно попробовать.
Но хотелось бы более "правильное" решение.
Как понимаю, такой тип переменных есть фичером cvavr, и другие компиляторы будут ругаться.
И не есть такое решение "религиозно правильное".

Пока, нашел только эту статью, но она для авр-гцц...
http://we.easyelectronics.ru/AVR/assemb ... r-gcc.html
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
menzoda
Вымогатель припоя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Re: Как передать параметры ассемблерной вставке?

Сообщение menzoda »

Выше уже дали ответ - ищем Calling Assembly Functions from C, или лучше C Calling conventions для интересующего компилятора. В найденном документе будет описаны соглашения о вызове функций: как параметры передаются и возвращаются.

Вариант номер два, для ленивых. Создаем простейшую функцию с желаемой сигнатурой, компилируем, изучаем полученный ассемблерный код, ..., профит!
Реклама
Аватара пользователя
zebrox
Встал на лапы
Сообщения: 117
Зарегистрирован: Вс апр 12, 2009 22:40:37

Re: Как передать параметры ассемблерной вставке?

Сообщение zebrox »

Calling Assembly Functions from C

там написано, что параметры передаются через стек, к ним можно обратится через "y+", эта часть понятна.

Но непонятен один момент.

Если я в своей ассемблерной функции, захочу записать какое-то значение в рекистр R30, скажем. К чему это может привести?
Ведь у меня, в этом регистре, может хранится какая-то переменная, скажем глобальная? Не получится ли так, что записав туда свое значение, я потеряю то, что там было раньше?
Реклама
Аватара пользователя
ibiza11
Поставщик валерьянки для Кота
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Re: Как передать параметры ассемблерной вставке?

Сообщение ibiza11 »

про размещение глобальных переменных аналогично читаем в мануале к компилятору F1.
Ставим плюсы: )
Аватара пользователя
zebrox
Встал на лапы
Сообщения: 117
Зарегистрирован: Вс апр 12, 2009 22:40:37

Re: Как передать параметры ассемблерной вставке?

Сообщение zebrox »

Почитал Allocation of variables to registers.

А так понял, что если я буду где-то в ассемблерной вставке использовать какие-то регистры, то должен держать эти регистры пустыми, и не позволять компилятору ничего глобального в них размещать.
Я так понял, что заблокировать какие-то регистры нельзя напрямую.
Но можно к регистру приписать какую-то переменную (как посоветовали в первом ответе), и выключить Smart register allocation.

В таком случае проподает необходимость из ассемблера обращаться к параметрам функции через стек, а просто пере вызовм такой функции, записывать необходимое значение в регистровую переменную, и из ассемблера она уже будет доступна "там где нужно".

Не совсем красиво конечно, но тоже может быть. Похоже, что это издержки компилятора.
Правильно думаю будет, перед вызовом ассемблерной вставки (либо внутри вставки), сохранить текущее значение используемого регистра, записать в него то, что нужно, сделать действия, а при выходе из вставки, восстанавливать старое значение.
Аватара пользователя
ILYAUL
Держит паяльник хвостом
Сообщения: 906
Зарегистрирован: Ср мар 28, 2012 21:45:24
Откуда: ВО

Re: Как передать параметры ассемблерной вставке?

Сообщение ILYAUL »

А так понял, что если я буду где-то в ассемблерной вставке использовать какие-то регистры, то должен держать эти регистры пустыми, и не позволять компилятору ничего глобального в них размещать.
Ерунда какая то
Вы можете в своей asm вставке сделать следующее

Код: Выделить всё

В самом начале
push  нужный вам регистр
а в самом конце вставки 
pop нужный Вам регистр
Перед командой ret
Аватара пользователя
zebrox
Встал на лапы
Сообщения: 117
Зарегистрирован: Вс апр 12, 2009 22:40:37

Re: Как передать параметры ассемблерной вставке?

Сообщение zebrox »

Всем спасибо за помощь.
из-за чего весь сыр-бор.
http://code.google.com/p/boot-loader-at ... c=svn9&r=9

Бутлодер в кодвижене.

Например, имеем такую вставку:

Код: Выделить всё

#asm
                movw r30, r6    ;//move CurrentAddress to Z pointer  
                mov r1, r3        ;//move Pagedata MSB reg 1
                mov r0, r2        ;//move Pagedata LSB reg 1  
                sts SpmcrAddr, r10   ;//move spmcrval to SPM control register
                spm                ;//store program memory
#endasm
CurrentAddress обявлена как register unsigned int @6.
Но так вставку использовать не хочется.
А хочется передать ей параметры через стек.

Правильно ли ее вынес во вставку?

Код: Выделить всё

void fill_temp_buffer(unsigned int CurrentAddress, unsigned int Pagedata, char cmd){
#asm
push r30
push r31
push r1
push r0          
      
                movw r30, y+3    ;//move CurrentAddress LSB to Z pointer  
                movw r31, y+4    ;//move CurrentAddress MSB to Z pointer
                mov r1, y+2        ;//move Pagedata MSB reg 1
                mov r0, y+1        ;//move Pagedata LSB reg 1  
                sts SpmcrAddr, y   ;//move spmcrval to SPM control register
                spm                ;//store program memory

pop r0
pop r1
pop r31
pop r30
#endasm

}
R30-31 и еще вопрос, для чего и как используется этот регистр?
Аватара пользователя
zebrox
Встал на лапы
Сообщения: 117
Зарегистрирован: Вс апр 12, 2009 22:40:37

Re: Как передать параметры ассемблерной вставке?

Сообщение zebrox »

http://www.avr-asm-tutorial.net/avr_en/ ... ISTER.html

A very special extra role is defined for the register pairs R26:R27, R28:R29 and R30:R31. The role is so important that these pairs have extra names in assembler: X, Y and Z. These pairs are 16-bit pointer registers, able to point to adresses with max. 16-bit into SRAM locations (X, Y or Z) or into locations in program memory (Z).

Всем спасибо!
Аватара пользователя
zebrox
Встал на лапы
Сообщения: 117
Зарегистрирован: Вс апр 12, 2009 22:40:37

Re: Как передать параметры ассемблерной вставке?

Сообщение zebrox »

Получилось сделать следующим образом:

Код: Выделить всё

void fill_temp_buffer(unsigned int data, unsigned int adr){   
while (SPMCSR&1); //wait for spm complete

#asm         
push r30
push r31 
push r20
push r0
push r1

ldi r20, 1         ;//put CMD to r20

ld  r30, y         ;//move CurrentAddress LSB to Z pointer   
ldd r31, y+1    ;//move CurrentAddress MSB to Z pointer  

ldd r0, y+2      ;//move data LSB
ldd r1, y+3      ;//move data MSB
   
sts 0x68, r20   ;//move CMD to SPM control register
spm                ;//store program memory     

pop r1
pop r0 
pop r20
pop r31
pop r30
#endasm
}
Но, остался непонятен один вопрос, теоретический.
Почему вызов команды push не вызывает увеличение указателя стека?
С помощью push, я сохраняю в стеке значение пяти регистров (я так думаю). Соответственно, что-бы после этого обратится к моим параметрам функции, я должен делать так:

Код: Выделить всё

ldd r30, y+5    ;//move CurrentAddress LSB to Z pointer   
ldd r31, y+6    ;//move CurrentAddress MSB to Z pointer  

ldd r0, y+7      ;//move data LSB
ldd r1, y+8      ;//move data MSB
Но если я так делаю, то у меня ничего не работает.
С чем это может быть связано?

Подозреваю, что команда push сохраняет значение в другой стек "hardware stack"? а передача параметров в функцию идет через "data stack", на его вершину казывает "y". Так ли это?
Аватара пользователя
ILYAUL
Держит паяльник хвостом
Сообщения: 906
Зарегистрирован: Ср мар 28, 2012 21:45:24
Откуда: ВО

Re: Как передать параметры ассемблерной вставке?

Сообщение ILYAUL »

Почему вызов команды push не вызывает увеличение указателя стека?
А куда он должен увеличится, Вы так сказать физически представляете где он находится?
Это ведь самый конец области SRAM-в стандартном (default) его определении.Правда его можно переназначать куда угодно , но Вам пока это не надо. И называется этот адрес ВЕРШИНА стека. Выше этой точки , для человека, только облака, озоновый слой, Господь Бог.
Для процессора- неконтролируемое падение вниз и "убивание" всех данных начиная с регистров и заканчивая SRAM.
Поэтому команда PUSH , уменьшает указатель адреса т.е. спускает Вас с горы плавненько так и без эксцессов. А команда POP увеличивает - поднимает Вас в гору.
Аватара пользователя
zebrox
Встал на лапы
Сообщения: 117
Зарегистрирован: Вс апр 12, 2009 22:40:37

Re: Как передать параметры ассемблерной вставке?

Сообщение zebrox »

Да, в даташите так и есть.
The Stack Pointer Register always points
to the top of the Stack. Note that the Stack is implemented as growing from higher memory locations
to lower memory locations. This implies that a Stack PUSH command decreases the Stack
Pointer.

Еще там есть такое:
The Stack is mainly used for storing temporary data, for storing local variables and for storing
return addresses after interrupts and subroutine calls.
А через какой stack передаются параметры в функуию, при ее вызове?
почему после вызова 5раз push.
вот этот код не работает?

Код: Выделить всё

ldd r30, y+5    ;//move CurrentAddress LSB to Z pointer   
ldd r31, y+6    ;//move CurrentAddress MSB to Z pointer 

ldd r0, y+7      ;//move data LSB
ldd r1, y+8      ;//move data MSB
а работает так:

Код: Выделить всё

ld  r30, y         ;//move CurrentAddress LSB to Z pointer   
ldd r31, y+1    ;//move CurrentAddress MSB to Z pointer 

ldd r0, y+2      ;//move data LSB
ldd r1, y+3      ;//move data MSB
т.е. почему после вызовов push не нужно увеличивать и y?
Аватара пользователя
ILYAUL
Держит паяльник хвостом
Сообщения: 906
Зарегистрирован: Ср мар 28, 2012 21:45:24
Откуда: ВО

Re: Как передать параметры ассемблерной вставке?

Сообщение ILYAUL »

почему после вызова 5раз push.
Если уж быть точным то как минимум 7. Всё зависит от памяти программ процессора.
Первым , и от вас не зависящим в стек уходит адрес возврата из функции, затем стек отдается на "разгробление" программисту. Сколько он посчитает нужным сохранить данных , столько раз он напишет push.

Что же касается вот этого

Код: Выделить всё

ldd r30, y+5    ;//move CurrentAddress LSB to Z pointer   
ldd r31, y+6    ;//move CurrentAddress MSB to Z pointer 

ldd r0, y+7      ;//move data LSB
ldd r1, y+8      ;//move data MSB
То это косвенная адресация к SRAM , комманда LDD давно заменена на LD. Расшифрую , что здесь написано

Код: Выделить всё

ldd r30, y+5
Загрузить регистр R30, данными которые надо взять из ячейки SRAM находящейся по адресу Y (какой-то базовый адрес) +5 . Если Y=60 , то данные в R30 загрузятся из адреса 65
Следующая строка R31 получит данные с адреса 66 ну и т.д 67/ Но , что Вы хотите сделать - мне не ясно
Аватара пользователя
zebrox
Встал на лапы
Сообщения: 117
Зарегистрирован: Вс апр 12, 2009 22:40:37

Re: Как передать параметры ассемблерной вставке?

Сообщение zebrox »

Немогу объяснить чего я хочу...

Получается так, что адрес хранящийся в y и адрес вершины стека это разные "вещи"?
И вызов команды push не вызывает увеличение y?
Куда в таком случае указывает у, на какую часть памяти проца, где она физически находится (по умолчанию)?
Аватара пользователя
U235
Встал на лапы
Сообщения: 135
Зарегистрирован: Вт фев 21, 2012 20:42:26
Откуда: Санкт-Петербург, Россия, Земля

Re: Как передать параметры ассемблерной вставке?

Сообщение U235 »

Использование оперативной памяти расписано на странице "RAM Memory Organization and Register Allocation", вот картинка оттуда.
Изображение
Стек данных используется для динамического хранения локальных переменных, передачи параметров функций и для сохранения значений регистров при прерывании.
Вложения
cvar.PNG
(25.63 КБ) 1894 скачивания
А из наших труб идет необычный дым. Стой! Опасная зона! Работа мозга!...
Аватара пользователя
zebrox
Встал на лапы
Сообщения: 117
Зарегистрирован: Вс апр 12, 2009 22:40:37

Re: Как передать параметры ассемблерной вставке?

Сообщение zebrox »

Согласен, именно эта картинка из хелпа меня и смущает... :)

Есть два стека, один аппаратный, другой програмный.
"Стек данных используется для динамического хранения локальных переменных, передачи параметров функций и для сохранения значений регистров при прерывании."
Обращение к этому стеку идет через Y, так понимаю для ассемблера y и Y и R32/33 это одно и то же?

И команда push, кладет значение регистра в аппаратный стек, а не в програмный? Правильно?
Для этого у меня не происходит "съезд" указателья Y, после вызова push?
jonic
Встал на лапы
Сообщения: 96
Зарегистрирован: Чт май 22, 2008 12:43:16

Re: Как передать параметры ассемблерной вставке?

Сообщение jonic »

Так, если честно не читал всю ветку, но.
Обычно, доступ к параметрам из asm представляется внутри функции.

При вызове функции в листинге ассемблера происходит слудующее:

Код: Выделить всё

push param3
push param2
push param1
call FucnAddr

FuncAddr:
pop param1
pop param2
pop param3 //Куда попать полученные данные без разницы. хоть в выделеную память хоть по регистрам, на выбор.
//производим действия с параметрами
//размещаем в eax результат выполнения (
mov eax, result 
ret
обязательно вычищаем всё что push, pop. Иначе ret не сможет отработать нормально, потому-что адрес возврата тоже кладётся в стек. Сейчас лень вспоминать многое. Поэтому можете рассказать подробнее что нужно. Приходилось изучать вопрос этого симбиоза.

Естественно, если мы используем си, то там за нас уже всё сделали. И по идее можно подставлять параметры уже готовые. Например:

Код: Выделить всё

int Test(char a,char b) {
  __asm {
      mov eax, a
      mov ebx, b
      sub eax, ebx
      ret // по логине это затрёт наше нижнее значение и вернёт результат.
  };
  return 0;
}
А вот живой и рабочий пример в C++

Код: Выделить всё

#include <stdlib.h>
#include <stdio.h>
#include <iostream>

using namespace std;
int Test(int a,int b);

int main(int argc,char* argv[])
{

	int res=Test(10,5);
	printf("Hello World! %d",res);

	cin.get();
	
	return 0;
}

int Test(int a,int b) {
  __asm {
      mov eax, a
      mov ebx, b
      sub eax, ebx  
//начиная отсюда, реализуется код который вставляет компилятор для обработки.
		pop         edi  
		pop         esi  
		pop         ebx  
		add         esp,0C0h  
		cmp         ebp,esp   
		mov         esp,ebp  
		pop         ebp  
      ret // по логине это затрёт наше нижнее значение и вернёт результат.
  };
  return 0;
}
Аватара пользователя
zebrox
Встал на лапы
Сообщения: 117
Зарегистрирован: Вс апр 12, 2009 22:40:37

Re: Как передать параметры ассемблерной вставке?

Сообщение zebrox »

Спасибо за помощь.

Чем дальше, тем больше вопросов...С ассемблером знаком пару дней, много не ясно.

1 (основной).
В какой стек команда push кладет свой аргумент. В аппаратный стек или програмный (стек данных)?

2. почему сделано разделение на два стека?
Почему бы все не хранить в одном стеке (локальные переменные, параметры функций, значения записанные туда с помощью push, адреса возвратов. Ведь все-равно, после выхода из функции, все локальные переменные удаляются, соответственно компилятор мог-бы автоматически удалять все эти временные данные.

Вопросы относительно кодвижена.

Вот.
Ответить

Вернуться в «AVR»