реклама на сайте
подробности

 
 
2 страниц V  < 1 2  
Reply to this topicStart new topic
> Необычное использование аппаратного умножителя
Rst7
сообщение Dec 14 2008, 21:38
Сообщение #16


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Цитата(singlskv @ Dec 14 2008, 22:08) *
я в том смысле что есть выбор, толи в перенос толи sbrs/sbrc.
А v -8ми битный ?

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

Цитата
Аа... Вы о том как это оттранслирует компилятор ?

Ну вменяемый компилятор оттранслирует это в пять команд плюс переход. Просто выражение со сдвигом в другую сторону не может быть обработано бесплатным сдвигом операнда в арм-режиме.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
Rst7
сообщение Jan 23 2009, 15:21
Сообщение #17


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Ну, продолжим наши игры. На этот раз под руки попало деление. 16 бит беззнаковое на 16 бит беззнаковое. Обычное деление в столбик - почти 200 тактов (зависит от операндов).

Если не жмет место во флеше и необходимо ускорить деление 16 на 16, предлагаю такую процедуру (код великоват, спрятал под спойлером)

CODE

#define ZL R30
#define ZH R31

PUBLIC fast_divu16

RSEG CODE:CODE:NOROOT(1)

// 92 UINT16 fast_divu16(UINT16 a, UINT16 cool.gif
fast_divu16:
// 93 {
LDI ZH,shift_mask_and_log>>8
CLR R3
// 101 if ((d=b>>8)!=0)
TST R19
BREQ byte_div
large_div:
// 103 UINT8 __flash *p=shift_mask_and_log+d;
// 104 s=*p;
MOV ZL,R19
LPM R22,Z ;s - R22
INC ZH
// 105 p=shift_mask_and_log+((b*s)>>8)+0x100;
MUL R19,R22
MOV ZL,R0
MUL R18,R22
ADD ZL,R1
// 106 c=*p<<8;
LPM R23,Z
// 107 p+=0x100;
INC ZH
// 108 c|=*p;
LPM ZH,Z
// 109 c=(UINT32)((UINT32)c*a)>>16;
MUL R23,R17
MOVW R21:R20,R1:R0
MUL ZH,R16
MOV R2,R1
MUL R23,R16
ADD R2,R0
ADC R20,R1
ADC R21,R3
MUL ZH,R17
ADD R2,R0
ADC R20,R1
ADC R21,R3
// 110 c=(UINT32)((UINT32)c*s)>>8;
MUL R21,R22
MOV R21,R1
MOV R2,R0
MUL R20,R22
MOV R20,R2
OR R20,R1
// 111 a-=b
SUB R16,R18
SBC R17,R19
; BRCS zero_result
//b - R19:R18, c - R21:R20, a - R17:R16, s - R22, e - ZH:ZL
// 112 e=b*c-a;
MUL R19,R20
MOV ZH,R0
MUL R18,R21
ADD ZH,R0
MUL R18,R20
MOV ZL,R0
ADD ZH,R1
SUB ZL,R16
SBC ZH,R17
// if (e>b) c--;
CP R18,ZL ;b-e, carry=1 if b<e
CPC R19,ZH
SBC R20,R3
SBC R21,R3
// 122 return c;
MOVW R17:R16,R21:R20
RET
;zero_result:
; LDI R16,0
; LDI R17,0
; RET
result_a_or_fault:
BREQ result_a
SER R16
SER R17
result_a:
RET
// 126 if ((d=cool.gif>1)
byte_div:
CPI R18, 2
BRCS result_a_or_fault
MOV ZL,R18
// 129 s=*p;
LPM R22,Z
// 130 p+=0x100;
INC ZH
// 131 c=*p<<8;
LPM R19,Z
// 132 p+=0x100;
INC ZH
// 133 c|=*p;
LPM R18,Z
// 134 c=(UINT32)((UINT32)c*a)>>16;
MUL R19,R17
MOVW R21:R20,R1:R0
MUL R18,R16
MOV R2,R1
MUL R19,R16
ADD R2,R0
ADC R20,R1
ADC R21,R3
MUL R18,R17
ADD R2,R0
ADC R20,R1
ADC R21,R3
// 135 a-=b;
SUB R16,ZL
SBCI R17,0
; BRCS zero_result
// 136 e=d*c-a;
MUL R21,ZL
MOV R19,R0
MUL R20,ZL
MOV R18,R0
ADD R19,R1
SUB R18,R16
SBC R19,R17
// if (e>b) c--;
CP ZL,R18 ;b-e, carry=1 if b<e
CPC R3,R19
SBC R20,R3
SBC R21,R3
// 122 return c;
MOVW R17:R16,R21:R20
RET

ASEGN NEAR_F:CODE:ROOT,0FD00H
//Таблица масок и обратных величин. Должна быть с круглого адреса
shift_mask_and_log:
DB 255, 128, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16, 16, 16, 16, 16, 8
DB 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 4, 4, 4
DB 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
DB 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
DB 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
DB 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1
DB 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
DB 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
DB 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
DB 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
DB 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
DB 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 128, 85, 64, 51, 42, 36, 32, 28, 25
DB 23, 21, 19, 18, 17, 16, 15, 14, 13, 12, 12, 11, 11, 10, 10, 9, 9, 9
DB 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5
DB 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
DB 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
DB 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
DB 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
DB 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
DB 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
DB 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
DB 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
DB 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1
DB 86, 1, 52, 171, 147, 1, 114, 154, 70, 86, 178, 74, 18, 1, 16, 57
DB 122, 205, 49, 163, 34, 171, 62, 217, 124, 37, 212, 137, 67, 1, 194
DB 136, 81, 29, 236, 189, 145, 103, 63, 25, 245, 210, 177, 145, 115, 86
DB 58, 31, 6, 237, 213, 190, 168, 147, 126, 106, 87, 69, 51, 34, 17, 1
DB 241, 225, 211, 196, 182, 169, 156, 143, 130, 118, 106, 95, 84, 73
DB 62, 52, 42, 32, 22, 13, 4, 251, 242, 233, 225, 217, 209, 201, 193
DB 186, 178, 171, 164, 157, 150, 144, 137, 131, 125, 119, 113, 107, 101
DB 95, 90, 84, 79, 74, 68, 63, 58, 53, 49, 44, 39, 35, 30, 26, 21, 17
DB 13, 9, 5, 1, 253, 249, 245, 241, 237, 234, 230, 226, 223, 219, 216
DB 213, 209, 206, 203, 200, 196, 193, 190, 187, 184, 181, 179, 176, 173
DB 170, 167, 165, 162, 159, 157, 154, 152, 149, 147, 144, 142, 139, 137
DB 135, 132, 130, 128, 126, 123, 121, 119, 117, 115, 113, 111, 109, 107
DB 105, 103, 101, 99, 97, 95, 93, 91, 89, 88, 86, 84, 82, 81, 79, 77
DB 75, 74, 72, 71, 69, 67, 66, 64, 63, 61, 60, 58, 57, 55, 54, 52, 51
DB 49, 48, 47, 45, 44, 42, 41, 40, 38, 37, 36, 34, 33, 32, 31, 29, 28
DB 27, 26, 25, 23, 22, 21, 20, 19, 18, 16, 15, 14, 13, 12, 11, 10, 9, 8
DB 7, 6, 5, 4, 3, 2


