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

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


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

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



Вот, сижу, мастерю один проектик. Понадобилось сделать Хаффмана. В принципе, ничего сложного, однако работа с битовыми полями - это всегда узкое место процов с отсутствием комманд для обработки данных такого класса. Например, при упаковке по Хаффману необходима процедура, которая запишет в выходной поток n бит значения - вызывается примерно так:
Код
write_bits(huff->codes[val],huff->bits[val])

где первый параметр - код, а второй - собственно его размер в битах. Вот обычно эта функция - write_bits и несет основные затраты по времени выполнения. Почему так происходит - понятно, надо сдвигать входные биты в нужное положение, вычислять новое положение в буфере и т.д.

Посему, сразу кодить не стал, сел - подумал... biggrin.gif

И вот что надумал...

У нас есть аппаратный умножитель, который за 2 такта даст нам сдвинутый сразу в двух направлениях байт - и влево, и вправо. Конечно, в качестве множителя надо использовать маску - 0x01,0x02,...,0x80 и в результате, после выполнения комманды MUL в R0 будем иметь байт данных, сдвинутый влево, в R1 - сдвинутый вправо. Это уже отлично, одной коммандой мы готовим данные для OR с текущим байтом и для занесения следующих данных в накопитель. Однако, соответствующую текущему моменту маску еще надо получить. Она зависит как от текущей битовой позиции в выходном буфере, так и от размера битовых данных. Опять пришлось поразмышлять. Размышления натолкнули на идею хранить битовую позицию в буфере тоже в виде маски:
Код
0x80(биты 7...0 свободны),0x40(бит 7 с данными, биты 6...0 свободны),....,0x01(биты 7...1 с данными, бит 0 свободен)


Если размер символа в битах тоже задать в виде маски, то происходит чудо wink.gif - умножение (аппаратное, конечно) размера на битовую позицию даст новую позицию и она же является необходимым (точнее, в 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 тактов).

Такая функция, кстати, будет полезна тем, кто пишет вывод пропорциональных символов на графический дисплей - вывод можно здорово ускорить.

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


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


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

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



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


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

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


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

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


Можно.

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

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

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


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

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


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


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


Знающий
****

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



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

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

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


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

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

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

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

Комментарии внутри. В конце.
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- Rst7   Необычное использование аппаратного умножителя   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


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

 


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


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