CPU采用流水线设计,跳转时的运行周期更长,则写代码时要尽量减少跳转(跳转断流水线)
流水线设计思想
设计的处理器是五级流水处理器,取指,译码,执行,访存,回写。
(1)取指: 取出指令存储器中的指令,PC值递增,准备取下一条指令。
(2)译码:对指令进行译码,依据译码结果,从32个通用寄存器中取出源操作数,有的 指令要求两个源操作数都是寄存器的值,比如or指令,有的指令要求其中一 个源操作数是指令中立即数的扩展,比如ori指令,所以这里有两个复用器, 用于依据指令要求,确定参与运算的操作数,最终确定的两个操作数会送到执 行阶段。
(3)执行:依据译码阶段送入的源操作数、操作码,进行运算,对于ori指令而言, 就是进行逻辑“或”运算,运算结果传递到访存阶段。
(4)访存:对于ori指令,在访存阶段没有任何操作,直接将运算结果向下传递到回写阶 段。
(5)回写:将运算结果保存到目的寄存器。
在程序指令依次执行的情况下,CPU流水线条数和CPU性能成正比。但当程序指令出现跳转或分支结构时就要另当别论了。比如当指令是jmp (无条件的转移到指令指定的地址去执行从该地址开始的命令)指令时,jmp指令会直接修改指令指针寄存器IP中的指令地址,所以当jmp指令执行时,指令指针寄存器IP中的指令地址会被更新,下一条指令应该是更新后新地址的第一条指令,之前流水线中的指令二到指令十都是无效指令了,这个时候就需要清空流水线中的指令,就意味着清空所有的独立电路以及相关寄存器,这个过程显然流水线越多 耗时越多 代价越大。
示例:
这种代码可读性较强,但跳转较多,程序运行周期较长
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| MyStack segment stack db 256 dup(?) MyStack ends
MyData segment MSG1 db "Hello World!",0dh,0ah,'$' MyData ends
MyCode segment MAIN: mov ax,MyData mov ds,ax mov es,ax
;if(ax>1) bx=0 cmp ax,1 jg IF1 ;ax>1 jmp IF_END1 ;ax<=1 IF1: mov bx,0
IF_END1: mov ax,4c00h int 21h MyCode ends
end MAIN
|
这种代码更简洁,且跳转较少,效率更高,由此可知将if中判断的内容取反可使程序更加高效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| MyStack segment stack db 256 dup(?) MyStack ends
MyData segment MSG1 db "Hello World!",0dh,0ah,'$' MyData ends
MyCode segment MAIN: mov ax,MyData mov ds,ax mov es,ax
;if(ax>1) bx=0 条件取反 cmp ax,1 jle IF_END1 ;小于等于时再跳转 mov bx,0
IF_END1: mov ax,4c00h int 21h MyCode ends
end MAIN
|
双分支常规写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| MyStack segment stack db 256 dup(?) MyStack ends
MyData segment MSG1 db "Hello World!",0dh,0ah,'$' MyData ends
MyCode segment MAIN: mov ax,MyData mov ds,ax mov es,ax
;if(ax>1) bx=0 else bx=1 cmp ax,1 jle IF_ELSE1 ;ax<=1 mov bx,0 ;ax>1 jmp IF_ELSE_END1 IF_ELSE1: mov bx,1 IF_ELSE_END1: mov ax,4c00h int 21h MyCode ends
end MAIN
|
这种写法在判断条件成立时可以不用跳转,但在不成立时需要跳转两次,故建议在判断条件成立的概率较大时采用这种写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| MyStack segment stack db 256 dup(?) MyStack ends
MyData segment MSG1 db "Hello World!",0dh,0ah,'$' MyData ends
MyCode segment MAIN: mov ax,MyData mov ds,ax mov es,ax
;if(ax>1) bx=0 else bx=1 cmp ax,1 jle IF_ELSE1 ;ax<=1 mov bx,0 ;ax>1
IF_ELSE_END1 mov ax,4c00h int 21h IF_ELSE1: mov bx,1 jmp IF_ELSE_END1 MyCode ends
end MAIN
|
多分支
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| MyStack segment stack db 256 dup(?) MyStack ends
MyData segment MSG1 db "Hello World!",0dh,0ah,'$' MyData ends
MyCode segment MAIN: mov ax,MyData mov ds,ax mov es,ax
;if(ax>1) bx=0 else if(ax==-2) bx=1 else bx=2 cmp ax,1 jle IF_ELSE1 ;ax<=1 mov bx,0 ;ax>1 jmp IF_ELSE_END1
IF_ELSE1: cmp ax,-2 jne IF_ELSE2 ;ax!=-2 mov bx,1 ;ax==-2 jmp IF_ELSE_END1 IF_ELSE2: mov bx,2
IF_ELSE_END1 mov ax,4c00h int 21h
MyCode ends
end MAIN
|
switch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| MyStack segment stack db 256 dup(?) MyStack ends
MyData segment MSG1 db "Hello World!",0dh,0ah,'$' MyData ends
MyCode segment MAIN: mov ax,MyData mov ds,ax mov es,ax
;switch 1 2 3 cmp ax,1 je CASE1 cmp ax,2 je CASE2 cmp ax,3 je CASE3 jmp CASE_END1 CASE1: mov bx,1 jmp CASE_END1 CASE2: mov bx,2 jmp CASE_END1 CASE3: mov bx,3 jmp CASE_END1 DEFAULT1: mov bx,4 CASE_END1: mov ax,4c00h int 21h
MyCode ends
end MAIN
|