END


Собственно деление представляет из себя выборку из таблицы значения, обратного делителю, и умножение на него делимого с последующей коррекцией результата. При делителе меньше 256 выборка производится непостредственно (таблица на 256 значений), а вот при большем делителе делается хитрость:

1. Определяется двоичный порядок делителя (в виде маски для последующего сдвига при помощи mul)
2. Делитель быстро сдвигается (нормализуется) в диапазон 0x80...0xFF.
3. Эта мантисса служит индексом в таблице обратных значений.
4. Обратное значение опять сдвигается при помощи умножений на ту же маску. Т.е. (1/(b*n))*a*n=a/b;
5. Умножение на делимое и коррекция, как и в случае делитель<256.

Вот такие пироги в худшем случае занимают 69 тактов и 176+768 байт флеша на собственно функцию и таблички.

Единственно что, лень доводить до ума, при делимом больше чем ~40000 и делителе в районе 256...512 бывает ошибается на 1 - возвращает результат на 1 больше чем надо. Если кому сильно необходимо, могут допилить (судя по всему, необходима отдельная ветка для делителей 0x100...0x1FF c отдельной табличкой обратных значений).


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
galjoen
сообщение Jan 27 2009, 10:38
Сообщение #18


Знающий
****

Группа: Свой
Сообщений: 841
Регистрация: 10-05-07
Из: Чебоксары (Россия)
Пользователь №: 27 640



Цитата(Rst7 @ Jan 23 2009, 18:21) *
Ну, продолжим наши игры.

Вроде разорбрался с вашим кодом. Для этого понаписал комментариев. Разбирался на асме..
Код
;//  111       a-=b; отсюда начинаются непонятки... :wassat:
    SUB    R16,R18; вычли из делимого (a) делитель (b).
    SBC    R17,R19; Зачем? Токо для проверки на 0?
;    BRCS    zero_result
;//b - R19:R18, c - R21:R20, a - R17:R16, s - R22, e - ZH:ZL
;//  112       e=b*c-a;
    MUL    R19,R20; ст.б. делителя * мл.б. рез-та
    MOV    ZH,R0
    MUL    R18,R21; мл.б. делителя * ст.б. рез-та
    ADD    ZH,R0
    MUL    R18,R20; мл.б. делителя * мл.б. рез-та
    MOV    ZL,R0; получили в ZH:ZL 2 мл. байта произведения
    ADD    ZH,R1; делителя на результат (восстановленное делимое)
    SUB    ZL,R16; вычли разницу между делимым и делителем т.е.
    SBC    ZH,R17; вычли делимое и прибавили делитель
; Зачем нужно прибавлять делитель? Для того чтоб сравнить с 0?
; Но ведь сравнивать-то будем с делителем.
;// if (e>b) c--;
    CP    R18,ZL;b-e, carry=1 if b<e
    CPC    R19,ZH; C=1 если разница больше собственно делителя
; А не глюк-ли это? Зачем разницу с ПРИБАВЛЕННЫМ ДЕЛИТЕЛЕМ сравнивать
; с делителем? Это ведь эквивалентно сравнению разницы с нулём!
    SBC    R20,RG00; вычитаем перенос - это
    SBC    R21,RG00; и есть собственно коррекция
;//  122       return c;
    MOVW    R17:R16,R21:R20
    RET
; А вот мой вариант. Начиная с непонятного места. :rolleyes:
    mul    R19,R20; ст.б. делителя * мл.б. рез-та
    mov    R2,R0; это корректно т.к. здесь R1=0
    mul    R18,R21; мл.б. делителя * ст.б. рез-та
    add    R2,R0; это корректно т.к. здесь R1=0
    mul    R18,R20; мл.б. делителя * мл.б. рез-та
    add    R1,R2; в R1:R0 получили восстановленное делимое
; Вычитаем из, восстановленного делимого, делимое реальное.
    sub    R0,R16; результат (разницу между восстановленным
    sbc    R1,R17; делимым и реальным) получаем в R1:R0
; видимо таблица обратных величин составлена так, чтобы результат мог
; получится только на 1 больше. Т.е. здесь не может быть отрицательного
; числа. Так? Если не так, то здесь нужно проверить C (перенос) на =1
; командой brcs (был заём). И пойти по другой ветке алгоритма. Или-же
; делитель для того и прибавлялся, чтобы здесь получилось >0?
; Хотя как-то зыбко всё это... Я бы написал подругому. Потом приведу
; свой вариант. Отличия начинаются с этого места.
    cp    R18,R0; сравним разницу с делителем, и если получилось
    cpc    R19,R1; больше - вычитаем единицу из результата.
; Сейчас C (перенос) =1 показывает, что был заём, и нужно вычесть 1.
    sbc    R20,RG00; вычитаем перенос - это и есть
    sbc    R21,RG00; собственно коррекция (на 0 или -1)
; Вот получился аналог, но на 3 такта быстрее и с исправленным багом.
; Ну вовсяком случае (насчёт бага) я так думаю... :biggrin:

; А вот как написал бы я (начиная с того места):
    brcc    large_div1; C=0, восстановленное - реальное делимое >=0
; Разница<0. При коррекции нужно будет прибавлять еденицу.
    add    R0,R18; к отрицательному числу (разнице)
    adc    R1,R19; прибавляем положительное (делитель)
    brlt    large_div2; <0 - коррекция не требуется (хотя корректность применение этой команды здесь под вопросом)
    inc    R20; увеличим мл. байт результата
    brne    large_div2; Z=0 - ст. байт увеличивать не нужно
    inc    R21; увеличим ст. байт результата
    rjmp    large_div2; на продолжение
large_div1:; Разница>=0. Здесь собственно тоже самое.
    cp    R18,R0; сравним разницу с делителем, и если получилось
    cpc    R19,R1; больше - вычитаем единицу из результата.
; Сейчас C (перенос) =1 показывает, что был заём, и нужно вычесть 1.
    sbc    R20,RG00; вычитаем перенос - это
    sbc    R21,RG00; и есть собственно коррекция
large_div2:    
; Т.е. здесь коррекция была на -1, 0 или +1. Если по результатам тестирования
; этого окажется недостаточно, то можно сделать и -2, -1, 0, +1. Или ещё как.

Я собственно собираюсь переписать всё на асм. У вас там есть ещё пара мест где хотелось бы подправить. Но это потом. А пока жел-но разобраться с непонятным местом...
Go to the top of the page
 
+Quote Post
Rst7
сообщение Jan 27 2009, 11:22
Сообщение #19


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Цитата
Я собственно собираюсь переписать всё на асм.


Гм. Я разве не на асме код выложил? Для тех, кто в танке - была написана рыба на Си, отлажена в MSVS, затем собрана IAR'ом, и листинг допилен вручную.

Щас продолжу, случайно не ту кнопку нажал smile.gif

Я не пойму, что Вас смущает?

a - делимое;
b - делитель;
с - результат, сначала приближение, потом он корректируется;
e - ошибка, равная b*c-a;

Если внести a-=b в выражение ошибки, то это эквивалентно e=b*c-( a - b )=b*c-a+b=b*(c+1)-a;

Если ошибка превышает делитель, то корректируем результат (уменьшением).


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
galjoen
сообщение Jan 27 2009, 12:11
Сообщение #20


Знающий
****

Группа: Свой
Сообщений: 841
Регистрация: 10-05-07
Из: Чебоксары (Россия)
Пользователь №: 27 640



Цитата(Rst7 @ Jan 27 2009, 14:22) *
Гм. Я разве не на асме код выложил? Для тех, кто в танке - была написана рыба на Си, отлажена в MSVS, затем собрана IAR'ом, и листинг допилен вручную.

Ну вот в наследство от Си и осталось... Если изначально на асме писать - лучше получится.
Цитата(Rst7 @ Jan 27 2009, 14:22) *
Щас продолжу, случайно не ту кнопку нажал smile.gif

Я не пойму, что Вас смущает?

a - делимое;
b - делитель;
с - результат, сначала приближение, потом он корректируется;
e - ошибка, равная b*c-a;

Если внести a-=b в выражение ошибки, то это эквивалентно e=b*c-( a - b )=b*c-a+b=b*(c+1)-a;

Если ошибка превышает делитель, то корректируем результат (уменьшением).

У вас, как вы и пишете, b*(c+1)-a сравнивается с b (делителем). Это эквивалентно b*c сравнить с a.
Приведём (преобразуем) ваш вариант к такому виду:
b*(c+1)-a?>b
b*c+b-a?>b
b*c-a?>0
b*c?>a
и если условие выполняется, то вы уменьшаете c (корректируете результат)
Вот так получается? Если так, то это же неверно!
Вот это меня и смущает biggrin.gif .
А нужно сравнивать так:
b*c-a?>b
И если условие выполняется - вычитать из c еденицу.
Go to the top of the page
 
+Quote Post
Rst7
сообщение Jan 27 2009, 12:51
Сообщение #21


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Цитата
Приведём (преобразуем) ваш вариант к такому виду:
....
b*c?>a
и если условие выполняется, то вы уменьшаете c (корректируете результат)


Согласен. Переумничал. Дело в том, что изначально там было весьма хитрое последовательное приближение за несколько этапов. Потом убралось, но не целиком. Оттуда и издержки, а совсем не от компилятора Си.

Цитата
Вот так получается? Если так, то это же неверно!


Почему?


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
galjoen
сообщение Jan 27 2009, 14:41
Сообщение #22


Знающий
****

Группа: Свой
Сообщений: 841
Регистрация: 10-05-07
Из: Чебоксары (Россия)
Пользователь №: 27 640



Цитата(Rst7 @ Jan 27 2009, 15:51) *
Почему?

Не совпадает с тем, что в описании.
А вообще тут всё зависит от того, нужно-ли округлять результат деления. В том случае получилось с обрезанием.

Еще хотелось бы узнать как вы считали таблицу обратных величин. Ну не в ручную же. Выложите код если можно.
Это нужно чтобы изменить коррекцию. Чтобы результат корректировался на +1, 0 и -1. Это добавляет всего 3 такта. М.б. удастся ту 1 при ~40000 скорректировать.
Ну и другие мысли по оптимизации на асме есть. Сделаю - выложу.
Go to the top of the page
 
+Quote Post
Rst7
сообщение Jan 27 2009, 14:58
Сообщение #23


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Цитата
Не совпадает с тем, что в описании.


Где не совпадает?

Цитата
А вообще тут всё зависит от того, нужно-ли округлять результат деления. В том случае получилось с обрезанием.


Операция / в Си не округляет результат. Так что все правильно.

Цитата
Еще хотелось бы узнать как вы считали таблицу обратных величин. Ну не в ручную же. Выложите код если можно.


Можно.

Это считатель:
Код
void Generate_log_table(void)
{
    unsigned int i=2;
    do
    {
        log_table[i]=((0x10000UL/i)+1);
        i++;
    }
    while(i<256);
}

Только оно потом ручками подправленно для i=1;

Цитата
Это нужно чтобы изменить коррекцию. Чтобы результат корректировался на +1, 0 и -1. Это добавляет всего 3 такта. М.б. удастся ту 1 при ~40000 скорректировать.


Не помню, но не получалось. Там значащих битов не хватает.

Цитата
Ну и другие мысли по оптимизации на асме есть.


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


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
galjoen
сообщение Jan 28 2009, 05:25
Сообщение #24


Знающий
****

Группа: Свой
Сообщений: 841
Регистрация: 10-05-07
Из: Чебоксары (Россия)
Пользователь №: 27 640



Цитата(Rst7 @ Jan 27 2009, 17:58) *

Ну вот, наваял:
CODE

.DEF RG00=R2 ; регистр всегда равный 0x00
;.DEF RGFF=R3 ; регистр всегда равный 0xFF
.DEF RBN0=R4 ; чётный регистр в диапазоне 2..15
.DEF RBN1=R5 ; нечётный регистр в диапазоне 2..15 (пара к предыдущему)
.DEF RBN2=R6 ; чётный регистр в диапазоне 2..15
.DEF RBX0=R16 ; чётный регистр в диапазоне 16..25
.DEF RBX1=R17 ; нечётный регистр в диапазоне 16..25 (пара к предыдущему)
.DEF RBX2=R18 ; чётный регистр в диапазоне 16..25
.DEF RBX3=R19 ; нечётный регистр в диапазоне 16..25 (пара к предыдущему)
.DEF RBX4=R20 ; чётный регистр в диапазоне 16..25
.DEF RBX5=R21 ; нечётный регистр в диапазоне 16..25 (пара к предыдущему)
.DEF ZL=R30
.DEF ZH=R31
; eor RG00,RG00 ; RG00=0x00
; ldi RBX0,0xFF
; out 0x3D,RBX0
; out 0x3E,RG00
;dfdf: rcall f16d
; rjmp dfdf


