实验四 微程序控制器

本次实验介绍了微程序控制器的工作原理和设计思路。通过设计一个简单的8位微处理器,包括数据通路和控制器,执行直接寻址指令。微处理器包含Load、Store、Add、Sub、BNE等五条指令,采用直接编码,微指令为20位,其中5位为下地址字段。微地址的形成根据OP码和Z_flag进行分支判断。实验展示了微处理器执行BNE指令后的程序流程,以及如何根据条件跳转执行其他指令。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实验内容:

1.掌握微程序控制器的工作流程

实验目的:

1.理解微程序控制器的控制原理

2.进一步掌握指令流程和功能

3.了解掌握微程序控制器的设计思路和方法

实验内容:(vhd完整代码会在最后给出)

        微程序控制器的组成原理框图:

                

        实验中,我们设计一个简单的微处理器,整个设计分成控制器和数据通路,执行简单的直接寻址指令。为了简化微处理器的设计,我们假定只有一条总线,且总线和所有数据通路组件的宽度都是8位。由于单总线可能会被许多不同的组件驱动,每个组件需要使用三态缓冲器以确保在任一时刻仅有一个组件能将有效数据送至总线上。我们用一个时钟驱动所有的时序块以确保设计完全同步。微处理器的模块图如图所示。

                

1.数据通路

       数据通路为:单总线8位CPU,由微处理器执行的程序与数据一起存储于存储器中,存储器地址寄存器(MAR)和数据寄存器(MDR)作为地址和数据信号在存储器与总线间的缓冲器。 算术逻辑单元(ALU)执行算术操作(ADD、SUB)。算术逻辑单元是一个组合模块,算术操作的结果保存于一个称为累加器(ACC)的寄存器中。ALU的输入是总线和ACC。ALU可以有更多的输出或者标志来表示ACC中结果的性质,比如为负,这些标志作为控制器的输入。

       程序的不同指令在存储器中是顺序存储的。因此需要保存下一条将要执行的指令的地址。这是使用程序计数器(PC)来完成的,如果执行一个分支,程序就要跳出顺序执行,所以必须加载一个新的地址到PC中。

       最后,从存储器中读取的指令需要保存与执行。指令寄存器(IR)保存当前指令。操作码的相应位输入至控制器,以产生相应的控制信号。

      控制器产生许多控制信号,这些信号决定写总线的组件、读总线的寄存器以及执行的ALU操作。

2.指令系统

       本微处理器的指令系统中包含5条指令:Load、Store、add、sub、bne。整个指令系统对应的微程序存放在控制存储器中。

3.指令格式怎样?写出五条指令的机器码(用二进制表示)

       微程序的编码采用直接编码方法,有15个控制信号,外加5位地址,所以一共20位。微处理器的所有数据通路宽度是8位,操作码是3位,只有直接寻址方式,所以说地址是5位。

                         load ->  01000

                         store ->  01001

                         add ->  01010

                         sub ->  01011

                         bne ->  01100

4.模拟时许执行的程序

        流程图:

                

5.微操作控制信号有哪些

控制信号

描述

ACC_bus

用ACC的内容驱动总线

load_ACC

将总线上的数据载入ACC

PC_bus

用PC的内容驱动总线

load_IR

将总线上的数据装载至IR

load_MAR

将总线上的数据装载至MAR

MDR_bus

用MDR的内容驱动总线

load_MDR

将总线上的数据装载至MDR

ALU_ACC

用ALU的结果装载ACC

INC_PC

PC+1并将结果存至PC中

Addr_bus

用IR中指令的操作码部分驱动总线

CS

片选。用MAR的内容设置存储器地址

R_NW

读取,不可写。当R_NW无效且CS有效时,MDR的内容存储于存储器中

ALU_add

在ALU中执行加法操作

ALU_sub

在ALU中执行减法操作

6.控制存储器中存储的微指令的格式,指出操作控制字段采用什么格式?多少位?下址字段多少位?

        控制器:微程序控制器

        微指令编码:水平型微指令

        采用长格式,一条微指令能控制数据通路中多个功能部件并行操作。

        共20位,下地址5位

