Математика на ассемблере в AVR.

AVR
За время программирования чипов AVR, нарыл я разных математических подпрограмм для этих чипов. Может кому пригодятся. Что мне жалко этого добра? Пущай народ чесной пользуется. Если у кого то есть что то еще, то можно добавить это в статью.

bcd2ascii.asm

; Вход R16
; Выход R16 младший полубайт - выходит на печать последним
; R17 старший полубайт - выходит на печать первым.
BCD2ASCII:	MOV	R17,R16
		LDI	R18,0x30
		ANDI 	R16,0x0F
		ADD	R16,R18

		ANDI	R17,0xF0
		SWAP	R17
		ADD	R17,R18
		RET			


bcdfp.asm
;********************************************************************************
;Текст подпрограммы "bcdfp" преобразования двоичного числа, представленого в формате  с 
;плавающей точкой в строку ASCII-кодов, содержащую знак, 6 десятичных значащих цифр и 
;десятичную точку.
;Подпрограмма может вызываться из головной программы, написанной на IAR C для AVR:
			;void main (void)  
			;{
			;void bcdfp (float, char*);
			;float binary=123.456;
			;char bcdstr[9];

			;bcdfp(binary,bcdstr);
			;...
			;}  

			;NAME bcdfp
			;#include "iom103.h"
			;PUBLIC bcdfp
			;RSEG CODE

;***** Использование регистров
;r16(LSB)-r19(MSB) - двоичное число на входе в программу
;r20(LSB)-r21(MSB)- указатель (адрес RAM) для выходной строки
;********************************************************************************



							
bcdfp: 
        push r19            ;сохранить знак
        push r20            ;сохранить указатель строки          
                            ;результата (LSB)
        push r21            ;сохранить указатель строки             
                            ;результата (MSB)
        st -y,r26           ;сохранить локальные 
                            ;регистры 
        st -y,r27
;вычисление порядка
        lsl r19	            ;см. IAR C float-формат
        bst r18,7
        bld r19,0 
        subi r19,126       
;добавление старшей значащей 1 к мантиссе 
        ori r18,$80
;очистка памяти
        clr r22
        clr r21
        clr r20  
;выделение целой части
        sbrc r19,7      
        rjmp int_bcd        ;если  порядок < 0, то целая 
                            ;часть отсутствует
        cpi r19,0           ;если  порядок = 0, то целая 
                            ;часть отсутствует
        breq int_bcd       
int_shift:   
        lsl r16
        rol r17
        rol r18
        rol r20
        rol r21
        rol r22
        dec r19
        brne int_shift 
;bcd-преобразование целой части 
int_bcd:
        ldi     r23, -1
int_loop_1:
        inc     r23
        subi    r20, low(100000)
        sbci    r21, byte2(100000)
        sbci    r22, byte3(100000)
        brsh    int_loop_1
        subi    r20, low(-100000)
        sbci    r21, byte2(-100000)
        sbci    r22, byte3(-100000)
        st      -y,r23
        ldi     r23,-1
int_loop_2:
        inc     r23
        subi    r20, low(10000)
        sbci    r21, byte2(10000)
        sbci    r22, byte3(10000)
        brsh    int_loop_2
        subi    r20, low(-10000)
        sbci    r21, byte2(-10000)
        sbci    r22, byte3(-10000) 
        st      -y,r23
        ldi     r23,-1
int_loop_3:
        inc     r23
        subi    r20, low(1000)
        sbci    r21, byte2(1000)
        brsh    int_loop_3
        subi    r20, low(-1000)
        sbci    r21, byte2(-1000)
        st     -y,r23
        ldi     r23,-1
int_loop_4:
        inc     r23
        subi    r20, 100 
        sbci    r21, byte2(100) 
        brsh    int_loop_4
        subi    r20, -100 
        sbci    r21, byte2(-100) 
        st     -y,r23
        ldi     r23,-1
int_loop_5:
        inc     r23
        subi    r20, 10
        brsh    int_loop_5 
        subi    r20, -10 
        st     -y,r23
        st     -y,r20
   ;
     sbrc r19,7      
     rjmp f_prep            ;if порядок < 0, сдвигать 
                            ;дробную часть     
     rjmp f_conv_0

;сдвиг дробной части
f_prep:     
        neg r19 
f_shift:
        lsr r18
        ror r17
        ror r16
        dec r19
        brne f_shift 
;
;bcd-преобразование дробной части 
f_conv_0: 
       ldi r23,24
f_conv_1: 
       lsr r18
       ror r17
       ror r16
       ror r22
       ror r21
       ror r20
;         
      sbrc r22,7
      subi r22,$30
      sbrc r22,3
      subi r22,$03
      sbrc r21,7
      subi r21,$30
      sbrc r21,3
      subi r21,$03
      sbrc r20,7
      subi r20,$30
      sbrc r20,3
      subi r20,$03
;
      dec r23
      brne f_conv_1          
;
;распаковка bcd-представления дробной части
      mov r23,r22 
      swap r23 
      andi r23,$0f
      st -y,r23
      mov r23,r22
      andi r23,$0f
      st -y,r23 
      mov r23,r21
      swap r23 
      andi r23,$0f
      st -y,r23
      mov r23,r21
      andi r23,$0f
      st -y,r23
      mov r23,r20 
      swap r23  
      andi r23,$0f
      st -y,r23
      mov r23,r20
      andi r23,$0f
      st -y,r23 
;
;нормализация результата 
      ldi r22,7
      mov r26,r28
      mov r27,r29
      adiw r26,12 
nor:  
      dec r22
      ld r23,-x
      cpi r23,0 
      brne  round 
      cpi r22,1 
      brne nor 
;
;округление результата           
round:
     mov r30,r26
     mov r31,r27
     sbiw r30,6   
     ld r23,z+ 
     ldi r16,4 
     sub r16,r23    
     brcc  move_str 
    
     ldi r16,6
next_digit:        
     ld r23,z     
     inc r23
     cpi r23,10
     brne round_end 
     ldi r23,0
     st  z+,r23
     dec r16
     brne next_digit 
;
     inc r22
     adiw r26,1
     ldi r23,1 
round_end:
     st z,r23   
; 
;запись результата в выходную строку
move_str: 
    pop r31           ;загрузить адрес строки
    pop r30 
    adiw r26,1
    ;
    ldi r23,' '
    pop r19           ;загрузить знак
    sbrc r19,7
    ldi r23,'-'
    st z+,r23  
    ;          
    ldi r16,6
int_digits:   
    ld r23,-x 
    subi r23,-$30 
    st z+,r23
    dec r16
    dec r22
    brne int_digits   
;
point:
    ldi r23,'.'
    st z+,r23        
; 
f_digits:
    cpi r16,0
    breq enndd
    ld r23,-x 
    subi r23,-$30  
    st z+,r23
    dec r16
    rjmp f_digits  
;              
enndd:
    adiw r28,12      ;восстановить стек данных
    ld r27,y+
    ld r26,y+
    ret
        
;   end
;********************************************************************************


bin16ASCII15.asm
;*********************************************************************
;2.Текст программы "bin16ASCII15"- преобразование 16-битного двоичного
;значения в неупакованный BCD формат, тоесть в ASII формат.
;*********************************************************************
;* Количество слов кода            :22 + возврат
;* Количество циклов               :60/220 (Мин/Макс) + возврат
;* Использованные младшие регистры :5 (fASCIIL/tASCII0,fASCIIH,tASCII2,
;*                                     tASCII3,tASCII4)
;* Использованные старшие регистры :3 (cnt16a/tASCII1,tmp16a,tmp16b)
;*********************************************************************

;***** Регистровые переменные подпрограммы

;* Примечания: 1. Переменные fASCIIL и tASCII0 должны размещаться в
;*                одном  регистре.
;*             2. Переменные cnt16a и tASCII1 должны размещаться в одном
;*                регистре.
;*             3. Переменные, определенные в младших регистрах могут быть
;*                также определены и в старших регистрах.
;*Обрабатываемое число нужно ввести в регистр r11 и r12. Введем число 34567
;*Получится ldii r11,0b00000111;  34567 это 10000111 00000111 
;*		  ldii r12,0b10000111
;*После обработки получим результат.
;* r11 - 7 число 5
;* r12 - ничего
;* r13 - 5 число 3
;* r14 - 4 число 2
;* r15 - 3 число 1
;* r16 - 6 число 4
;* не попорядку но ничего.



