Rst7 5 14 декабря, 2008 Опубликовано 14 декабря, 2008 · Жалоба я в том смысле что есть выбор, толи в перенос толи sbrs/sbrc. А v -8ми битный ? Дык после &170 уже пофиг :) Вообще, на архитектурах типа арма, мипса, ппц я рекомендую использовать регистровые переменные только размером в регистр, иначе ведро оверхеда обеспечено. Аа... Вы о том как это оттранслирует компилятор ? Ну вменяемый компилятор оттранслирует это в пять команд плюс переход. Просто выражение со сдвигом в другую сторону не может быть обработано бесплатным сдвигом операнда в арм-режиме. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 23 января, 2009 Опубликовано 23 января, 2009 · Жалоба Ну, продолжим наши игры. На этот раз под руки попало деление. 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 отдельной табличкой обратных значений). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
galjoen 0 27 января, 2009 Опубликовано 27 января, 2009 · Жалоба Ну, продолжим наши игры. Вроде разорбрался с вашим кодом. Для этого понаписал комментариев. Разбирался на асме.. ;// 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. Или ещё как. Я собственно собираюсь переписать всё на асм. У вас там есть ещё пара мест где хотелось бы подправить. Но это потом. А пока жел-но разобраться с непонятным местом... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 27 января, 2009 Опубликовано 27 января, 2009 · Жалоба Я собственно собираюсь переписать всё на асм. Гм. Я разве не на асме код выложил? Для тех, кто в танке - была написана рыба на Си, отлажена в MSVS, затем собрана IAR'ом, и листинг допилен вручную. Щас продолжу, случайно не ту кнопку нажал :) Я не пойму, что Вас смущает? a - делимое; b - делитель; с - результат, сначала приближение, потом он корректируется; e - ошибка, равная b*c-a; Если внести a-=b в выражение ошибки, то это эквивалентно e=b*c-( a - b )=b*c-a+b=b*(c+1)-a; Если ошибка превышает делитель, то корректируем результат (уменьшением). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
galjoen 0 27 января, 2009 Опубликовано 27 января, 2009 · Жалоба Гм. Я разве не на асме код выложил? Для тех, кто в танке - была написана рыба на Си, отлажена в 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 (корректируете результат) Вот так получается? Если так, то это же неверно! Вот это меня и смущает . А нужно сравнивать так: b*c-a?>b И если условие выполняется - вычитать из c еденицу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 27 января, 2009 Опубликовано 27 января, 2009 · Жалоба Приведём (преобразуем) ваш вариант к такому виду: .... b*c?>a и если условие выполняется, то вы уменьшаете c (корректируете результат) Согласен. Переумничал. Дело в том, что изначально там было весьма хитрое последовательное приближение за несколько этапов. Потом убралось, но не целиком. Оттуда и издержки, а совсем не от компилятора Си. Вот так получается? Если так, то это же неверно! Почему? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
galjoen 0 27 января, 2009 Опубликовано 27 января, 2009 · Жалоба Почему? Не совпадает с тем, что в описании. А вообще тут всё зависит от того, нужно-ли округлять результат деления. В том случае получилось с обрезанием. Еще хотелось бы узнать как вы считали таблицу обратных величин. Ну не в ручную же. Выложите код если можно. Это нужно чтобы изменить коррекцию. Чтобы результат корректировался на +1, 0 и -1. Это добавляет всего 3 такта. М.б. удастся ту 1 при ~40000 скорректировать. Ну и другие мысли по оптимизации на асме есть. Сделаю - выложу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 27 января, 2009 Опубликовано 27 января, 2009 · Жалоба Не совпадает с тем, что в описании. Где не совпадает? А вообще тут всё зависит от того, нужно-ли округлять результат деления. В том случае получилось с обрезанием. Операция / в Си не округляет результат. Так что все правильно. Еще хотелось бы узнать как вы считали таблицу обратных величин. Ну не в ручную же. Выложите код если можно. Можно. Это считатель: 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 скорректировать. Не помню, но не получалось. Там значащих битов не хватает. Ну и другие мысли по оптимизации на асме есть. Вы бы не забывали соблюдать соглашения о вызовах сишного компилятора, полезнее будет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
galjoen 0 28 января, 2009 Опубликовано 28 января, 2009 · Жалоба Ну вот, наваял: .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. Соптимизировал кое-какие вычисления. См. текст. ; ; На АВР проверил конечно не всё варианты делимое+делитель. Проверял ; алгоритм на компьютере (там проверил всё), а на АВР с компьютерного ; Си переносил вручную. Надо сказать, что с некоторых пор совершенно ; не использую Си на АВР. Забыл как дурной сон. Поэтому м.б. не ; выполнил все Си-шные соглашения. Но если вы мне их напомните - могу ; подкорректировать код. Комментарии внутри. В конце. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 28 января, 2009 Опубликовано 28 января, 2009 · Жалоба Поэтому м.б. не ; выполнил все Си-шные соглашения. Но если вы мне их напомните - могу ; подкорректировать код. Для IAR: Вход: Делимое R17:R16 Делитель R19:R18 Выход: Частное R17:R16 Можно не сохранять регистры R0...R3,R16...R23,R30,R31. Никаких предустановленных регистров нет. Но на самом деле, по алгоритму - там надо было решать вопрос не коррекцией на +1 и -1, а добавить значащих бит в таблицу обратных величин в диапазоне 0x80-0xFF. Тогда нет необходимости в лишней проверке. Через пару дней положу новый вариант. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
galjoen 0 28 января, 2009 Опубликовано 28 января, 2009 · Жалоба Но на самом деле, по алгоритму - там надо было решать вопрос не коррекцией на +1 и -1, а добавить значащих бит в таблицу обратных величин в диапазоне 0x80-0xFF. Тогда нет необходимости в лишней проверке. Я попробовал что-то подобное промоделировать на компьютере - у меня не получилось. Формулу, по которой таблицы вычисляются, менял. Всё равно результат на еденичку пляшет. Я даже дополнительно сдвигал на 1 разряд налево приведённый делитель (старший бит всё равно всегда 1 равен) - всё равно с ошибками получалсь. Т.е. без коррекции видимо не обойтись... Вообще меня не столько быстрое делении интересует, как быстрое вычисление арктангенса. Точнее быстрый переход от декартовых координат к полярным (там и деление конечно используется). С вычислением амплитуды проблем нет, а вот угол... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
galjoen 0 30 января, 2009 Опубликовано 30 января, 2009 · Жалоба Сделал 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). ; Пока не всё проверил (на компьютере всё). Перепроверю - тогда выложу ; ещё раз. Подробные комментарии внутри. Внизу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться