计算机的基本概念
快速的向用户返回计算结果是编写一个成功的软件中的关键部分.
操作系统是用户程序和硬件的接口,它提供许多服务和管理功能.其中,最重要的功能有:1)处理基本输入输出操作;2)分配存储空间和内存;3)为多个程序同时使用计算机提供支持.
系统软件提供公共服务,包括操作系统,编译器,汇编器; 编译器:将高级语言语句翻译成汇编语言语句的程序.
任何计算机的底层硬件都执行着同样的基本功能:输入数据,输出数据,处理数据和存储数据. 计算机的五个经典组成部分是输入,输出,存储器,数据通路以及控制器,后两个我们有时合称为处理器.
有些设备即向计算机提供输入也接受输出,例如:网络和硬盘.
光电式鼠标取代机电式鼠标再次例证了一个普遍现象:电子设备成本的下降和可靠性的提高促使电子方案取代旧的机电方案.
动态随机存储器(DRAM):集成电路式存储器,可以随机访问任何单元;
高速缓存(cache:一块小容量高速存储器,作为大容量存储器的缓冲区.高速缓存使用了不同的内存技术—静态随机存储器(SRAM).SRAM更快但集成度低,因此也就比DRAM更贵些.
内存(memory):正在运行着的程序以及其所需的数据所驻留的存储介质; 易失性存储器:持续供电才能保存数据的存储设备,如DRAM. 内存是易失性存储器.
摩尔定律:晶体管容量没18~24个月就会翻一倍.
硬件设计中的四个基本准则:1)简单源自规整;2)越少越快;3)加快执行常用操作;4)好的设计需要合适的折衷.
当前的计算机构造基于两个关键性原则:1)指令以数据形式表示;2)和数据一样,程序存储在存储器中,并且可以读写.
CPU与指令集(Instruction Set) 1. 什么是CPU ?
电脑的核心!CPU (Central Process Unit)中央处理器 2. CPU的主要工作是什么? 执行一串指令.
3. 指令:CPU能执行的最基本的操作单元 譬如说:两个整数相加、相减 4. 不同的CPU=>指令集不同。
5. 某个特定CPU所实现的指令集称为指令集结构Instruction Set Architecture (ISA).
a) 例: Intel 80x86 (Pentium 4), IBM/Motorola PowerPC (Macintosh), ARM, Intel IA64
RISC思想(精减指令集)
指令集更小,更简单, 从而能有效构建更快硬件. 由软件通过组合简单运算来完成复杂运算.
为什么MIPS,而不是 Intel的X86?
1.MIPS简单,漂亮。不希望大家被一些细节所困扰(只见树木,不见森林);
2.MIPS广泛应用于嵌入式系统,x86很少应用嵌入式系统, 而嵌入式计算机比PCs机多很多; 3.中国芯?龙芯I代, II代(95%MIPS),获得MIPS授权.
*寄存器registers
与高级语言不同(如C或Java), 汇编语言不能使用变量 为什么呢? 让硬件简单一些
汇编语言的操作数是寄存器registers
寄存器位于计算机硬件的某个特殊位置,数量有限 操作只能在寄存器上进行! MIPS寄存器数量:32个 为什么?
越小(少?)越快——Smaller is faster 优点:
由于寄存器在硬件中, 其访问速度非常快(10亿分之一秒——1 billionth of a second) 缺点:
由于寄存器在硬件中, 其数量有上限——32个 变量多于32个怎么办?
放在核心硬件外面,用的时候拿进来 效率问题
如果不是太多:仔细编写代码来高效使用寄存器 A=3 B=4 C=A+B D=A-B E=C*D F=C/D 使用6个 A=3 B=4 C=A+B D=A-B A=C*D B=C/D 使用4个 A=3 B=4 C=A+B A=C-B A=C-B B=C/A A=C/A 使用3个 每个MIPS寄存器是 32位宽
在MIPS中我们将32位组织在一起,称为字word 寄存器编号:0 到 31
每个寄存器可通过编号和名字来指定 通过编号指定:
$0, $1, $2, ? $30, $31
C语言(其他大多数高级语言也一样)中,变量首先要声明并给定一个类型 例如:
int fahr, celsius; char a, b, c, d, e;
每个变量只能表示其所声明的类型的值 (不能混用及比较int型和char型变量).
在汇编语言中, 寄存器没有类型; 运算(符)决定如何处理寄存器,即运算(符)确定寄存器内容的数据类型.
*例1: a = b + c + d - e;(注意理解) add $t0, $s1, $s2 # temp = b + c add $t0, $t0, $s3 # temp = temp + d sub $s0, $t0, $s4 # a = temp-e
例2: f = (g + h) - (i + j); add $t0,$s1,$s2 # temp = g + h add $t1,$s3,$s4 # temp = i + j sub $s0,$t0,$t1 # f=(g+h)-(i+j)
MIPS汇编语言中: 寄存器=变量
一行一条指令 (简单操作)
C 变量: $s0 - $s7,对应寄存器16~23;
临时变量(temporary): $t0 - $t7,对应寄存器8~15; Zero: $zero
立即数:数值常数
代码中经常出现,因此有专门的指令. 加立即数指令(Add Immediate): addi $s0,$s1,10 (in MIPS) f = g + 10 (in C)
这里MIPS寄存器 $s0,$s1对应于C变量f,g 语法和add指令类似
区别:最后一个参数是数,而不是寄存器 register *没有减立即数
C变量映射到寄存器,但寄存器有限 超过32个元素的数组怎么办?
一般把这种数据结构放在内存memory中
MIPS算术指令仅能对寄存器操作,不能直接操作内存. 数据传送指令 在寄存器和内存之间传送数据: 内存到寄存器;寄存器到内存
*指定内存地址:
寄存器:包含指向内存的指针
数值偏移量offset (以字节为单位) 内存地址为这两个值的和 *例:8($t0)
内存地址为:$t0的值+8(字节)
Load 指令语法(Instruction Syntax): 1 2,3(4)
1是指令名字(operation name)
2是接收值的寄存器(register that will receive value) 3数值偏移量(单位:字节)numerical offset in bytes
4包含指向内存指针的寄存器(register containing pointer to memory) MIPS 指令名字(Instruction Name):
lw (意即Load Word, 故每次装入32位即一个字) *
例: lw $t0,12($s0)
该指令取出$s0中的指针, 加上12, 然后从计算的和所指的位置的内存中取得值,放到$t0中.
$s0 称为 基寄存器base register 12 称为 偏移offset
偏移通常用于访问结构体或数组的元素: 基寄存器指向结构体或数组的起始位置(注意偏移量必须是常数 (即在编译时已知)).
*sw (即Store Word, 每次存储32位或一个字) 例: sw $t0,12($s0)
该指令将$s0中的指针加上12,得到内存地址,然后把寄存器$t0中的值存储到该内存地址中
*lw和sw一个是取出,一个是存储,注意区分
重要概念: 寄存器可以保存任意32-位数值. 该值可以是 对于 add $t2,$t1,$t0 $t0和$t1中一般为数值 而对于 lw $t2,0($t0) $t0中一般为指针 不要混用!
内存中的每个字都有地址, 这和数组中的下标类似
早年的计算机对内存的编号方法类似于 C 对数组的编号: Memory[0], Memory[1], Memory[2], ?
计算机既要访问 8-位 字节 也要访问字 (4 bytes/word)
现代计算机按字节编址, (即,“字节寻址”) 因此相临两个32-位(4 byte)字的地址差别为 4. Memory[0], Memory[4], Memory[8], ?
*lw 如何确定C变量A[5]的偏移量? A[5] 4x5=20 : byte v. word 手工编译以下语句: g = h + A[5];
g: $s1, h: $s2, $s3: A 的基地址
首先将数据从内存传到寄存器:
lw $t0,20($s3) # $t0 gets A[5] 将20与$s3相加来选定择A[5], 放到 $t0中 然后将结果和h相加,并放到g中 add $s1,$s2,$t0 # $s1 = h+A[5]
*缺陷:经常会忘记,对于计算机的操作单位“字”序列,但在机器编址是字节。故两个相临的字之间地址不是差一个。
很多汇编程序员常犯的错误是,取下一个地址时,简单加1。
另外, 谨记对于 lw 和 sw, 基址和偏移量之和必须是4的倍数 (即需要 字对齐alignment)
注:Aligned:对齐的.
法则:寄存器 PK 内存
如果变量数比寄存器个数还多,怎么办? 1.编译器试图把最常用的变量放到寄存器中 2.不是很常用的变量放到内存中: spilling
为什么不把所有变量都放到内存中呢? 1.Smaller is faster:寄存器比内存快 2.寄存器能力更强:
MIPS一个算术指令就可以完成,读两个数,进行运算,并写结果 MIPS一个数据传送指令只能读或写一个操作数,而无运算
C (MIPS也一样) 提供了语句标号Labels 来支持 “goto” 跳转到代码所在处.