标签:
Qemu采用TCG(Tiny code generator)翻译引擎,TCG的作用也和一个真正的编译器后端一样,主要负责分析、优化Target代码以及生成Host代码。所谓“微指令”,是qemu用于指令翻译的中间表示,进行指令翻译时,qemu首先将每条target的指令分解为多条类似RISC指令的微指令,这个阶段可以进行一些优化,如微指令的生命周期分析(liveness analysis)等,之后微指令在后端由host机的指令实现。
CPU指令一般都是很规则的,每条指令的长度、操作码、操作数都有固定格式,根据前面就可推导出后面,微指令的设计也采用了类似的规则,每条微指令都有固定的输入、输出与常数操作数(除了call指令有不定数目的输入输出操作数)。另外,与cpu指令对应,微指令也设计了数据传送、算术运算、逻辑运算、程序控制几大类指令。
下面对Qemu提供的微指令类型进行分析归纳:
1. 微指令基本格式
微指令在tcg/tcg-opc.h中定义。定义格式为
DEF(name, oargs,iargs, cargs, flags)
其中name为微指令名,oargs为输出操作数个数,iargs为输入操作数个数,cargs为常数操作数个数,flags表示 为特殊指令的一些标志,如flags取值为TCG_OPF_SIDE_EFFECTS表示该指令会影响内存中内容。
例如,一条add指令微操作定义为:
DEF(add_i32, 1,2, 0, 0)
其含义为:
add_i32 t0, t1, t2 (t0 <- t1 + t2), i32表示target机为32位机。t0为输出操作数,t1、t2为两个输入操作数,没有常数操作数。
2.qemu预定义的微指令
cpu指令对应,微指令也设计了数据传送、算术运算、逻辑运算、程序控制几大类指令。且针对32位和64位的目标机,qemu分别定义了一套微指令,即[opname]_i32、[opname]_i64,由于目前csky的cpu为32位,因此我们先只关注32位的微指令。
1) 数据传送
2) 算术运算
3) 逻辑运算
4) 程序控制
3. 微指令类型归纳
| 指令名 | 指令格式 | 指令含义 | 
| /* predefined ops */ | ||
| end | end | end of tb | 
| nop | 
 | 
 | 
| nop1 | 
 | 
 | 
| nop2 | 
 | 
 | 
| nop3 | 
 | 
 | 
| nopn | 
 | 
 | 
| discard | discard t0 | mark t0 as dead variable | 
| set_label | set_label $label | Define label ‘label‘ at the current program point. | 
| call | call <ret><params> ptr | call function ‘ptr‘ (pointer type) | 
| jmp | jmp t0 | Absolute jump to address t0 (pointer type) | 
| br | br $label | Jump to label. | 
| mov_i32 | mov_i32 t0, t1 | t0 = t1 | 
| movi_i32 | mov_i32 t0, $(constant) | t0 = $(constant) | 
| setcond_i32 | setcond_i32 cond, dest, t1, t2 | dest = (t1 cond t2) | 
| brcond_i32 | brcond_i32 cond, t0, t1, label | Conditional jump if t0 cond t1 is true | 
| 
 | ||
| /* load/store */ | ||
| ld8u_i32 | ld8u_i32 t0, t1, offset | t0 = read(t1 + offset) Load 8, 16, 32 or 64 bits with or without sign extension from host memory. offset must be a constant. | 
| ld8s_i32 | ld8s_i32 t0, t1, offset | |
| ld16u_i32 | ld16u_i32 t0, t1, offset | |
| ld16s_i32 | ld16s_i32 t0, t1, offset | |
| ld_i32 | ld_i32 t0, t1, offset | |
| st8_i32 | st8_i32 t0, t1, offset | write(t0, t1 + offset) Write 8, 16, 32 or 64 bits to host memory. | 
| st16_i32 | st16_i32 t0, t1, offset | |
| st_i32 | st_i32 t0, t1, offset | |
| 
 | ||
| /* arith */ | ||
| add_i32 | add_i32 t0, t1, t2 | t0=t1+t2 | 
| sub_i32 | sub_i32 t0, t1, t2 | t0=t1-t2 | 
| mul_i32 | mul_i32 t0, t1, t2 | t0=t1*t2 | 
| div_i32 | div_i32 t0, t1, t2 | t0=t1/t2 (signed) | 
| divu_i32 | divu_i32 t0, t1, t2 | t0=t1/t2 (unsigned) | 
| rem_i32 | rem_i32 t0, t1, t2 | t0=t1%t2 (signed) | 
| remu_i32 | remu_i32 t0, t1, t2 | t0=t1%t2 (unsigned) | 
| and_i32 | and_i32 t0, t1, t2 | t0=t1&t2 | 
| or_i32 | or_i32 t0, t1, t2 | t0=t1|t2 | 
| xor_i32 | xor_i32 t0, t1, t2 | t0=t1^t2 | 
| 
 | ||
| /* shifts/rotates */ | ||
| shl_i32 | shl_i32 t0, t1, t2 | t0=t1 << t2 | 
| shr_i32 | shr_i32 t0, t1, t2 | t0=t1 >> t2 | 
| sar_i32 | sar_i32 t0, t1, t2 | t0=t1 >> t2 (signed) | 
| rotl_i32 | rotl_i32 t0, t1, t2 | Rotation of t2 bits to the left | 
| rotr_i32 | rotr_i32 t0, t1, t2 | Rotation of t2 bits to the right | 
| deposit_i32 | deposit_i32 dest, t1, t2, pos, len | LEN - the length of the bitfield POS - the position of the first bit, counting from the LSB For example, pos=8, len=4: dest = (t1 & ~0x0f00) | ((t2 << 8) & 0x0f00) | 
| ext8s_i32 | ext8s_i32 t0, t1 | 8 bit sign extension | 
| ext8u_i32 | ext8u_i32 t0, t1 | 8 bit zero extension | 
| ext16s_i32 | ext16s_i32 t0, t1 | 16 bit sign extension | 
| ext16u_i32 | ext16u_i32 t0, t1 | 16 bit zero extension | 
| bswap16_i32 | bswap16_i32 t0, t1 | 16 bit byte swap on a 32 bit value | 
| bswap32_i32 | bswap32_i32 t0, t1 | 32 bit byte swap on a 32 bit value | 
| not_i32 | not_i32 t0, t1 | t0=~t1 | 
| neg_i32 | neg_i32 t0, t1 | t0=-t1 | 
| andc_i32 | andc_i32 t0, t1, t2 | t0=t1&~t2 | 
| orc_i32 | orc_i32 t0, t1, t2 | t0=t1|~t2 | 
| eqv_i32 | eqv_i32 t0, t1, t2 | t0=~(t1^t2), or equivalently, t0=t1^~t2 | 
| nand_i32 | nand_i32 t0, t1, t2 | t0=~(t1&t2) | 
| nor_i32 | nor_i32 t0, t1, t2 | t0=~(t1|t2) | 
| 
 | ||
| /* QEMU specific */ | ||
| debug_insn_start | debug_insn_start $pc | write the PC of the corresponding QEMU CPU instruction | 
| exit_tb | exit_tb t0 | Exit the current TB and return the value t0 (word type) | 
| goto_tb | goto_tb index | Exit the current TB and jump to the TB index ‘index‘ (constant) if the current TB was linked to this TB. Otherwise execute the next instructions. | 
| 
 | 
 | 
 | 
| qemu_ld8u | qemu_ld8u t0, t1, flags | Load data at the QEMU CPU address t1 into t0. t1 has the QEMU CPU address type. ‘flags‘ contains the QEMU memory index (selects user or kernel access) for example. | 
| qemu_ld8s | qemu_ld8s t0, t1, flags | |
| qemu_ld16u | qemu_ld16u t0, t1, flags | |
| qemu_ld16s | qemu_ld16s t0, t1, flags | |
| qemu_ld32 | qemu_ld32 t0, t1, flags | |
| qemu_ld32u | qemu_ld32u t0, t1, flags | |
| qemu_ld32s | qemu_ld32s t0, t1, flags | |
| qemu_ld64 | qemu_ld64 t0, t1, flags | |
| 
 | 
 | 
 | 
| qemu_st8 | qemu_st8 t0, t1, flags | Store the data t0 at the QEMU CPU Address t1. t1 has the QEMU CPU address type. ‘flags‘ contains the QEMU memory index (selects user or kernel access) for example. | 
标签:
原文地址:http://blog.csdn.net/lulu901130/article/details/45716883