|
Необычное использование аппаратного умножителя |
|
|
|
May 7 2008, 17:14
|

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

|
Вот, сижу, мастерю один проектик. Понадобилось сделать Хаффмана. В принципе, ничего сложного, однако работа с битовыми полями - это всегда узкое место процов с отсутствием комманд для обработки данных такого класса. Например, при упаковке по Хаффману необходима процедура, которая запишет в выходной поток n бит значения - вызывается примерно так: Код write_bits(huff->codes[val],huff->bits[val]) где первый параметр - код, а второй - собственно его размер в битах. Вот обычно эта функция - write_bits и несет основные затраты по времени выполнения. Почему так происходит - понятно, надо сдвигать входные биты в нужное положение, вычислять новое положение в буфере и т.д. Посему, сразу кодить не стал, сел - подумал... И вот что надумал... У нас есть аппаратный умножитель, который за 2 такта даст нам сдвинутый сразу в двух направлениях байт - и влево, и вправо. Конечно, в качестве множителя надо использовать маску - 0x01,0x02,...,0x80 и в результате, после выполнения комманды MUL в R0 будем иметь байт данных, сдвинутый влево, в R1 - сдвинутый вправо. Это уже отлично, одной коммандой мы готовим данные для OR с текущим байтом и для занесения следующих данных в накопитель. Однако, соответствующую текущему моменту маску еще надо получить. Она зависит как от текущей битовой позиции в выходном буфере, так и от размера битовых данных. Опять пришлось поразмышлять. Размышления натолкнули на идею хранить битовую позицию в буфере тоже в виде маски: Код 0x80(биты 7...0 свободны),0x40(бит 7 с данными, биты 6...0 свободны),....,0x01(биты 7...1 с данными, бит 0 свободен) Если размер символа в битах тоже задать в виде маски, то происходит чудо  - умножение (аппаратное, конечно) размера на битовую позицию даст новую позицию и она же является необходимым (точнее, в 2 раза меньше) множителем для сдвига символа. Причем, в зависимости, от того, какой байт результата, старший или младший, не равен 0 - то это и есть выбор двух альтернатив - новый символ требует перехода через границу байта или не требует. Осталась маленькая тонкость, что новая позиция как множитель данных в 2 раза меньше (т.е. сдвинута вправо). Можно конечно сдвинуть при помощи LSL, но лучше использовать тот факт, что FMUL - есть Rs*Rd<<1, это поможет в оптимизации. Букаф много (могут ниасилить), посему код: Код //Кластеризация вручную, при необходимости изготавливается нормальная структура struct { char bitstream_byte; char bitstream_bit; char *bitstream; };
//Инициализация битового потока //p - указатель на первый байт выходного буфера void init_bitstream(char *p) { bitstream_byte=0; bitstream_bit=0x80; bitstream=p; }
//Финализация потока - слив неслитого //bp - указатель на первый байт выходного буфера (для расчета размера) //на выходе - размер потока в байтах unsigned int finish_bitstream(char *bp) { char *p=bitstream; if (bitstream_bit!=0x80) *p++=bitstream_byte; return p-bp; }
void write_bits_by_mask(char sym, char msb);
//Запись n бит из символа sym, необходимо, чтобы неиспользуемые биты равнялись 0 void write_n_bits(char sym, char n) { //Генерация обратной маски static __flash const char mask[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; write_bits_by_mask(sym,mask[n-1]); }
//Записать в битовый поток биты из sym //Биты записываются от 0 до бита, определенного установленным битом в msb в обратном порядке //msb=0x80 sym=0000000a //msb=0x40 sym=000000ab //msb=0x20 sym=00000abc //msb=0x10 sym=0000abcd //msb=0x08 sym=000abcde //msb=0x04 sym=00abcdef //msb=0x02 sym=0abcdefg //msb=0x01 sym=abcdefgh //Запись идет от 7 к 0, например запись символов 000abcde, 0000xyzt будет лежать в байтах как //[abcdexyz][t.......] //Если есть возможность хранить msb, лучше применять эту функцию, меньше накладных расходов void write_bits_by_mask(char sym, char msb) { char b=bitstream_byte; char m=bitstream_bit; char *p=bitstream; //--> Если есть возможнось, эта часть инлайнится во внешний цикл unsigned short i; i=__multiply_unsigned(m,msb); //ih - множитель для sym, чтобы согласовать положение if (i>>8) { //Требуется сдвиг влево m=i>>8; i=__fractional_multiply_unsigned(sym,m); b|=i; } else { //Требуется сдвиг вправо m=i; i=__fractional_multiply_unsigned(sym,m); b|=i>>8; *p++=b; b=i; } //<-- Конец части для инлайна bitstream=p; bitstream_byte=b; bitstream_bit=m; } Компилятор - IAR 5.10 Ну и листинг, который особо радует глаз (приведу только внутренности функции write_bits_by_mask) Код 54 void write_bits_by_mask(char sym, char msb) \ write_bits_by_mask: 55 { \ 00000000 2F5B MOV R21, R27 \ 00000002 2F6A MOV R22, R26 \ 00000004 2F20 MOV R18, R16 56 char b=bitstream_byte; \ 00000006 .... LDI R30, LOW(_A_bitstream_byte) \ 00000008 .... LDI R31, (_A_bitstream_byte) >> 8 \ 0000000A 8130 LD R19, Z 57 char m=bitstream_bit; 58 char *p=bitstream; \ 0000000C 81A2 LDD R26, Z+2 \ 0000000E 81B3 LDD R27, Z+3 \ 00000010 8101 LDD R16, Z+1 59 //--> Если есть возможнось, эта часть инлайнится во внешний цикл 60 unsigned short i; 61 i=__multiply_unsigned(m,msb); //ih - множитель для sym, чтобы согласовать положение \ 00000012 9F01 MUL R16, R17 62 if (i>>8) \ 00000014 2011 TST R1 \ 00000016 F021 BREQ ??write_bits_by_mask_0 63 { 64 //Требуется сдвиг влево 65 m=i>>8; \ 00000018 2D41 MOV R20, R1 66 i=__fractional_multiply_unsigned(sym,m); 67 b|=i; \ 0000001A 032C FMUL R18, R20 \ 0000001C 2930 OR R19, R0 \ 0000001E C005 RJMP ??write_bits_by_mask_1 68 } 69 else 70 { 71 //Требуется сдвиг вправо 72 m=i; \ ??write_bits_by_mask_0: \ 00000020 2D40 MOV R20, R0 73 i=__fractional_multiply_unsigned(sym,m); \ 00000022 032C FMUL R18, R20 74 b|=i>>8; 75 *p++=b; \ 00000024 2931 OR R19, R1 \ 00000026 933D ST X+, R19 76 b=i; \ 00000028 2D30 MOV R19, R0 77 } 78 //<-- Конец части для инлайна 79 bitstream=p; \ ??write_bits_by_mask_1: \ 0000002A 83A2 STD Z+2, R26 \ 0000002C 83B3 STD Z+3, R27 80 bitstream_byte=b; \ 0000002E 8330 ST Z, R19 81 bitstream_bit=m; \ 00000030 8341 STD Z+1, R20 82 } \ 00000032 2FA6 MOV R26, R22 \ 00000034 2FB5 MOV R27, R21 \ 00000036 9508 RET Конечно, если есть возможность, выжимку кода необходимо вставлять прямо в цикл генерации символов, чтобы меньше оверхеда было на загрузку/выгрузку. В этом случае добавление битового поля будет занимать 10 или 12 тактов, в зависимости от того, происходит переход через границу байта или не происходит. Опять же, если есть возможность, надо хранить размеры символов в виде масок, а не в обычном виде - это уберет оверхед на функцию write_n_bits (7 тактов). Такая функция, кстати, будет полезна тем, кто пишет вывод пропорциональных символов на графический дисплей - вывод можно здорово ускорить. Вообще, подобный подход можно использовать там, где необходимо организовывать сдвиги на произвольное количество бит.
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
 |