.def    fASCIIL =r11
.def    tASCII0 =r11
.def    fASCIIH =r12
.def    tASCII2 =r13
.def    tASCII3 =r14
.def    tASCII4 =r15
.def    tASCII1 =r16
.def    cnt16a  =r16
.def    tmp16a  =r17
.def    tmp16b  =r18

;***** Код
bin2ASCII15:
			        ldi     tmp16a, low(10000)
			        ldi     tmp16b, high(10000)
			        rcall   bin2ASCII_digit
			        mov     tASCII4, cnt16a
			        ldi     tmp16a, low(1000)
			        ldi     tmp16b, high(1000)
			        rcall   bin2ASCII_digit
			        mov     tASCII3, cnt16a
			        ldi     tmp16a, low(100)
			        ldi     tmp16b, high(100)
			        rcall   bin2ASCII_digit
			        mov     tASCII2, cnt16a
			        ldi     tmp16a, low(10)
			        ldi     tmp16b, high(10)
bin2ASCII_digit:	        ldi     cnt16a, -1
				   
bin2ASCII_digit_loop:           inc     cnt16a
			        sub     fASCIIL, tmp16a
			        sbc     fASCIIH, tmp16b
			        brsh    bin2ASCII_digit_loop
			        add     fASCIIL, tmp16a
			        adc     fASCIIH, tmp16b
			        
ret

;Переводим в символы дисплея и попорядку раскладываем в регистры

dop: mov r18,r15
	ori r18,0b00110000;1
	mov r19,r14
	ori r19,0b00110000;2
	mov r20,r13
	ori r20,0b00110000;3
	mov r21,r16
	ori r21,0b00110000;4
	mov r22,r11
	ori r22,0b00110000;5
ret


bin16bcd5.asm
;===================================================================
;"bin16BCD5"- преобразование 16-битного двоичного
;значения в упакованный BCD формат
;===================================================================
;Количество слов кода            :25 + возврат
;Количество циклов               :25/176 (Мин/Макс) + возврат
;Использованные младшие регистры :нет
;Использованные старшие регистры :4(fbinL,fbinH/tBCD0,tBCD1,tBCD2)
;Использованные указатели        :нет


;Вход
.def    fbinL   =r16            ;двоичное значение, младший байт
.def    fbinH   =r17            ;двоичное значение, старший байт

;Выход
.def    tBCD0   =r17            ;BCD значение, цифры 1 и 0
.def    tBCD1   =r18            ;BCD значение, цифры 3 и 2
.def    tBCD2   =r19            ;BCD значение, цифра 4
;Примечание: Переменные fbinH и tBCD0 должны размещаться в одном
;регистре.
;После преобразования числа 65535 в итоге будет. 
/*
r17: 0b0011_0101 это 3 и 5
r18: 0b0101_0101 это 5 и 5
r19: 0b0000_0110 это 6
*/
bin16BCD5:  	        ldi     tBCD2,-1
b16BCD5_l1: 	        inc     tBCD2
								;255
	        	subi    fbinL,low(10000)		;r17 0101_0101	
	        	sbci    fbinH,high(10000)		;r18 0000_0010
								;
	        	brsh    b16BCD5_l1			;1500
							        ;r17 0000_0000
	        	subi    fbinL,low(-10000)		;r18 0001_0101
	        	sbci    fbinH,high(-10000)		
							        
	        	ldi     tBCD1,-0x11				

b16BCD5_l2:		subi    tBCD1,-0x10
        	  	subi    fbinL,low(1000)
	       		sbci    fbinH,high(1000)
    
	    		brsh    b16BCD5_l2
    
	    		subi    fbinL,low(-1000)
        		sbci    fbinH,high(-1000)

b16BCD5_l3:		inc     tBCD1
        		subi    fbinL,low(100)
        		sbci    fbinH,high(100)
    
	    		brsh    b16BCD5_l3
    
	    		subi    fbinL,-100
        		ldi     tBCD0,-0x10

b16BCD5_l4:		subi    tBCD0,-0x10
        		subi    fbinL,10
    
	    		brsh    b16BCD5_l4
	    		subi    fbinL,-10
        		add     tBCD0,fbinL

ret


div8s.asm
;**********************************************************************

; 6. Текст программы div8s деления 8-и разрядных целых знаковых чисел, 

;оптимизированной  с точки зрения времени исполнения 

;**********************************************************************

;***** Использование регистров

.def		d8s      =r14		;регистр знака
.def		drem8s 	 =r15		;остаток
.def		dres8s   =r16		;результат
.def		dd8s     =r16		;делимое
.def		dv8s     =r17		;делитель
.def		dcnt8s   =r18		;счетчик цикла



div8s:		mov	d8s,dd8s		;переслать делимое в регистр знака
		eor	d8s,dv8s		;xor регистра знака и делителя
		sbrc	dv8s,7			;iесли MSBделителя  установлен
		neg	dv8s			;изменить знак делителя
		sbrc	dd8s,7			;iесли MSB делимого установлен
		neg	dd8s			;изменить знак делимого
		sub	drem8s,drem8s	        ;очистить остаток и перенос
		ldi	dcnt8s,9		;инициализировать счетчик цикла

d8s_1:		rol	dd8s			;делимое сдвинуть влево
		dec	dcnt8s			;decrement counter
		brne	d8s_2			;если счетчик цикла равен нулю
		sbrc	d8s,7			;если MSB регистра знака
		neg	dres8s			;изменить знак результата
		ret				;выход из подпрограммы

d8s_2:  	rol	drem8s			;сдвинуть делимое
		sub	drem8u,dv8s		;остаток = остаток - делитель
		brcc	d8s_3			;если результат отрицательный
		add	drem8u,dv8s		;восстановить остаток
		clc				;сбросить перенос для формирования результата

  		rjmp	d8s_1			;иначе

d8s_3:		sec				;установить перенос для формирования результата
		rjmp	d8s_1			




div8u_c.asm
;**********************************************************************

;4.Текст программы div8u_с деления 8-и разрядных целых беззнаковых чисел,
 
;оптимизированной  с точки зрения длины кода 

;**********************************************************************

;***** Использование регистров


.def	drem8u	=r15;остаток
.def	dres8u  =r16;результат
.def	dd8u    =r16;делимое
.def	dv8u    =r17;делитель
.def	dcnt8u	=r18;счетчик цикла



div8u_c:	sub	drem8u,drem8u	;очистить остаток и перенос
		ldi	dcnt8u,9	;инициализировать счетчик цикла
d8u_1:		rol	dd8u		;делимое/результат сдвинуть влево
		dec	dcnt8u		;уменьшить на единицу счетчик цикла
		brne	d8u_2		;переход, если не ноль
		ret



d8u_2:		rol	drem8u		;остаток сдвинуть влево
		sub	drem8u,dv8u	;остаток= остаток -  делитель
		brcc	d8u_3	        ;если результат < 0
		add	drem8u,dv8u 	;восстановить остаток
		clc			;сбросить перенос для формирования результата

		rjmp    d8u_1        	;иначе установить перенос для
d8u_3:		sec			;формирования результата

		rjmp	d8u_1        	;вернуться назад


div8u_s.asm
;**************************************************************************

;5. Текст программы div8u_s деления 8-и разрядных целых беззнаковых чисел, 

;оптимизированной с точки зрения времени исполнения 

;**************************************************************************

;***** Использование регистров


.def	drem8u	=r15;остаток
.def	dres8u  =r16;результат
.def	dd8u    =r16;делимое
.def	dv8u    =r17;делитель
.def	dcnt8u	=r18;счетчик цикла



div8u_s:    sub		drem8u,drem8u	; очистить  остаток и перенос
	    rol		dd8u		; делимое/результат сдвинуть влево
	    rol		drem8u		; остаток сдвинуть влево
	    sub		drem8u,dv8u	; остаток = остаток - делитель
	    brcc	d8u_01		; если результат < 0
	    add		drem8u,dv8u     ; восстановить остаток
	    clc                         ; сбросить перенос для формирования результата

	    rjmp   	d8u_02		; иначе установить перенос для
d8u_01:     sec				; формирования результата



d8u_02: 	rol	dd8u		; делимое/результат сдвинуть влево
		rol	dd8u		; делимое/результат сдвинуть влево
		rol	drem8u		; остаток сдвинуть влево
		sub	drem8u,dv8u	; остаток = остаток - делитель
		brcc	d8u_03		; если результат < 0
		add	drem8u,dv8u	; восстановить остаток
		clc			; сбросить перенос для формирования результата


		rjmp    d8u_4		; иначе установить перенос для
d8u_03: 	sec			; формирования результата


