Я не могу придумать другого способа сделать это просто потому, что вам нужно и поменять местами, и сравнить, чтобы определить, разрешено ли вам продолжать. Если у вас нет команды сравнения и обмена, вам придется реализовать ее с помощью циклического обмена и сравнения, что-то вроде:
; Emulate atomic add/sub with atomic swap.
; On entry:
; r0 contains address of variable
; r1 contains value to add or subtract.
mutex: defw 0 ; mutual exclusion semaphore (0=free, 1=busy).
chng: push r2 ; save variables.
ld r2,1 ; claiming value.
spin: swap r2,(mutex) ; atomic swap (sounds like a good name for a band).
bnz spin ; loop until you have it.
add (r0),r1 ; emulated atomic change.
swap r2,(mutex) ; free mutex for everyone else.
pop r2 ; restore registers.
ret
Это действительно глупо, если вы делаете это во многих местах своего кода. Я часто обнаруживал, что изоляция кода «klunky» от функции (как выше) делает его гораздо менее хитрым, поскольку в результате вы получаете множество сегментов кода, которые выглядят намного проще:
myvar: defw 0
: : : : :
ld r0,myvar
ld r1,1 ; increment
call chng
или, если вы хотите, чтобы ваш код был еще проще, предоставьте отдельные функции incr
и decr
:
; Emulate atomic incr/decr with emulated atomic change.
; On entry:
; r0 contains address of variable
incr: push r1 ; save registers.
ld r1,1 ; increment.
call chng ; do it.
pop r1 ; restore registers.
ret
decr: push r1 ; save registers.
ld r1,-1 ; decrement.
call chng ; do it.
pop r1 ; restore registers.
ret
Тогда ваши кодовые последовательности станут:
ld r0,myvar
call incr
или, если вы можете делать макросы, еще проще:
atincr: defm ; do this once to define macro
ld r0,&1
call incr
endm
atincr myvar ; do this in your code, as much as you like.