Отправляет email-рассылки с помощью сервиса Sendsay

Assembler - Просто и Эффективно.

  Все выпуски  

Assembler - Просто и Эффективно. Глава #14 - MMX


Assembler

Глава #14 - MMX

  MMX
Технология MMX создана для упрощения и ускорения алгоритмов применяющих однотипные вычисления над несколькими единицами данных. В основном это работа с графикой и звуком.

Технология MMX представлена в виде восьми 64 битных регистров (называемых mm0-mm7) и дополнительном наборе команд для их обработки. Регистры MMX находятся в контексте FPU, но адресуются по номерам, а не относительно вершины стэка. Из - за воздействия MMX на контекст FPU эти блоки одновременно не используются. Очистку контекста FPU после MMX можно произвести командой emms.
Для вычислений с плавающей точкой во время использования MMX можно использовать технологию XMM (SSE), которая появилась позже. XMM также содержит некоторые дополнительные команды для блока MMX. Также, расширение 3DNow! от AMD позволяет производить FP вычисления в регистрах MMX.

MMX существует, начиная с процессоров Pentium MMX, поэтому, на данный момент, практически любой компьютер поддерживает эту технологию. Определить наличие MMX можно по установленному биту #23 в edx после вызова команды cpuid с eax=1.

Дополнительную информацию о MMX можно получить из следующих документов:
с сайта AMD:
-AMD64 Architecture Programmer’s Manual Volume 5: 64-Bit Media and x87 Floating- Point Instructions -> 64-Bit Media Programming
-AMD64 Technology AMD64 Architecture Programmer’s Manual Volume 1: Application Programming -> 64-Bit Media Instruction Reference
с сайта Intel:
IA-32 Intel® Architecture Software Developer’s Manual Volume 1: Basic Architecture -> CHAPTER 9 PROGRAMMING WITH INTEL® MMX™ TECHNOLOGY
   -------------------------------

  SIMD