f16d:
; RBX1:RBX0=R17:R16=делимое=a
; RBX3:RBX2=R19:18=делитель=b
; RBX5:RBX4=R21:R20=результат=с
eor RG00,RG00 ; RG00=0x00 (хотя я обычно делаю это
; только один раз при инициализации)
ldi ZH,high(tb_3e<<1) ; ст. байт адреса таблиц (3 шт.)
tst RBX3 ; ст. байт делителя
breq f16db ; Z=1 - делим на байт
f16wd: ; делим на слово
; прочтем из таблицы соответствующий сдвигатель
mov ZL,RBX3 ; ст. байт делителя
lpm RBN2,Z ; s - сдвиг
; приведём делитель в диапазон 0x80..0xFF (по сдвигателю)
mul RBX3,RBN2 ; ст. байт делителя
mov ZL,R0
mul RBX2,RBN2 ; мл. байт делителя
or ZL,R1 ; ZL=приведённый делитель
; получим обратную величину из таблицы по приведённому делителю
inc ZH ; ук-ль на мл. байты обратной
lpm RBN0,Z ; мл. байт обратной из таблицы
inc ZH ; ук-ль на ст. байты
lpm RBN1,Z ; ст. байт обратной из таблицы [21]
; множим делимое на обратную величину (результат в ZH:ZL, RBX5:RBX4)
mul RBN1,RBX1 ; ст. б. обратного * ст. байт делимого
movw ZH:ZL,R1:R0 ; щас результат получим в ZH:ZL
mul RBN0,RBX0 ; мл. б. обратного * мл. б. делимого
movw RBX5:RBX4,R1:R0
mul RBN1,RBX0 ; ст. б. обратного * мл. б. делимого
add RBX5,R0
adc ZL,R1
adc ZH,RG00
mul RBN0,RBX1 ; мл. б. обратного * ст. б. делимого
add RBX5,R0
adc ZL,R1
adc ZH,RG00 ; ZH:ZL=несдвинутый и
; нескорректированный результат [37]
; сдвинем результат назад на величину сдвигателя s (RBN2)
mul ZH,RBN2 ; ст. байт
movw RBX5:RBX4,R1:R0
mul ZL,RBN2 ; мл. байт
or RBX4,R1 ; RBX5:RBX4= нескорректированный результат
; восстановим делимое по нескорректированному результату
mul RBX2,RBX4 ; мл.б. делителя * мл.б. рез-та
movw ZH:ZL,R1:R0
mul RBX3,RBX4 ; ст.б. делителя * мл.б. рез-та
add ZH,R0
mul RBX2,RBX5 ; мл.б. делителя * ст.б. рез-та
add ZH,R0 ; ZH:ZL=восстановленное делимое [52]
; если (восстановленное делимое)>(делимое), то (результат)--
cp RBX0,ZL ; RBX1:RBX0=делимое
cpc RBX1,ZH ; если C=1 - корректируем
sbci RBX4,0x00 ; из RBX5:RBX4=(нескорректированному
sbci RBX5,0x00 ; результату) вычитаем C (перенос)
; вычисляем (восстановленное делимое ZH:ZL)+(делитель RBX3:RBX2)
add ZL,RBX2
adc ZH,RBX3 ; ZH:ZL += RBX3:RBX2
brcs f16wd1 ; C=1 - переполнение (без проверки)
; если ZH:ZL=<RBX1:RBX0, то (результат)++
cp RBX0,ZL
cpc RBX1,ZH ; если C=0 - корректируем (++)
sbci RBX4,0xFF ; к RBX5:RBX4=(нескорректированному
sbci RBX5,0xFF ; результату) прибавляем инверсный C
f16wd1:
movw RBX1:RBX0,RBX5:RBX4 ; результат в RBX1:RBX0 [64]
ret ; [68]

f16db: ; делим слово на байт (0=RBX3)
cpi RBX2,0x02 ; проверим случаи 0 и 1
brcs f16db01
; прочтем из таблицы соответствующий сдвигатель (в ZL уже весь делитель)
mov ZL,RBX2 ; мл. байт делителя
lpm RBN2,Z ; s - сдвиг
; получим обратную величину из таблицы по делителю
inc ZH ; ук-ль на мл. байты обратной
lpm RBN0,Z ; мл. байт обратной из таблицы
inc ZH ; ук-ль на ст. байты
lpm RBN1,Z ; ст. байт обратной из таблицы
; множим делимое на обратную величину (результат в RBX5:RBX4, ZH:ZL)
mul RBN1,RBX1 ; ст. б. обратного * ст. байт делимого
movw RBX5:RBX4,R1:R0 ; щас результат получим в RBX5:RBX4
mul RBN0,RBX0 ; мл. б. обратного * мл. б. делимого
movw ZH:ZL,R1:R0
mul RBN1,RBX0 ; ст. б. обратного * мл. б. делимого
add ZH,R0
adc RBX4,R1
adc RBX5,RG00
mul RBN0,RBX1 ; мл. б. обратного * ст. б. делимого
add ZH,R0
adc RBX4,R1
adc RBX5,RG00 ; RBX5:RBX4=(нескорректированный результат)
; восстановим делимое по нескорректированному результату
mul RBX2,RBX4 ; мл.б. делителя * мл.б. рез-та
movw ZH:ZL,R1:R0
mul RBX3,RBX4 ; ст.б. делителя * мл.б. рез-та
add ZH,R0
mul RBX2,RBX5 ; мл.б. делителя * ст.б. рез-та
add ZH,R0 ; ZH:ZL=восстановленное делимое
; если (восстановленное делимое)>(делимое), то (результат)--
cp RBX0,ZL ; RBX1:RBX0=делимое
cpc RBX1,ZH ; если C=1 - корректируем
sbci RBX4,0x00 ; из RBX5:RBX4=(нескорректированному
sbci RBX5,0x00 ; результату) вычитаем C (перенос)
; вычисляем (восстановленное делимое ZH:ZL)+(делитель RBX2)
add ZL,RBX2
adc ZH,RBX3 ; ZH:ZL += RBX3:RBX2
brcs f16db1 ; C=1 - переполнение (без проверки)
; если ZH:ZL=<RBX1:RBX0, то (результат)++
cp RBX0,ZL
cpc RBX1,ZH ; если C=0 - корректируем (++)
sbci RBX4,0xFF ; к RBX5:RBX4=(нескорректированному
sbci RBX5,0xFF ; результату) прибавляем инверсный C
f16db1:
movw RBX1:RBX0,RBX5:RBX4 ; результат в RBX1:RBX0
ret

