Навигатор
My RISC-V home
Индекс
Инструкции
расширения A
(атомарные операции)
RV32A
RV64A
|
Инструкции SC.W и SC.D
SC.W rd, rs2, (rs1)
SC.D rd, rs2, (rs1)
Набор команд: RV32A – с .W и
RV64A – с .D
Формат: R
Операнды: rs1 – адрес памяти, rd и rs2 – регистры
Действие: если зарезервированные ранее командой LR данные не были изменены, то rd := 0, (rs1) := rs2; иначе rd < > 0 и запись в память отменяется
Примечания
- SC = Store-Conditional.
- Работает «в паре» с
LR . Параметры LR и SC (адрес, число байтов) должны совпадать.
- В 64-битном режиме в команде с .W при записи в регистр rd в 32-битном слове расширяется знак.
- Адрес памяти в rs1 должен быть выровнен в соответствии с разрядностью операнда (т.е. делиться без остатка на 4 для .W и на 8 для .D). При нарушении возникает исключительная ситуация (exception). Возможность работы с невыровненными данными не предполагается.
- Общие правила для задания значений битов aq (acquire – захват) и rl (release – освобождение) такие же, как и в остальных инструкциях расширения A. Но во всех (немногочисленных) имеющихся примерах используются только нулевые значения битов aq и rl – см. пример 2.
- Инструкции с .W отличаются от таковых с .D значением в поле func3 (2 или 3 соответственно). Остальной код совпадает.
Пример 1
Инструкция SC.W x31, x7, (x11) выполняет следующие действия. Сначала проверяет сохранность всех 4 байтов данных в ОЗУ с адреса из x11 (точнее говоря, факт отсутствия записи в них после LR ). Затем устанавливает x31 = 0 при отсутствии изменений и ненулевое значение в противном случае. Только когда проверка была успешной и x31 = 0, содержимое младших 4 байт из x7 записывается в память, начиная с адреса из x11 .
Код инструкции содержит следующие поля:
поле | разрядность | содержимое | примечание |
func5 | 5 битов | 00011 |
всегда |
aq | 1 бит | 0 | aq = 0 |
rl | 1 бит | 0 | rl = 0 |
rs2 | 5 битов | 00111 | x7 |
rs1 | 5 битов | 01011 | x11 |
func3 | 3 бита | 010 |
всегда |
rd | 5 битов | 11111 | x31 |
opcode | 7 битов | 0101111 |
всегда |
Итоговый код
00011 00 00111 01011 010 11111 01011112 = 18 75 AF AF16
Пример 2
Атомарная организация занятия ресурса с помощью пары команд LR/SC (как обычно, значение 1 – это занято, 0 – свободно; предполагается, что в x20 находится адрес памяти).
addi x12, x0, 1 # константу занятости 1 заносим в x12
again: lr.d x10, (x20) # считываем признак занятости для проверки
bne x10, x0, again # повторить, если кем-то уже занято (x10<>0)
sc.d x11, x12, (x20) # пытаемся занять
bne x11, x0, again # повторить, если не удалось (x11<>0)
# ...
sd x0, 0(x20) # освобождаем (заносим 0)
Пример 3
В известной книге Дэвида Паттерсона и Джона Хеннесси “Computer Organization and Design. The Hardware/Software Interface: RISC-V Edition” кроме приведенного выше примера 2 дана еще одна рекомендация по использованию пары LR/SC : между ними можно поместить несколько команд атомарной модификации прочитанного из памяти содержимого. Команд не должно быть много и допускаются не все инструкции, но так можно делать. Например, упомянуты примитивы синхронизации atomic compare and swap (CAS, близко к AMOSWAP ) и atomic fetch-and-increment (полный аналог AMOADD ).
Насколько я понимаю, следуя этой идее, атомарное увеличение счетчика можно написать так.
again: lr.d x6, (x10) # считываем значение из памяти
addi x6, x6, 1 # +1
sc.d x7, x6, (x10) # пытаемся записать результат
bne x7, x0, again # повторять, если не удалось (x7<>0)
Хотя, конечно, вариант с AMOADD выглядит проще и привлекательнее.
|