d8u_4:		rol	dd8u
		rol	dd8u
		rol	drem8u
		sub	drem8u,dv8u
		brcc	d8u_5
		add	drem8u,dv8u
		clc

		rjmp    d8u_6		; иначе установить перенос для
d8u_5:		sec			; формирования результата



d8u_6:		rol	dd8u
		rol	dd8u
		rol	drem8u
		sub	drem8u,dv8u
		brcc	d8u_7
		add	drem8u,dv8u
		clc

		rjmp    d8u_8		; иначе установить перенос для
d8u_7:		sec			; формирования результата


d8u_8:		rol	dd8u
		rol	dd8u
		rol	drem8u
		sub	drem8u,dv8u
		brcc	d8u_9
		add	drem8u,dv8u
			clc

		rjmp    d8u_10		; иначе установить перенос для
d8u_9:		sec			; формирования результата


d8u_10:		rol	dd8u
		rol	dd8u
		rol	drem8u
		sub	drem8u,dv8u
		brcc	d8u_11
		add	drem8u,dv8u
		clc

		rjmp    d8u_12		; иначе установить перенос для
d8u_11:		sec			; формирования результата


d8u_12:		rol	dd8u
		rol	dd8u
		rol	drem8u
		sub	drem8u,dv8u
		brcc	d8u_13
		add	drem8u,dv8u
		clc


		rjmp    d8u_14		; иначе установить перенос для
d8u_13:		sec			; формирования результата



d8u_14:		rol	dd8u
		rol	dd8u
		rol	drem8u
		sub	drem8u,dv8u
		brcc	d8u_15
		add	drem8u,dv8u
		clc


		rjmp    d8u_16		; иначе установить перенос для
d8u_15:		sec			; формирования результата


d8u_16:		rol     dd8u            ; делимое/результат сдвинуть влево

		ret


div16.asm
;Деление 16 битного числа на 8 ми битное без дробной части.

.DEF rd1l = R0 ; LSB 16-bit-number to be divided   делимое младший
.DEF rd1h = R1 ; MSB 16-bit-number to be divided   делимое старший
.DEF rd1u = R2 ; interim register
.DEF rd2  = R3 ; 8-bit-number to divide with        делитель
.DEF rel  = R4 ; LSB result                         результат младший
.DEF reh  = R5 ; MSB result                         результат старший
.DEF rmp  = R16; multipurpose register for loading
.DEF temp = R17;для временных данных в процессе деления.



;start:	ldi rmp,0b10000000 ; делимое (старший)
;	mov rd1h,rmp ;--------------
;	ldi rmp,0b00001011; делимое (младший)
;	mov rd1l,rmp ;--------------
;	ldi rmp,0b00000101 ;делитель
;	mov rd2,rmp ;-------------
  



div16:	clr rd1u ; clear interim register 
  	clr reh ; clear result (the result registers 
  	clr rel ; are also used to count to 16 for the 
 	inc rel ; division steps, is set to 1 at start)
  

div8a:	clc ; clear carry-bit
	rol rd1l ; rotate the next-upper bit of the number
	rol rd1h ; to the interim register (multiply by 2)
	rol rd1u
	brcs div8b ; a one has rolled left, so subtract
	cp rd1u,rd2 ; Division result 1 or 0?
	brcs div8c ; jump over subtraction, if smaller
  

div8b:	sub rd1u,rd2; subtract number to divide with
	sec ; set carry-bit, result is a 1
	rjmp div8d ; jump to shift of the result bit
  
div8c:  clc ; clear carry-bit, resulting bit is a 0
  

div8d:  rol rel ; rotate carry-bit into result registers
        rol reh
        brcc div8a ; as long as zero rotate out of the result
; registers: go on with the division loop
; End of the division reached
	RET


f_conv.asm
;*******************************************************************
;3. Текст программы f_conv преобразования двоичной дроби
;в двоично-десятичную дробь.
;*******************************************************************
;***** Использование регистров

.def	binH	=r23		;старший байт двоичной дроби
.def	binM	=r24		;средний байт двоичной дроби
.def	binL	=r25		;младший байт двоичной дроби
.def	bcdH	=r20		;старший байт десятичной дроби
.def	bcdM	=r21		;средний байт десятичной дроби
.def	bcdL	=r22		;младший байт десятичной дроби
.def	count	=r27		;счетчик числа циклов

;*****Код
f_conv: 
       ldi count,24		;инициализация счетчика циклов
f_conv1: 
       lsr binH			;сдвиг двоичного
       ror binM
       ror binL			
       ror bcdH			;сдвиг десятичного
       ror bcdM
       ror bcdL
         
      sbrc bcdH, 7		;коррекция десятичного
      subi bcdH, $30
      sbrc bcdH, 3
      subi bcdH, $03
      sbrc bcdM, 7
      subi bcdM, $30
      sbrc bcdM, 3
      subi bcdM, $03
      sbrc bcdL, 7
      subi bcdL, $30
      sbrc bcdL, 3
      subi bcdL, $03

      dec count
      brne f_conv1


FLOAT.INC
; ************* Floating point library for AVR microprocessors *************
;
; Assembler     AVRASM v. 1.21
; Processor     AT90S2313, AT90S8515
; Code Size     256 words (512 bytes)
; **************************************************************************
; Author        Y.Andrienko
; Phone         (057-2) 44-85-40, 98-07-58
; FIDO          2:461/44.14
; E-mail        yurik@aqua.kharkov.ua, aya@apexmail.com
;
; Last modification     - 28.09.1999
; **************************************************************************
; Floating point number format: 3-bytes
; 1st - order - bit 7 - number sign (1 - negative number)
;                   6 - order sign (1 - positive order)
;                   0..5 - order value
; 2nd - mantissa low byte
; 3d  - mantissa high byte

; !!! This variables must be defined in main programm !!!

;.def  Float1O =r16
;.def  Float1L =r17
;.def  Float1H =r18
;
;.def  Float2O =r19
;.def  Float2L =r20
;.def  Float2H =r21

;.def  FTempO  =r22
;.def  FTempL  =r23
;.def  FTempH  =r24
;.def  FCnt    =r25


; ************************************************************************
; Fix2Float - translate fixed format number to floating point format
; Float2Fix - translate floating point number to fixed format
; FNeg      - negate floating point number
; SwapFl    - exchange Float1 and Float2
; FAdd      - floating point addition Float2=Float2+Float1
; FSub      - floating point substraction Float2=Float2-Float1
; FMul      - floating point multiplication Float2=Float2*Float1
; FDiv      - floating point division Float2=Float1/Float2
;*************************************************************************

; translate number from fix to floating point format
; Input - 2-byte number in Float2L,Float2H
; Output - 3-byte floating point number in Float2
;
; high registers used - Float2O,Float2L,Float2H

Fix2Float:
        clc                     ; clear carry
        tst     Float2L         ; check number for 0
        brne    Fx2Fl_A
        tst     Float2H
        brne    Fx2Fl_A
        ldi     Float2O,$40     ; if Float2L=Float2H=0 set number to 0
        ret
Fx2Fl_A:
        ldi     Float2O,$50     ; if fixed num # 0 set order to 50H
Fx2Fl_B:
        sbrc    Float2H,7       ; skip if bit 7#0
        ret                     ; else return
        rol     FLoat2L         ; shift number left
        rol     Float2H
        dec     Float2O         ; and decrement order
        rjmp    Fx2Fl_B         ; continue while bit 7#1



; translate floating point number to fixed format
; Input - Float2
; Output - Float2L, Float2H
; carry=1 if overflow
;
; registers used - Float2O, Float2L, Float2H

Float2Fix:
        sbrc    Float2O,7       ; check number sign
        rjmp    SetOverflow     ; for negative number set overflow and return
        sbrs    Float2O,6       ; check order sign
        rjmp    Float2eq0       ; for neg.order set number to 0
        andi    Float2O,$3f     ; mask sign bits
        cpi     Float2O,$11     ; check maximal order
        brlo    Fl2Fx_A         ; jump if order<11H
        rjmp    SetOverflow     ; else set overflow and return
Fl2Fx_A:
        subi    Float2O,$10
        neg     Float2O         ; Float2O=10H-Float2O
Fl2Fx_C:
        clc                     ; clear carry
        tst     Float2O         ; check order
        brne    Fl2Fx_B
        ret                     ; return if order 0
Fl2Fx_B:
        ror     Float2H         ; shift right
        ror     Float2L
        dec     Float2O         ; decrement order
        rjmp    Fl2Fx_C         ; repeat while order # 0

Float2eq0:
        clr     Float2L
        clr     Float2H
        ret