f16db01: ; делитель = 0..1
tst RBX2 ; проверим 0 или 1
brne f16db11 ; Z=0 - (результат)=(делимому)
or RBX0,RBX1 ; проверим деление 0 на 0
ldi RBX0,0xFF ; это переполнение при
ldi RBX1,0xFF ; делении на 0 такое
brne f16db11 ; Z=0 - щас не 0/0
ldi RBX0,0x01 ; при делении 0 на
ldi RBX1,0x00 ; 0 результат =1
f16db11:
ret
ENDCOD: ; эта метка токо шоб корректировался выровненный адрес
.org ((ENDCOD+0x7F)&0xFF80)
tb_3e:
; таблица сдвигателей
.db 0xFF, 0x80, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20 ; 00..07
.db 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 ; 08..0F
.db 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 ; 10..17
.db 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 ; 18..1F
.db 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 ; 20..27
.db 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 ; 28..2F
.db 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 ; 30..37
.db 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 ; 38..3F
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; 40..47
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; 48..4F
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; 50..57
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; 58..5F
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; 60..67
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; 68..6F
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; 70..77
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; 78..7F
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; 80..87
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; 88..8F
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; 90..97
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; 98..9F
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; A0..A7
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; A8..AF
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; B0..B7
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; B8..BF
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; C0..C7
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; C8..CF
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; D0..D7
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; D8..DF
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; E0..E7
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; E8..EF
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; F0..F7
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; F8..FF
; младший байт обратных величин
.db 0x00, 0x00, 0x00, 0x55, 0x00, 0x33, 0xAA, 0x92 ; 00..07
.db 0x00, 0x71, 0x99, 0x45, 0x55, 0xB1, 0x49, 0x11 ; 08..0F
.db 0x00, 0x0F, 0x38, 0x79, 0xCC, 0x30, 0xA2, 0x21 ; 10..17
.db 0xAA, 0x3D, 0xD8, 0x7B, 0x24, 0xD3, 0x88, 0x42 ; 18..1F
.db 0x00, 0xC1, 0x87, 0x50, 0x1C, 0xEB, 0xBC, 0x90 ; 20..27
.db 0x66, 0x3E, 0x18, 0xF4, 0xD1, 0xB0, 0x90, 0x72 ; 28..2F
.db 0x55, 0x39, 0x1E, 0x05, 0xEC, 0xD4, 0xBD, 0xA7 ; 30..37
.db 0x92, 0x7D, 0x69, 0x56, 0x44, 0x32, 0x21, 0x10 ; 38..3F
.db 0x00, 0xF0, 0xE0, 0xD2, 0xC3, 0xB5, 0xA8, 0x9B ; 40..47
.db 0x8E, 0x81, 0x75, 0x69, 0x5E, 0x53, 0x48, 0x3D ; 48..4F
.db 0x33, 0x29, 0x1F, 0x15, 0x0C, 0x03, 0xFA, 0xF1 ; 50..57
.db 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB9, 0xB1 ; 58..5F
.db 0xAA, 0xA3, 0x9C, 0x95, 0x8F, 0x88, 0x82, 0x7C ; 60..67
.db 0x76, 0x70, 0x6A, 0x64, 0x5E, 0x59, 0x53, 0x4E ; 68..6F
.db 0x49, 0x43, 0x3E, 0x39, 0x34, 0x30, 0x2B, 0x26 ; 70..77
.db 0x22, 0x1D, 0x19, 0x14, 0x10, 0x0C, 0x08, 0x04 ; 78..7F
.db 0x00, 0xFC, 0xF8, 0xF4, 0xF0, 0xEC, 0xE9, 0xE5 ; 80..87
.db 0xE1, 0xDE, 0xDA, 0xD7, 0xD4, 0xD0, 0xCD, 0xCA ; 88..8F
.db 0xC7, 0xC3, 0xC0, 0xBD, 0xBA, 0xB7, 0xB4, 0xB2 ; 90..97
.db 0xAF, 0xAC, 0xA9, 0xA6, 0xA4, 0xA1, 0x9E, 0x9C ; 98..9F
.db 0x99, 0x97, 0x94, 0x92, 0x8F, 0x8D, 0x8A, 0x88 ; A0..A7
.db 0x86, 0x83, 0x81, 0x7F, 0x7D, 0x7A, 0x78, 0x76 ; A8..AF
.db 0x74, 0x72, 0x70, 0x6E, 0x6C, 0x6A, 0x68, 0x66 ; B0..B7
.db 0x64, 0x62, 0x60, 0x5E, 0x5C, 0x5A, 0x58, 0x57 ; B8..BF
.db 0x55, 0x53, 0x51, 0x50, 0x4E, 0x4C, 0x4A, 0x49 ; C0..C7
.db 0x47, 0x46, 0x44, 0x42, 0x41, 0x3F, 0x3E, 0x3C ; C8..CF
.db 0x3B, 0x39, 0x38, 0x36, 0x35, 0x33, 0x32, 0x30 ; D0..D7
.db 0x2F, 0x2E, 0x2C, 0x2B, 0x29, 0x28, 0x27, 0x25 ; D8..DF
.db 0x24, 0x23, 0x21, 0x20, 0x1F, 0x1E, 0x1C, 0x1B ; E0..E7
.db 0x1A, 0x19, 0x18, 0x16, 0x15, 0x14, 0x13, 0x12 ; E8..EF
.db 0x11, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09 ; F0..F7
.db 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 ; F8..FF
; старший байт обратных величин
.db 0x00, 0x00, 0x80, 0x55, 0x40, 0x33, 0x2A, 0x24 ; 00..07
.db 0x20, 0x1C, 0x19, 0x17, 0x15, 0x13, 0x12, 0x11 ; 08..0F
.db 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0C, 0x0B, 0x0B ; 10..17
.db 0x0A, 0x0A, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08 ; 18..1F
.db 0x08, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06 ; 20..27
.db 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05 ; 28..2F
.db 0x05, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04 ; 30..37
.db 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 ; 38..3F
.db 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 ; 40..47
.db 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 ; 48..4F
.db 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02 ; 50..57
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; 58..5F
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; 60..67
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; 68..6F
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; 70..77
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; 78..7F
.db 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; 80..87
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; 88..8F
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; 90..97
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; 98..9F
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; A0..A7
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; A8..AF
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; B0..B7
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; B8..BF
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; C0..C7
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; C8..CF
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; D0..D7
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; D8..DF
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; E0..E7
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; E8..EF
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; F0..F7
.db 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ; F8..FF

; Нашёл у вас ошибочку:
;result_a_or_fault:
; CPI R18,1 ; вы "потеряли" эту команду
; BREQ result_a
;
; У меня получилось тоже 69 тактов в худшем случае, но ошибок
; не бывает (или я пока не нашёл). Изменил:
; 1. Таблицу обратных величин. Вычисляю её по формуле
; log_table[i]=(0x10000UL/i), а не log_table[i]=((0x10000UL/i)+1)
; как было у вас.
; 2. Расположение старших и младших байтов в таблице обратных величин.
; Ну это дело вкуса.
; 3. Корректирую результат на +1, 0 или -1. У вас корретировался
; только на 0 и -1. Видимо для этого и была предназначена та, убранная
; мною, еденичка в формуле. Но такой коррекции было недостаточно.
; Оттуда и ошибки.
; 4. Соптимизировал кое-какие вычисления. См. текст.
;
; На АВР проверил конечно не всё варианты делимое+делитель. Проверял
; алгоритм на компьютере (там проверил всё), а на АВР с компьютерного
; Си переносил вручную. Надо сказать, что с некоторых пор совершенно
; не использую Си на АВР. Забыл как дурной сон. Поэтому м.б. не
; выполнил все Си-шные соглашения. Но если вы мне их напомните - могу
; подкорректировать код.

Комментарии внутри. В конце.
Go to the top of the page
 
+Quote Post
Rst7
сообщение Jan 28 2009, 06:57
Сообщение #25


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Цитата
Поэтому м.б. не
; выполнил все Си-шные соглашения. Но если вы мне их напомните - могу
; подкорректировать код.


