Имеем 32-битное значение abcdabcd abcdabcd abcdabcd abcdabcd, где a,b,c,d = биты 0 или 1. Нужно преобразовать в aaaaaaaa bbbbbbbb cccccccc dddddddd. Интересуют варианты для 32- и 16-битного кода. Делалость это поочередным сдвигом - RCR/RCL с использованием разных регистров. Каки есть ещё варианты? Как это можно сделать наиболее быстро?
Если я вас правильно понял, то есть некий паттерн из 4 бит повторный восемь раз? Тогда взять его и заполнить по нему регистр.
Не, человек, как понимаю, имеет в виду упакованые биты. a0 b0 c0 d0 a1 b1 c1 d1 a2 b2 c2 d2 a3 b3 c3 d3 a4 b4 c4 d4 a5 b5 c5 d5 a6 b6 c6 d6 a7 b7 c7 d7 Путь это хранится здесь: uint32_t x; Делаем раз: x = (x & 0xa5a5a5a5) | ((x & 0x0a0a0a0a) << 3) | ((x & 0x50505050) >> 3); Получаем: a0 a1 c0 c1 b0 b1 d0 d1 a2 a3 c2 c3 b2 b3 d2 d3 a4 a5 c4 c5 b4 b5 d4 d5 a6 a7 c6 c7 b6 b7 d6 d7 Делаем два: x = (x & 0xcc33cc33) | ((x & 0x33003300) >> 4) | ((x & 0x00cc00cc) << 4); Получаем: a0 a1 a2 a3 b0 b1 b2 b3 c0 c1 c2 c3 d0 d1 d2 d3 a4 a5 a6 a7 b4 b5 b6 b7 c4 c5 c6 c7 d4 d5 d6 d7 Делаем три: x = (x & 0xf0f00f0f) | ((x & 0x0f0f0000) >> 8) | ((x & 0x0000f0f0) << 8); Получаем: a0 a1 a2 a3 a4 a5 a6 a7 c0 c1 c2 c3 c4 c5 c6 c7 b0 b1 b2 b3 b4 b5 b6 b7 d0 d1 d2 d3 d4 d5 d6 d7 Ну и последний шаг: x = (x & 0xff0000ff) | ((x & 0x00ff0000) >> 8) | ((x & 0x0000ff00) << 8); Получаем: a0 a1 a2 a3 a4 a5 a6 a7 b0 b1 b2 b3 b4 b5 b6 b7 c0 c1 c2 c3 c4 c5 c6 c7 d0 d1 d2 d3 d4 d5 d6 d7 Должно быть всё ОК, если где-то с масками не налажал.
// DOS, 16-bit code, 286+ CPU Код (ASM): Lodsw ; Mov Bx,Ax Lodsw ; Mov Cx,Ax mov ax,bx shr bx,3 xor bx,ax and bx,0x0a0a xor ax,bx shl bx,3 xor bx,ax mov ax,cx shr cx,3 xor cx,ax and cx,0x0a0a xor ax,cx shl cx,3 xor cx,ax mov ax,bx shr bx,10 xor bx,ax and bx,0x0033 xor ax,bx shl bx,10 xor bx,ax mov ax,cx shr cx,10 xor cx,ax and cx,0x0033 xor ax,cx shl cx,10 xor cx,ax mov ax,cx shr cx,4 xor cx,bx and cx,0x0f0f xor bx,cx shl cx,4 xor cx,ax На выходе в BX:CX переставленная "как надо" строка.
BMI2 не подойдёт? Код (ASM): ; source in EAX mov ecx,11111111h pext ebx,eax,ecx shrd edx,ebx,8 shl ecx,1 pext ebx,eax,ecx shrd edx,ebx,8 shl ecx,1 pext ebx,eax,ecx shrd edx,ebx,8 shl ecx,1 pext ebx,eax,ecx shrd edx,ebx,8 ; result in EDX
Ну или так (чуток быстрее будет за счёт меньшего кол-ва shrd): Код (ASM): ; source in EAX mov ecx,22222222h pext ebx,eax,ecx shrd edx,ebx,8 shl ecx,1 pext ebx,eax,ecx shrd edx,ebx,8 shl ecx,1 pext ebx,eax,ecx shrd edx,ebx,8 mov ecx,11111111h ; или shr ecx,3, но так дольше pext eax,eax,ecx or eax,edx ; result in EAX
Сдаётся мне, что автор напутал с буквами, и должно быть это так... дано: abcdefgh ijklmnop ABCDEFGH IJKLMNOP надо: aeimAEIM bfjnBFJN cgkoCGKO dhlpDHLP Угадал? p.s. Вообще, вариант с BMI2 можно ещё ускорить, если использовать esi, edi (возможно и ebp) и перетасовать используемые регистры, чтобы распараллелить работу. Но учтите, что это всё НЕ будет работать на компах более 5-летней давности (да и на более свежих, наверное, тоже не на каждом).
Возможна ошибка в формулировке задания но мой вариант для 16-битного кода 100% правильный. Вот неоптимизированный вариант. Здесь смысл сдвига должен быть понятнее. Код (ASM): Lodsw // AX <- DS:[SI] Rol Al,1 // AL to BX:CX Adc Ch,Ch Rol Al,1 Adc Cl,Cl Rol Al,1 Adc Bh,Bh Rol Al,1 Adc Bl,Bl Rol Al,1 Adc Ch,Ch Rol Al,1 Adc Cl,Cl Rol Al,1 Adc Bh,Bh Rol Al,1 Adc Bl,Bl Rol Ah,1 // AH to BX:CX Adc Ch,Ch Rol Ah,1 Adc Cl,Cl Rol Ah,1 Adc Bh,Bh Rol Ah,1 Adc Bl,Bl Rol Ah,1 Adc Ch,Ch Rol Ah,1 Adc Cl,Cl Rol Ah,1 Adc Bh,Bh Rol Ah,1 Adc Bl,Bl Lodsw // AX <- DS:[SI] Rol Al,1 // AL to BX:CX Adc Ch,C Rol Al,1 Adc Cl,Cl Rol Al,1 Adc Bh,Bh Rol Al,1 Adc Bl,Bl Rol Al,1 Adc Ch,Ch Rol Al,1 Adc Cl,Cl Rol Al,1 Adc Bh,Bh Rol Al,1 Adc Bl,Bl Rol Ah,1 // AH to BX:CX Adc Ch,C Rol Ah,1 Adc Cl,Cl Rol Ah,1 Adc Bh,Bh Rol Ah,1 Adc Bl,Bl Rol Ah,1 Adc Ch,Ch Rol Ah,1 Adc Cl,Cl Rol Ah,1 Adc Bh,Bh Rol Ah,1 Adc Bl,Bl // Result in BX:CX В первую очередь мне нужен именно 16-битный алгоритм. В идеале даже 8088/8086+ CPU.
Вот ещё вариант (должен быть быстрее вашего с rol, adc, ибо здесь 28 сдвигов против 32 в вашем коде): Код (ASM): ; source in AX ; dddd mov dx,ax mov cx,ax and dx,0101h and cx,1010h shl dh,2 shr cl,3 shr ch,1 or dx,cx or dl,dh ; cccc mov bx,ax mov cx,ax and bx,0202h and cx,2020h shl bl,3 ror bh,3 shl ch,2 or bx,cx or bl,bh or dl,bl ; bbbb mov bx,ax mov cx,ax and bx,0404h and cx,4040h shr bl,2 rol cl,3 shr ch,3 or bx,cx or bh,bl mov dh,bh ; aaaa mov bx,ax mov cx,ax and bx,0808h and cx,8080h shl bl,1 shr cl,2 shl bh,3 or bx,cx or bh,bl or dh,bh ; result in DX Что-то я не очень понимаю, как из AX (16 бит) получилось BX:CX (32 бита)?
А вот табличный метод (кстати, должен быть быстрее, при этом занимает меньше памяти). Код (ASM): ; source in AX mov si,OFFSET Tbl ; dddd mov bx,ax and bx,0Fh shl bx,1 mov dx,[si+bx] ; cccc shr al,3 and al,not 1 shr dx,1 mov bl,al or dx,[si+bx] ; bbbb mov bl,ah shr dx,1 and bx,0Fh shl bx,1 or dx,[si+bx] ; aaaa shr ah,3 and ah,not 1 shr dx,1 mov bl,ah or dx,[si+bx] ; result in DX Tbl DW 0000h, 0008h, 0080h, 0088h, 0800h, 0808h, 0880h, 0888h, 8000h, 8008h, 8080h, 8088h, 8800h, 8808h, 8880h, 8888h Это вариант с таблицей на 32 байта, но можно сделать и на 512 или даже 1024, будет быстрее.
Вот так лучше всё же: Код (ASM): ; source in AX mov dx,ax and ax,0F0F0h and dx,0F0Fh shr ax,3 shl dx,1 mov cx,ax ; CH:DH:CL:DL xor bx,bx mov si,OFFSET Tbl ; aaaa mov bl,ch mov ax,[si+bx] ; bbbb shl ax,1 mov bl,dh or ax,[si+bx] ; cccc shl ax,1 mov bl,cl or ax,[si+bx] ; dddd shl ax,1 mov bl,dl or ax,[si+bx] ; result in AX Tbl DW 0000h, 0001h, 0010h, 0011h, 0100h, 0101h, 0110h, 0111h, 1000h, 1001h, 1010h, 1011h, 1100h, 1101h, 1110h, 1111h Думаю, это наиболее оптимальный вариант...
Прошу заметить, что AX как основной регистр для операция выбран намеренно, т.к. работа с ним быстрее, чем с другими регистрами (на 8086, по крайней мере). И адресация [si+bx] будет быстрее, чем [Tbl+bx]. p.s. Что ж здесь идущие друг за другом сообщения не объединяются в одно?
18 команд, без дополнительной памяти. Вход - ax, выход - он же. Для вычислений используются ещё два регистра - dx и cx. Код (ASM): mov dx, ax mov cx, ax and dx, 0x3300 and cx, 0x00cc and ax, 0xcc33 shr dx, 6 shl cx, 6 or ax, dx or ax, cx mov dx, ax mov cx, ax and dx, 0x5050 and cx, 0x0a0a and ax, 0xa5a5 shr dx, 3 shl cx, 3 or ax, dx or ax, cx
SadKo, зачёт! Но на 8086 будет 32 инструкции (shr dx,6 развернутся в 6 шт shr dx,1; аналогично shr cx,6 и пр.) Монжо упростить так: Код (ASM): mov dx, ax and dx, 0x33cc and ax, 0xcc33 shl dh, 2 shr dl, 2 or al, dh or ah, dl mov dx, ax mov cx, ax and dx, 0x5050 and cx, 0x0a0a and ax, 0xa5a5 shr dx, 3 shl cx, 3 or ax, dx or ax, cx 16 инструкций (44 байта), а на 8086 будет 22 инструкции (52 байта)