Перейти к содержанию
    

Необычное использование аппаратного умножителя

я в том смысле что есть выбор, толи в перенос толи sbrs/sbrc.

А v -8ми битный ?

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

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

#define ZL R30
#define ZH R31

PUBLIC fast_divu16

       RSEG CODE:CODE:NOROOT(1)

//   92 UINT16 fast_divu16(UINT16 a, UINT16 B)
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=B)>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 отдельной табличкой обратных значений).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну, продолжим наши игры.

Вроде разорбрался с вашим кодом. Для этого понаписал комментариев. Разбирался на асме..

;//  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. Или ещё как.

Я собственно собираюсь переписать всё на асм. У вас там есть ещё пара мест где хотелось бы подправить. Но это потом. А пока жел-но разобраться с непонятным местом...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

Щас продолжу, случайно не ту кнопку нажал :)

 

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

 

a - делимое;

b - делитель;

с - результат, сначала приближение, потом он корректируется;

e - ошибка, равная b*c-a;

 

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Ну вот в наследство от Си и осталось... Если изначально на асме писать - лучше получится.

Щас продолжу, случайно не ту кнопку нажал :)

 

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

 

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: .

А нужно сравнивать так:

b*c-a?>b

И если условие выполняется - вычитать из c еденицу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приведём (преобразуем) ваш вариант к такому виду:

....

b*c?>a

и если условие выполняется, то вы уменьшаете c (корректируете результат)

 

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

 

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

 

Почему?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Почему?

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

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

 

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

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

Ну и другие мысли по оптимизации на асме есть. Сделаю - выложу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

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

 

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

 

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

 

Можно.

 

Это считатель:

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 скорректировать.

 

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

 

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

.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. Соптимизировал кое-какие вычисления. См. текст.
;
;  На АВР проверил конечно не всё варианты делимое+делитель. Проверял
; алгоритм на компьютере (там проверил всё), а на АВР с компьютерного
; Си переносил вручную. Надо сказать, что с некоторых пор совершенно
; не использую Си на АВР. Забыл как дурной сон. Поэтому м.б. не
; выполнил все Си-шные соглашения. Но если вы мне их напомните - могу
; подкорректировать код.

Комментарии внутри. В конце.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Поэтому м.б. не

; выполнил все Си-шные соглашения. Но если вы мне их напомните - могу

; подкорректировать код.

 

Для IAR:

Вход:

Делимое R17:R16

Делитель R19:R18

Выход:

Частное R17:R16

 

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

 

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

 

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

Вообще меня не столько быстрое делении интересует, как быстрое вычисление арктангенса. Точнее быстрый переход от декартовых координат к полярным (там и деление конечно используется). С вычислением амплитуды проблем нет, а вот угол...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

.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).
; Пока не всё проверил (на компьютере всё). Перепроверю - тогда выложу
; ещё раз.

Подробные комментарии внутри. Внизу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...