7.如何形成后继微地址?微码中有两处分支,一是根据OP多路分支,二是根据Z_flag二路分支,微码设计没有采用P1和P2等测试位的方法,分析代码,回答该微码是如何实现分支的?

        直接由微指令的下地址字段指出。微指令格式中设置一个下地址字段,由微指令的下地址字段直接指出后继微指令的地址。根据微地址取出微代码,生成下地址如果下址是01111则根据op得到后继地址,如果下址是10000则根据Z_flag得到后继地址,如Z_flag为“1”,则后继地址为01110,如Z_flag为“0”,则后继地址为01101。

8.执行完bne指令后程序转到什么地方执行

        bne执行完毕后,由于Z_flag不为0,跳转至内存7地址所指的地址执行指令,内存地址7的内容为0,所以跳转至第0条指令load4重复执行。

仿真结果分析:

      

续上一个周期内的变化:

        

程序的执行结果:6号地址单元的内容变为5

最开始系统resset为0,add_r也全部为0,在下一个时钟上升沿,根据add_r的0号地址读出0号地址里的微指令,在读取完3号微指令以后跳转至8号,接着跳转至4,最后又跳转至0号地址

附件(vhd完整代码):

1)cpu.vhd

-- 微程序控制器实验 
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL,IEEE.NUMERIC_STD.ALL;
USE WORK.CPU_DEFS.ALL;

ENTITY CPU IS
PORT( clock      : IN   STD_LOGIC;
      reset      : IN   STD_LOGIC;
	  mode       : IN   STD_LOGIC_VECTOR(2 DOWNTO 0);--确定output输出什么信息。      
	  mem_addr   : IN 	UNSIGNED(4 DOWNTO 0);	--内存地址,范围0-31,修改其值,可观察内存不同单元储存的内容。

	 -- output     : OUT  STD_LOGIC_VECTOR(7 DOWNTO 0); 	
 	  outbus     : OUT  STD_LOGIC_VECTOR(7 DOWNTO 0);   --总线
	  outpc      : OUT  STD_LOGIC_VECTOR(7 DOWNTO 0);   --PC	
	  outalu     : OUT  STD_LOGIC_VECTOR(7 DOWNTO 0);   --ALU结果
	  outir     : OUT  STD_LOGIC_VECTOR(7 DOWNTO 0);   --IR	
	  outmar     : OUT  STD_LOGIC_VECTOR(7 DOWNTO 0);   --MAR	
	  outmdr     : OUT  STD_LOGIC_VECTOR(7 DOWNTO 0);   --MDR	
	  outmem     : OUT  STD_LOGIC_VECTOR(7 DOWNTO 0);   -- mem ,用mem_addr寻址。	
 
	  data_r_out : OUT  STD_LOGIC_VECTOR(19 DOWNTO 0);  --控制器输出微码。(应为实验观察用)
	  op_out     : OUT  STD_LOGIC_VECTOR(2 DOWNTO 0);  --控制器输出OP。(应为实验观察用)
	  add_r_out  : OUT  UNSIGNED(4 DOWNTO 0)  	 --控制器输出微地址。 (应为实验观察用)
	);	         
END ENTITY;

