Математика на ассемблере в 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
- +4
- 23 мая 2013, 19:32
- Papandopala
Да, это, конечно, круто, но лично я вряд ли возьмусь за ассемблер АВР, хотя если бы были комментарии, кое-что, возможно, использовал бы в пиковском ассемблере, например bin2bcd. Хотя можно и в этом разобраться при желании.
вряд ли возьмусь за ассемблер АВРЛогическое ударение на ассемблер или на АВР? Конечно лучше бы платформо-независимые алгоритмы, чем конкретная реализация.
Логическое ударение на ассемблер или на АВР?На Авр. Ассемблер Пик16 мне даже понравился, всего 35 команд
Я когда начинал изучать эти чипы, начинал с асма. На самом деле там многие команды дублирующие и вообще никогда ненужны.
- Papandopala
- 24 мая 2013, 16:16
- ↑
- ↓
Всего 35 команд? Это же ужас как неудобно. Все приходится через задницу делать. Чем больше команд тем проще!
Команд или мнемоник? Тут есть нюанс… У Z80 было под 700 команд. Включая такие которые одной мнемоникой могли целый блок памяти скопировать. Это было круто! У пика же все очень и очень куцо. Даже сложения вроде бы нету.
В обоих вариантов есть плюсы и минусы. Для программирования удобнее всего трехадресные системы команд с ортогональной адресацией (когда любой из операндов и результат можно достать/положить любым доступным способом адресации). Эти же наборы команд сложнее всего реализовать в железе и параллельно исполнять. И так же трудно добиться малого потребления. Малое число простых команд, отсутствие заумных методов адресации + (относительно) большой регистровый блок — другая альтернатива. Скорость и малое потребление достигаются относительно легко, малыми затратами железа, но писать становится, мягко говоря, совсем не просто. Неудобство писания на асме решается переходом на более высокоуровневые языки, а вот скорость и потребление так в лоб не решаются. Потому, вобщем, и ушли от сложных систем команд. Впрочем, можно сломать сразу все, в чем легко убедиться посмотрев на х86 — горбатая и при этом сложная система команд, неудобная ни для писания на асме ни для оптимизации ЯВУ. При этом сложная чисто аппаратно и плохо поддающаяся оптимизации под малое потребление.
Ну почему же ничего другого. Я штук шесть архитектур относительно свободно знаю.
А по х86… не любишь сегменты? Протект мод и флат режим к твоим услугам :) Хотя можно и без ПМ в флэт режиме работать. У Зубкова пример был. Опять же до 64к можно было в COM прекрасно уложиться и в одном сегменте. Вот узкое регистровое горло это да, порой вымораживает. Зато самих комбинаций регистров навалом. Хоть целый, хоть побайтно, в любой комбинации. Куча разных косвенных индексаций, возможность делать паровозы из адресов и смещений. Вообще удобно было с памятью работать, в отличии от той же load-Store. А еще сопроцессор и mmx добавляют лулзов. Хотя я их особо глубоко не копал. Так пару раз для вычисления одной шняги делал, когда писал на асме курсач по МПС (там надо было сэмулировать систему управления из движка, нагрузки и двух обратных связей по моменту и оборотам с ПИД регулятором). Лохов, наш препод по МПС, жог напалмом в заданиях.
А по х86… не любишь сегменты? Протект мод и флат режим к твоим услугам :) Хотя можно и без ПМ в флэт режиме работать. У Зубкова пример был. Опять же до 64к можно было в COM прекрасно уложиться и в одном сегменте. Вот узкое регистровое горло это да, порой вымораживает. Зато самих комбинаций регистров навалом. Хоть целый, хоть побайтно, в любой комбинации. Куча разных косвенных индексаций, возможность делать паровозы из адресов и смещений. Вообще удобно было с памятью работать, в отличии от той же load-Store. А еще сопроцессор и mmx добавляют лулзов. Хотя я их особо глубоко не копал. Так пару раз для вычисления одной шняги делал, когда писал на асме курсач по МПС (там надо было сэмулировать систему управления из движка, нагрузки и двух обратных связей по моменту и оборотам с ПИД регулятором). Лохов, наш препод по МПС, жог напалмом в заданиях.
А по х86… не любишь сегменты?Угу.
Протект мод и флат режим к твоим услугам :)Да-да, на 8086 :)
Опять же до 64к можно было в COM прекрасно уложиться и в одном сегменте.Угу. Только мало-мальски серьезное приложение работающее с достаточно большими объемами данных уложить в 64К было проблематично. Причем «серьезное» это, например, редактор текстов. Конечно, все это решаемо, но обходить грабли архитектуры вместо того, что бы решать задачу, это изврат.
Куча разных косвенных индексаций, возможность делать паровозы из адресов и смещений.Эти все режимы в подметки не годились возможностям PDP-11 или, скажем, Motorola 68000. Замечу, М68К и i86 — одногодки, объяснить кривость x86 тем, что они, типа, первопроходцы, не получается.
Вопрос не в количестве команд — у иных RISC'ов оно достигает нескольких сотен (например, старшие ARM с допмодулями вроде VFP и NEON), что больше, чем у иных CISC'ов (того же 8051). Так что если верить википедии, сегодня RISC — примерно синоним архитектуры load-and-store. И я, кстати, не уверен, является ли RISC'ом PIC.
Ну, согласно вики и его собственным даташитам — RISC, хотя и не load-and-store вроде бы (видимо, можно считать, что у него вообще нет ОЗУ — только здоровенный регистровый файл).
Но судить здесь приходится не по количеству команд (некоторые CISC'и имеют 8 команд), а по другим критериям, которые я так до конца и не понял.
Но судить здесь приходится не по количеству команд (некоторые CISC'и имеют 8 команд), а по другим критериям, которые я так до конца и не понял.
Было бы хорошо в начале статьи добавить перечень всех функций, которые тут есть. В идеале с разбивкой по подразделам (двухуровневый список).
Просто у меня в куче эти подпрограммы были, я их вывалил как есть. Некоторыми я даже никогда не пользовался. Сейчас разбираться не было времени. Но аассемблерщики разберутъся махом.
- Papandopala
- 24 мая 2013, 11:09
- ↑
- ↓
Так все ж эти подпрограммы расписаны и комментарии есть в самих подпрограммах. Сразу вроде видно что к чему.
- Papandopala
- 24 мая 2013, 11:13
- ↑
- ↓
[HolyWarMode]
Вот часто говорят, что ассемблерные программы работают быстрее, чем написанные на высокоуровневых язаках. Я вот эксперимента ради проверил приведенную здесь функцию bcdfp. Так вот, она мало того, что не работает с числами больше 10^6 и меньше 10^-6, +/-Inf и NAN, так еще и работет всреднем медленнее (~850 тактов), чем функция my_ftoa, написанная на Си (точнее С++) всреднем 759 тактов. При этом my_ftoa делает полное форматирование, используя при необходимости как обычное, так и экспоненциальное представление, работает во всём диапазоне float, корректно обрабатывает +/-Inf и NAN.
Почему более функциональная функция на Си работает быстрее, чем менее функциональная функция на ассемблере? Ведь на ассемблере есть полный доступ ко всем регистрам и коммандам процессора, недоступным из Си, к битам переноса, переполнения и другие клёвые штуки. Сишный-же компилятор сохраняет регистры в стек почем зря, делает ненужные пересылки данных, делает целочисленное расширение когда не надо и прочие нехорошие вещи.
[/HolyWarMode]
Вот часто говорят, что ассемблерные программы работают быстрее, чем написанные на высокоуровневых язаках. Я вот эксперимента ради проверил приведенную здесь функцию bcdfp. Так вот, она мало того, что не работает с числами больше 10^6 и меньше 10^-6, +/-Inf и NAN, так еще и работет всреднем медленнее (~850 тактов), чем функция my_ftoa, написанная на Си (точнее С++) всреднем 759 тактов. При этом my_ftoa делает полное форматирование, используя при необходимости как обычное, так и экспоненциальное представление, работает во всём диапазоне float, корректно обрабатывает +/-Inf и NAN.
Почему более функциональная функция на Си работает быстрее, чем менее функциональная функция на ассемблере? Ведь на ассемблере есть полный доступ ко всем регистрам и коммандам процессора, недоступным из Си, к битам переноса, переполнения и другие клёвые штуки. Сишный-же компилятор сохраняет регистры в стек почем зря, делает ненужные пересылки данных, делает целочисленное расширение когда не надо и прочие нехорошие вещи.
[/HolyWarMode]
Потому что там разный код(ход мысли кодера), т.е. алгоритм. Сравнивать надо одинаковые алгоритмы, но реализованные на Си и asm, при этом asm, как минимум чуть-чуть, но сделает Си, т.е. хороший кодер на asm vs компилятор.
- well-man2000
- 24 мая 2013, 15:52
- ↑
- ↓
Только это сейчас не нужно почти никому — памяти сейчас много, даже алгоритмы DSP пишут на Си, но при этом разворачивают циклы, и в итоге имеют время исполнения всего на 5-7% больше(что часто допустимо, т.к. частота процов тоже выросла и запас есть), чем на asm, но не имея гемороя и имея короткий понятный людям код.
- well-man2000
- 24 мая 2013, 16:00
- ↑
- ↓
Ну есть же мелкие Attiny у которых в основном 2к памяти. Только у некоторых моделей 4к. В этом случае если например памяти мало, а вместить надо много, то это может и пригодится. Или если человек начинает осваивать программирование чипов на асме и ему нужны математические функции, тоже могут пригодится.
- Papandopala
- 24 мая 2013, 16:13
- ↑
- ↓
Ну есть же мелкие Attiny у которых в основном 2к памяти.IMHO, мое имя в этом вопросе — ARM_Strong (или ARM_& Hummer), а avr мне интересен(чисто корыстно) только как Arduino «рыба» под соусом wiring.
- well-man2000
- 24 мая 2013, 16:47
- ↑
- ↓
А есть у ARM DIP корпуса? Нету. Для многих радиолюбителей это большое препятствие. Думаю это одна из причин почему они не вытеснят полностью AVR в сердцах радиолюбителей.
- Papandopala
- 24 мая 2013, 17:06
- ↑
- ↓
Есть! Все есть: былый верх — черный низ, черный верх — былый низ, с пряжкой, лакированные, все есть! А вскоре их станет еще больше.
- well-man2000
- 24 мая 2013, 17:09
- ↑
- ↓
Проблема выбора avr vs arm, оставаться ли на avr:
В 1989-м году лучше быть фарсовщиком(пикейным жилетом читающем только про arm), чем ударником коммунистического труда(писать с float point на asm на avr).
В 1989-м году лучше быть фарсовщиком(пикейным жилетом читающем только про arm), чем ударником коммунистического труда(писать с float point на asm на avr).
- well-man2000
- 24 мая 2013, 17:29
- ↑
- ↓
отсутствие DIP для многих давно не препятствие т.к. SOIC или TQFP делаются любым доступным способом без особых гемороев, да и LQFP тоже. У DIP корпуса осталось всего пара достоинств: можно протащить 1-2 дороги между ногами и можно воткнуть в безпаечную макетку или панельку, что тоже нужно далеко не всегда. Ну и третье «достоинство» — можно еще под корпус воткнуть smd-мелочевку, что не даст какого-то особого выигрыша.
А есть у ARM DIP корпуса? Нету.Отчего же, вполне себе есть. Вопрос только в том, нафига они нужны, учитывая, что сделать или заказать плату сейчас не проблема. В крайнем случае покупается готовый брейкаут (ака переходник в дип). Так что это точно не причина. Если уж искать причину, то она, скорее, в неготовности многих лезть и менять програмную часть, а не железо. Впрочем, с выходом новой ардуины на арме эта ситуация быстро изменится.
Кстати, пару дней назад пришел отчет от конторы, которая занималась опросом ембеддеров. Доля новых проектов на авр неуклонно сокращается и даже если команды остаются верны атмелу, проекты делаются под их армы, а не под авр.
Не, сравнивать одинаковые алгоритмы, реализованные на Си и asm не надо — исход очевиден. Я хотел сказать немного другое, когда человек пишет на ассемблере, он волей- неволей начитает начинает концентрироваться на низкоуровневых деталях, на локальных микро-оптимизациях, зачастую упуская из виду общую стратегию. Объем внимания человека сильно ограничен и без повышения уровня абстракции часто возникает ситуация «за деревьями леса не видно». Часто именно язык определяет способ решения(мышления).
Недавно случайно наткнулся на интересного MCU неофита asmi, так что: Asm will live forever!
- well-man2000
- 24 мая 2013, 17:01
- ↑
- ↓
Программы для микропроцессоров
progbook.ru/assembler/1022-gurtovcev-programmy-dlya-mikroprocessorov.html
А. Л. Гуртовцев, С. В. Гудыменко
Издание «Программы для микропроцессоров» содержит целый комплекс типичных системных и прикладных программ для микропроцессорных систем. Здесь детально рассматриваются различные задачи арифметической обработки чисел с плавающей и фиксированной запятой, вычисления значений элементарных функций, преобразования представлений данных, обработки структур данных, а также диалога мониторного типа и обмена данными с внешними устройствами. В этой книге предоставляются методы и алгоритмы программирования этих задач. Книга предназначена для программистов, инженеров и студентов вузов.
progbook.ru/assembler/1022-gurtovcev-programmy-dlya-mikroprocessorov.html
А. Л. Гуртовцев, С. В. Гудыменко
Издание «Программы для микропроцессоров» содержит целый комплекс типичных системных и прикладных программ для микропроцессорных систем. Здесь детально рассматриваются различные задачи арифметической обработки чисел с плавающей и фиксированной запятой, вычисления значений элементарных функций, преобразования представлений данных, обработки структур данных, а также диалога мониторного типа и обмена данными с внешними устройствами. В этой книге предоставляются методы и алгоритмы программирования этих задач. Книга предназначена для программистов, инженеров и студентов вузов.
собственно по этой книге ( лет 7 тому как) я писал для авр меги162 пакет математики с плавающей точкой. на ассемблере(!) в нестандартном формате(!)
(спасибо, блдь, тогдашнему руководителю, блдь)
к исходу второго месяца арифмометр тикал как часы. я даже сам удивился.
исходники весили 14К = конвертер форматов и 12К = сама математика.
отличная книга.
(спасибо, блдь, тогдашнему руководителю, блдь)
к исходу второго месяца арифмометр тикал как часы. я даже сам удивился.
исходники весили 14К = конвертер форматов и 12К = сама математика.
отличная книга.
По поводу программы hex40_bcd13.asm. http://radiokot.ru/forum/viewtopic.php?p=1417529#p1417529 Здесь были даны ссылки на первоисточник и автора программы. avreal, далее, несколько улучшил её.
По программам умножения/деления больших чисел. Писались мною очень давно, используют примитивный алгоритм и ни на что не претендуют. Извините.
По программам умножения/деления больших чисел. Писались мною очень давно, используют примитивный алгоритм и ни на что не претендуют. Извините.
Комментарии (45)
RSS свернуть / развернуть