Основная особенность MMX - это поддержка SIMD (single-instruction, multiple-data) операций, иногда называемых также векторными или упакованными. Большинство команд MMX позволяют одновременно обработать сразу несколько единиц данных. Интерпретация данных регистра MMX зависит от применяемой команды. 64 битный регистр обычно можно воспринимать как:
  • одно учетверенное слово (qword)
  • два двойных слова (dword)
  • четыре слова (word)
  • восемь байт (byte)
    Пример:
    .data
    AnyQword dq 1234567890ABCDEFh
     .code
    ;Поместим в регистр mm0 учетверенное слово AnyQword
    movq mm0,[AnyQword]  ;mm0=1234567890ABCDEFh
    ;осуществим сдвиг вправо, интерпретируя данные в mm0 как 4 слова:
    psrlw mm0,8  ;mm0=0012 0056 0090 00CDh
    ;осуществим сдвиг влево, интерпретируя данные в mm0 как учетверенное слово:
    psllq mm0,12  ;mm0=20056009000CD000h
    Чтобы отобразить содержимое регистров MMX используется команда wf отладчика SoftIce с параметром b, w или d для указания формата.
       -------------------------------

  •   Арифметика с насыщением
    Еще одна важное свойство MMX - это поддержка арифметики с насыщением. В этом случае вместо циклического переполнения результатом становится максимальное или минимальное значение для данного типа, зависящее от размера операнда и знаковый он или нет. Данное свойство очень полезно для работы с цветом.
    Пример:
    mov eax,060708090h
    movd mm3,eax ;mm3=60708090h
    ;прибавим значение регистра mm3 к mm3, интерпретируя как байты с беззнаковым насыщением.
    paddusb mm3,mm3 ;mm3=0C0E0FFFFh
    Как видно из примера, младшие два беззнаковых байта результата приняли свои максимальные значения. Арифметика с насыщением используется для избежания лишних ветвлений алгоритма, что может сильно повысить скорость выполнения, особенно на современных компьютерах.
       -------------------------------

      Команды MMX
    Для использования команд блока MMX, нужно указать компилятору директиву .MMX
    Большинство команд MMX придерживаются следующего формата:
    первая буква "P" обозначает что команда работает с упакованными данными
    Далее идет название команды
    Суффикс B, W, D или Q обозначает размер обрабатываемых единиц данных команды.
    Символ "S" перед суффиксом обозначает знаковое насыщение, "US" - беззнаковое

    Большинство команд имеют два операнда, обычно второй может быть не только регистром MMX, а еще и переменной в памяти.

    Ниже представлен список команд MMX с кратким пояснением. Здесь указан только набор команд первоначальной реализации MMX. Для изучения последующих команд, появившихся с блоком XMM, и более детального описания этих, с.м документы, указанные вначале главы.
    emmsПодготовка FPU контекста для выполнения FPU операций после MMX
    movdЗапись младшего двойного слова из регистра MMX в регистр общего назначения или ячейку памяти. При записи в регистр MMX старшее двойное слово обнуляется.
    movqЗапись qword из регистра MMX в память и из памяти в регистр MMX
    pack[ssdw,sswb,uswb] Преобразование (с насыщением) размеров единиц данных из первого операнда в младшее двойное слово результата, из второго - в старшее. С.м пример ниже.
    padd[b, w, d, s[b,w], us[b,w]]Сложение элементов данных регистра. возможно насыщение.
    pand[n]Операция AND/ AND и XOR над данными регистра
    pcmpeq[b, w, d]сравнить элементы данных, если равны установить биты элемента в единицы, если нет то в нули.
    pcmpgt[b, w, d]сравнить элементы данных, если соответствующий элемент данных первого операнда больше соответствующего второго, то установить его в единицы, если нет то в нули.
    pmaddwdПеремножить каждое соответствующее слово операндов, сложить результат умножения старших двух слов и записать в старшее двойное слово результата, младших - в младшее.
    pmul[h,l]wЗнаковое умножение упакованных слов. Возврат старших/младших слов результата.
    porОперация OR
    psll[w, d, q]Логический сдвиг влево упакованных единиц данных
    psra[w, d]Арифметический сдвиг вправо
    psrl[w, d, q]Логический сдвиг вправо
    psub[b, w, d, s[b, w], us[b,w]]Вычитание упакованных элементов. Возможно насыщение.
    punpck[h,l][bw,wd,dq]Распаковка старших/младших двойных слов операндов. С.м ниже.
    pxorОперация XOR
    Данные команды не влияют на регистр флагов.

    Для преобразования типов данных существует группа команд, осуществляющих их распаковку и упаковку. Это команды PACK* PUNPCK*.
    Пример распаковки:
    .data
    AnyQword1 dq 0011223344556677h
    AnyQword2 dq 8899AABBCCDDEEFFh
     .code
    movq mm0,[AnyQword1]
    movq mm1,mm0
    movq mm2,[AnyQword2]
    ;распаковка младших 4 байт регистров mm0 и mm2 в слова
    punpcklbw mm0,mm2 ;CC44 DD55 EE66 FF77
    ;распаковка старших двух слов регистров mm1 и mm2 в двойные слова
    punpckhwd mm1,mm2 ;8899 0011 AABB 2233
    pxor mm3,mm3
    ;распаковка младших четырех байт регистров mm2 и mm3 в слова
    punpcklbw mm2,mm3 ;00CC 00DD 00EE 00FF
    Т.е распаковка - это чередование элементов данных старшего или младшего двойного слова первого операнда со вторым. При распаковке чаще всего один из операндов обнулен.

    Пример (Умножим каждый байт двойного слова AnyDword на 4 с беззнаковым насыщением):
    .data
    AnyDword dd 20304050h
     .code
    pxor mm0,mm0  ;mm0=0
    movd mm1,[AnyDword]  ;mm1=20304050h
    punpcklbw mm1,mm0 ;mm1 = 0020 0030 0040 0050
    ;умножим на 4 каждое слово (используя сдвиг)
    psllw mm1,2  ;mm1= 0080 00C0 0100 0140
    ;упакуем резултат (из слов в байты) с беззнаковым насыщением.
    packuswb mm1,mm0  ;mm1=80C0FFFF
    movd [AnyDword],mm1  ;AnyDword=80C0FFFF
    При упаковке каждый элемент первого операнда преобразуется до указанного типа и помещается в младшее двойное слово результата, а второго - в старшее.
       -------------------------------

      Пример
    Данный пример - наипростейшая реализация фильтра "Edge Detect". Фильтр применяется к .bmp файлу, имя которого указано в переменной SrcImageName, создавая новое изображения (имя указано в NewImageName). Программа работает следующим образом:

    Загрузим .bmp файл SrcImageName при помощи ф-ции LoadImage.
    При помощи ф-ции GetDIBits получим данные о цветах пикселей изображения в выделенную память (адрес находится в переменной pImgBits). 3 младших байта каждого двойного слова обозначают уровень красного, зеленого и синего цвета.
    Организуем цикл, проверяющий каждую точку изображения (уровни ее цвета обозначены как r g b): Если хоть одно уравнение верно, то данная точка - граница объекта (помечаются в результате другим цветом):
    (r-r1)*(r-r1)+(g-g1)*(g-g1)+(b-b1)*(bb1)>EdgeDist*EdgeDist
    (r-r2)*(r-r2)+(g-g2)*(g-g2)+(b-b2)*(bb2)>EdgeDist*EdgeDist
    Где EdgeDist - число, определяющее уровень допустимой границы, r1 g1 b1 - уровень цвета прилегающего сбоку пикселя, а r2 g2 b2 - сверху или снизу.
    Запишем результат в файл NewImageName. Формат .bmp файла (вкратце) следующий:
    Заполненная структура BmpHeader, после BITMAPINFO (с палитрой - если есть), после массив данных, обозначающих цвет каждой точки (строки выровнены на dword и перевернутый если biHeight>0).

    Как всегда, программа содержит недостаточно проверок на ошибки, чтобы не усложнять пример. Также, данный пример показывает только использование команд MMX, а не работу с графикой под Windows, которая здесь очень проста и годится только для наглядного примера.
    .586
     .mmx
     .model flat,stdcall
    ;используем inc и lib файлы из пакета masm32 (с.м главу #8)
    include c:\masm32\include\windows.inc
    include c:\masm32\include\kernel32.inc
    includelib c:\masm32\lib\kernel32.lib
    include c:\masm32\include\user32.inc
    includelib c:\masm32\lib\user32.lib
    include c:\masm32\include\gdi32.inc
    includelib c:\masm32\lib\gdi32.lib
    
    ;Константа, обозначающая допустимую границу фильтра
    EdgeDist=30
    
     .data
    SrcImageName db 'c:\windows\winnt.bmp',0  ;изображение - источник
    NewImageName db "c:\output.bmp",0   ;изображение - результат
    ErrLdImage db 'Error loading image',0
    ErrFileWrite db "Can't write to file",0
    CmpDword dd EdgeDist*EdgeDist
    AndDword dd 0FFFFFFh
    ;данные две структуры запишутся в .bmp файл как заголовок
    BmpHeader BITMAPFILEHEADER <"MB",0,0,0,size BITMAPFILEHEADER + size BITMAPINFOHEADER>
    ImgHdr BITMAPINFO <>
    pImgBits dd ? ;указатель на массив пикселей изображения
     .code
    start:
     invoke CreateCompatibleDC,0
     xchg eax,ebx
    ;загрузим изображение - источник
     invoke LoadImageA,0,offset SrcImageName,IMAGE_BITMAP,0,0,LR_LOADFROMFILE
     xchg eax,edi
     or edi,edi
     jnz ImgLoaded
     invoke MessageBox,0,offset ErrLdImage,offset SrcImageName,MB_OK or MB_ICONERROR
     invoke ExitProcess,0
    ImgLoaded:
    
     mov esi,offset ImgHdr
     assume esi:ptr BITMAPINFOHEADER
    ;получим информацию о изображении (ширину и высоту)
     invoke GetDIBits,ebx,edi,0,0,0,esi,DIB_RGB_COLORS
     mov eax,[esi].biHeight
    IsTopDown:
     neg eax
     or eax,eax
     js IsTopDown
     mov [esi].biHeight,eax
     mul [esi].biWidth
     shl eax,2
    ;выделим память для массива пикселей изображения, размером (высота*ширина*4)
     invoke LocalAlloc,LMEM_FIXED,eax
     mov [pImgBits],eax
     mov [esi].biBitCount,32
     mov [esi].biCompression,0
    ;получим пиксели изображения в выделенную память.
     invoke GetDIBits,ebx,edi,0,[esi].biHeight,eax,esi,DIB_RGB_COLORS
     mov [esi].biSizeImage,0
     invoke DeleteObject,edi
     invoke DeleteDC,ebx
    
     dec dword ptr [esi].biHeight
    
     mov ebx,[esi].biWidth
     lea ecx,[ebx-1]
     mov edx,[esi].biHeight
     assume esi:nothing
     mov esi,[pImgBits]
    
     movd mm7,[CmpDword]
     movd mm6,[AndDword]
     pxor mm0,mm0
    ;цикл проверки изображения на границы. esi - адрес массива с цветами изображения
     align 10h
    CopyNextLine:
    CopyNextPixel:
     movd mm1,dword ptr [esi]  ;mm1= 0rgb
     punpcklbw mm1,mm0   ;mm1=0000 00r 00g 00b
     movq mm2,mm1    ;mm2=mm1
    
    ;Макрос, проверяющий на границу EdgeDist.
    CalcDiff macro ResultReg,SrcAddr
     movd mm3,SrcAddr  ;mm3=0r12g12b12
     punpcklbw mm3,mm0  ;mm3=0000 00r12 00g12 00b12
     psubw ResultReg,mm3  ;mm1|2=0000 r-r12 g-g12 b-b12
     pmaddwd ResultReg,ResultReg ;mm1|2= dw#1=0+(r-r12)*(r-r12)
      ;dw#0=(g-g12)*(g-g12)+(b-b12)*(b-b12)
     movq mm3,ResultReg  ;mm3=mm1|2
     psrlq mm3,32   ;mm3=0 (r-r12)*(r-r12)
    
     paddd ResultReg,mm3 ;mm1|2(dw#0)=(r-r12)*(r-r12)+(g-g12)*(g-g12)+(b-b12)*(b-b12)
     pcmpgtd ResultReg,mm7
     ;младший dword mm1|2 =FFFFFFFFh если найдена граница, 0 если нет.
    endm
    
     CalcDiff mm1,dword ptr [esi+4]
     CalcDiff mm2,dword ptr [esi+ebx*4]
     por mm1,mm2  ;mm1=mm1 or mm2
     pandn mm1,mm6  ;mm1=(mm1 and 0FFFFFFh) xor 0FFFFFFh
     movd dword ptr [esi],mm1 ;запишем результат
    
     add esi,4
     dec ecx
     jnz CopyNextPixel
     mov dword ptr [esi],ecx
     lea ecx,[ebx-1]
     add esi,4
     dec edx
     jnz CopyNextLine
    
    ;Подготовим контекст FPU для операций FPU.
    ;Если этого не сделать то при дальнейшем использовании FPU может возникнуть ошибка.
     emms
    
    ;создадим файл - новое изображение.
     invoke _lcreat,offset NewImageName,0
     mov edi,eax
     inc eax
     jnz NormalCreated
    FileWriteError:
     invoke _lclose,edi
     invoke MessageBox,0,offset ErrFileWrite,offset NewImageName,MB_OK or MB_ICONERROR
     invoke ExitProcess,0
    NormalCreated:
    ;запишем заголовки .bmp изображения
     invoke _lwrite,edi,offset BmpHeader,size BITMAPFILEHEADER+size BITMAPINFOHEADER
     cmp eax,size BITMAPFILEHEADER+size BITMAPINFOHEADER
     jnz FileWriteError
     mov eax,[ImgHdr.bmiHeader.biWidth]
     mul [ImgHdr.bmiHeader.biHeight]
     lea ebx,[eax*4]
    ;запишем данные о цветах пикселей изображения
     invoke _lwrite,edi,[pImgBits],ebx
     cmp eax,ebx
     jnz FileWriteError
     invoke _lclose,edi
     invoke ExitProcess,0
    end start

       -------------------------------

    Сайт рассылки перемещен на asm-x86.by.ru.
    Теперь вы можете легко задать вопрос относительно любой из размещенных статей в журнале http://asm-x86.livejournal.com/profile
    Содержание дальнейших выпусков зависит от вас. Будут разъясняться те темы, которые непонятны большинству читателей.
    Присылайте свои вопросы и предложения по адресу: asm-x86@by.ru .
       -------------------------------


    Автор рассылки Владимир Пронин. Любое коммерческое использование материалов рассылки без ведома и прямого согласия автора запрещено.
    Письма присланные автору рассылки могут быть опубликованы целиком или частично без предварительного уведомления. Если вы не хотите, чтобы ваше письмо было опубликовано укажите это в начале письма.
    Перепечатка материалов разрешена только с непосредственной ссылкой на asm-x86.by.ru


    В избранное