Как я могу извлечь биты в ассемблерном коде Risc v.

#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 . Более простой способ сделать то же самое. Также, вероятно, полезно отделить эту настройку ввода от извлечения битового поля хотя бы пустой строкой, чтобы было ясно, какая часть вводится, а какая часть является фактическим ответом.