ARCHITECTURE rtl OF CPU IS	
				--程序
	TYPE mem_array IS ARRAY (0 TO 31) OF STD_LOGIC_VECTOR(7 DOWNTO 0);
	SIGNAL   mem       : mem_array;
	CONSTANT prog      : mem_array:=(
				0=> op2slv(load)  & STD_LOGIC_VECTOR(TO_UNSIGNED(4,5)),--地址码为4
				 --&是一个连接操作
				 --TO_UNSIGNED(4,5)将整数4转换成5位的unsigned类型(与std_logic_vector(4 downtown 0)类型相似)
				1=> op2slv(add)   & STD_LOGIC_VECTOR(TO_UNSIGNED(5,5)),--地址码为5
				2=> op2slv(store) & STD_LOGIC_VECTOR(TO_UNSIGNED(6,5)),--地址码为6
				3=> op2slv(bne)   & STD_LOGIC_VECTOR(TO_UNSIGNED(7,5)),--地址码为7	
				4=> STD_LOGIC_VECTOR(TO_UNSIGNED(2,8)),--存了一个数据2,将来load指令装入
				5=> STD_LOGIC_VECTOR(TO_UNSIGNED(3,8)),--存了一个数据3,将来add指令用作另一个操作数
				OTHERS => (OTHERS =>'0'));	
				--控存
	TYPE microcode_array IS ARRAY (0 TO 14) OF STD_LOGIC_VECTOR(19 DOWNTO 0);
	CONSTANT code      : microcode_array:=(
				0=> "00010100010000000001",
				--   0         0         0         1        0          1        0         0         0        1      0         0   0    0   0   0   0   0   0   1
		        --  19        18        17        16       15         14       13        12        11       10      9         8   7    6   5   4   3   2   1   0
	            --load_PC    ACC_bus  load_ACC   PC_bus  load_IR   load_MAR  MDR_bus   load_MDR  ALU_ACC  INC_PC  Addr_bus   CS  R_NW  +   - ua4 ua3 ua2 ua1  ua0
				
				1=> "00000000000110000010",
				--   0         0         0         0        0          0        0         0         0        0      0         1    1   0   0   0   0   0   1   0
		        --  19        18        17        16       15         14       13        12        11       10      9         8    7   6   5   4   3   2   1   0
	            --load_PC    ACC_bus  load_ACC   PC_bus  load_IR   load_MAR  MDR_bus   load_MDR  ALU_ACC  INC_PC  Addr_bus   CS  R_NW  +   - ua4 ua3 ua2 ua1  ua0
								
				2=> "00001010000000000011",
				--   0         0         0         0        1          0        1         0         0        0      0         0    0   0   0   0   0   0   1   1
		        --  19        18        17        16       15         14       13        12        11       10      9         8    7   6   5   4   3   2   1   0
	            --load_PC    ACC_bus  load_ACC   PC_bus  load_IR   load_MAR  MDR_bus   load_MDR  ALU_ACC  INC_PC  Addr_bus   CS  R_NW  +   - ua4 ua3 ua2 ua1  ua0
				
				
				3=> "00000100001000001111",	
				--   0         0         0         0        0          1        0         0         0        0      1         0    0   0   0   0   1   1   1   1
		        --  19        18        17        16       15         14       13        12        11       10      9         8    7   6   5   4   3   2   1   0
	            --load_PC    ACC_bus  load_ACC   PC_bus  load_IR   load_MAR  MDR_bus   load_MDR  ALU_ACC  INC_PC  Addr_bus   CS  R_NW  +   - ua4 ua3 ua2 ua1  ua0
				
				
				4=> "00100010000000000000",   --load第二条微指令
				5=> "00000000000100000000",   --store第二条微指令
				6=> "00000010100001000000",   --add第二条微指令
				7=> "00000010100000100000",   --sub第二条微指令
				8=> "00000000000110000100",   --load入口
				9=> "01000001000000000101",   --store入口
			   10=> "00000000000110000110",	  --add入口
			   11=> "00000000000110000111",   --sub入口
			   12=> "00000000000110010000",   --bne入口
       		   13=> "10000010000000000000",   --如Z_flag为“0”,bne第二条微指令
		       14=> "00000000000000000000");  --如Z_flag为“1”,bne第二条微指令

	
	SIGNAL count    :  UNSIGNED(4 DOWNTO 0);
	SIGNAL op       :  STD_LOGIC_VECTOR(2 DOWNTO 0);		
	SIGNAL z_flag   :  STD_LOGIC;                          
	SIGNAL mdr_out  :  STD_LOGIC_VECTOR(7 DOWNTO 0);   
	SIGNAL mar_out  :  UNSIGNED(4 DOWNTO 0);       
	SIGNAL IR_out   :  STD_LOGIC_VECTOR(7 DOWNTO 0);    	
	SIGNAL acc_out  :  UNSIGNED(7 DOWNTO 0);            	
	SIGNAL sysbus_out : STD_LOGIC_VECTOR(7 DOWNTO 0);  
	