Для IAR:
Вход:
Делимое R17:R16
Делитель R19:R18
Выход:
Частное R17:R16

Можно не сохранять регистры R0...R3,R16...R23,R30,R31.

Никаких предустановленных регистров нет.

Но на самом деле, по алгоритму - там надо было решать вопрос не коррекцией на +1 и -1, а добавить значащих бит в таблицу обратных величин в диапазоне 0x80-0xFF. Тогда нет необходимости в лишней проверке.

Через пару дней положу новый вариант.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
galjoen
сообщение Jan 28 2009, 15:53
Сообщение #26


Знающий
****

Группа: Свой
Сообщений: 841
Регистрация: 10-05-07
Из: Чебоксары (Россия)
Пользователь №: 27 640



Цитата(Rst7 @ Jan 28 2009, 09:57) *
Но на самом деле, по алгоритму - там надо было решать вопрос не коррекцией на +1 и -1, а добавить значащих бит в таблицу обратных величин в диапазоне 0x80-0xFF. Тогда нет необходимости в лишней проверке.

Я попробовал что-то подобное промоделировать на компьютере - у меня не получилось. Формулу, по которой таблицы вычисляются, менял. Всё равно результат на еденичку пляшет. Я даже дополнительно сдвигал на 1 разряд налево приведённый делитель (старший бит всё равно всегда 1 равен) - всё равно с ошибками получалсь. Т.е. без коррекции видимо не обойтись...

Вообще меня не столько быстрое делении интересует, как быстрое вычисление арктангенса. Точнее быстрый переход от декартовых координат к полярным (там и деление конечно используется). С вычислением амплитуды проблем нет, а вот угол...
Go to the top of the page
 
+Quote Post
galjoen
сообщение Jan 30 2009, 10:06
Сообщение #27


Знающий
****

Группа: Свой
Сообщений: 841
Регистрация: 10-05-07
Из: Чебоксары (Россия)
Пользователь №: 27 640



Сделал 50-ти тактовую версию беззнакового деления 16/16. Но с ошибками. Ошибки в "правильную" сторону и не больше чем на 1. Т.е. что-то вроде округления.
CODE

.DEF RG00=R2 ; регистр всегда равный 0x00
;.DEF RGFF=R3 ; реги
;.DEF RBN0=R4 ; чётный регистр в диапазоне 2..15
;.DEF RBN1=R5 ; нечётный регистр в диапазоне 2..15 (пара к предыдущему)
.DEF RBN0=R22 ; чётный регистр IAR!
.DEF RBN1=R23 ; нечётный регистр (пара к предыдущему) IAR!
.DEF RBN2=R3 ; чётный регистр в диапазоне 2..15 IAR!
.DEF RBX0=R16 ; чётный регистр в диапазоне 16..25
.DEF RBX1=R17 ; нечётный регистр в диапазоне 16..25 (пара к предыдущему)
.DEF RBX2=R18 ; чётный регистр в диапазоне 16..25
.DEF RBX3=R19 ; нечётный регистр в диапазоне 16..25 (пара к предыдущему)
.DEF RBX4=R20 ; чётный регистр в диапазоне 16..25
.DEF RBX5=R21 ; нечётный регистр в диапазоне 16..25 (пара к предыдущему)
.DEF ZL=R30
.DEF ZH=R31
eor RG00,RG00 ; RG00=0x00
ldi RBX0,0xFF
out 0x3D,RBX0
out 0x3E,RG00
dfdf: rcall f16d
rjmp dfdf


f16d:
; RBX1:RBX0=R17:R16=делимое=a + возвращаем результат
; RBX3:RBX2=R19:18=делитель=b
; RBX5:RBX4=R21:R20=результат=с, но возвращаем в RBX1:RBX0
eor RG00,RG00 ; RG00=0x00 (хотя я обычно делаю это
; только один раз при инициализации)
ldi ZH,high(tb_3e<<1) ; ст. байт адреса таблиц (3 шт.)
cpi RBX3,1
brcc f16d1 ; C=0 - делим не на байт

f16db: ; делим слово на байт (0==RBX3)
cpi RBX2,0x02 ; проверим случаи 0 и 1
brcs f16db01
; прочтем из таблицы соответствующий сдвигатель
mov ZL,RBX2 ; мл. байт делителя
lpm RBN2,Z ; s - сдвиг
; приведём делитель в диапазон 0x100..0x1FF (по сдвигателю)
mul RBX2,RBN2 ; делитель
mov ZL,R0 ; ZL=приведённый делитель
cpi ZL,0 ; его проверим на 0x100
breq f16db1 ; Z=1 получилось 0x100 - не множим
; получим обратную величину из таблицы по делителю
inc ZH ; ук-ль на мл. байты обратной
lpm RBN0,Z ; мл. байт обратной из таблицы
inc ZH ; ук-ль на ст. байты
lpm RBN1,Z ; ст. байт обратной из таблицы
; множим делимое на обратную величину (результат в ZH:ZL, RBX5:RBX4)
mul RBN1,RBX1 ; ст. б. обратного * ст. байт делимого
movw ZH:ZL,R1:R0 ; щас результат получим в ZH:ZL
mul RBN0,RBX0 ; мл. б. обратного * мл. б. делимого
movw RBX5:RBX4,R1:R0
mul RBN1,RBX0 ; ст. б. обратного * мл. б. делимого
add RBX5,R0
adc ZL,R1
adc ZH,RG00
mul RBN0,RBX1 ; мл. б. обратного * ст. б. делимого
add RBX5,R0
adc ZL,R1
adc ZH,RG00 ; ZH:ZL=несдвинутый результат
; сдвинем результат назад на величину сдвигателя s (RBN2)
mul ZH,RBN2 ; ст. байт
movw RBX1:RBX0,R1:R0
mul ZL,RBN2 ; мл. байт
or RBX0,R1 ; RBX5:RBX4= нескорректированный результат
ret ; [50]
f16db1:; приведённый делитель, это 0x100
mul RBX0,RBN2
mov ZL,R1
mul RBX1,RBN2
movw RBX1:RBX0,R1:R0
or RBX0,ZL
ret

f16db01: ; делитель = 0..1
cpi RBX2,0 ; проверим делитель - 0 или 1
brne f16db11 ; Z=0 - (результат)=(делимому)
or RBX0,RBX1 ; проверим деление 0 на 0
ldi RBX0,0xFF ; это переполнение при
ldi RBX0,0xFF ; делении на 0 такое
brne f16db11 ; Z=0 - щас не 0/0
ldi RBX0,0x01 ; при делении 0 на
ldi RBX1,0x00 ; 0 результат =1
f16db11: ; делили на 0
ret