; Change sign of floating point number Float2=-Float2
; Input - Float2
; Output - Float2
; registers used - Float2O,Float2L,Float2H

FNeg:
        neg     Float2O
        subi    Float2O,$80
        neg     Float2O
        clc
        ret

; Swap Float1 and Float2 numbers
; (Thanks for A.Redchhuk)
SwapFl:
;       it is                        it was
        eor Float1O,Float2O        ; push    Float1O
        eor Float2O,Float1O        ; mov     Float1O,Float2O
        eor Float1O,Float2O        ; pop     Float2O

        eor Float1L,Float2L        ; push    Float1L
        eor Float2L,Float1L        ; mov     Float1L,Float2L
        eor Float1L,Float2L        ; pop     Float2L

        eor Float1H,Float2H        ; push    Float1H
        eor Float2H,Float1H        ; mov     Float1H,Float2H
        eor Float1H,Float2H        ; pop     Float2H
        ret

; Floating point addition Float2=Float1+Float2
; Input - Float1, Float2
; Output - Float2
; registers used - Float1O, Float1L, Float1H, Float2O, Float2L, Float2H

FAdd:
        sbrc    Float1O,7       ; skip if Float1>0
        rjmp    FAdd_A          ; jump if Float1<0
        sbrs    Float2O,7       ; skip if Float2<0
        rjmp    FAdd_B          ; jump if FLoat1 and Float2 < 0

; if numbers signs not equal (Float1>0,Float2<0 or Float1<0, Float2>0)
; if Float1>0 Float2<0  result = Float1-Float2
FAdd_C:
        rcall   FNeg            ; change Float2 sign
        rcall   SwapFl
        rjmp    FSub            ; and continue in substraction programm
; If Float1<0,Float2>0 result = Float2-Float1
FAdd_X:
        rcall   SwapFl          ; Change Float1 sign
        rcall   FNeg
        rcall   SwapFl
        rjmp    FSub
FAdd_A:
        sbrs    Float2O,7       ; skip if Float1<0 and Float2<0
        rjmp    FAdd_X
; if numbers signs are equal
FAdd_B:
        tst     Float1H         ; check Float1 for 0
        brne    FAdd_D
        tst     Float1L
        brne    FAdd_D
        ret                     ; if Float1=0 result =Float2
FAdd_D:
        tst     Float2H         ; check Float2 for 0
        brne    FAdd_E
        tst     Float2L
        brne    FAdd_E
        rjmp    Fl1toFl2        ; if Float2=0 copy Float1 as result and return
FAdd_E:
        cp      Float2O,Float1O ; compare orders
        breq    FAdd_G          ; if orders are equal
        brlo    FAdd_F          ; if Float2O<Float1O
        rcall   SwapFl          ; else swap numbers
FAdd_F:
        sub     Float2O,Float1O
        neg     Float2O         ; Float2O=Float1O-Float2O
        cpi     Float2O,$10
        brlo    FAdd_H          ; if Float1O-Float2O<16
        rjmp    Fl1toFl2        ; else copy Float1 as result and return
FAdd_H:
        clc                     ; clear carry
        ror     Float2H         ; shift Float2 right
        ror     Float2L
        dec     Float2O         ; decrement order
        brne    FAdd_H          ; repeat while orders not equal
; if orders are equal
FAdd_G:
        add     Float2L,Float1L ; add numbers
        adc     Float2H,Float1H
        brcs    FAdd_I          ; jump if carry set
FAdd_J:
        mov     Float2O,Float1O ; copy order value
        ret                     ; and return
FAdd_I:
        ror     FLoat2H         ; shift number
        ror     Float2L
        inc     Float1O         ; increment order
        rjmp    FAdd_J

; Floating point numbers substraction Float2=Float1-Float2
; Input - Float1, Float2
; Output - Float2
; registers used - Float1O, Float1L, Float1H, Float2O, Float2L, Float2H

FSub:
        sbrc    Float1O,7       ; skip if Float1>0
        rjmp    FSub_A          ; jump if Float1<0
        sbrs    Float2O,7       ; skip if Float2<0
        rjmp    FSub_B          ; jump if Float1>0 and Float2>0

; if numbers signs not equal
FSub_C:
        rcall   SwapFl
        rcall   FNeg            ; change sign of 2nd number
        rcall   SwapFl
        rjmp    FAdd            ; and continue in substraction programm
FSub_A:
        sbrs    Float2O,7       ; skip if Float2<0 and Float1<0
        rjmp    FSub_C          ; jump if Float2>0 (Float1<0)

; if signs of numbers are equal
FSub_B:
        tst     Float1H         ; check Float1 for 0
        brne    FSub_D
        tst     Float1L
        brne    FSub_D
        ret                     ; if Float1=0  result = Float2 - return
FSub_D:
        tst     Float2H         ; check Float2 for 0
        brne    FSub_E
        tst     Float2L
        brne    FSub_E
        rcall   Fl1toFl2        ; if FLoat2=0, result = -Float1, copy an return
        rjmp    FNeg            ; change sign and return
FSub_E:
        clt
        cp      Float1O,Float2O ; compare orders
        breq    FSub_G          ; if orders are equal
        brlo    FSub_F          ; if Float1O<Float2O
        set                     ; set flag
        rcall   SwapFl          ; swap numbers if Float1O>Float2O
FSub_F:
        sub     Float1O,Float2O
        neg     Float1O         ; Float1O=Float2O-Float1O
        cpi     Float1O,$10
        brlo    FSub_H          ; if Float2O-Float1O<16
        ret                     ; else result=Float2

; equalize orders
FSub_H:
        clc
        ror     Float1H         ; shift Float right
        ror     Float1L
        dec     Float1O
        brne    FSub_H          ; repeat before orders not equal
        brtc    FSub_G          ;
        rcall   SwapFl          ; swap again
        clt
FSub_G:
        cp      Float2L,Float1L
        cpc     Float2H,Float1H
        brlo    FSub_I
FSub_J:
        sub     Float2L,Float1L ; add numbers
        sbc     Float2H,Float1H
        sbrc    Float2H,7       ; skip if MSB=0
        ret                     ; else return
        rjmp    Fx2Fl_B         ; normalise result
FSub_I:
        rcall   SwapFl          ; swap numbers
        rcall   FNeg            ; change result sign
        rjmp    FSub_J

        ror     FLoat2H         ; shift number
        ror     Float2L
        inc     Float2O         ; increment order
        rcall   FNeg            ; and change sign
        ret                     ; else return


; Floating point multiplication Float2 = Float1 * Float2
; Input - Float1, Float2
; Output - Float2
; registers used - Float1O, Float1L, Float1H, Float2O, Float2L, Float2H
;                  FTempO, FTempL, FCnt
;
FMul:
        tst     Float1H         ; check Float1 for 0
        brne    FMul_A
        tst     Float1L
        brne    FMul_A
        rjmp    SetRes0         ; if Float1=0, set Float2=0 and return
FMul_A:
        tst     Float2H         ; check Float2 for 0
        brne    FMul_B
        tst     Float2L
        brne    FMul_B
        ret                     ; if Float2=0 - return

FMul_B:
        mov     FTempO,Float1O  ; Find result sign
        eor     FTempO,Float2O  ; FTempO bit 7 equal result sign
        cbr     Float1O,$80     ; reset numbers signs
        cbr     Float2O,$80
        bst     FTempO,7        ; save result sign in T
        add     Float2O,Float1O ; add orders
        ldi     Float1O,$40     ;
        add     Float2O,Float1O
        bld     Float2O,7

; 16x16 bits unsigned multiplication from ****AVR200**** application note
FMul_D:
        clr     FTempO          ;clear 2 highest bytes of result
        clr     FTempL
        ldi     FCnt,16         ;init loop counter
        lsr     Float2H
        ror     Float2L
FMul_E:
        brcc    FMul_F          ;if bit 0 of multiplier set
        add     FTempO,Float1L  ;add multiplicand Low to byte 2 of res
        adc     FTempL,Float1H  ;add multiplicand high to byte 3 of res
FMul_F:
        ror     FTempL          ;shift right result byte 3
        ror     FTempO          ;rotate right result byte 2
        ror     Float2H         ;rotate result byte 1 and multiplier High
        ror     Float2L         ;rotate result byte 0 and multiplier Low
        dec     FCnt            ;decrement loop counter
        brne    FMul_E          ;if not done, loop more
; after multiplication - normalise result
FMul_H:
        sbrc    FTempL,7
        rjmp    FMul_G          ; jump if result is normalised
        rol     Float2L         ; shift number left
        rol     Float2H
        rol     FTempO
        rol     FTempL
        dec     Float2O         ; decrement result order
        rjmp    FMul_H
