8种机械键盘轴体对比
本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?
以MIPS架构的汇编为主进行说明1
2
3
4
5
6
7
8__asm__ __volatile__(
"1: ll %1, %2 # arch_read_lock n"
" bltz %1, 1b n"
" addu %1, 1 n"
"2: sc %1, %0 n"
: "=m" (rw->lock), "=&r" (tmp)
: "m" (rw->lock)
: "memory");基本形式: __asm__ __volatile__("ssnopnt");ssnop: 空指令
汇编扩展以__asm__开头表示后面部分为汇编,__volatile__严禁将此处的汇编语句和其他语句进行重组优化,就是希望gcc不要修改我们这个部分。
构成
主要由四部分构成,之间以:分隔:instruction指令:每条指令之后最好使用"nt"结尾,这样在gcc产生汇编格式比较好.
output operand输出:每个输出部分使用,分隔.”=”作为修饰符,”m”表示存放位置/约束符,()里面表示对应C程序值.
input operand输入:这个部分和输出是一样的.
clobber(装备):这个部分是告诉gcc在这条指令里面我们会修改什么值.
约束符
束符影响的内容包括:whether an operand may be in a register
which kinds of register
whether the operand can be a memory reference
which kinds of address
whether the operand may be an immediate constant
which possible values it may have
约束符包括:p 内存地址
m 内存变量
o 内存变量,但是寻址方式必须是偏移量的,就是基址寻址或者是基址变址寻址.
V 内存变量,但是寻址方式是非偏移量的.
r general寄存器操作数
i 立即操作数,内容在编译器可以确定.
n 立即操作数.有些系统不支持字(双字节)以外的立即操作数,这些操作数以n非i来表示.
E/F 浮点常数
g 内存操作数,整数常数,非genernal寄存器操作数
X 任何操作数
0,1,2…9 和编号指定操作数匹配的操作数束符影响的内容包括
修饰符
修饰符包括:= 操作数是write only的
+ 操作数是可读可写的
& 常用于输出限定符,表示某个寄存器不会被输入所使用.1
2
3
4
5
6
7
8__asm__ __volatile__(
" .set mips3 n"
" ll %0, %1 # atomic_sub n"
" subu %0, %2 n"
" sc %0, %1 n"
" .set mips0 n"
: "=&r" (temp), "+m" (v->counter)
: "Ir" (i));
实例
读取CP0 25号硬件计数寄存器的值1
2
3
4
5
6
7
8
9
10
11int get_counter()
{
int rst;
__asm__ __volatile__(/* mfc0 为取cp0 寄存器值的指令 */
"mfc0%0, $25nt"/* %0 表示列表开始的第一个寄存器 */
: "=r" (rst)/* 告诉gcc 让rst对应一个通用寄存器 */
);
return rst;
}“=r” 中,’=’ 为修饰符,表示该操作对象只写,一般用于修饰输出参数列表中。’r’ 表示任意一个通用寄存器
设置CP0 24号硬件计数寄存器的值1
2
3
4
5
6
7unsigned int op = 0x80f;
__asm__ __volatile__(
"mtc0 %0, $24nt"
:/* 没有输出,列表为空 */
:"r"(op)/* 输入参数,告诉gcc 让op对应一个通用寄存器 */
);
重设后,读取CP0 24号寄存器的值1
2
3
4
5
6
7
8
9unsigned int rst;
unsigned int op = 0x80f;
__asm__ __volatile__(
"mtc0%1, $24nt"/* %1 表示 op 对应的寄存器 */
"mfc0%0, $25nt"/* %0 表示 rst 对应的寄存器 */
: "=r" (rst)
: "r" (op)
);输入输出参数列表,按先后顺序,从0开始编号, %0, %1。
解读开头汇编代码
读写锁中读锁上锁的汇编实现:1
2
3
4
5
6
7
8__asm__ __volatile__(
"1: ll %1, %2 # arch_read_lock n"
" bltz %1, 1b n"
" addu %1, 1 n"
"2: sc %1, %0 n"
: "=m" (rw->lock), "=&r" (tmp)
: "m" (rw->lock)
: "memory");"=m" (rw->lock): 只写内存操作
"=&r" (tmp) : 只写的输出变量,使用一个通用寄存器
"memory": 告诉gcc编译,该指令会修改内存中的值通过原子操作ll,将rw->lock读到tmp
加一:tmp = tmp + 1
通过原子操作sc,将tmp写入rw->lock
barrier
内存屏障:保证前后指令的执行顺序1file: include/linux/compiler-gcc.h
"memory"作为clobber部分另外一个作用是可以让在这条指令之后的指令,告诉gcc应该刷新内存状态.内存的状态可能发生修改,如果需要操作的话,需要重新把内存内容载入寄存器
参考