Вставка ASM кода в C

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Аватара пользователя
dem66
Встал на лапы
Сообщения: 141
Зарегистрирован: Ср окт 26, 2011 13:38:13

Вставка ASM кода в C

Сообщение dem66 »

Доброго времени суток.
Возникла необходимость вставить ассемблеровский код в сишную прошивку, пытаюсь сделать аналог стандартной функции atoi.

Код на ASM
Спойлер

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

bits 32

_atoi:
                push    ebx
                mov     ecx, dword [esp+8]       ;; input string ptr

;; scan and skip leading spaces
.skip_space:
                movzx   eax, byte [ecx]
                cmp     eax, ' '
                jnz     short .check_sign
                inc     ecx
                jmp     short .skip_space

;; check and save sign
.check_sign:
                mov     edx, eax                 ;; save posible sign byte
                xor     ebx, ebx
                cmp     eax, '-'
                jz      short .check_char
                cmp     eax, '+'
                jnz     short .no_sign
.check_char:
                inc     ecx
                movzx   eax, byte [ecx]
.no_sign:
                sub     eax, '0'
                cmp     eax,  9
                ja      short .non_digit
                lea     ebx, [ebx+ebx*4]
                lea     ebx, [eax+ebx*2]
                jmp     short .check_char     
.non_digit:
                cmp     edx, '-'                 ;; check sign byte
                jnz     short .done
                neg     ebx
.done:
                mov     eax, ebx
                pop     ebx
                retn

end
Подскажите как такое сделать, раньше с этим вобще не стыкался.
Заранее благодарен
Это не хвост, это антенна
Реклама
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: Вставка ASM кода в C

Сообщение oleg110592 »

Не указали какой компилятор, какой микроконтроллер. Если АВР, то у Чена хорошая реализация: http://elm-chan.org/docs/avrlib/xitoa.zip
Реклама
Аватара пользователя
pyzhman
Друг Кота
Сообщения: 7016
Зарегистрирован: Вс июл 12, 2009 19:15:29
Откуда: Ижевск
Контактная информация:

Re: Вставка ASM кода в C

Сообщение pyzhman »

окснитесь! какой АВР? тут пентиумами пахнет.
Docendo discimus
Аватара пользователя
Ser60
Друг Кота
Сообщения: 3784
Зарегистрирован: Ср дек 24, 2008 09:58:58

Re: Вставка ASM кода в C

Сообщение Ser60 »

Это не AVR, а х86. Код atoi есть практичеки в любом учебнике по ассемблеру как стандартный пример. В чем проблема с Вашим?
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: Вставка ASM кода в C

Сообщение oleg110592 »

Да я понял что код x86, но прошивка для x86? Наверное автор хочет все таки для микроконтроллера
Судя по по сообщениям автора, про мега8 - таки угадал АВР, ну я и телепат :))
Реклама
Аватара пользователя
ChipKiller
Сверлит текстолит когтями
Сообщения: 1163
Зарегистрирован: Ср янв 05, 2011 16:25:15

Re: Вставка ASM кода в C

Сообщение ChipKiller »

pyzhman писал(а):окснитесь! какой АВР? тут пентиумами пахнет.
...вообще-то 32 разрядные регистры пошли у х86 начиная с 386, но это сейчас музейный вариант :) ....
Похоже ТС на ломаном русском пытается спросить, как организовать вызов *.asm-функции из C и как происходит передача/возврат параметров, но это только мое "телепатическое " ИМХО :) .....
Реклама
Аватара пользователя
dem66
Встал на лапы
Сообщения: 141
Зарегистрирован: Ср окт 26, 2011 13:38:13

Re: Вставка ASM кода в C

Сообщение dem66 »

именно так, дело в том что стандартная сишная занимает много места, вот и думаю как упростить.

P.S если раздел "Микроконтроллеры и ПЛИС" то значит для микроконтроллера. Про то какой контроллер и правда ступил.
Контроллер Atmega-8a
Компилятор avr-gcc(linux версия)
Это не хвост, это антенна
Аватара пользователя
dem66
Встал на лапы
Сообщения: 141
Зарегистрирован: Ср окт 26, 2011 13:38:13

Re: Вставка ASM кода в C

Сообщение dem66 »

Так как? :(
Это не хвост, это антенна
Аватара пользователя
ILYAUL
Держит паяльник хвостом
Сообщения: 906
Зарегистрирован: Ср мар 28, 2012 21:45:24
Откуда: ВО

Re: Вставка ASM кода в C

Сообщение ILYAUL »

Есть такой сайт - ATMEL, полностью посвящённый только продукции сей фирмы. В числе документов на этом сайте имеется и такой, что рассказывает , как делать такие вставки. Успехов!
P.S Между прочим файл asm генерируемый компилятором - ПРЕКРАСНЫЙ пример как это делать
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: Вставка ASM кода в C

Сообщение oleg110592 »

выше ссылка почему не подходит?
Спойлер

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

;---------------------------------------------------------------------------
; Extended numeral string input
;
;Prototype:
; char xatoi (           /* 1: Successful, 0: Failed */
;      const char **str, /* pointer to pointer to source string */
;      long *res         /* result */
; );
;


#if USE_XATOI
.func xatoi
.global xatoi
xatoi:
	_MOVW	r1, r0, r23, r22
	_MOVW	XH, XL, r25, r24
	ld	ZL, X+
	ld	ZH, X+
	clr	r18		;r21:r18 = 0;
	clr	r19		;
	clr	r20		;
	clr	r21		;/
	clt			;T = 0;

	ldi	r25, 10		;r25 = 10;
	rjmp	41f		;/
40:	adiw	ZL, 1		;Z++;
41:	ld	r22, Z		;r22 = *Z;
	cpi	r22, ' '	;if(r22 == ' ') continue
	breq	40b		;/
	brcs	70f		;if(r22 < ' ') error;
	cpi	r22, '-'	;if(r22 == '-') {
	brne	42f		; T = 1;
	set			; continue;
	rjmp	40b		;}
42:	cpi	r22, '9'+1	;if(r22 > '9') error;
	brcc	70f		;/
	cpi	r22, '0'	;if(r22 < '0') error;
	brcs	70f		;/
	brne	51f		;if(r22 > '0') cv_start;
	ldi	r25, 8		;r25 = 8;
	adiw	ZL, 1		;r22 = *(++Z);
	ld	r22, Z		;/
	cpi	r22, ' '+1	;if(r22 <= ' ') exit;
	brcs	80f		;/
	cpi	r22, 'b'	;if(r22 == 'b') {
	brne	43f		; r25 = 2;
	ldi	r25, 2		; cv_start;
	rjmp	50f		;}
43:	cpi	r22, 'x'	;if(r22 != 'x') error;
	brne	51f		;/
	ldi	r25, 16		;r25 = 16;

50:	adiw	ZL, 1		;Z++;
	ld	r22, Z		;r22 = *Z;
51:	cpi	r22, ' '+1	;if(r22 <= ' ') break;
	brcs	80f		;/
	cpi	r22, 'a'	;if(r22 >= 'a') r22 =- 0x20;
	brcs	52f		;
	subi	r22, 0x20	;/
52:	subi	r22, '0'	;if((r22 -= '0') < 0) error;
	brcs	70f		;/
	cpi	r22, 10		;if(r22 >= 10) {
	brcs	53f		; r22 -= 7;
	subi	r22, 7		; if(r22 < 10) 
	cpi	r22, 10		;
	brcs	70f		;}
53:	cp	r22, r25	;if(r22 >= r25) error;
	brcc	70f		;/
60:	ldi	r24, 33		;r21:r18 *= r25;
	sub	r23, r23	;
61:	brcc	62f		;
	add	r23, r25	;
62:	lsr	r23		;
	ror	r21		;
	ror	r20		;
	ror	r19		;
	ror	r18		;
	dec	r24		;
	brne	61b		;/
	add	r18, r22	;r21:r18 += r22;
	adc	r19, r24	;
	adc	r20, r24	;
	adc	r21, r24	;/
	rjmp	50b		;repeat

70:	ldi	r24, 0
	rjmp	81f
80:	ldi	r24, 1
81:	brtc	82f
	clr	r22
	com	r18
	com	r19
	com	r20
	com	r21
	adc	r18, r22
	adc	r19, r22
	adc	r20, r22
	adc	r21, r22
82:	st	-X, ZH
	st	-X, ZL
	_MOVW	XH, XL, r1, r0
	st	X+, r18
	st	X+, r19
	st	X+, r20
	st	X+, r21
	clr	r1
	ret
.endfunc
#endif
Аватара пользователя
da-nie
Говорящий с текстолитом
Сообщения: 1590
Зарегистрирован: Вс июн 24, 2012 16:07:00
Откуда: Лен.Обл.
Контактная информация:

Re: Вставка ASM кода в C

Сообщение da-nie »

вставить ассемблеровский код в сишную прошивку
В смысле как оформляются такие вставки?

Для AVR, например, так:
Спойлер

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


 //вычисляем начальные RAS и CAS
  unsigned long addr=Track;
  addr*=12800UL;
  unsigned char RAS_L=addr&0xff;
  unsigned char RAS_H=(addr>>8)&0x3;
  unsigned char CAS_L=(addr>>10)&0xff;
  unsigned char CAS_H=(addr>>18)&0x3;
  DRIVE_INDEX_PORT|=(1<<DRIVE_INDEX);


 //ассемблерная вставка
  
  //R16 - выдаваемый байт
  //R17 - число выдаваемых битов
  //R18 - байт на выдачу
  //R19,R20 - счётчик числа байт
  //r21 - вспомогательный регистр
  //R26-R29 - параметры RAS и CAS
  asm volatile
  (  
					//задаём начальный счётчик в 12801
					"ldi r19,0x01"								"\n\t"//младший байт					
					"ldi r20,0x32"								"\n\t"//старший байт					
					//задаём начальное значение RAS и CAS				
					"mov r26,%[ras_l]"							"\n\t"//младший байт
					"mov r27,%[ras_h]"							"\n\t"//старший байт
					"mov r28,%[cas_l]"							"\n\t"//младший байт
					"mov r29,%[cas_h]"							"\n\t"//старший байт
					//задаём нужные нам переменные
					"ldi r16,0"									"\n\t"//выдаваемый байт
					"ldi r17,8"									"\n\t"//счётчик битов
					"ldi r18,0"									"\n\t"//следующий на выдачу байт
					//основной цикл (31 такт)
	"repeat%=:" 	"sbi %[drive_data_port],%[drive_data]"		"\n\t"//2 устанавливаем разряд данных с диска (2 такта)
					"lsl r16"									"\n\t"//3 сдвигаем влево байт - 7-й бит вытесняется в флаг C (1 такт)
					"brcc bit0%="								"\n\t"//4 если (С==0), переходим (2 такта за переход, иначе 1 такт)
					//если надо выдать 1 на линию
					"cbi %[drive_data_port],%[drive_data]"		"\n\t"//6 сбрасываем разряд данных с диска (2 такта)					
					"rjmp continue%="							"\n\t"//8 переход (2 такта)
					//если надо выдать 0 на линию
	"bit0%=:"		"nop"										"\n\t"//6 пауза (1 такт)
					"nop"										"\n\t"//7 пауза (1 такт)
					"nop"										"\n\t"//8 пауза (1 такт)
	"continue%=:"	"dec r17"									"\n\t"//9 уменьшаем счётчик битов на 1
					"breq counter0%="							"\n\t"//10 считать следующий байт, если счётчик на нуле (Z=1) (2 такта за переход, иначе 1 такт)
					//распределяем выполнение подпрограмм
					"cpi r17,5"									"\n\t"//11 сравниваем счётчик битов с 6
					"breq mode2s%="								"\n\t"//12 если совпало (Z==1), переходим (2 такта за переход, иначе 1 такт)
					"cpi r17,7"									"\n\t"//13 сравниваем счётчик битов с 6
					"breq mode1s%="								"\n\t"//14 если совпало (Z==1), переходим (2 такта за переход, иначе 1 такт)
					"cpi r17,4"									"\n\t"//15 сравниваем счётчик битов с 5
					"breq mode3s%="								"\n\t"//16 если совпало (Z==1), переходим (2 такта за переход, иначе 1 такт)
					"cpi r17,1"									"\n\t"//17 сравниваем счётчик битов с 4
					"breq mode4s%="								"\n\t"//18 если совпало (Z==1), переходим (2 такта за переход, иначе 1 такт)
					
					"in r21,%[gifr]"							"\n\t"//19 (1 такт)
					"andi r21,%[gifr_intf0_mask]"				"\n\t"//20 (1 такт)
					"brne exits%="								"\n\t"//21 (1 такт)
					
					"nop"										"\n\t"//22 пауза (1 такт)
					"nop"										"\n\t"//23 пауза (1 такт)
					"nop"										"\n\t"//24 пауза (1 такт)
					"nop"										"\n\t"//25 пауза (1 такт)
					"nop"										"\n\t"//26 пауза (1 такт)
					"nop"										"\n\t"//27 пауза (1 такт)
					"nop"										"\n\t"//28 пауза (1 такт)
					"nop"										"\n\t"//29 пауза (1 такт)
					"rjmp repeat%="								"\n\t"//31 возвращаемся (2 такта)
	"counter0%=:"	"ldi r17,8"									"\n\t"//12 инициализация счётчика битов
					"mov r16,r18"								"\n\t"//13 считываем следующий байт
					//уменьшаем счётчик выданных байт на 1
					"tst r19"									"\n\t"//14 проверяем, не 0 ли в младшем байте счётчика
					"breq zero%="								"\n\t"//15 в младшем регистре 0
					//производим регенерацию памяти
					"cbi %[portd],%[dram_cas1]"					"\n\t"//17 сбрасываем разряд CAS (2 такта)
					"cbi %[portd],%[dram_cas2]"					"\n\t"//19 сбрасываем разряд CAS (2 такта)
					"dec r19"									"\n\t"//29 уменьшаем счётчик на 1
					"cbi %[portd],%[dram_ras]"					"\n\t"//21 сбрасываем разряд CAS (2 такта)
					"nop"										"\n\t"//22 пауза (1 такт)					
					"sbi %[portd],%[dram_ras]"					"\n\t"//24 устанавливаем разряд RAS (2 такта)
					"sbi %[portd],%[dram_cas1]"					"\n\t"//26 устанавливаем разряд CAS (2 такта)
					"sbi %[portd],%[dram_cas2]"					"\n\t"//28 устанавливаем разряд CAS (2 такта)					
					"rjmp repeat%="								"\n\t"//31 возвращаемся (2 такта)
	"zero%=:"		"tst r20"									"\n\t"//17 не ноль ли в старшем байте? (1 такт)
					"breq exits%="								"\n\t"//18 в старшем регистре 0 и в младшем тоже 0 (Z==1)
					"dec r20"									"\n\t"//19 уменьшаем старший байт адреса на 1
					"ldi r19,0xff"								"\n\t"//20 младший байт					
					"nop"										"\n\t"//21 пауза (1 такт)
					"nop"										"\n\t"//22 пауза (1 такт)
					"nop"										"\n\t"//23 пауза (1 такт)
					"in r21,%[gifr]"							"\n\t"//19 (1 такт)
					"andi r21,%[gifr_intf0_mask]"				"\n\t"//20 (1 такт)
					"brne exits%="								"\n\t"//21 (1 такт)
					"nop"										"\n\t"//27 пауза (1 такт)
					"nop"										"\n\t"//28 пауза (1 такт)
					"nop"										"\n\t"//29 пауза (1 такт)					
					"rjmp repeat%="								"\n\t"//31 возвращаемся (2 такта)
	//------------------------------------------------------------------------------------------------------------------------------------------------------
					//длинные переходы
	"mode1s%=:"		"rjmp mode1%="								"\n\t"//17 переходим (2 такта)
	"mode2s%=:"		"rjmp mode2%="								"\n\t"//15 переходим (2 такта)
	"mode3s%=:"		"rjmp mode3%="								"\n\t"//19 переходим (2 такта)
	"mode4s%=:"		"rjmp mode4%="								"\n\t"//21 переходим (2 такта)
	//------------------------------------------------------------------------------------------------------------------------------------------------------	
					//подпрограмма выбора RAS
	"mode1%=:"		"out %[portc],r26"							"\n\t"//18 выставляем младший байт адреса
					//читаем состояние порта D
					"in r18,%[portd]"							"\n\t"//19 читаем состояние порта D
					"andi r18,252"								"\n\t"//20 накладываем маску
					"or r18,r27"								"\n\t"//21 добавляем старшую часть адреса
					"out %[portd],r18"							"\n\t"//22 выдаём старшую часть адреса
					"cbi %[portd],%[dram_ras]"					"\n\t"//24 сбрасываем разряд RAS (2 такта)
					"ld r18,X+"									"\n\t"//26 увеличиваем RAS на 1 (2 такта)
					"nop"										"\n\t"//27 пауза (1 такт)
					"nop"										"\n\t"//28 пауза (1 такт)
					"nop"										"\n\t"//29 пауза (1 такт)
					"rjmp repeat%="								"\n\t"//31 возвращаемся (2 такта)
	//------------------------------------------------------------------------------------------------------------------------------------------------------
	"exits%=:"		"rjmp exit%="								"\n\t"//выходим (2 такта)
	//------------------------------------------------------------------------------------------------------------------------------------------------------
					//подпрограмма выбора CAS
	"mode2%=:"		"out %[portc],r28"							"\n\t"//16 выставляем младший байт адреса
					//читаем состояние порта D
					"in r18,%[portd]"							"\n\t"//17 читаем состояние порта D
					"andi r18,252"								"\n\t"//18 накладываем маску старших бит RAS (если они появятся, значит, мы вышли за 10 бит по RAS)
					"or r18,r29"								"\n\t"//19 добавляем старшую часть адреса					
					"out %[portd],r18"							"\n\t"//20 выдаём старшую часть адреса
					"in r18,%[drive_side1_pin]"					"\n\t"//21 определяем сторону
					"andi r18,%[drive_side1_mask]"				"\n\t"//22 накладываем маску сигнала DRIVE_SIDE1 (1 такт)
					"brne side0%="								"\n\t"//23 выбрана сторона 0 (Z==1) (2 такта за переход, иначе 1 такт) 
					//выбрана сторона 1
					"cbi %[portd],%[dram_cas2]"					"\n\t"//25 сбрасываем разряд CAS (2 такта)					
					"nop"										"\n\t"//26 пауза (1 такт)					
					"nop"										"\n\t"//27 пауза (1 такт)
					"nop"										"\n\t"//28 пауза (1 такт)
					"nop"										"\n\t"//29 пауза (1 такт)				
					"rjmp repeat%="								"\n\t"//31 возвращаемся (2 такта)
	"side0%=:"		"cbi %[portd],%[dram_cas1]"					"\n\t"//26 сбрасываем разряд CAS (2 такта)		
					"nop"										"\n\t"//27 пауза (1 такт)
					"nop"										"\n\t"//28 пауза (1 такт)
					"nop"										"\n\t"//29 пауза (1 такт)
					"rjmp repeat%="								"\n\t"//31 возвращаемся (2 такта)
	//------------------------------------------------------------------------------------------------------------------------------------------------------
					//подпрограмма чтения байта и модификации CAS при переполнении RAS
	"mode3%=:"		"mov r18,r27"								"\n\t"//20 берём RAS_H (1 такт)
					"andi r18,0b11111100"						"\n\t"//21 накладываем маску
					"brne mode3ras%="							"\n\t"//22 если не 0 (Z=0), то модифицируем RAS и CAS (2 такта за переход, иначе 1 такт) 
					"nop"										"\n\t"//23 пауза (1 такт)
					"in r18,%[pina]"							"\n\t"//24 получаем байт из ОЗУ (1 такт)
					"nop"										"\n\t"//25 пауза (1 такт)
					"nop"										"\n\t"//26 пауза (1 такт)
					"nop"										"\n\t"//27 пауза (1 такт)
					"nop"										"\n\t"//28 пауза (1 такт)
					"nop"										"\n\t"//29 пауза (1 такт)
					"rjmp repeat%="								"\n\t"//31 возвращаемся (2 такта)
	"mode3ras%=:"	"ld r18,Y+"									"\n\t"//25 увеличиваем CAS на 1 (1 такт)
					"ldi r26,0"									"\n\t"//26 младший байт RAS=0
					"ldi r27,0"									"\n\t"//27 старший байт RAS=0
					"in r18,%[pina]"							"\n\t"//28 получаем байт из ОЗУ (1 такт)
					"nop"										"\n\t"//29 пауза (1 такт)
					"rjmp repeat%="								"\n\t"//31 возвращаемся (2 такта)
	//------------------------------------------------------------------------------------------------------------------------------------------------------
					//подпрограмма сброса сигнала с линий
	"mode4%=:"		"sbi %[portd],%[dram_cas1]"					"\n\t"//23 устанавливаем разряд CAS (2 такта)
					"sbi %[portd],%[dram_cas2]"					"\n\t"//25 устанавливаем разряд CAS (2 такта)
					"sbi %[portd],%[dram_ras]"					"\n\t"//27 устанавливаем разряд RAS (2 такта)					
					"nop"										"\n\t"//28 пауза (1 такт)
					"nop"										"\n\t"//29 пауза (1 такт)					
					"rjmp repeat%="								"\n\t"//31 возвращаемся (2 такта)					
	//------------------------------------------------------------------------------------------------------------------------------------------------------
	"exit%=:"		"sbi %[portd],%[dram_cas1]"					"\n\t"//23 устанавливаем разряд CAS (2 такта)
					"sbi %[portd],%[dram_cas2]"					"\n\t"//25 устанавливаем разряд CAS (2 такта)
					"sbi %[portd],%[dram_ras]"					"\n\t"//27 устанавливаем разряд RAS (2 такта)					
					:
					:
					[ras_h]"d"(RAS_H),
					[cas_h]"d"(CAS_H),
					[ras_l]"d"(RAS_L),
					[cas_l]"d"(CAS_L),
					[dram_ras]"M"(DRAM_RAS),
					[dram_cas1]"M"(DRAM_CAS1),
					[dram_cas2]"M"(DRAM_CAS2),
					[drive_data]"M"(DRIVE_DATA),
					[drive_side1_mask]"M"(1<<DRIVE_SIDE1),
					[gifr_intf0_mask]"M"(1<<INTF0),
					[pina]"I"(_SFR_IO_ADDR(PINA)),
					[drive_data_port]"I"(_SFR_IO_ADDR(DRIVE_DATA_PORT)),
					[drive_side1_pin]"I"(_SFR_IO_ADDR(DRIVE_SIDE1_PIN)),
					[gifr]"I"(_SFR_IO_ADDR(GIFR)),
					[portd]"I"(_SFR_IO_ADDR(PORTD)),
					[portc]"I"(_SFR_IO_ADDR(PORTC)):
					"r16","r17","r18","r19","r20","r21","r26","r27","r28","r29"
  );
И день и ночь в пути...
Мои программки: https://github.com/da-nie
Мои публикации: https://habr.com/ru/users/da-nie/posts/
Мои видео: https://www.youtube.com/channel/UCUroi3 ... 52g/videos
Аватара пользователя
ibiza11
Поставщик валерьянки для Кота
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Re: Вставка ASM кода в C

Сообщение ibiza11 »

da-nie писал(а):Для AVR, например, так:
извращенство от неумения. понял бы, если бы вставили 2-3 команды, а тут целая портянка. В таких случаях пишется ассемблерный файл, в котором описывается функция, которая уже вызывается как обычная СИшная функция из другого Си-файла. Формат ассемблерного файла зависит от компилятора. Как это пишется для gcc не знаю. Есть пример для IAR.
Ставим плюсы: )
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: Вставка ASM кода в C