FMul_G:
        bld     Float2O,7       ; restore result sign from T
        mov     Float2L,FTempO  ; copy mantissa to result
        mov     Float2H,FTempL
        ret

; Floating point division  Float2 = Float1/Float2
; Input - Float1, Float2
; Output - Float2
; registers used - Float1O, Float1L, Float1H, Float2O, Float2L, Float2H
;                  FTempO, FTempL, FTempH, FCnt

FDiv:
        mov     FTempO,Float1L  ; Check Float1 for 0
        or      FTempO,Float1H
        tst     FTempO
        brne    FDiv_A
        rjmp    SetRes0         ; if Float1=0 - result = 0
FDiv_A:
        sbrs    Float2H,7
        rjmp    SetOverflow     ; if Float2 not normalized or 0 - overflow
        ldi     FCnt,$10        ; bits counter
        mov     FTempO,Float1O
        andi    FTempO,$80      ; select sign bit
        add     FTempO,Float2O  ;
        bst     FTempO,7        ; store result sign in T
        mov     FTempO,Float1O  ; read 1st number order
        sub     FTempO,Float2O  ; substract orders
        subi    FTempO,-$41     ; add 41H
        bld     FTempO,7        ; restore result sign
        clr     Float1O         ; clear orders
        clr     Float2O
        clr     FTempH
        ldi     FTempL,1
; main division cykle
FDiv_C:
        sbrs    FTempL,0
        rjmp    FDiv_D
        sub     Float1L,Float2L
        sbc     Float1H,Float2H
        sbc     Float1O,Float2O ; set carry
        rjmp    FDiv_E
FDiv_D:
        add     Float1L,Float2L
        adc     Float1H,Float2H
        adc     Float1O,Float2O
FDiv_E:
        andi    Float1O,$01
        push    Float1O         ; save order
        clc
        eor     Float1O,Float2O
        brne    FDiv_F
        sec
FDiv_F:
        pop     Float1O         ; restore order
        rol     FTempL
        rol     FTempH
        clc                     ; clear carry
        rol     Float1L
        rol     Float1H
        mov     Float1O,FTempH
        rol     Float1O
        dec     FCnt            ; decremet counter
        brne    FDiv_C          ; repeate while FCnt#0
        mov     Float2L,FTempL  ; copy result
        mov     Float2H,FTempH
        mov     Float2O,FTempO
        rjmp    Fx2Fl_B         ; normalise result

; Common subroutines

; Set overflow flag and return
SetOverflow:
        sec
        ret

; Copy Float1 to Float2
Fl1toFl2:
        mov     Float2O,Float1O
        mov     Float2H,Float1H
        mov     Float2L,Float1L
        ret

; Set result to 0 (Float2=0)
SetRes0:
        clr     Float2L         ; set result=0
        clr     Float2H
        ldi     Float2O,$40
        ret


hex2ascii.asm
;-----------------------------------------------
; HEX TO ASCII преобразование числа в символы дисплея тоесть в ASII формат.
;-----------------------------------------------
;I think, this was the smallest (only 10 words). 

;вход: R16  число от 0 ... 255 
;выход: R18 число 2, R17 число 1, R16 число 0  = digits 
;байтов: 20 

;пример на вход ldi r16,255
;выход r18 = 00110010 это 2, r17 = 00110101 это 5, r16 = 00110101 это 5.                
Hex2Ascii:	LDI r18,-1+'0' 
bcd1:		INC r18
		SUBI r16,100 
		BRCC bcd1 
		LDI r17,10+'0' 
bcd2:		DEC r17 
		SUBI r16,-10 
		BRCS bcd2 
		SBCI r16,-'0' 
		RET


hex40_bcd13.asm
; Преобразователь HEX40-BCD13 
;
; 02.01.2008
; 02.01.2008

        .INCLUDE "8515def.inc"

	; Арифметические регистры

		.def	A	=r16

		.CSEG

	RESET:  RJMP    START	; On Reset

;		.
;		.
;		.
;		.
;		.
;************************************************
        START:
		CLI
		LDI	A,LOW(RAMEND)
		OUT	SPL,A
		LDI	A,HIGH(RAMEND)
		OUT	SPH,A

;************************************************
		LDS	R16,$70
		LDS	R17,$71
		LDS	R18,$72
		LDS	R19,$73		; HEX IN
		LDS	R20,$74

		CLR	R25		; BCD OUT 10'000'000'000'000,1'000'000'000'000
		CLR	R26		; BCD OUT 100'000'000'000,10'000'000'000
		CLR	R27		; BCD OUT 1'000'000'000,100'000'000
		CLR	R28		; BCD OUT 10'000'000,1'000'000
		CLR	R29		; BCD OUT 100'000,10'000
		CLR	R30		; BCD OUT 1'000,100
		CLR	R31		; BCD OUT 10,1

		LDI	R24,40
bin40bcd13:
	subi r31,-0x33	;add 0x33
	sbrs r31, 3	;if carry to bit 3
	subi r31, 3	;subtract 3
	sbrs r31, 7	;if carry to bit 7
	subi r31, 0x30	;subtract 0x30

	subi r30,-0x33      ; \n" /*add 0x33*/
	sbrs r30, 3         ; \n" /*if carry to bit 3,*/
	subi r30, 3         ; \n" /*subtract 3*/
	sbrs r30, 7         ; \n" /*if carry to bit 7,*/
	subi r30, 0x30      ; \n" /*subtract 0x30*/

	subi r29,-0x33       ;\n" /*add 0x33*/
	sbrs r29, 3          ;\n" /*if carry to bit 3,*/
	subi r29, 3          ;\n" /*subtract 3*/
	sbrs r29, 7          ;\n" /*if carry to bit 7,*/
	subi r29, 0x30       ;\n" /*subtract 0x30*/

	subi r28,-0x33       ;\n" /*add 0x33*/
	sbrs r28, 3          ;\n" /*if carry to bit 3,*/
	subi r28, 3          ;\n" /*subtract 3*/
	sbrs r28, 7          ;\n" /*if carry to bit 7,*/
	subi r28, 0x30       ;\n" /*subtract 0x30*/

	subi r27,-0x33       ;\n" /*add 0x33*/
	sbrs r27, 3          ;\n" /*if carry to bit 3,*/
	subi r27, 3          ;\n" /*subtract 3*/
	sbrs r27, 7          ;\n" /*if carry to bit 7,*/
	subi r27, 0x30       ;\n" /*subtract 0x30*/

	subi r26,-0x33       ;\n" /*add 0x33*/
	sbrs r26, 3          ;\n" /*if carry to bit 3,*/
	subi r26, 3          ;\n" /*subtract 3*/
	sbrs r26, 7          ;\n" /*if carry to bit 7,*/
	subi r26, 0x30       ;\n" /*subtract 0x30*/

	subi r25,-0x33       ;\n" /*add 0x33*/
	sbrs r25, 3          ;\n" /*if carry to bit 3,*/
	subi r25, 3          ;\n" /*subtract 3*/
	sbrs r25, 7          ;\n" /*if carry to bit 7,*/
	subi r25, 0x30       ;\n" /*subtract 0x30*/

	lsl r31
	rol r30
	rol r29
	rol r28		; \n" /*shift out buffer*/
	rol r27
	rol r26
	rol r25
   
	sbrc R16, 7	;skip if msbit of input =0*/
	ori  R31, 1        ;set lsb of output*/

	lsl R20
	rol R19
	rol R18
	rol R17		;shift input*/
	rol R16
   
	dec R24		;\n"
	brne bin40bcd13	;repeat for all bits*/

	RJMP	START
;************************************************
;		END


mpy8s.asm
;**********************************************************************

;3. Текст программы mpy8s умножения 8-и разрядных целых знаковых чисел 

;**********************************************************************

;***** Использование регистров

.def	mc8s    =r16;множимое
.def	mp8s    =r17;множитель
.def	m8sL   	=r17;младший байт результата
.def	m8sH   	=r18;сташий байт результата
.def	mcnt8s 	=r19;счетчик цикла

mpy8s:		sub	m8sH,m8sH	;очистить старший байт результата и перенос


		ldi	mcnt8s,8	;инициализировать счетчик цикла
m8s_1:		brcc	m8s_2		;переход, если С=0
		add	m8sH,mc8s	;прибавить множимое к старшему байту результата