BEGIN	
		
	PROCESS(reset,clock)
		VARIABLE instr_reg : STD_LOGIC_VECTOR(7 DOWNTO 0);	
		VARIABLE acc       : UNSIGNED(7 DOWNTO 0);
		CONSTANT zero      : UNSIGNED(7 DOWNTO 0):=(OTHERS =>'0');		
		VARIABLE mdr       : STD_LOGIC_VECTOR(7 DOWNTO 0);
		VARIABLE mar       : UNSIGNED(4 DOWNTO 0);
		VARIABLE sysbus    : STD_LOGIC_VECTOR(7 DOWNTO 0);			
		VARIABLE microcode : microcode_array;
		VARIABLE add_r     : UNSIGNED(4 DOWNTO 0);	        
		 --add_r定义为5位UNSIGNED,将来可转换为INTEGER,用作下标,访问存放微码的数组microcode_array.
    	
    	VARIABLE data_r    : STD_LOGIC_VECTOR(19 DOWNTO 0);  --存放微码,作用相当于uIR
		VARIABLE temp      : STD_LOGIC_VECTOR(4 DOWNTO 0);
	BEGIN		
	
		IF reset='0' THEN	--初始化
			add_r:=(OTHERS =>'0');			         
			count     <= (OTHERS =>'0');
			instr_reg := (OTHERS =>'0');
			acc       := (OTHERS =>'0');
			mdr       := (OTHERS =>'0');
			mar       := (OTHERS =>'0');
			z_flag    <='0';
			mem       <= prog;
			sysbus    :=(OTHERS =>'0');	
			
		ELSIF RISING_EDGE(clock) THEN			
			--微程序控制器	
			data_r  := code(TO_INTEGER(add_r));	 --根据微地址取出微代码		
			--生成下地址
			IF data_r(4 DOWNTO 0)="01111" THEN -- 如果下址是01111则根据op得到后继地址,
				                               --“01”并上OP,如load指令的op为“000”,则load指令的后继地址为01000。
			    temp:="01" & op(2 DOWNTO 0);
				add_r := UNSIGNED(temp);
			ELSIF data_r(4 DOWNTO 0)="10000"  THEN-- 如果下址是10000则根据Z_flag得到后继地址,
							                      --如Z_flag为“1”,则后继地址为01110。
							                      --如Z_flag为“0”,则后继地址为01101。
				IF z_flag='1' THEN
					add_r:="01110";
				ELSE
					add_r :="01101";
				END IF;
			ELSE
				add_r   := UNSIGNED(data_r(4 DOWNTO 0)); --由下址字段确定后继地址
			END IF;			
			data_r_out <=data_r;  --控制器输出微码。(应为实验观察用)
			add_r_out <= add_r;   --控制器输出微地址。(应为实验观察用)
			
		    --PC
			IF data_r(16)='1' THEN     --PC_bus='1'
				sysbus := rfill & STD_LOGIC_VECTOR(count);   --rfill="000"为常量,count为5位UNSIGNED(4 DOWNTO 0)信号
				                                             --转换为STD_LOGIC_VECTOR,连接后形成8位地址(PC的值),送sysbus
			END IF;		
			IF data_r(19)='1' THEN     --load_PC='1',转移指令修改PC
				count <= UNSIGNED(mdr(4 DOWNTO 0));
			ELSIF data_r(10)='1' THEN    --INC_PC='1',取指令后PC自加1
				count <= count+1;					
			ELSE 
				count <= count;          --其他微周期count保持不变
			END IF;				
			
			--IR
			IF data_r(15)='1' THEN   --load_IR
				instr_reg := mdr;				
			END IF;
			IF data_r(9)='1' THEN    --Addr_bus='1' , 送直接地址,指令中的低5位。load、store、add用,因为本例中有3条指令用,放在译码之前一个周期(即第3个周期)。
				sysbus := rfill & instr_reg(4 DOWNTO 0);--instr_reg为STD_LOGIC_VECTOR
			END IF;	
			op     <= instr_reg(7 DOWNTO 5);			
			IR_out <= instr_reg; --控制器输出取到的指令。(应为实验观察用)
			op_out <=op;   --控制器输出OP。(应为实验观察用)
			
			--ALU
			IF data_r(17)='1' THEN    --load_ACC='1',mdr保存的数据送累加器ACC		
				acc:=UNSIGNED(mdr);
			END IF;
			IF data_r(11)='1' THEN  --ALU_ACC='1',ACC送ALU
				IF data_r(6)='1' THEN   --ALU_add='1',add指令,做加法
					acc := acc + UNSIGNED(mdr);
				ELSIF data_r(5)='1' THEN   --ALU_sub='1',sub指令,做减法
			 		acc := acc - UNSIGNED(mdr);
				END IF;
			END IF;
			IF data_r(18)='1' THEN  --ACC_bus='1',ACC送bus,store指令用来将结果保存在mem中.
				sysbus := STD_LOGIC_VECTOR(acc);
			END IF;
			IF acc=zero THEN --计算完后置标志位
				z_flag <='1';
			ELSE
				z_flag <='0';
			END IF;
			acc_out<= acc;--控制器输出计算结果ACC。(应为实验观察用)
			
			--RAM
			IF data_r(14)='1' THEN  --load_MAR='1'
				mar := UNSIGNED(sysbus(4 DOWNTO 0));
			ELSIF data_r(12)='1' THEN   --load_MDR='1'
				mdr := sysbus;
			ELSIF data_r(8)='1' THEN   --CS='1'
				IF data_r(7)='1' THEN      --R_NW='1'
					mdr := mem(TO_INTEGER(mar));	--读存储器,读出数据送MDR	
				ELSE
					mem(TO_INTEGER(mar))<=mdr; --写存储器,MDR中的数据写入存储器
				END IF;
			END IF;			
			IF data_r(13)='1' THEN   --MDR_bus='1'
				sysbus:=mdr;
			END IF;
			mdr_out <= mdr;--数据寄存器输出。(应为实验观察用)
			mar_out <= mar;--地址寄存器输出。(应为实验观察用)
		END IF;	
		
		sysbus_out <=sysbus;--系统总线输出。(应为实验观察用)	
		
		 
	END PROCESS;
	
			outbus<=sysbus_out;
			outpc(4 DOWNTO 0)<= STD_LOGIC_VECTOR(count);	
			outalu <= STD_LOGIC_VECTOR(acc_out);
			outir <= IR_out;	
			outmar(4 DOWNTO 0) <= STD_LOGIC_VECTOR(mar_out);
			outmdr <= mdr_out;	
			outpc(4 downto 0)<=STD_LOGIC_VECTOR(count);
			outmem <= mem(TO_INTEGER(mem_addr));	
									
END ARCHITECTURE;						
										
										

2)cpu_defs.vhd

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;

PACKAGE cpu_defs IS
	TYPE     opcode IS (load, store, add, sub, bne);	
	CONSTANT rfill: STD_LOGIC_VECTOR(2 downto 0):=(others =>'0');
		FUNCTION op2slv(op:in opcode) RETURN STD_LOGIC_VECTOR;
END PACKAGE cpu_defs;

PACKAGE BODY cpu_defs IS
	TYPE     optable IS ARRAY(opcode) OF STD_LOGIC_VECTOR(2 DOWNTO 0);
	CONSTANT trans_table:optable :=("000", "001", "010", "011", "100");
	FUNCTION op2slv(op:IN opcode) RETURN STD_LOGIC_VECTOR IS
	BEGIN
			RETURN trans_table(op);
	END FUNCTION op2slv;
	
END PACKAGE BODY cpu_defs;

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值