f16d1: breq f16dp ; делим на 0x100..0x1FF
f16wd: ; делим на 0x200..0xFFFF
; прочтем из таблицы соответствующий сдвигатель
mov ZL,RBX3 ; ст. байт делителя
lpm RBN2,Z ; s - сдвиг
; приведём делитель в диапазон 0x100..0x1FF (по сдвигателю)
mul RBX3,RBN2 ; ст. байт делителя
mov ZL,R0
mul RBX2,RBN2 ; мл. байт делителя
or ZL,R1 ; ZL=приведённый делитель
breq f16wd1 ; Z=1 получилось 0x100 - не множим
; получим обратную величину из таблицы по приведённому делителю
inc ZH ; ук-ль на мл. байты обратной
lpm RBN0,Z ; мл. байт обратной из таблицы
inc ZH ; ук-ль на ст. байты
lpm RBN1,Z ; ст. байт обратной из таблицы
; множим делимое на обратную величину (результат в ZH:ZL, RBX5:RBX4)
mul RBN1,RBX1 ; ст. б. обратного * ст. байт делимого
movw ZH:ZL,R1:R0 ; щас результат получим в ZH:ZL
mul RBN0,RBX0 ; мл. б. обратного * мл. б. делимого
movw RBX5:RBX4,R1:R0
mul RBN1,RBX0 ; ст. б. обратного * мл. б. делимого
add RBX5,R0
adc ZL,R1
adc ZH,RG00
mul RBN0,RBX1 ; мл. б. обратного * ст. б. делимого
add RBX5,R0
adc ZL,R1
adc ZH,RG00 ; ZH:ZL=несдвинутый результат
; сдвинем результат назад на величину сдвигателя s (RBN2)
mul ZH,RBN2 ; токо ст. байт т.к. результат в этом
mov RBX0,R1 ; случае м.б. токо однобайтовый
ldi RBX1,0 ; RBX5:RBX4= нескорректированный результат
ret ; [49]

f16wd1: ; приведённый делитель 0x100. Но не из делителя 0x100.
mul RBX1,RBN2 ; мл. байт делимого * сдвигатель
mov RBX0,R1 ; мл. байт результата
ldi RBX1,0 ; ст. байт рез-та точно =0
ret

f16dp: ; делим слово на 0x100..0x1FF
cpi RBX2,0
breq f16dp1 ; делим слово на 0x100
mov ZL,RBX2 ; мл. байт делителя (уже приведённого)
; получим обратную величину из таблицы по делителю
inc ZH ; ук-ль на мл. байты обратной
lpm RBN0,Z ; мл. байт обратной из таблицы
inc ZH ; ук-ль на ст. байты
lpm RBN1,Z ; ст. байт обратной из таблицы
; множим делимое на обратную величину (результат в ZH:ZL, RBX5:RBX4)
mul RBN1,RBX1 ; ст. б. обратного * ст. байт делимого
movw ZH:ZL,R1:R0 ; щас результат получим в ZH:ZL
mul RBN0,RBX0 ; мл. б. обратного * мл. б. делимого
movw RBX5:RBX4,R1:R0
mul RBN1,RBX0 ; ст. б. обратного * мл. б. делимого
add RBX5,R0
adc ZL,R1
adc ZH,RG00
mul RBN0,RBX1 ; мл. б. обратного * ст. б. делимого
add RBX5,R0
adc ZL,R1
adc ZH,RG00 ; ZH:ZL=несдвинутый результат
; сдвинем результат, в нашем случае >>8
mov RBX0,ZH
ldi RBX1,0
ret ; [40]
f16dp1: ; делим на 0x100
mov RBX0,RBX1 ; мл. байт результата
ldi RBX1,0 ; ст. байт рез-та точно =0
ret

