Пн июн 24, 2019 12:47:12
;----------;
; Universal decimal string conversion (8/16 bit unsigned)
;
; Register Variables:
; Call: var1:0 = 16 bit value to be converted
; len = String length
; tmp1:0 = <Don't care> (high register must be assigned)
; tmp2 = <Don't care>
;
; Result: var1:0 = <Unknown>
; len = <Not changed>
; tmp1:0 = <Unknown>
; tmp2 = 0
;
; Size: 30 words
; Clock: depends on output routine
; Stack: 10 bytes max (+output routine)
;
; Examples: var1 len output
; 100 0 "100"
; 1234 0 "1234"
; 0 7 " 0"
; 100 5 " 100"
; 100 2 "100"
mk_decu8: clr var1 ;8 bit entry
mk_decu16: ;16 bit entry
clr tmp2 ;digit counter
inc tmp2 ;---- decimal string generating loop
clr tmp0 ;var1 /= 10;
ldi tmp1,16 ;
lsl var0 ;
rol var1 ;
rol tmp0 ;
cpi tmp0,10 ;
brcs PC+3 ;
subi tmp0,10 ;
inc var0 ;
dec tmp1 ;
brne PC-8 ;/
subi tmp0,-'0' ;Push the remander (a decimal digit)
push tmp0 ;/
cp var0,tmp1 ;if(var =! 0)
cpc var1,tmp1 ; continue digit loop;
brne PC-16 ;/
cp tmp2,len ;Adjust string length (this can be removed for auto-length)
brcc PC+5 ;
inc tmp2 ;
ldi var0,' ' ;
push var0 ;
rjmp PC-5 ;/
pop var0 ;Put decimal string
rcall xmit ;<-- Put a char (var0) to memory, console or any display device
dec tmp2 ;
brne PC-3 ;/
ret
Пн июн 24, 2019 13:08:13
Вт июн 25, 2019 06:57:35
;==============
.def val1 = r16
.def val2 = r17
.def tmp1 = r18
.def tmp2 = r19
.def cntr = r20
;==============
; Процедура преобразует двухбайтную величину в строку цифр
; и сохраняет её в памяти
; Время выполнения 217 тактов
; Размер 84 слова (168 байт) включая таблицу
ldi val1, 0x5F ; Преобразуемая
ldi val2, 0xEA ; в десятичный вид величина
ldi YH, 0x00 ; Адрес в ОЗУ
ldi YL, 0x60 ; для сохранения результата
ldi ZH, HIGH(2 * t10div) ; Таблица разложения чисел 0..99
ldi tmp1, 0x00 ; 2^6 * 10^3
ldi tmp2, 0xFA
rcall subroutine ; Первая и вторая цифры
ldi tmp1, 0x80 ; 2^6 * 10^1
ldi tmp2, 0x02
rcall subroutine ; Третья и четвёртая цифры
st Y+, val1 ; Пятая цифра
; Конец процедуры
;==============
; Подпрограмма выделяет очередную пару десятичных цифр числа и сохраняет их в памяти
; Технически процедура осуществляет деление с остатком, где частное является числом
; из диапазона 0..99, которое разделяется на две цифры с помощью таблицы
; Время выполнения 103 тактов включая вызов
subroutine: ldi cntr, 0x07 ; Счётчик битов выделяемой сотни
clr ZL ; Подготовка выделяемой сотни
subroutine_1: lsl ZL ; Удвоение выделяемой сотни
sub val1, tmp1 ; Вычитание из делимого
sbc val2, tmp2 ; величины текущего бита результата
brcs subroutine_2 ; Если был перенос -- значение бита 0
inc ZL ; Инкремент выделяемой сотни если бит равен 1
rjmp subroutine_3
subroutine_2: add val1, tmp1 ; Восстановление
adc val2, tmp2 ; делимого
subroutine_3: lsr tmp2 ; Величина
ror tmp1 ; следующего бита результата
dec cntr ; Повтор
brne subroutine_1 ; для всех битов
subroutine_4: lpm tmp1, Z ; Разложение
mov tmp2, tmp1 ; выделенной
swap tmp1 ; сотни на две
andi tmp1, 0x0F ; десятичные цифры
andi tmp2, 0x0F ; с помощью таблицы
st Y+, tmp1 ; Сохранение
st Y+, tmp2 ; результата в памяти
ret
;==============
; Таблица преобразования величин диапазона 0..99 в десятичные цифры
.org 0x0300
t10div: .dw 0x0100,0x0302,0x0504,0x0706,0x0908,0x1110,0x1312,0x1514,0x1716,0x1918
.dw 0x2120,0x2322,0x2524,0x2726,0x2928,0x3130,0x3332,0x3534,0x3736,0x3938
.dw 0x4140,0x4342,0x4544,0x4746,0x4948,0x5150,0x5352,0x5554,0x5756,0x5958
.dw 0x6160,0x6362,0x6564,0x6766,0x6968,0x7170,0x7372,0x7574,0x7776,0x7978
.dw 0x8180,0x8382,0x8584,0x8786,0x8988,0x9190,0x9392,0x9594,0x9796,0x9998
;==============
;==============
.def val1 = r16
.def val2 = r17
.def tmp1 = r18
.def tmp2 = r19
.def tmp3 = r20
.def sbtr = r21
;==============
; Процедура преобразует двухбайтную величину в строку цифр
; и сохраняет её в памяти
; Время выполнения 78 + 6 * {сумма цифр, кроме последней} тактов
; Размер 27 слов (54 байта)
ldi val1, 0x5F ; Преобразуемая
ldi val2, 0xEA ; в десятичный вид величина
ldi YH, 0x00 ; Адрес в ОЗУ
ldi YL, 0x60 ; для сохранения результата
ldi tmp1, 0x10 ; 10^4
ldi tmp2, 0x27
rcall subroutine ; Первая цифра
ldi tmp1, 0xE8 ; 10^3
ldi tmp2, 0x03
rcall subroutine ; Вторая цифра
ldi tmp1, 0x64 ; 10^2
ldi tmp2, 0x00
rcall subroutine ; Третья цифра
ldi tmp1, 0x0A ; 10^1
ldi tmp2, 0x00
rcall subroutine ; Четвёртая цифра
st Y+, val1 ; Пятая цифра
; Конец процедуры
;==============
; Подпрограмма выделяет очередную цифру десятичного числа и сохраняет её в памяти
; Время выполнения 16 + 6 * {выделяемая цифра} тактов включая вызов
subroutine: clr tmp3 ; Подготовка выделяемой цифры
subroutine_1: sub val1, tmp1 ; Вычитание позиционного значения
sbc val2, tmp2 ; выделяемой цифры
brcs subroutine_2 ; Окончание цикла, если перенос вычитания
inc tmp3 ; Инкремент выделяемой цифры
rjmp subroutine_1 ; Повтор цикла вычитания
subroutine_2: add val1, tmp1 ; Коррекция остатка
adc val2, tmp2 ; после лишнего вычитания
st Y+, tmp3 ; Сохранение результата в памяти
ret
;==============
Вт июн 25, 2019 07:44:38
Вт июн 25, 2019 08:23:43
;==============
.def val1 = r16
.def val2 = r17
.def cntr = r18
.def tmp1 = r19
.def tmp2 = r20
.def tmp3 = r21
;==============
; Процедура преобразует двухбайтную величину в строку цифр
; методом Double Dabble и сохраняет её в памяти
; Время выполнения 313 тактов
; Размер 38 слов (76 байт)
ldi val1, 0x5F ; Преобразуемая
ldi val2, 0xEA ; в десятичный вид величина
ldi cntr, 0x10 ; Счётчик числа битов исходной величины
ldi YH, 0x00 ; Адрес в ОЗУ
ldi YL, 0x60 ; для сохранения результата
clr tmp1 ; Инициализация
clr tmp2 ; регистров для хранения
clr tmp3 ; выделяемых цифр
loop: ; Разряды 0 и 1
subi tmp1, 0xCD ; Прибавление значения 3 к каждому
sbrs tmp1, 3 ; полубайту промежуточных величин
subi tmp1, 0x03 ; если их значение больше 4 для
sbrs tmp1, 7 ; правильного осуществления переноса
subi tmp1, 0x30 ; цифр 5+ в следующую ячейку
; Разряды 2 и 3
subi tmp2, 0xCD
sbrs tmp2, 3
subi tmp2, 0x03
sbrs tmp2, 7
subi tmp2, 0x30
; Последний 5-й разряд коррекции не требует
lsl val1 ; Перенос битов исходной величины
rol val2 ; в регистры промежуточных результатов
rol tmp1 ; Побитовый
rol tmp2 ; сдвиг
rol tmp3 ; промежуточных результатов
dec cntr ; Повтор для всех
brne loop ; оставшихся битов
st Y+, tmp3 ; Сохранение 1-й цифры
mov tmp3, tmp2 ; Разделение
swap tmp3 ; второй
andi tmp2, 0x0F ; и третьей
andi tmp3, 0x0F ; цифр
st Y+, tmp3 ; Сохранение 2-й цифры
st Y+, tmp2 ; Сохранение 3-й цифры
mov tmp3, tmp1 ; Разделение
swap tmp3 ; четвёртой
andi tmp1, 0x0F ; и пятой
andi tmp3, 0x0F ; цифр
st Y+, tmp3 ; Сохранение 4-й цифры
st Y+, tmp1 ; Сохранение 5-й цифры
; Конец процедуры
;==============
Вт июн 25, 2019 10:18:08
Вт июн 25, 2019 11:07:38
в общем, это правильно.B@R5uk писал(а): Мне больше интересен баланс между размером и быстродействием.
а зачем так часто?B@R5uk писал(а):Так что к процедуре, которая вызывается раз в 20-40 мс, нет смысла предъявлять жёсткие требования по быстродействию.
Вт июн 25, 2019 11:33:46
;==============
.def dig3 = r16
.def dig2 = r17
.def dig1 = r18
;==============
; Процедура преобразует байт
; в строку цифр методом Double Dabble
; Время выполнения 44 такта
; Размер 44 слова (88 байт)
ldi dig3, 0xFF ; Преобразуемая в десятичный вид величина
clr dig2 ; Инициализация регистров
clr dig1 ; для хранения выделяемых цифр
; 1
lsl dig3 ; Первые два сдвига не требуют коррекции
rol dig2
; 2
lsl dig3
rol dig2
; 3
lsl dig3 ; Коррекция только младшего полубайта
rol dig2 ; для 3-го, 4-го и 5-го сдвигов
subi dig2, 0xFD
sbrs dig2, 3
subi dig2, 0x03
; 4
lsl dig3
rol dig2
subi dig2, 0xFD
sbrs dig2, 3
subi dig2, 0x03
; 5
lsl dig3
rol dig2
subi dig2, 0xFD
sbrs dig2, 3
subi dig2, 0x03
; 6
lsl dig3 ; 6-й и 7-й сдвиги требуют полной коррекции
rol dig2 ; байта с единицами и десятками
subi dig2, 0xCD
sbrs dig2, 3
subi dig2, 0x03
sbrs dig2, 7
subi dig2, 0x30
; 7
lsl dig3 ; 7-й и 8-й сдвиги задействуют старшую
rol dig2 ; цифру, которая не требует коррекции
rol dig1
subi dig2, 0xCD
sbrs dig2, 3
subi dig2, 0x03
sbrs dig2, 7
subi dig2, 0x30
; 8
lsl dig3
rol dig2
rol dig1
; =
mov dig3, dig2 ; Разделение 2-й и 3-й цифр результата
swap dig2
andi dig2, 0x0F
andi dig3, 0x0F
; Конец процедуры
;==============
Вт июн 25, 2019 13:32:59
Вт июн 25, 2019 14:44:59
Вт июн 25, 2019 16:18:16
Вт июн 25, 2019 17:17:57
Пт июн 28, 2019 15:17:32
;==============
.def val1 = r16
.def val2 = r17
.def val3 = r18
.def cntr = r19
.def tmp1 = r20
.def tmp2 = r21
.def tmp3 = r22
.def tmp4 = r24
;==============
; Процедура преобразует трёхбайтную величину в строку цифр
; методом Double Dabble и сохраняет её в памяти
; Время выполнения 713 тактов
; Размер 61 слов (122 байта)
ldi val1, 0xFF ; Величина,
ldi val2, 0x23 ; преобразуемая
ldi val3, 0xF4 ; в десятичный вид
ldi cntr, 0x18 ; Счётчик числа битов исходной величины
ldi YH, 0x00 ; Адрес в ОЗУ
ldi YL, 0x60 ; для сохранения результата
clr tmp1 ; Инициализация
clr tmp2 ; регистров
clr tmp3 ; для хранения
clr tmp4 ; выделяемых цифр
loop: ; Разряды 0 и 1
subi tmp1, 0xCD ; Прибавление значения 3 к каждому
sbrs tmp1, 3 ; полубайту промежуточных величин
subi tmp1, 0x03 ; если их значение больше 4 для
sbrs tmp1, 7 ; правильного осуществления переноса
subi tmp1, 0x30 ; цифр 5+ в следующую ячейку
; Разряды 2 и 3
subi tmp2, 0xCD
sbrs tmp2, 3
subi tmp2, 0x03
sbrs tmp2, 7
subi tmp2, 0x30
; Разряды 4 и 5
subi tmp3, 0xCD
sbrs tmp3, 3
subi tmp3, 0x03
sbrs tmp3, 7
subi tmp3, 0x30
; Разряд 6, 7-ой разряд коррекции не требует
subi tmp4, 0xFD
sbrs tmp4, 3
subi tmp4, 0x03
; =
lsl val1 ; Перенос битов исходной
rol val2 ; величины в регистры
rol val3 ; промежуточных результатов
rol tmp1 ; Побитовый
rol tmp2 ; сдвиг
rol tmp3 ; промежуточных
rol tmp4 ; результатов
dec cntr ; Повтор для всех
brne loop ; оставшихся битов
; =
mov val1, tmp4 ; Разделение
swap val1 ; 1-й и
andi val1, 0x0F ; 2-й
andi tmp4, 0x0F ; цифр
st Y+, val1 ; Сохранение 1-й цифры
st Y+, tmp4 ; Сохранение 2-й цифры
; =
mov val1, tmp3 ; Разделение
swap val1 ; 3-й и
andi val1, 0x0F ; 4-й
andi tmp3, 0x0F ; цифр
st Y+, val1 ; Сохранение 3-й цифры
st Y+, tmp3 ; Сохранение 4-й цифры
; =
mov val1, tmp2 ; Разделение
swap val1 ; 5-й и
andi val1, 0x0F ; 6-й
andi tmp2, 0x0F ; цифр
st Y+, val1 ; Сохранение 5-й цифры
st Y+, tmp2 ; Сохранение 6-й цифры
; =
mov val1, tmp1 ; Разделение
swap val1 ; 7-й и
andi val1, 0x0F ; 8-й
andi tmp1, 0x0F ; цифр
st Y+, val1 ; Сохранение 7-й цифры
st Y+, tmp1 ; Сохранение 8-й цифры
; Конец процедуры
;==============
;==============
.def val1 = r16
.def val2 = r17
.def val3 = r18
.def cntr = r19
.def quo1 = r20
.def quo2 = r21
.def tmp1 = r22
.def tmp2 = r23
.def tmp3 = r24
;==============
; Процедура преобразует трёхбайтную величину в строку цифр
; и сохраняет её в памяти. Для этого исходная величина делится
; с остатком на 10000, затем частное и остаток в свою очередь
; делятся с остатком на 100 и полученные сотни раскладываются
; с помощью таблицы на цифры, их составляющие.
; Время выполнения 423 такта
; Размер 115 слов (230 байт) включая таблицу
ldi val1, 0xFF ; Величина
ldi val2, 0x23 ; преобразуемая
ldi val3, 0xF4 ; в десятичный вид
ldi YH, 0x00 ; Адрес в ОЗУ
ldi YL, 0x60 ; для сохранения результата
ldi ZH, HIGH(2 * t10div) ; Таблица разложения чисел 0..99
; =
ldi cntr, 0x0B ; Счётчик битов частного
clr quo1 ; Обнуление
clr quo2 ; частного
ldi tmp1, 0x00 ; Делитель 10000,
ldi tmp2, 0x40 ; умноженный
ldi tmp3, 0x9C ; на 2^10
loop: lsl quo1 ; Удвоение
rol quo2 ; частного
sub val1, tmp1 ; Вычитание из делимого
sbc val2, tmp2 ; величины текущего
sbc val3, tmp3 ; бита частного
brcs branch_1 ; Если был перенос -- значение бита 0
inc quo1 ; Инкремент частного, если бит равен 1
nop
rjmp branch_2
branch_1: add val1, tmp1 ; Восстановление
adc val2, tmp2 ; делимого
adc val3, tmp3
branch_2: lsr tmp3 ; Величина
ror tmp2 ; следующего
ror tmp1 ; бита частного
dec cntr ; Повтор
brne loop ; для всех битов
; =
rcall subroutine ; Выделение и сохранение первой четвёрки цифр
mov quo1, val1 ; Копирование остатка от деления
mov quo2, val2 ; на 10000 для преобразования в цифры
rcall subroutine ; Выделение и сохранение второй четвёрки цифр
; Конец процедуры
;==============
; Подпрограмма преобразует число из диапазона 0..9999 в строку цифр и сохраняет её
; в памяти. Технически это осуществляется делением входных данных с остатком
; на 100 и последующим табличным разложением частного и остатка на искомые цифры.
subroutine: ldi cntr, 0x07 ; Счётчик битов частного
clr ZL ; Обнуление частного
ldi tmp1, 0x00 ; Делитель 100,
ldi tmp2, 0x19 ; умноженный на 2^6
subroutine_1: lsl ZL ; Удвоение частного
sub quo1, tmp1 ; Вычитание из делимого
sbc quo2, tmp2 ; величины текущего бита частного
brcs subroutine_2 ; Если был перенос -- значение бита 0
inc ZL ; Инкремент частного, если бит равен 1
rjmp subroutine_3
subroutine_2: add quo1, tmp1 ; Восстановление
adc quo2, tmp2 ; делимого
subroutine_3: lsr tmp2 ; Величина
ror tmp1 ; следующего бита частного
dec cntr ; Повтор
brne subroutine_1 ; для всех битов
lpm tmp1, Z ; Разложение
mov tmp2, tmp1 ; найденного
swap tmp1 ; частного на
andi tmp1, 0x0F ; десятичные цифры
andi tmp2, 0x0F ; с помощью таблицы
st Y+, tmp1 ; Сохранение
st Y+, tmp2 ; результата в памяти
mov ZL, quo1 ; Копирование остатка в индексный регистр
lpm tmp1, Z ; Разложение
mov tmp2, tmp1 ; полученного
swap tmp1 ; от деления остатка
andi tmp1, 0x0F ; на десятичные цифры
andi tmp2, 0x0F ; с помощью таблицы
st Y+, tmp1 ; Сохранение
st Y+, tmp2 ; результата в памяти
ret
;==============
; Таблица преобразования величин диапазона 0..99 в десятичные цифры
.org 0x0300
t10div: .dw 0x0100,0x0302,0x0504,0x0706,0x0908,0x1110,0x1312,0x1514,0x1716,0x1918
.dw 0x2120,0x2322,0x2524,0x2726,0x2928,0x3130,0x3332,0x3534,0x3736,0x3938
.dw 0x4140,0x4342,0x4544,0x4746,0x4948,0x5150,0x5352,0x5554,0x5756,0x5958
.dw 0x6160,0x6362,0x6564,0x6766,0x6968,0x7170,0x7372,0x7574,0x7776,0x7978
.dw 0x8180,0x8382,0x8584,0x8786,0x8988,0x9190,0x9392,0x9594,0x9796,0x9998
;==============
;==============
.def val1 = r16
.def val2 = r17
.def val3 = r18
.def dig = r19
.def tmp1 = r20
.def tmp2 = r21
.def tmp3 = r22
;==============
; Процедура преобразует трёхбайтную величину в строку цифр
; и сохраняет её в памяти. Для этого исходная величина с помощью
; циклов вычитаний делится с остатком на последовательные степени
; десяток в убывающем порядке, взятые из таблицы в ПЗУ.
; Время выполнения 169 + 7 * {сумма цифр, кроме последней} такта.
; Лучше время 169 тактов, худшее -- 547 тактов
; Размер 35 слов (70 байт) включая таблицу
ldi val1, 0x76 ; Величина,
ldi val2, 0x96 ; преобразуемая
ldi val3, 0x98 ; в десятичный вид
ldi YH, 0x00 ; Адрес в ОЗУ
ldi YL, 0x60 ; для сохранения результата
ldi ZH, HIGH(2 * pow10t) ; Таблица степеней десяток
ldi ZL, LOW(2 * pow10t)
loop_1: lpm tmp1, Z+ ; Загрузка
lpm tmp2, Z+ ; из ПЗУ очередной
lpm tmp3, Z+ ; степени десятки
clr dig ; Очистка счётчика вычитаний
loop_2: sub val1, tmp1 ; Вычитание
sbc val2, tmp2 ; из преобразуемой величины
sbc val3, tmp3 ; текущей степени десяток
brcs branch ; Наличие переноса -- окончание счёта
inc dig ; Инкремент счётчика вычитаний
rjmp loop_2 ; Повтор вычитания
branch: add val1, tmp1 ; Коррекция
adc val2, tmp2 ; лишнего
adc val3, tmp3 ; вычитания
st Y+, dig ; Сохранение найденной цифры в ОЗУ
cpi tmp1, 0x0A ; Повтор цикла, пока остатком
brne loop_1 ; не станут единицы
st Y+, val1 ; Сохранение последней цифры
; Конец процедуры
;==============
; Таблица степеней десяток начиная с 10^7 в убывающем порядке
pow10t: .dw 0x9680, 0x4098, 0x0F42, 0x86A0, 0x1001, 0x0027, 0x03E8, 0x6400
.dw 0x0000, 0x000A, 0x0000
;==============
Пт июн 28, 2019 17:26:15
mov.w R4, &BIN2BCD
mov.w &BIN2BCD, R5
Пт июн 28, 2019 18:33:06
Сб июн 29, 2019 04:43:14
Сб июн 29, 2019 05:30:21
Сб июн 29, 2019 06:12:22
пардон, перепутал регистры, извиняюсь.B@R5uk писал(а):Регистры tmpX — это делитель,
с загрузкой таблицы из памяти очень невыгодное решение в плане производительности - команда LPM выполняется за 3 машинных цикла (ну, пусть будем их звать тактами). а загрузка непосредственного операнда занимает 1 машинный цикл (такт).B@R5uk писал(а):Там ещё куча времени сэкономится на загрузке из памяти: вместо трёх тактов операция займёт один
Сб июн 29, 2019 06:45:45
Сб июн 29, 2019 07:24:23