10.31 计算机组成原理82页代码

65 阅读1分钟
/*

		a = b + e

		b = b + f

	*/

	lw $t1, 0($t0)      // load b
	lw $t2, 4($t0)		// load e
	add $t3, $t1, $t2	// a = b + e
	sw t3, 12($t0) 		// save a to memory 12
	lw $t4, 8($t0)		// load fabs
	add $t5, $t1, $t4	// b = b + f
	sw  $t5, 16($t0)	// save b to memory 16

	/*

	可以看见 add 指令都需要先取得数才行,所以 lw 指令会阻塞。
	此时如果将指令重排一下就可以提高性能,如下

	*/

	lw $t1, 0($t0)      // load b
	lw $t2, 4($t0)		// load e
	lw $t4, 8($t0)		// load f
	add $t3, $t1, $t2	// a = b + e
	sw t3, 12($t0) 		// save a to memory 12
	add $t5, $t1, $t4	// b = b + f
	sw  $t5, 16($t0)	// save b to memory 16

	/*

	这里等到 b和e 取的时候,

	继续取f,在取 f 的过程中,

	然后再将 a = b + e 的操作,

	可以减小阻塞情况的发生,前面的代码是说必须取得 b, e才能执行后续指令,

	而此时 b 和 e 很可能在执行 f 的过程中就取完了

	*/

===========================================================
/* 目标:实现原子交换,即 $s4 中的值和内存中锁单元的值交换,锁单元的基址保存在 $s1 中 */

again: 	addi $t0, $zero, 1   // $t0 = 0 + $s4,此时 $t0 中保存了 $s4 的值 1
	ll 	$t1, 0($s1)   		 // $t1 = Memory[$s1 + 0],此时 $t1 中保存了 $s1 指向的锁单元的值 ?
	sc 	$t0, 0($s1) 		 /* Memory[$s1 + 0] = $t0,当执行成功,此时 $s1 所指向的锁单元的值就是 $s4 的值了,并且将 $t0 的值修改为 1。
							  *			  			   当执行失败,不保存 $s4 的值到锁单元,并且将 $t0 的值修改为 0。
							  */
							  
	beq $t0, $zero, again	 /* if $tp == $zero, jump again; else continue,如果 $t0 为 0,则说明执行失败,应该跳到 again,
							  * 											如果 $t0 为 1,则说明锁单元的值已经是 s4 了,
							  * 											接下来只需要将 s4 中的值改为锁单元的值就行了
							  */
	add $s4, $zero, $t1		 // $s4 = $zero + $t1,前面将锁单元的值放在了 $t1 中,只需要将其赋值到 $s4 即可
	
	
/* 提出思考:按照常理来说交换俩个值使用一个 temp 即可,
 * 但是此时却采用了两个 temp,
 * 这里多出来的 temp0 其实有两个作用:
 * ① 是 sc 执行成功与失败的开关,
 * ② 携带 $s4 的值,便于交换
 * 如果没有 temp0 的话,那么将要修改 $s4 的值作为开关,这样是不可取的