ENDCOD: ; эта метка токо шоб корректировался выровненный адрес
.org ((ENDCOD+0x7F)&0xFF80)
tb_3e:
; таблица сдвигателей
.db 0xFF, 0x00, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40 ; 00..07
.db 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 ; 08..0F
.db 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 ; 10..17
.db 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 ; 18..1F
.db 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 ; 20..27
.db 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 ; 28..2F
.db 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 ; 30..37
.db 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 ; 38..3F
.db 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 ; 40..47
.db 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 ; 48..4F
.db 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 ; 50..57
.db 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 ; 58..5F
.db 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 ; 60..67
.db 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 ; 68..6F
.db 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 ; 70..77
.db 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 ; 78..7F
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; 80..87
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; 88..8F
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; 90..97
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; 98..9F
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; A0..A7
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; A8..AF
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; B0..B7
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; B8..BF
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; C0..C7
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; C8..CF
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; D0..D7
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; D8..DF
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; E0..E7
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; E8..EF
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; F0..F7
.db 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ; F8..FF
; младший байт обратных величин
.db 0xFF, 0x01, 0x04, 0x09, 0x10, 0x19, 0x24, 0x30 ; 00..07
.db 0x3F, 0x4F, 0x61, 0x75, 0x8A, 0xA1, 0xBA, 0xD5 ; 08..0F
.db 0xF1, 0x10, 0x2F, 0x51, 0x74, 0x98, 0xBE, 0xE6 ; 10..17
.db 0x0F, 0x3A, 0x66, 0x94, 0xC3, 0xF4, 0x26, 0x5A ; 18..1F
.db 0x8F, 0xC5, 0xFD, 0x36, 0x71, 0xAD, 0xEA, 0x28 ; 20..27
.db 0x68, 0xA9, 0xEC, 0x30, 0x75, 0xBB, 0x02, 0x4B ; 28..2F
.db 0x95, 0xE0, 0x2C, 0x79, 0xC8, 0x18, 0x69, 0xBB ; 30..37
.db 0x0E, 0x62, 0xB7, 0x0E, 0x65, 0xBD, 0x17, 0x72 ; 38..3F
.db 0xCD, 0x2A, 0x88, 0xE6, 0x46, 0xA7, 0x08, 0x6B ; 40..47
.db 0xCF, 0x33, 0x99, 0xFF, 0x66, 0xCF, 0x38, 0xA2 ; 48..4F
.db 0x0D, 0x79, 0xE5, 0x53, 0xC1, 0x31, 0xA1, 0x12 ; 50..57
.db 0x83, 0xF6, 0x6A, 0xDE, 0x53, 0xC9, 0x3F, 0xB7 ; 58..5F
.db 0x2F, 0xA8, 0x22, 0x9C, 0x18, 0x94, 0x10, 0x8E ; 60..67
.db 0x0C, 0x8B, 0x0A, 0x8B, 0x0C, 0x8D, 0x10, 0x93 ; 68..6F
.db 0x17, 0x9B, 0x20, 0xA6, 0x2D, 0xB4, 0x3B, 0xC4 ; 70..77
.db 0x4D, 0xD6, 0x61, 0xEC, 0x77, 0x03, 0x90, 0x1D ; 78..7F
.db 0xAB, 0x3A, 0xC9, 0x58, 0xE9, 0x7A, 0x0B, 0x9D ; 80..87
.db 0x30, 0xC3, 0x56, 0xEA, 0x7F, 0x14, 0xAA, 0x41 ; 88..8F
.db 0xD8, 0x6F, 0x07, 0x9F, 0x38, 0xD2, 0x6C, 0x06 ; 90..97
.db 0xA1, 0x3D, 0xD9, 0x75, 0x12, 0xAF, 0x4D, 0xEC ; 98..9F
.db 0x8A, 0x2A, 0xC9, 0x6A, 0x0A, 0xAB, 0x4D, 0xEF ; A0..A7
.db 0x91, 0x34, 0xD8, 0x7B, 0x20, 0xC4, 0x69, 0x0F ; A8..AF
.db 0xB5, 0x5B, 0x02, 0xA9, 0x50, 0xF8, 0xA1, 0x49 ; B0..B7
.db 0xF3, 0x9C, 0x46, 0xF0, 0x9B, 0x46, 0xF2, 0x9D ; B8..BF
.db 0x4A, 0xF6, 0xA3, 0x51, 0xFE, 0xAC, 0x5B, 0x0A ; C0..C7
.db 0xB9, 0x68, 0x18, 0xC8, 0x79, 0x2A, 0xDB, 0x8C ; C8..CF
.db 0x3E, 0xF1, 0xA3, 0x56, 0x09, 0xBD, 0x71, 0x25 ; D0..D7
.db 0xD9, 0x8E, 0x43, 0xF9, 0xAF, 0x65, 0x1B, 0xD2 ; D8..DF
.db 0x89, 0x40, 0xF8, 0xB0, 0x68, 0x21, 0xDA, 0x93 ; E0..E7
.db 0x4C, 0x06, 0xC0, 0x7A, 0x35, 0xEF, 0xAA, 0x66 ; E8..EF
.db 0x22, 0xDD, 0x9A, 0x56, 0x13, 0xD0, 0x8D, 0x4B ; F0..F7
.db 0x09, 0xC7, 0x85, 0x44, 0x03, 0xC2, 0x81, 0x41 ; F8..FF
; старший байт обратных величин
.db 0xFF, 0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9 ; 00..07
.db 0xF8, 0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1 ; 08..0F
.db 0xF0, 0xF0, 0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA ; 10..17
.db 0xEA, 0xE9, 0xE8, 0xE7, 0xE6, 0xE5, 0xE5, 0xE4 ; 18..1F
.db 0xE3, 0xE2, 0xE1, 0xE1, 0xE0, 0xDF, 0xDE, 0xDE ; 20..27
.db 0xDD, 0xDC, 0xDB, 0xDB, 0xDA, 0xD9, 0xD9, 0xD8 ; 28..2F
.db 0xD7, 0xD6, 0xD6, 0xD5, 0xD4, 0xD4, 0xD3, 0xD2 ; 30..37
.db 0xD2, 0xD1, 0xD0, 0xD0, 0xCF, 0xCE, 0xCE, 0xCD ; 38..3F
.db 0xCC, 0xCC, 0xCB, 0xCA, 0xCA, 0xC9, 0xC9, 0xC8 ; 40..47
.db 0xC7, 0xC7, 0xC6, 0xC5, 0xC5, 0xC4, 0xC4, 0xC3 ; 48..4F
.db 0xC3, 0xC2, 0xC1, 0xC1, 0xC0, 0xC0, 0xBF, 0xBF ; 50..57
.db 0xBE, 0xBD, 0xBD, 0xBC, 0xBC, 0xBB, 0xBB, 0xBA ; 58..5F
.db 0xBA, 0xB9, 0xB9, 0xB8, 0xB8, 0xB7, 0xB7, 0xB6 ; 60..67
.db 0xB6, 0xB5, 0xB5, 0xB4, 0xB4, 0xB3, 0xB3, 0xB2 ; 68..6F
.db 0xB2, 0xB1, 0xB1, 0xB0, 0xB0, 0xAF, 0xAF, 0xAE ; 70..77
.db 0xAE, 0xAD, 0xAD, 0xAC, 0xAC, 0xAC, 0xAB, 0xAB ; 78..7F
.db 0xAA, 0xAA, 0xA9, 0xA9, 0xA8, 0xA8, 0xA8, 0xA7 ; 80..87
.db 0xA7, 0xA6, 0xA6, 0xA5, 0xA5, 0xA5, 0xA4, 0xA4 ; 88..8F
.db 0xA3, 0xA3, 0xA3, 0xA2, 0xA2, 0xA1, 0xA1, 0xA1 ; 90..97
.db 0xA0, 0xA0, 0x9F, 0x9F, 0x9F, 0x9E, 0x9E, 0x9D ; 98..9F
.db 0x9D, 0x9D, 0x9C, 0x9C, 0x9C, 0x9B, 0x9B, 0x9A ; A0..A7
.db 0x9A, 0x9A, 0x99, 0x99, 0x99, 0x98, 0x98, 0x98 ; A8..AF
.db 0x97, 0x97, 0x97, 0x96, 0x96, 0x95, 0x95, 0x95 ; B0..B7
.db 0x94, 0x94, 0x94, 0x93, 0x93, 0x93, 0x92, 0x92 ; B8..BF
.db 0x92, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90 ; C0..C7
.db 0x8F, 0x8F, 0x8F, 0x8E, 0x8E, 0x8E, 0x8D, 0x8D ; C8..CF
.db 0x8D, 0x8C, 0x8C, 0x8C, 0x8C, 0x8B, 0x8B, 0x8B ; D0..D7
.db 0x8A, 0x8A, 0x8A, 0x89, 0x89, 0x89, 0x89, 0x88 ; D8..DF
.db 0x88, 0x88, 0x87, 0x87, 0x87, 0x87, 0x86, 0x86 ; E0..E7
.db 0x86, 0x86, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84 ; E8..EF
.db 0x84, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82 ; F0..F7
.db 0x82, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80 ; F8..FF
;
;Для IAR:
;Вход:
;Делимое R17:R16
;Делитель R19:R18
;Выход:
;Частное R17:R16
;Можно не сохранять регистры R0...R3,R16...R23,R30,R31.
;Никаких предустановленных регистров нет.

; Версия 2.0
; Изменения:
; 1. Убрал коррекцию.
; 2. Считает не точно. Иногда ошибается на 1 в большую сторону.
; Зависит от соотношения делимое/делитель. Получается что-то вроде
; округления результата.
; 3. В худшем случае 50 тактов.
; 4. Делитель привожу в диапазон 0x100..0x1FF. В рассчётах не использую
; старший бит т.к. он всегда =1.
; 5. Соответственно пересчитал таблицу сдвигателей.
; 6. Таблицу обратных величин считаю по формуле
; ((0x1000000/(0x100+i+0))+1).
; Пока не всё проверил (на компьютере всё). Перепроверю - тогда выложу
; ещё раз.

Подробные комментарии внутри. Внизу.
Go to the top of the page
 
+Quote Post

2 страниц V  < 1 2
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 24th June 2025 - 23:29
Рейтинг@Mail.ru


Страница сгенерированна за 0.01572 секунд с 7
ELECTRONIX ©2004-2016