Сообщение oleg110592 »

повторюсь я уже выше привел ссылку - там и пример и внешний асм файл и make файл и готовая atoi
если что: http://elm-chan.org/cc_e.html
->AVR assembler libraries for gcc projects
->General purpose numeral output module (smaller than printf)
з.ы. там еще есть: Getting started for writing asm functions , правда на японском, но можно перевести
Аватара пользователя
dem66
Встал на лапы
Сообщения: 141
Зарегистрирован: Ср окт 26, 2011 13:38:13

Re: Вставка ASM кода в C

Сообщение dem66 »

oleg110592 писал(а):выше ссылка почему не подходит?
Эта чтоли? http://elm-chan.org/docs/avrlib/xitoa.zip

Вобще то она не открывается, меня на яху перекидывает
-----------

Уже скачал, сейчас буду пробывать, опера ступила
Это не хвост, это антенна
Аватара пользователя
da-nie
Говорящий с текстолитом
Сообщения: 1590
Зарегистрирован: Вс июн 24, 2012 16:07:00
Откуда: Лен.Обл.
Контактная информация:

Re: Вставка ASM кода в C

Сообщение da-nie »

извращенство от неумения. понял бы, если бы вставили 2-3 команды, а тут целая портянка. В таких случаях пишется ассемблерный файл, в котором описывается функция, которая уже вызывается как обычная СИшная функция из другого Си-файла. Формат ассемблерного файла зависит от компилятора. Как это пишется для gcc не знаю. Есть пример для IAR.
А я думаю, не поняли бы даже если было бы 2-3 команды. ;) Судя по началу вашего комментария, вы слишком торопитесь в своей оценке.
Для начала - это как раз вставка в WinAVR, который использует gcc. WinAVR умеет удачно перераспределять регистры и экранировать задействованные во вставке, если я ему укажу, какие именно регистры использую (что и сделано). Так же он напрочь избавляет меня от запоминания в каких регистрах передаются данные и в каких возвращаются (подробнее о преимуществе встроенного кода писал AVR http://radiokot.ru/forum/viewtopic.php? ... view=print в сообщении "ARV [ Пн апр 13, 2009 11:20:27 ]"). Оформление этого кода как функцию во внешнем s-файле совершенно излишне. Вся причина по которой этот код написан на ассемблере - необходимость строгого выравнивания по тактам. Вызывается он ровно в одном месте программы.
И день и ночь в пути...
Мои программки: https://github.com/da-nie
Мои публикации: https://habr.com/ru/users/da-nie/posts/
Мои видео: https://www.youtube.com/channel/UCUroi3 ... 52g/videos
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: Вставка ASM кода в C

Сообщение YS »

Разница между теорией и практикой на практике гораздо больше, чем в теории.
HHIMERA
Друг Кота
Сообщения: 4583
Зарегистрирован: Вс дек 05, 2010 06:10:34
Откуда: ЮВ

Re: Вставка ASM кода в C

Сообщение HHIMERA »

da-nie писал(а):Оформление этого кода как функцию во внешнем s-файле совершенно излишне.
Та ну...
В некоторых случаях это единственная возможность...
"Я не даю готовых решений, я заставляю думать!"(С)
Аватара пользователя
ibiza11
Поставщик валерьянки для Кота
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Re: Вставка ASM кода в C

Сообщение ibiza11 »

da-nie писал(а):А я думаю, не поняли бы даже если было бы 2-3 команды.
Я же написал, что понял бы, не стоит меня уверять в обратном. Я это использовал в свое время при программировании AVR для входа в спящий режим.
da-nie писал(а):WinAVR умеет удачно перераспределять регистры и экранировать задействованные во вставке, если я ему укажу, какие именно регистры использую (что и сделано).
И что же в Вашем случае он так "удачно перераспределил"? От чего происходит экранирование задействованных во вставке регистров? как вы себе представляете "удачное перераспределение регистров" в случае использования ассемблерной функции? Там перераспределять нечего, все регистры, которые можно использовать, оговорены в соответствующих документах на компилятор.
da-nie писал(а):Так же он напрочь избавляет меня от запоминания в каких регистрах передаются данные и в каких возвращаются
Ну-ну, от того, что Вы сами в начале листинга скопировали нужные данные в регистры - чуда не произошло. Вы все равно оперирует регистрами, номера которых нужно либо запомнить, либо постоянно подглядывать. Вот эти строчки:
da-nie писал(а):

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

"mode1%=:"     "out %[portc],r26"                     "\n\t"//18 выставляем младший байт адреса

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

               "or r18,r27"                        "\n\t"//21 добавляем старшую часть адреса

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

"mode2%=:"     "out %[portc],r28"                     "\n\t"//16 выставляем младший байт адреса

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

               "or r18,r29"                        "\n\t"//19 добавляем старшую часть адреса

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

               "ldi r26,0"                           "\n\t"//26 младший байт RAS=0
               "ldi r27,0"                           "\n\t"//27 старший байт RAS=0 
Обратите внимание на Ваши комментарии к коду, они по-началу изобилуют растактовкой, но в приведенных выше строчках про длительность выполнения ни знака, только напоминание, с какими именно данными Вы сейчас оперируете. Это еще раз подтвержает то, что Ваше утверждение "он напрочь избавляет меня от запоминания в каких регистрах передаются данные и в каких возвращаются" - ложь.
Аналогично можно в ассемблерной функции в комментариях оперировать именами переменных.
da-nie писал(а):Оформление этого кода как функцию во внешнем s-файле совершенно излишне.
Оформление этого кода во внешнем файле решает эстетическую и логическую составляющие проблемы ассемлерных вставок. При разборе программы постоянно попадающаяся на глаза портянка ассемблерных команд будет мешать. Логически Ваш код должен представлять из себя функцию, которую невозможно определить из этой вставки не разбирающемуся в ассемблере человеку. К тому же Ваше решение не дает видимых плюсов по сравнению с вариантом написания отдельной функции.
Кстати говоря, уважаемый ARV, на утверждение которого Вы так полагаетесь, также упоминает о том, что я говорю:
Ставим плюсы: )
Аватара пользователя
da-nie
Говорящий с текстолитом
Сообщения: 1590
Зарегистрирован: Вс июн 24, 2012 16:07:00
Откуда: Лен.Обл.
Контактная информация:

Re: Вставка ASM кода в C

Сообщение da-nie »

Та ну...
В некоторых случаях это единственная возможность...
Так никто и не запрещает.
И что же в Вашем случае он так "удачно перераспределил"?
Вся эта программа компилируется с максимальной оптимизацией. Указывая, какие регистры я задействую, я минимально вмешиваюсь в оптимизацию окружающего кода.
От чего происходит экранирование задействованных во вставке регистров?
Он порчи их содержимого внутри ассемблерной вставки. Если gcc потребуется, он сохранит перед вызовом регистры на стеке. А если не потребуется - оставит без изменений. А учитывая, что код получает ряд переменных просчитанных заранее, gcc вполне может уже на этом этапе хранить эти переменные в регистрах.
Там перераспределять нечего, все регистры, которые можно использовать, оговорены в соответствующих документах на компилятор.
В данном коде можно использовать абсолютно любые регистры, доступные из ассемблера, не заботясь о том, используются они компилятором или нет при условии их перечисления. Всё что нужно, он сам сохранит на стеке в случае необходимости.
Ну-ну, от того, что Вы сами в начале листинга скопировали нужные данные в регистры - чуда не произошло. Вы все равно оперирует регистрами, номера которых нужно либо запомнить, либо постоянно подглядывать. Вот эти строчки:
В данном коде переданные значения были скопированы в 4 регистра исключительно потому, что требовалось поместить их именно в индексные регистры (что, вообще-то можно было бы сделать и явным указанием передать параметр в индексном регистре (как [ras] "x" (RAS), но сделано было на тот момент именно так). А поскольку более значения этих переменных не нужны, то они и не используются. Эта программа не есть демонстрация возможностей встроенного ассемблера в WinAVR. Эта программа решает вполне себе свою задачу.
Кстати, компилятор позволяет чётко отслеживать типы переменных:
[ras_h]"d"(RAS_H), - передаётся в верхнем регистре
[cas_h]"d"(CAS_H), - передаётся в верхнем регистре
[ras_l]"d"(RAS_L), - передаётся в верхнем регистре
[cas_l]"d"(CAS_L), - передаётся в верхнем регистре
[dram_ras]"M"(DRAM_RAS), - передаётся как 8 битная константа
[dram_cas1]"M"(DRAM_CAS1), - передаётся как 8 битная константа
[dram_cas2]"M"(DRAM_CAS2), - передаётся как 8 битная константа
[drive_data]"M"(DRIVE_DATA), - передаётся как 8 битная константа
[drive_side1_mask]"M"(1<<DRIVE_SIDE1), - передаётся как 8 битная константа
[gifr_intf0_mask]"M"(1<<INTF0), - передаётся как 8 битная константа
[pina]"I"(_SFR_IO_ADDR(PINA)), - передаётся как 6 битная константа
[drive_data_port]"I"(_SFR_IO_ADDR(DRIVE_DATA_PORT)), - передаётся как 6 битная константа
[drive_side1_pin]"I"(_SFR_IO_ADDR(DRIVE_SIDE1_PIN)), - передаётся как 6 битная константа
[gifr]"I"(_SFR_IO_ADDR(GIFR)), - передаётся как 6 битная константа
[portd]"I"(_SFR_IO_ADDR(PORTD)), - передаётся как 6 битная константа
[portc]"I"(_SFR_IO_ADDR(PORTC)): - передаётся как 6 битная константа
они по-началу изобилуют растактовкой,
Потому что у программы была предшественница, где указывалась длительность операций. Однако, номер такта и в этой программе сохраняется для того участка, где он важен.
Оформление этого кода во внешнем файле решает эстетическую и логическую составляющие проблемы ассемблерных вставок.
Это, извиняюсь, уже ваше личное мнение. ;) В данном случае никакой надобности не было оформлять s-файл с отдельным кодом.
При разборе программы постоянно попадающаяся на глаза портянка ассемблерных команд будет мешать.
Да вообще, в данном случае не сильно мешает. Сильно это мешало в GENS 4.51, где текст листать было не очень приятно (да и шрифт мелкий). Но ничего, и с ним справлялись.
К тому же Ваше решение не дает видимых плюсов по сравнению с вариантом написания отдельной функции.
Отдельная функция так же не даёт в данном случае никаких плюсов. Вот когда там будет около 200 строк ассемблерного кода, тогда да - это во внешний файл. А такие крохотные кусочки совершенно незачем выносить куда-то ещё.
Кстати говоря, уважаемый ARV, на утверждение которого Вы так полагаетесь, также упоминает о том, что я говорю:
Это сугубо вопрос вкуса.
Последний раз редактировалось da-nie Вт мар 19, 2013 17:40:01, всего редактировалось 1 раз.
И день и ночь в пути...
Мои программки: https://github.com/da-nie
Мои публикации: https://habr.com/ru/users/da-nie/posts/
Мои видео: https://www.youtube.com/channel/UCUroi3 ... 52g/videos
Аватара пользователя
ibiza11
Поставщик валерьянки для Кота
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Re: Вставка ASM кода в C

Сообщение ibiza11 »

da-nie писал(а):Это сугубо вопрос вкуса.
Ну вот и решили. :beer: не вижу смысла дальше спорить.
Ставим плюсы: )
Ответить

Вернуться в «Разные вопросы по МК»