Ответов
|
Jan 27 2009, 14:58
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 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 скорректировать. Не помню, но не получалось. Там значащих битов не хватает. Цитата Ну и другие мысли по оптимизации на асме есть. Вы бы не забывали соблюдать соглашения о вызовах сишного компилятора, полезнее будет.
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Jan 28 2009, 05:25
|
Знающий
   
Группа: Свой
Сообщений: 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. Соптимизировал кое-какие вычисления. См. текст. ; ; На АВР проверил конечно не всё варианты делимое+делитель. Проверял ; алгоритм на компьютере (там проверил всё), а на АВР с компьютерного ; Си переносил вручную. Надо сказать, что с некоторых пор совершенно ; не использую Си на АВР. Забыл как дурной сон. Поэтому м.б. не ; выполнил все Си-шные соглашения. Но если вы мне их напомните - могу ; подкорректировать код.
Комментарии внутри. В конце.
|
|
|
|
Сообщений в этой теме
Rst7 Необычное использование аппаратного умножителя May 7 2008, 17:14 SasaVitebsk Цитата(Rst7 @ May 7 2008, 21:14) Вообще, ... May 7 2008, 18:22 Rst7 ЦитатаПравда если есть возможность организовывать ... May 7 2008, 18:50 galjoen А вот мне только-что мысль пришла - ещё не проверя... May 7 2008, 19:49  Rst7 Цитата(galjoen @ May 7 2008, 22:49) А вот... May 8 2008, 07:24 vet galjoen
2*255 = 510 = 0x01FE, 7 бит=1
3*255 = 765 ... May 8 2008, 04:22 vet сдвигами четность все равно шустрее выйдет:
Код M... May 8 2008, 07:54 Rst7 Цитата(vet @ May 8 2008, 09:54) сдвигами ... Dec 13 2008, 21:05  singlskv Цитата(Rst7 @ Dec 14 2008, 00:05) Случайн... Dec 14 2008, 19:11   Rst7 Цитата(singlskv @ Dec 14 2008, 21:11) ИМХ... Dec 14 2008, 19:57    singlskv Цитата(Rst7 @ Dec 14 2008, 22:57) Да вооб... Dec 14 2008, 20:08     Rst7 Цитата(singlskv @ Dec 14 2008, 22:08) я в... Dec 14 2008, 21:38 Rst7 Цитатасдвигами четность все равно шустрее выйдет:
... May 8 2008, 08:00 _Pasha Америки не открою, и особой экзотики в использован... May 29 2008, 19:41 ae_ Как быть, когда результат (zL:zH)/yH > 255? про... May 31 2008, 11:55 _Pasha Цитата(ae_ @ May 31 2008, 14:55) Как быть... May 31 2008, 18:57 Rst7 Ну, продолжим наши игры. На этот раз под руки попа... Jan 23 2009, 15:21 galjoen Цитата(Rst7 @ Jan 23 2009, 18:21) Ну, про... Jan 27 2009, 10:38 Rst7 ЦитатаЯ собственно собираюсь переписать всё на асм... Jan 27 2009, 11:22 galjoen Цитата(Rst7 @ Jan 27 2009, 14:22) Гм. Я р... Jan 27 2009, 12:11 Rst7 ЦитатаПриведём (преобразуем) ваш вариант к такому ... Jan 27 2009, 12:51 galjoen Цитата(Rst7 @ Jan 27 2009, 15:51) Почему?... Jan 27 2009, 14:41 Rst7 ЦитатаПоэтому м.б. не
; выполнил все Си-шные согла... Jan 28 2009, 06:57 galjoen Цитата(Rst7 @ Jan 28 2009, 09:57) Но на с... Jan 28 2009, 15:53  galjoen Сделал 50-ти тактовую версию беззнакового деления ... Jan 30 2009, 10:06
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|