m8s_2:		sbrc	mp8s,0		;если нулевой бит множителя установлен,
		sub	m8sH,mc8s	;вычесть множимое из старшего байта результата
		asr	m8sH		;сдвинуть вправо старший байт результата

		ror	m8sL		;сдвинуть вправо младший байт результата и множитель

		dec	mcnt8s		;уменьшить на 1 счетчик цикла
		brne	m8s_1		;переход, если счетчик цикла не равен 0

		ret


mpy8u_c.asm
;**********************************************************************

;1. Текст программы mpy8u_c умножения 8-и разрядных целых  беззнаковых 

;чисел, оптимизированной с точки зрения кода.

;**********************************************************************

;*****Использование регистров

.def		mc8u   =r16;множимое
.def		mp8u   =r17;множимое
.def		m8uL   =r17;младший байт результата
.def		m8uH   =r18;старший байт результата
.def		mcnt8u =r19	;счетчик цикла
			
		
mpy8u_c:	clr	m8uH 	   ;очистить старший байт результата
		ldi	mcnt8u,8   ;инициализировать счетчик цикла
		lsr	mp8u       ;cдвинуть вправо  множитель

m8u_1:		brcc m8u_2     ;переход, если С=0
		add  m8uH,mc8u ;прибавить множимое к старшему байту результата

m8u_2:		ror  m8uH      ;сдвинуть вправо старший байт результата
		ror  m8uL      ;сдвинуть вправо младший байт результата и множитель
		dec  mcnt8u    ;уменьшить на 1 счетчик цикла
		brne m8u_1     ;переход, если счетчик цикла еще не равен 0
			     
		ret


mpy8u_s.asm
;**********************************************************************

;2. Текст программы mpy8u_s умножения 8-и разрядных целых  беззнаковых 

;чисел, оптимизированной с точки зрения времени исполнения.

;**********************************************************************

;*****Использование регистров

.def		mc8u   =r16;множимое
.def		mp8u   =r17;множимое
.def		m8uL   =r17;младший байт результата
.def		m8uH   =r18;старший байт результата
.def		mcnt8u =r19	;счетчик цикла



mpy8u_s:        clr   m8uH      ;очистить  старший байт результата
 		lsr   mp8u      ;cдвинуть вправо  множитель
 		brcc  noad80    ;переход, если С=0
  		add   m8uH,mc8u ;прибавить множимое к старшему байту результата

noad80:   	ror   m8uH 	;сдвинуть вправо старший байт результата
		ror   m8uL 	;сдвинуть вправо младший байт результата и множитель
		brcc  noad81 	;переход, если С=0
		add   m8uH,mc8u ;прибавить множимое к старшему байту результата

noad81:         ror  m8uH
		ror  m8uL
		brcc noad82
		add  m8uH,mc8u


noad82:		ror  m8uH
		ror  m8uL
		brcc noad83
		add  m8uH,mc8u


noad83:		ror  m8uH
		ror  m8uL
		brcc noad84
		add  m8uH,mc8u


noad84:		ror  m8uH
		ror  m8uL
		brcc noad85
		add  m8uH,mc8u


noad85:		ror  m8uH
		ror  m8uL
		brcc noad86
		add  m8uH,mc8u


noad86:		ror  m8uH
		ror  m8uL
		brcc noad87
		add  m8uH,mc8u


noad87:		ror m8uH
		ror m8uL
		ret


MULT.ASM
; 25.03.2001
; 16.02.2009

	.INCLUDE "2313def.inc"

	.CSEG

	RESET:
		RJMP	START		; On Reset
;		.
;		.
;		.
;		.
;		.
;		.
	START:
		LDI	R31,LOW(RAMEND)
		OUT	SPL,R31

		LDS	R0,$60
		LDS	R1,$61
		LDS	R2,$62
		LDS	R3,$63
		LDS	R4,$64
		LDS	R5,$65
		LDS	R6,$66
		LDS	R7,$67
		LDS	R8,$68
		LDS	R9,$69			; Занесение делимого или множимого (опция)

		LDS	R10,$70
		LDS	R11,$71
		LDS	R12,$72
		LDS	R13,$73
		LDS	R14,$74
		LDS	R15,$75
		LDS	R16,$76
		LDS	R17,$77
		LDS	R18,$78
		LDS	R19,$79			; Занесение делителя или множителя (опция)

;		RCALL	MULT
;		RJMP	START
		

		RCALL	DIV
		RJMP	START
;************************************************
; Программа умножения 80 разрядного числа на 80 разрядное число
; Для получения корректного результата сумма разрядов множимого и множителя должна быть меньше 80 
; R0...R9-MNOGIMOE,R10...R19-MNOGITEL,R20...R29-RAB
; R0...R9-RESULT
; R20...R29-RESULT
; ZL(R30)-TEMP
;************************************************
	MULT:
 		CLT		; сбос флага ошибки, если это не было сделано при входе в программу
		LDI	ZL,80		; установить счетчик сдвигов
		
		CLR	R20
		CLR	R21
		CLR	R22
		CLR	R23
		CLR	R24
		CLR	R25
		CLR	R26
		CLR	R27
		CLR	R28
		CLR	R29		; начальное значение результата
	OBRAT:
  		LSR	R10
   		ROR	R11
 		ROR	R12
 		ROR	R13
 		ROR	R14
   		ROR	R15
 		ROR	R16
 		ROR	R17
 		ROR	R18
   		ROR	R19		; показать значение младшего разряда множителя в С,
  		BRCC	NO_SUMMIR	; С=0 пропустить суммирование
	SUMMIR:
					; С=1 суммировать значение множимого с частичным результатом
		ADD	R29,R9
		ADC	R28,R8
		ADC	R27,R7
		ADC	R26,R6
		ADC	R25,R5
		ADC	R24,R4
		ADC	R23,R3
		ADC	R22,R2
		ADC	R21,R1
		ADC	R20,R0
		BRLT	ERROR_MULT	; S-флаг установлен
		BRCS	ERROR_MULT
	NO_SUMMIR:
		LSL	R9
		ROL	R8
		ROL	R7
		ROL	R6
		ROL	R5
		ROL	R4
		ROL	R3
		ROL	R2
		ROL	R1
		ROL	R0		; множимое*2

		DEC	ZL
		BRNE	OBRAT

		MOV	R0,R20
		MOV	R1,R21
		MOV	R2,R22
		MOV	R3,R23
		MOV	R4,R24
		MOV	R5,R25
		MOV	R6,R26
		MOV	R7,R27
		MOV	R8,R28
		MOV	R9,R29
		
		RET
		
	ERROR_MULT:
		SET
		RET
;**********************************************************************
; Программа деления 78 разрядного числа на 78 разрядное число
; R0...R9-ДЕЛИМОЕ,  R10...R19-ДЕЛИТЕЛЬ!!!!R0...R9-РЕЗУЛЬТАТ
; R20...R29-РЕЗУЛЬТАТ,ZL-TEMP, ZH-ZERO
;**********************************************************************
	GDIV_ERROR:
		SET
	GDIV_OUT2:
		RET
 	DIV:
 		CLT		; сбос флага ошибки, если это небыло сделано при входе в программу
 		
		CLR	ZH	; zero-регистр

		CLR	R20
		CLR	R21
		CLR	R22
		CLR	R23
		CLR	R24
		CLR	R25
		CLR	R26
		CLR	R27
		CLR	R28
		CLR	R29	; начальное значение результата
;**********************************************************************
; проверка области допустимых значений делимого и делителя
		TST	R0
		BRMI	GDIV_ERROR	; делимое отрицательное, ERROR
		
		CP	R19,R29
		CPC	R18,R28
		CPC	R17,R27
		CPC	R16,R26
		CPC	R15,R25
		CPC	R14,R24
		CPC	R13,R23
		CPC	R12,R22
		CPC	R11,R21
		CPC	R10,R20
      		BREQ	GDIV_ERROR	; YES,DELITEL=0, ERROR

		CP	R29,R9
		CPC	R28,R8
		CPC	R27,R7
		CPC	R26,R6
		CPC	R25,R5
		CPC	R24,R4
		CPC	R23,R3
		CPC	R22,R2
		CPC	R21,R1
		CPC	R20,R0
		BREQ	GDIV_OUT2	; YES,DELIMOE=0, REZULTAT=0

		CP	R9,R19
		CPC	R8,R18
		CPC	R7,R17
		CPC	R6,R16
		CPC	R5,R15
		CPC	R4,R14
		CPC	R3,R13
		CPC	R2,R12
		CPC	R1,R11
		CPC	R0,R10
		BRPL	DIV_GO1		; NO, DELITEL<DELIMOGO
		RJMP	DIV_OUT1
	DIV_GO1:
		BRNE	DIV_GO
		RJMP	DIV_EQU		; делитель=делимому, результат=1
;***************************************************************************
; выравнивание порядков делителя с делимым
;***************************************************************************
	DIV_GO:
      		CLR	ZL		; очистить счетчик сдвигов
 	DIV1:
		CP	R19,R9
		CPC	R18,R8
		CPC	R17,R7
		CPC	R16,R6
		CPC	R15,R5
		CPC	R14,R4
		CPC	R13,R3
		CPC	R12,R2
		CPC	R11,R1
		CPC	R10,R0
      		BRCC	DIV2		; YES,DELITEL>DELIMOGO
      		
		LSL	R19
		ROL	R18
		ROL	R17
		ROL	R16
		ROL	R15
		ROL	R14
		ROL	R13
		ROL	R12
		ROL	R11
		ROL	R10		; DELITEL*2
		
		INC	ZL
		CPI	ZL,80
		BRNE	DIV1
;***************************************************************************
; порядкок делителя найден с превышением
;***************************************************************************
DIV2:
T_DIV0:
		CLT
		
		LSL	R9
		ROL	R8
		ROL	R7
		ROL	R6
		ROL	R5
		ROL	R4
		ROL	R3
		ROL	R2
		ROL	R1
		ROL	R0		; делимое или остаток*2

		CP	R19,R9
		CPC	R18,R8
		CPC	R17,R7
		CPC	R16,R6
		CPC	R15,R5
		CPC	R14,R4
		CPC	R13,R3
		CPC	R12,R2
		CPC	R11,R1
		CPC	R10,R0		; делитель больше делимого ?
		BRCS	T_DIV20		; да,оставляем в 0 сооответствующий разряд результата
		
		SET			; нет, взвести в 1 сооответствующий разряд результата
T_DIV20:
		ROL	R29
		ROL	R28
		ROL	R27
		ROL	R26
		ROL	R25
		ROL	R24
		ROL	R23
		ROL	R22
		ROL	R21
		ROL	R20
		BRTS	T_DIV40

		SUB	R9,R19
		SBC	R8,R18
		SBC	R7,R17
		SBC	R6,R16
		SBC	R5,R15
		SBC	R4,R14
		SBC	R3,R13
		SBC	R2,R12
		SBC	R1,R11
		SBC	R0,R10
T_DIV40:
		DEC	ZL
		BRNE	T_DIV0
;***************************************************************************
; проверка остатка для округления результата
DIV_OUT:
		LSL	R9
		ROL	R8
		ROL	R7
		ROL	R6
		ROL	R5
		ROL	R4
		ROL	R3
		ROL	R2
		ROL	R1
		ROL	R0		; остаток*2 или 0.ххх*2

		CP	R9,R19
		CPC	R8,R18
		CPC	R7,R17
		CPC	R6,R16
		CPC	R5,R15
		CPC	R4,R14
		CPC	R3,R13
		CPC	R2,R12
		CPC	R1,R11
		CPC	R0,R10		; делитель больше остатка или остаток >0.5 ?
		BRCS	DIV_OUT1	; нет, остаток <0.5
					; да остаток > 0.5, добавить 1
;***************************************************************************
DIV_EQU:		
		SEC
		
		ADC	R29,ZH		
		ADC	R28,ZH		
		ADC	R27,ZH		
		ADC	R26,ZH		
		ADC	R25,ZH		
		ADC	R24,ZH		
		ADC	R23,ZH		
		ADC	R22,ZH		
		ADC	R21,ZH		
		ADC	R20,ZH		
DIV_OUT1:		
		MOV	R0,R20
		MOV	R1,R21
		MOV	R2,R22
		MOV	R3,R23
		MOV	R4,R24
		MOV	R5,R25
		MOV	R6,R26
		MOV	R7,R27
		MOV	R8,R28
		MOV	R9,R29

		CLT
      		RET
;END

Комментарии (45)

RSS свернуть / развернуть
Да, это, конечно, круто, но лично я вряд ли возьмусь за ассемблер АВР, хотя если бы были комментарии, кое-что, возможно, использовал бы в пиковском ассемблере, например bin2bcd. Хотя можно и в этом разобраться при желании.
0
вряд ли возьмусь за ассемблер АВР
Логическое ударение на ассемблер или на АВР? Конечно лучше бы платформо-независимые алгоритмы, чем конкретная реализация.
0
Логическое ударение на ассемблер или на АВР?
На Авр. Ассемблер Пик16 мне даже понравился, всего 35 команд
0
Я когда начинал изучать эти чипы, начинал с асма. На самом деле там многие команды дублирующие и вообще никогда ненужны.
0
Всего 35 команд? Это же ужас как неудобно. Все приходится через задницу делать. Чем больше команд тем проще!
0
100 тоже мало, даешь 6к команд!
Меж тем MSP430 обходится 27-ю и в ус не дует.
+1
Команд или мнемоник? Тут есть нюанс… У Z80 было под 700 команд. Включая такие которые одной мнемоникой могли целый блок памяти скопировать. Это было круто! У пика же все очень и очень куцо. Даже сложения вроде бы нету.
0
По моему, таки команд. Я про x86. Если про MSP430 — у него 27 команд и 53 (или около того) мнемоники.
0
В обоих вариантов есть плюсы и минусы. Для программирования удобнее всего трехадресные системы команд с ортогональной адресацией (когда любой из операндов и результат можно достать/положить любым доступным способом адресации). Эти же наборы команд сложнее всего реализовать в железе и параллельно исполнять. И так же трудно добиться малого потребления. Малое число простых команд, отсутствие заумных методов адресации + (относительно) большой регистровый блок — другая альтернатива. Скорость и малое потребление достигаются относительно легко, малыми затратами железа, но писать становится, мягко говоря, совсем не просто. Неудобство писания на асме решается переходом на более высокоуровневые языки, а вот скорость и потребление так в лоб не решаются. Потому, вобщем, и ушли от сложных систем команд. Впрочем, можно сломать сразу все, в чем легко убедиться посмотрев на х86 — горбатая и при этом сложная система команд, неудобная ни для писания на асме ни для оптимизации ЯВУ. При этом сложная чисто аппаратно и плохо поддающаяся оптимизации под малое потребление.
0
Низнай. У меня х86 одна из любимых систем команд. А вообще самая тру была Z80 и MSC-51
0
У меня х86 одна из любимых систем команд.
Это если не знать ничего другого. За сегментную адресацию и привязку некоторых команд к регистрам (которых мало) всегда хотелось стукнуть разработчиков чем-нибудь тяжелым.
0
Ну почему же ничего другого. Я штук шесть архитектур относительно свободно знаю.

А по х86… не любишь сегменты? Протект мод и флат режим к твоим услугам :) Хотя можно и без ПМ в флэт режиме работать. У Зубкова пример был. Опять же до 64к можно было в COM прекрасно уложиться и в одном сегменте. Вот узкое регистровое горло это да, порой вымораживает. Зато самих комбинаций регистров навалом. Хоть целый, хоть побайтно, в любой комбинации. Куча разных косвенных индексаций, возможность делать паровозы из адресов и смещений. Вообще удобно было с памятью работать, в отличии от той же load-Store. А еще сопроцессор и mmx добавляют лулзов. Хотя я их особо глубоко не копал. Так пару раз для вычисления одной шняги делал, когда писал на асме курсач по МПС (там надо было сэмулировать систему управления из движка, нагрузки и двух обратных связей по моменту и оборотам с ПИД регулятором). Лохов, наш препод по МПС, жог напалмом в заданиях.
0
А по х86… не любишь сегменты?
Угу.
Протект мод и флат режим к твоим услугам :)
Да-да, на 8086 :)
Опять же до 64к можно было в COM прекрасно уложиться и в одном сегменте.
Угу. Только мало-мальски серьезное приложение работающее с достаточно большими объемами данных уложить в 64К было проблематично. Причем «серьезное» это, например, редактор текстов. Конечно, все это решаемо, но обходить грабли архитектуры вместо того, что бы решать задачу, это изврат.
Куча разных косвенных индексаций, возможность делать паровозы из адресов и смещений.
Эти все режимы в подметки не годились возможностям PDP-11 или, скажем, Motorola 68000. Замечу, М68К и i86 — одногодки, объяснить кривость x86 тем, что они, типа, первопроходцы, не получается.
0
У пика же все очень и очень куцо. Даже сложения вроде бы нету.
есть

