#assembly #bit-manipulation #bit-fields #riscv
#сборка #манипулирование битами #битовые поля #riscv
Вопрос:
В регистре x5 хранится 0x00C0_C000, в регистре x6 хранится 0x0000_C0000. В это время вы хотите извлечь значение бита [15: 8] из регистра x5 и поместить его в бит [31: 16] регистра x6, . Для этого выполните ассемблерный код RISC-V. Однако другие биты x5 и x6 не должны меняться.
Замените бит x6 [31: 16] на 8 бит [15:8] в регистре x5, но выровняйте 8 бит с младшим битом бита [31: 16].
Я подумал, что мне следует использовать slli
и srli
для извлечения бита. Но при их использовании изменяется другой бит x5 и x6. Как я могу извлечь биты, не изменяя другие биты?
Комментарии:
1.
0x0000_C0000
имеет 9 шестнадцатеричных цифр, 36 бит, если все эти нули действительно присутствуют. Я предполагаю, что вы имели в виду какое-то другое значение. В любом случае, вы подумали, как бы вы это сделали на C? Или просто посмотрите на вывод компилятора C для структуры с элементами битового поля? Вы, конечно, можете перейти в другой регистр, напримерunsigned tmp = x6 >> 16;
Ответ №1:
Что вы хотите сделать, так это: очистить верхнюю часть x6, если он не уверен, что он все время равен 0. Вы можете сделать это с помощью маски :
li x28,0xffff
and x6,x6,x28
или
slli x6,x6,16
srli x6,x6,16
Поскольку вы не можете изменить x5, вам необходимо использовать другой регистр tmp:
mv x28,x5
получите 8 из битов [15:8] и поместите их в [31:16]
srli x28,x28,8
andi x28,x28,0xff
slli x28,x28,16
и, наконец, вы выполняете или, чтобы поместить эти биты в x6:
or x6,x6,x29
Попробуйте также взглянуть на https://raw.githubusercontent.com/riscv/riscv-bitmanip/master/bitmanip-0.90.pdf . Расширение RISC-V Bitmanip может быть интересным, если оно поддерживается.
Ответ №2:
Я бы предложил следующее решение, я использую 0x00debc00 для упрощения просмотра: для RV64I
lui a1,0xDEB # loads 0x00deb of 0x00debc00
li a2,0xC00 # loads 0xc00 of 0x00debc00
add a1,a1,a2 # stick together 0x00deb c00 = 0x00debc00
slli a3,a1,48 # took 0x00de"bc"00 and moves to left corner to clean unnecessary bits
srli a4,a3,48 # move "bc" back into 0xbc00
xor a1,a1,a4 # use 0xbc00 for masking initial 0x00debc00 and get 0x00de0000
srli a3,a3,32 # move 0xbc from left corner of $a3 to it's place 0x0000bc00
add a1,a1,a3 # concatenate it all - voila! 0xbcde0000
может быть, проще, но я пока не волшебник)
Для RV32I вам просто нужно меньше смещаться влево:
lui a1,0xDEB
li a2,0xC00
add a1,a1,a2
slli a3,a1,16
srli a4,a3,16
xor a1,a1,a4
#srli a3,a3,32 no need to move back its already in it's place
add a1,a1,a3
Извините за «английский».
Комментарии:
1. Вам не нужен отдельный lui / li, просто используйте
li a1, 0x00debc00
.li
это псевдо-инструкция, которая будет собираться сlui
addi
(или только с одним или другим, если одна часть равна нулю). Или, если вы хотите сделать это вручную,lui a1,0xDEB
/addi a1, a1, 0xc00
(Но обратите внимание, чтоaddi a1, a1, 0xc00
это не поддается кодированию: 12-разрядное поле immediate расширено до ширины регистра, но 12-разрядное0xc00
имеет свой верхний бит; посмотрите на вывод дизассемблированияli a1, 0x00debc00
, чтобы увидеть, что происходит: увеличьте верхнюю часть на 1 докомпенсировать.)2. я знаю об addi, поэтому я им не пользуюсь. Спасибо за совет, теперь я буду стараться лучше.
3. Хорошо, верно, потерял представление о том, куда я шел с этим комментарием. Я должен был просто сказать
li a2,0xC00
, что сам по себе уже принимает 2 инструкции самостоятельно (потому что он не вписывается в расширенный 12-битный знак), так что вы могли бы просто сделатьli a1, 0x00debc00
. Более простой способ сделать то же самое. Также, вероятно, полезно отделить эту настройку ввода от извлечения битового поля хотя бы пустой строкой, чтобы было ясно, какая часть вводится, а какая часть является фактическим ответом.