Навигатор
My RISC-V home
Индекс
Инструкции
расширения A
(атомарные операции)
RV32A
RV64A
|
Инструкции AMOSWAP.W и AMOSWAP.D
AMOSWAP.W rd, rs2, (rs1)
AMOSWAP.D rd, rs2, (rs1)
Набор команд: RV32A – с .W и
RV64A – с .D
Формат: R
Операнды: rs1 – адрес памяти, rd и rs2 – регистры
Действие: rd := (rs1), (rs1) := rs2 (атомарно!), т.е. обменять местами значение в памяти по адресу в rs1 со значением в rs2; гарантируется, что на время выполнения инструкции все прочие обращения к памяти будут заблокированы
Примечания
- AMO = Atomic Memory Operation.
- Специальная команда для синхронизации потоков (организации критической секции). Альтернативой является использование пары инструкций
LR и SC .
- Формально, видимо, ради общности, можно назначить в качестве rd регистр x0, но это лишено логического смысла: алгоритм синхронизации должен проверять считанное значение (см. пример 3). Есть ощущение, что занесение «старого» значения в rd вообще введено только ради данной инструкции, а во всех остальных команд с AMO является практически бесполезным «рудиментом».
- В 64-битном режиме в команде с .W при записи в регистр rd в 32-битном слове расширяется знак.
- Адрес памяти в rs1 должен быть выровнен в соответствии с разрядностью операнда (т.е. делиться без остатка на 4 для .W и на 8 для .D). При нарушении возникает исключительная ситуация (exception). Предполагается возможность работы с невыровненными данными при наличии специального расширения Zam (пока не детализированного).
- Общие правила для задания значений битов aq (acquire – захват) и rl (release – освобождение) остаются в силе, но логика синхронизации требует перед критической секцией писать
AMOSWAP.W/D.AQ , а в конце ее - AMOSWAP.W/D.RL (см. примеры).
- Инструкции с .W отличаются от таковых с .D значением в поле func3 (2 или 3 соответственно). Остальной код совпадает.
Пример 1
Инструкция AMOSWAP.W x31, x7, (x11) атомарным образом читает в x31 содержимое 32-битного слова по адресу из x11 , а вместо него записывает 32 младших бита регистра x7 .
Код инструкции содержит следующие поля:
поле | разрядность | содержимое | примечание |
func5 | 5 битов | 00001 |
всегда |
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 |
всегда |
Итоговый код
00001 00 00111 01011 010 11111 01011112 = 08 75 AF AF16
Пример 2
Инструкции AMOSWAP.W.AQ x31, x7, (x11) и AMOSWAP.W.RL x31, x7, (x11) имеют коды 0C 75 AF AF и 0A 75 AF AF соответственно.
Пример 3
Создание критической секции с помощью команды AMOSWAP (общепринято, что 1 – секция занята, 0 – свободна; в a0 задан адрес памяти).
li t0, 1 # константа занятия секции
again: lw t1, (a0) # проверка, свободна ли секция
bnez t1, again # повторять, если нет
amoswap.w.aq t1, t0, (a0) # пытаемся занять секцию
bnez t1, again # повторять, если не удалось (кто-то уже успел занять!)
# ...
# Критическая секция (выполняется только одним потоком)
# ...
amoswap.w.rl x0, x0, (a0) # освобождаем (заносим 0)
Забавно, что в некоторых источниках команды lw и bnez опускают. Логика работы при этом полностью сохраняется, но есть нюанс: вариант цикла ожидания с lw не применяет AMO. Возможно, это меньше «тормозит» общее выполнение?
|