Вообще есть расширенный набор команд, используется в пик18 и в новых сериях пик16
0
CISC vs. RISC. Тот ещё холивор.
0
Ну вот тот же AVR он вроде как RISC, но количество команд у него нифига не рисковое.
0
Вопрос не в количестве команд — у иных RISC'ов оно достигает нескольких сотен (например, старшие ARM с допмодулями вроде VFP и NEON), что больше, чем у иных CISC'ов (того же 8051). Так что если верить википедии, сегодня RISC — примерно синоним архитектуры load-and-store. И я, кстати, не уверен, является ли RISC'ом PIC.
0
PIC всегда считался RISC. Так как — restricted (reduced) instruction set computer.
0
Ну, согласно вики и его собственным даташитам — RISC, хотя и не load-and-store вроде бы (видимо, можно считать, что у него вообще нет ОЗУ — только здоровенный регистровый файл).
Но судить здесь приходится не по количеству команд (некоторые CISC'и имеют 8 команд), а по другим критериям, которые я так до конца и не понял.
0
Было бы хорошо в начале статьи добавить перечень всех функций, которые тут есть. В идеале с разбивкой по подразделам (двухуровневый список).
+3
Просто у меня в куче эти подпрограммы были, я их вывалил как есть. Некоторыми я даже никогда не пользовался. Сейчас разбираться не было времени. Но аассемблерщики разберутъся махом.
0
Так все ж эти подпрограммы расписаны и комментарии есть в самих подпрограммах. Сразу вроде видно что к чему.
0
Ну найдите функцию преобразования двоичной дроби в двоично-десятичную.

P.S.: Очевидно, что «Содержание» в книгах/документах тоже озбыточные, всё же понятно и по-русски написано, любой человек, владеющий языком, сможет найти.
0
[HolyWarMode]
Вот часто говорят, что ассемблерные программы работают быстрее, чем написанные на высокоуровневых язаках. Я вот эксперимента ради проверил приведенную здесь функцию bcdfp. Так вот, она мало того, что не работает с числами больше 10^6 и меньше 10^-6, +/-Inf и NAN, так еще и работет всреднем медленнее (~850 тактов), чем функция my_ftoa, написанная на Си (точнее С++) всреднем 759 тактов. При этом my_ftoa делает полное форматирование, используя при необходимости как обычное, так и экспоненциальное представление, работает во всём диапазоне float, корректно обрабатывает +/-Inf и NAN.
Почему более функциональная функция на Си работает быстрее, чем менее функциональная функция на ассемблере? Ведь на ассемблере есть полный доступ ко всем регистрам и коммандам процессора, недоступным из Си, к битам переноса, переполнения и другие клёвые штуки. Сишный-же компилятор сохраняет регистры в стек почем зря, делает ненужные пересылки данных, делает целочисленное расширение когда не надо и прочие нехорошие вещи.
[/HolyWarMode]
+3
Потому что там разный код(ход мысли кодера), т.е. алгоритм. Сравнивать надо одинаковые алгоритмы, но реализованные на Си и asm, при этом asm, как минимум чуть-чуть, но сделает Си, т.е. хороший кодер на asm vs компилятор.
0
Только это сейчас не нужно почти никому — памяти сейчас много, даже алгоритмы DSP пишут на Си, но при этом разворачивают циклы, и в итоге имеют время исполнения всего на 5-7% больше(что часто допустимо, т.к. частота процов тоже выросла и запас есть), чем на asm, но не имея гемороя и имея короткий понятный людям код.
0
Ну есть же мелкие Attiny у которых в основном 2к памяти. Только у некоторых моделей 4к. В этом случае если например памяти мало, а вместить надо много, то это может и пригодится. Или если человек начинает осваивать программирование чипов на асме и ему нужны математические функции, тоже могут пригодится.
0
Ну есть же мелкие Attiny у которых в основном 2к памяти.
IMHO, мое имя в этом вопросе — ARM_Strong (или ARM_& Hummer), а avr мне интересен(чисто корыстно) только как Arduino «рыба» под соусом wiring.
0
А есть у ARM DIP корпуса? Нету. Для многих радиолюбителей это большое препятствие. Думаю это одна из причин почему они не вытеснят полностью AVR в сердцах радиолюбителей.
0
Есть! Все есть: былый верх — черный низ, черный верх — былый низ, с пряжкой, лакированные, все есть! А вскоре их станет еще больше.
0
Проблема выбора avr vs arm, оставаться ли на avr:
В 1989-м году лучше быть фарсовщиком(пикейным жилетом читающем только про arm), чем ударником коммунистического труда(писать с float point на asm на avr).
0
отсутствие DIP для многих давно не препятствие т.к. SOIC или TQFP делаются любым доступным способом без особых гемороев, да и LQFP тоже. У DIP корпуса осталось всего пара достоинств: можно протащить 1-2 дороги между ногами и можно воткнуть в безпаечную макетку или панельку, что тоже нужно далеко не всегда. Ну и третье «достоинство» — можно еще под корпус воткнуть smd-мелочевку, что не даст какого-то особого выигрыша.
+1
А есть у ARM DIP корпуса? Нету.
Отчего же, вполне себе есть. Вопрос только в том, нафига они нужны, учитывая, что сделать или заказать плату сейчас не проблема. В крайнем случае покупается готовый брейкаут (ака переходник в дип). Так что это точно не причина. Если уж искать причину, то она, скорее, в неготовности многих лезть и менять програмную часть, а не железо. Впрочем, с выходом новой ардуины на арме эта ситуация быстро изменится.

Кстати, пару дней назад пришел отчет от конторы, которая занималась опросом ембеддеров. Доля новых проектов на авр неуклонно сокращается и даже если команды остаются верны атмелу, проекты делаются под их армы, а не под авр.
0
Есть и с 0,5к памяти (Аttiny4,5). Вот тут явно только асм :)
0
Даже под PIC10F200 (384 байта) можно на С писать.
0
Не, сравнивать одинаковые алгоритмы, реализованные на Си и asm не надо — исход очевиден. Я хотел сказать немного другое, когда человек пишет на ассемблере, он волей- неволей начитает начинает концентрироваться на низкоуровневых деталях, на локальных микро-оптимизациях, зачастую упуская из виду общую стратегию. Объем внимания человека сильно ограничен и без повышения уровня абстракции часто возникает ситуация «за деревьями леса не видно». Часто именно язык определяет способ решения(мышления).
+2
Недавно случайно наткнулся на интересного MCU неофита asmi, так что: Asm will live forever!
0
Но отчего-то ассемблерщики погоняют сишников вне зависимости от алгоритмов :)
0
Умножение двух 80-ти битных чисел реализовано крайне неоптимально — порядка 3000 тактов. Если запользовать алгоритм Кнута, то можно в 1000 тактов уложиться. А если алгоритм Кнута и аппаратное умножение 8 бит х 8 бит => 16 бит, то в 500.
Деление — аналогично.
0
Вот так, пришел Ржевский и всё опошлил.
Еще повредничаю. FLOAT.INC афигенно полезная штука, самописные нестандартные 3-х байтовые флоты, всего лет 10 назад были еще актуальны.
0
Программы для микропроцессоров
progbook.ru/assembler/1022-gurtovcev-programmy-dlya-mikroprocessorov.html
А. Л. Гуртовцев, С. В. Гудыменко
Издание «Программы для микропроцессоров» содержит целый комплекс типичных системных и прикладных программ для микропроцессорных систем. Здесь детально рассматриваются различные задачи арифметической обработки чисел с плавающей и фиксированной запятой, вычисления значений элементарных функций, преобразования представлений данных, обработки структур данных, а также диалога мониторного типа и обмена данными с внешними устройствами. В этой книге предоставляются методы и алгоритмы программирования этих задач. Книга предназначена для программистов, инженеров и студентов вузов.
0
Книга класс. Но для AVR там готовых алгоритмов нету.
0
легко пишутся на ассемблере AVR, практически — один к одному.
0
собственно по этой книге ( лет 7 тому как) я писал для авр меги162 пакет математики с плавающей точкой. на ассемблере(!) в нестандартном формате(!)
(спасибо, блдь, тогдашнему руководителю, блдь)
к исходу второго месяца арифмометр тикал как часы. я даже сам удивился.
исходники весили 14К = конвертер форматов и 12К = сама математика.
отличная книга.
0
По поводу программы hex40_bcd13.asm. http://radiokot.ru/forum/viewtopic.php?p=1417529#p1417529 Здесь были даны ссылки на первоисточник и автора программы. avreal, далее, несколько улучшил её.
По программам умножения/деления больших чисел. Писались мною очень давно, используют примитивный алгоритм и ни на что не претендуют. Извините.
0
  • avatar
  • akl
  • 30 мая 2013, 12:35
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.