Использование Assembler’a. Фишка 1

от автора

Решил по мере сил делиться примерами использования ассемблера в своих проектах. Я не буду рассуждать о том, надо это или не надо конкретно в вашем проекте. Просто показываю, а выводы делаете вы сами.

Вводные данные

В данный момент заканчиваю разработку цифрового синтезатора Kaleidoscope собственного авторства. Синтезатор работает на базе микроконтроллера stm32f446, процессор которого имеет ряд очень интересных и полезных инструкций, описанных в Programming Manual.

Вывод всей информации осуществляется на черно-белый OLED дисплей с разрешением 128×64 точки. Или 8 строк по 128 байтов. На экране нельзя задавать яркость отдельного пикселя, можно писать только байтами.

Особенность дисплея в том, что нижнему пикселю байта соответствует наиболее значащий бит записываемого байта. Вы пишете в память 0b11001010, а на экране рисуется

низ.11001010.верх

Мне необходимо вывести бинарно кодированное число 8 бит на шкалу из 24 вертикальных пикселей.

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

Параметр MSK - это и есть 8-бит паттерн

Параметр MSK — это и есть 8-бит паттерн

Например, число 0xAE = 0b10101110 должно отображаться на 24 пикселя экрана так:

низ .00011111.11110001.11000111. верх

Для начала я получаю маску 24 битов, которые надо нарисовать.

uint32_t t = 0; uint8_t  b_num = 0xAE;  for(int i = 0; i < 8; i++) {   if(b_num & (1<<i) != 0)   {     t |= 0b111 << (i*3);     }   // 0xAE = 0b10101110 -> t = 0b00000000111000111000111111111000 }  // отобразить надо // низ .00011111.11110001.11000111. верх

Значит в память дисплея надо написать 3 байта, с учетом того, что нижнему пикселю соответствует наиболее значащий бит байта. То есть надо разбить одно число на байты, а потом развернуть в каждом из них биты.

0b00011111. Биты [0:7] числа t в обратном порядке.

0b11110001. Биты [8:15] числа t в обратном порядке.

0b11000111. Биты [16:23] числа t в обратном порядке.

Конечно, всё это можно сделать софтверно.

Через циклы.

// t уже хранит в себе маску битов uint8_t b[3]; for(int j = 0; j < 3; j++) {   uint8_t b, bj;   b  = 0;   bj = (t>>(8*j)) & 0xFF;    //сдвигаем, а потом маскируем нижние 8 бит    for(int i = 0; i < 8; i++)   {     if(0!= (1<<i) & bj)       b |= 1<<(7-i);   }   b[j] = b; }

Через LUT на 256 значений, где каждому i будет соответствовать его число с обратным порядком битов.

// t уже хранит в себе маску битов uint8_t b[3]; for(int j = 0; j < 3; j++) {   uint8_t bj;   bj = (t>>(8*j)) & 0xFF;    //сдвигаем, а потом маскируем нижние 8 бит    b[j] = rev_bit_lut_256[bj];    //лут хранит заранее вычисленные числа с обратным порядком битов }

А можно воспользоваться специальными ассемблерными инструкциями процессора:

RBIT — берет слово и возвращает за один цикл процессора число с обратным порядком битов.

REV — берет слово и возвращает за один цикл процессора слово с обратным порядком байтов.

.global rev_bit_word .text rev_bit_word: //r0 - address of x     uint32 //r1 - address of res uint32  ldrr2, [r0] // load x to r2 register   rbit    r2, r2      // reversed bit  order   rev     r2, r2      // reversed byte order str     r2, [r1]    // store x to destination address  bx     lr          // return

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

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

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

Кстати, на борту процессора также есть инструкции, позволяющие производить умножение-бабочку за один цикл для полуслов. Но это уже совсем другая история.


ссылка на оригинал статьи https://habr.com/ru/articles/870180/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *