冯诺依曼结构计算机的功能通过执行程序实现,程序的执行过程就算所包含的指令的执行过程。
指令(instruction)是用0和1表示的一串0/1序列,用来指示CPU完成一个特定的原子操作。
指令(instruction)在计算机科学中,指的是机器语言中的命令,用于告诉计算机执行某个特定的操作或动作。这些指令通常由0和1组成的二进制序列表示,这些序列是CPU能够识别和执行的。
关于原子操作(atomic operation),它是一个在执行过程中不可分割的操作。也就是说,这个操作要么完全执行,要么完全不执行,不存在只执行一部分的情况。原子操作在多线程环境中尤为重要,因为它可以确保数据的一致性和完整性。
以计算机中的加法操作为例,可以将其视为一个指令,这个指令告诉CPU完成一个特定的原子操作。具体来说,假设我们有两个数值A和B,我们需要将它们相加。这个加法操作就是一个原子操作,因为在执行过程中,它不能被其他操作打断。CPU会完整地读取A和B的值,完成加法运算,然后将结果存储到指定的内存位置。这个过程中,不会有其他操作插入进来改变A或B的值,从而保证了加法运算的准确性和一致性。
值得注意的是,虽然单个的加法操作是原子的,但在更复杂的操作序列中,可能需要使用特定的同步机制来确保整个序列的原子性。例如,在多线程环境中,如果一个线程正在读取A和B的值进行加法运算,而另一个线程同时修改了A或B的值,那么最终的结果可能是错误的。为了避免这种情况,可能需要使用锁或其他同步机制来确保加法操作的原子性。
总的来说,指令是计算机执行操作的基础,而原子操作则是确保这些操作在多线程环境中正确执行的关键。
例如,取数指令(load)从主存单元中取出数据存放到通用寄存器中;存数指令(store)将通用寄存器的内容写入主存单元;加法指令(add)将两个通用寄存器内容相加后送入结果寄存器;传送指令(mov)将一个通用寄存器的内容送到另一个通用寄存器;如此等等。
指令通常被划分为若干个字段,有操作码、地址码等字段。操作码字段指出指令额操作类型,如取数、存数、加、减、传送、跳转等;地址码字段指出指令所处理的操作数的地址,如寄存器编号、主存单元编号等。
【例】假设图1.1所示模型机字长为8位;有4个通用寄存器r0~r3,编号分别位0~3;有16个主存单元,编号为0~15。每个主存单元和CPU中的ALU、通用寄存器、IR、MDR的宽度都是8位,PC和MAR的宽度都是4位;连接CPU和主存的总线中有4位地址线、8位数据线和若干位控制线(包括读/写命令线)。该模型机采用8位定长指令字,即每条指令有8位。指令格式有R型和M型两种,如图所示:
根据其描述,其冯诺依曼结构对应的模型图 (我自己画的)如下:
op为操作码字段,R型指令的op为0000时是寄存器间传送mov操作,为0001时是寄存器间相加add操作,M型指令的op为1110时是取数操作load,为1111时是存数操作store,rs和rt为通用寄存器编号,addr为主存单元地址。
R[r]表示编号为r的通用寄存器中的内容,M[addr]表示地址为addr的主存单元内容,“←”表示从右向左传送数据。比如,指令1110 0110,1110是取数load,其要取的数据在主存中的地址为0110,取得的数据要存放在第0号通用寄存器,则R[0]←M[0110],也就表示将0110B(末尾写B表示二进制)=6号主存单元中的内容取到0号寄存器;指令0001 0001,0001是add操作,它是R型指令,也就是后面那个0001要拆开看成00和01,也就是将1号寄存器和0号寄存器的内容相加并保存到0号寄存器,即R[0]←R[0]+R[1],表示将0号和1号寄存器内容相加的结果送0号寄存器。
若在该模型机上实现z=x+y,x和y分别存放在主存5号和6号单元中,结果z存放在7号单元中,则相应程序在主存单元中的初始内容为(字长8位,主存地址就8位):
其对应的结构图是:
主存地址为0时:
1110 0110是M型指令,1110是取数,从主存地址0110取数据存到0号通用寄存器,也就是R[0]←M[0110B]即R[0]←M[6];
主存地址为1时:
0000 0100是R型指令,0000是寄存器间传送mov操作,也就是R[01]←R[01]+R[00],将0号通用寄存器和1号通用寄存器的数据相加保存到1号通用寄存器中;
主存地址为2时:
1110 0101是M型指令,1110是取数,从主存地址0101取数据存到0号通用寄存器,也就是R[0]←M[0101B]即R[0]←M[5];
主存地址为3时:
0001 0001是R型指令,0001是add操作,即R[00]←R[00]+R[01]亦即R[0]←R[0]+R[1]
主存地址为4时:
1111 0111是M型指令,1111是存数,是将0号通用寄存器的数据存入0111B即7号主存单元中M[0111B]←R[0]即M[7]←R[0]
主存地址为5时,此时是数据,不是指令:
0001 0000操作数x,值为16(二进制转十进制后)
主存地址为6时,此时是数据,不是指令:
0010 0001操作数y,值为1+32=33
主存地址为7时,此时是数据,不是指令:
0000 0000结果z,初始值为0
“存储程序”工作方式规定,程序执行前,需将程序包含的指令和数据先送入主存,一旦启动程序执行,则计算机必须能够在不需操作人员干预下自动完成逐条指令取出和执行的任务。如图所示:
一个程序的执行就算周而复始地执行一条一条指令的过程。每条指令的执行过程包括:从主存取指令、对指令进行译码、PC增量(也就是图中的PC+“1”表示PC的内容加上当前这一条指令的长度)、取操作数并执行、将结果送主存或寄存器保存。
程序执行前,首先将程序的起始地址存放在PC中,取指令时,将PC的内容作为地址访问主存。每条指令执行过程中,都需要计算下一条将执行指令的主存地址,并送入到PC中。若当前指令为顺序型指令,则下条指令地址为PC的内容加上当前指令的长度;若当前指令为跳转型指令,则下条指令地址为指令中指定的目标地址。
当前指令执行完后,根据PC的值到主存中取到的是下条将要执行的指令,因而计算机能够周而复始地自动取出并执行一条一条指令。
刚才的程序,首地址为0,因此程序开始执行时,PC为0000(题目说明PC宽度为4位),下面就演示的刚才程序执行的指令,但是它从l1开始,不是从l0开始:
注意PC的变化,
l1:1110 0110:首先,IR通过MDR将主存地址0000对应的内容取过来(即1110 0110),它是M型指令,操作码是1110。
1110是取数指令,将1110送入控制部件CU进行译码,同时PC进行“+1”操作,PC(4位宽度)中的内容变为0001,因为是取数指令,控制部件CU产生“主存读”控制信号read,同时控制在取数并执行阶段将read信号送控制线,指令后4位的0110(addr字段)作为主存地址送MAR并自动送地址线,经过一段时间,主存将0110B=6号主存单元的33(0010 0001B)变量y送到数据线并自动存储在MDR中,最后由控制器控制将MDR的内容送入0号通用寄存器,因此,指令L1执行的结果是R[0]=33。
指令执行的各阶段包含若干个微操作,微操作需要相应的控制信号(control signal)进行控制。
取指令阶段IR←M[PC]微操作有:MAR←PC;控制线←Read;IR←MDR。(如果是刚开机,将PC设定的预定义地址(看起来这个模型结构,预定义地址是0000,如果不是刚开机,PC传送的是上一条加1后的指令的地址)送入MAR,然后MAR通过地址总线和主存通信,将Read读数指令送入控制线,控制线再将读数指令送入主存,主存再将0000这个地址对应的主存的内容1110 0110送入通过数据总线送入MDR,MDR将读取到的数据1110 0110送入IR)
【注】计算机开机时,程序计数器pc的值通常会被设置为一个预定义的地址,这个地址指向操作系统的启动程序或者BIOS程序的入口点。当计算机开始执行这个地址所指向的程序时,程序计数器pc的值会逐步增加,指向下一条要执行的指令的地址。
取数阶段R[0]←M[addr]微操作有:
MAR←addr;控制线←Read;R[0]←MDR(addr地址送入MAR,MAR通过地址总线将addr送入主存,发送Read读数信号,主存收到读数信号后,将addr地址对应在主存中的数据通过数据总线送入MDR,MDR将读取到的数据送入R[0]寄存器)
存数阶段M[addr]←R[0]微操作有:
MAR←addr;MDR←R[0];控制线←Write
(addr地址送入MAR,MAR通过地址总线将addr送入主存,主存接收到这是存数指令,然后将R[0]寄存器的数据送入MDR,MDR通过数据总线将数据送入主存,主存将数据存入addr地址对应的内存空间内)
ALU运算R[0]←R[0]+R[1]微操作有:
A←R[0];B←R[1];ALUop←add;R[0]←F(R[0]寄存器的数据送入输出端A,R[1]寄存器的数据送入输出端B,ALU执行加指令,A+B,最后将计算结果送入输出端F,输出端F将计算结果送入R[0]寄存器)
这里的Read、Write、mov、add等微操作控制信号部件对op字段进行译码后送出,冯诺依曼结构图中虚线是控制信号线,每条指令执行过程中,所包含的微操作具有先后顺序关系,需要定时信号进行定时。通常,CPU中所有微操作都由时钟信号进行定时,时钟信号(clock signal)的宽度为一个时钟周期(clock cycle)。一条指令的执行时间包含一个或多个时钟周期。