实 验 报 告
第二篇:8位cpu实验报告
精简8位CPU设计报告
07110401 于露
一、实验原理
RISC即精简指令集计算机(Reduced Instruction Set Computer)的缩写。RISC-CPU与一般的CPU相比,通过简化指令系统使计算机的结构更加简单合理,从而提高了运算速度。本文对RISC-CPU的架构进行了分析,并使用VHDL语言设计了8位RISC-CPU IP软核。
SAP-1 CPU部分:程序计数器、MAR、指令寄存器、控制器/序列发生器、累加器、加减法器、B寄存器、输出寄存器。
1.1 SAP-1 CPU及计算机的组成架构简介
1.程序计数器
它是一个4Bits的计数器,计数范围由0~15。主要功用是记录下每个执行的指令地址,并把这个地址传送至MAR寄存器存放。
2.输入与MAR(Memory Access Register)
这个方块应分成两个部分,一个是接受由“输入”部分输入到RAM内存的外部程序和数据,另一部分“MAR”是用来在CPU执行上述所加载的程序时,暂存下一个要执行的指令地址。
3.16×8 RAM
这个RAM有16个存储单元,每个单元为1字节,即8bits。所以这个RAM的地址总线是4bit,地址编码是由0000,0001,0010…1111,这个地址内容是由上述MAR传送过来,然后通过译码将地址存放的8位数据或指令输出至Wbus。
4.指令寄存器
属于CPU内的控制单元,主要是将在RAM的8位数据,通过Wbus后读入指令寄存器,然后再把数据一分为二,较高的4位属于指令部分,送至下一级的“控制器”,而较低的4位属于数据部分,将会被送至Wbus。
5.控制器/序列发生器
这个模块也是属于CPU内控制单元的一部分,这个控制器在程序执行时,负责送出整个计算机的时序信号CLK,而且会把指令寄存器送来的4位指令,解译成12位的控制信号,由这组控制信号指挥其它的功能方块,完成该指令的运作。由于使用VHDL语言设计整个SAR-1,依照语法的使用,这部分会被省略,而且不会影响整个CPU运作。
6.累加器
累加器是个8位的缓冲寄存器,它是存放目前计算机执行的实时数据地方。不同的指令也将使它产生不同的工作方式。
7.加减法器
这个加减法器负责执行数学的加法和减法运算,而且运算的结果会放回“累加器”暂存。
8.B寄存器
这个寄存器用来配合“累加器”、“加减法器”,执行“加法” 或“减法”的工作。
9.输出寄存器
这个输出寄存器的用途是,CPU执行到“输出结果”的指令时,便将“累加器”的结果传至“输出寄存器”,所以它是负责存放输出结果,当然这个存放的结果是二进制形式的。
1.2 SAP-1 CPU指令.寻址法.程序设计
SAP-1的CPU指令,共有5个且可分成两种类型,如表
直接寻址法(Direct Addressing)
零位寻址法(Zero Addressing)
二、实验要求
配合SAP-1指令,设计16(Word)x8(Bit)的ROM,使其能够执行如下预算:
10+14+18-20=1C(Hex)
三、实验设计与过程
3.1 SAP-1 CPU设计
SAP-CPU在前面所提的指令,它们执行的指令周期总长度基本上都是6个脉冲长度,这可以用下图说明
SAP-1指令周期(Instruction Cycle)
时序状态S0-S2范围为取指令周期,而时序状态S3-S5为指令执行周期.下面是每个时序状态下,SAP-1 CPU的工作任务:
1.取指令周期(Fetch Cycle)
(1)状态S0: (寻址状态, Address State)
这个状态下,“程序计数器”负责将所要执行的指令地址值传递至MAR存放.
(2)状态S2: (增加状态,Increment State)
这个状态下,“程序计数器”的值加1,代表计数器将指针指向下一个要执行的指令地址值.
例如:
原先在状态S0时,“程序计数器”的值是01H,它会传递01H给 “MAR”,然后在这个状态S1时,将内容值加1后变成02H,这样以便记录下次要执行的指令地址值.
(3)状态S2: (记忆状态, Memory State)
这个状态下,将把记录在 “MAR”里的指令地址值,送入 “RAM”里后,由 “RAM”读出该地址的指令码,再将该指令放入 “指令寄存器”.
有一点必须强调的是,不论是执行哪个指令,它们的状态S0-S2的动作方式都是相同的,不过状态S3-S5的动作方式就会因执行对那个指令而有所不同.
2.指令执行周期
(1)LDA指令
状态S3:
这个状态下,上述的09H数据传入MAR,以便下个状态能取出该数值所代表的地址里的值,比如20H.
状态S4:
这个状态是将存放在 “MAR”里的09数据,通过RAM读出09H地址的数据,比如是数值20H数值至 “累加器”
状态S5:
这个状态下的LDA指令并没有作用
(2)ADD指令
状态S3:
这个状态下,上述的AH数据将传入MAR,以便下个状态取出该数值所代表地址里的内容值,比如是数值14H
状态S4:
这个状态是将存放 “MAR”里的AH数据,通过RAM读出AH地址内的数据,放到B寄存器中
状态S5:
这个状态是将存在 “累加器”和 “B 寄存器”的数值内容存放入 “加减法器”相加后,再将相加结果放回 “累加器”
(3)SUB指令
状态S3:
这个状态下,上述的BH数据传入MAR,以便下个状态能取出该数值所代表地址里的值
状态S4:
这个状态是将存放在 “MAR”的BH数据,通过RAM读出BH地址内的数据,并放到B寄存器中
状态S5:
这个状态是将存放在 “累加器”和 “B寄存器”的数值放入 “加减法器”相减后,再将相减后结果放回 “累加器”
(4)OUT指令
状态S3:
这个状态下,累加器的内容将经Wbus传至 “输出寄存器”,然后显示在二进制显示装置.
状态S4:
这个状态OUT指令没有作用.
状态S5:
这个状态OUT指令没有作用
(5)HLT指令
状态S3:
这个状态下 “控制器/序列发生器”将停止送出脉冲信号CLK,这时SAP-1 CPU会停止执行工作.
状态S4:
这个状态HLT指令没有作用
状态S5:
这个状态HLT指令没有作用
3.2 设计思路
使用三个IO端口,分别为时钟输入clk,复位使能rst,及结果输出端口output_data。
使用portmap语句进行了元件例化,将CPU与ROM相连接了。
3.3 ROM16_8.VHDl程序
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY ROM16_8 is
PORT(
DATAOUT :OUT STD_LOGIC_VECTOR(7 DOWNTO 0);--Data Output
ADDR :IN STD_LOGIC_VECTOR(3 DOWNTO 0);--ADDRESS
CE :IN STD_LOGIC --Chip Enable
);
END ROM16_8;
ARCHITECTURE a OF ROM 16_8 IS
BEGIN
DATA<=“00001001”WHEN ADDR=“0000”AND CE=‘0’ --LDA 9H
“00011010”WHEN ADDR=“0001”AND CE=‘0’ELSE --ADD AH
“00011011”WHEN ADDR=“0010”AND CE=‘0’ELSE --ADD BH
“00101100”WHEN ADDR=“0011”AND CE=‘0’ELSE --SUB CH
“11100000”WHEN ADDR=“0100”AND CE=‘0’ELSE --OUT
“11110000”WHEN ADDR=“0101”AND CE=‘0’ELSE --HLT
“00010000”WHEN ADDR=“1001”AND CE=‘0’ELSE
“00010100”WHEN ADDR=“1010”AND CE=‘0’ELSE
“00011000”WHEN ADDR=“1011”AND CE=‘0’ELSE
“00100000”WHEN ADDR=“1100”AND CE=‘0’ELSE
“00000000”;
END a;
3.4 SAP1.vhdl程序
ARCHITECTURE a OF SAP1 IS
……
TYPE STATE IS (SO,S1,S2,S3,S4,S5); --state type declare
SIGNAL PState :STATE; --present state
SIGNAL NState :STATE; --next state
……
BEGIN
..**********************************************
ChangeStateMode:PROCESS(CR,RST) --state s0~s5
BEGIN
IF RST=‘1’THEN --reset cpu
PC <=“0000”; --pogram counter=0H
ACC<=“00000000”; --accumulator=0H
RUN <=‘1’; --CPU run program enable
PState<=S0; --Initial cpu present state
ELSIF CP’EVENT AND CP =‘0’THEN --clock negative edage
IF RUN =‘1’THEN --run program eanble?
CASE PState IS --check cpu present state
WHEN S0=> --(address state & fetch cycle-1)
NState<=S1; --cpu next state
WHEN S1=> --(increment state & fetch cycle-2)
NState<=S2; --cpu next state
WHEN S2=> --(memory state & fetch cycle-3)
NState<=S3; --cpu next state
WHEN S3=> --STATE S3 (Execution cycle -1)
NState<=S4; --cpu next state
WHEN S4=> --STATE S4 (Execution cycle-2)
NState<=S5; --cpu next state
WHEN S5=> --STATE S5 (Execution cycle-3)
NState<=S0; --cpu next state
END CASE;
PState<=NState; --切换状态
END IF;
END IF;
END PROCESS ChangeStateMode;
END a;
3.5指令捕捉周期(fetch cycle)
Changestatemode:process(cp,rst) --state s0~s5
variable flag,f1:boolean;
begin
if rst =‘1’ then
…….
Pstate<=s0;
flag:=ture; ---PC指针允许加1标志打开
elsif cp’event and cp=‘0’then
if run=‘1’ then
case pstate is
when so =>
nstate<=s1;
mar<=std_logic_vector(pc);
when s1=>
nstate <=s2;
if flag=ture then
pc <=pc+1;
flag:=false;
end if;
When s2=>
Nastate <=s3;
Flag :ture;
Ir<=databus;
When s3=>
……
End case;
……
3.6指令执行周期(fetch cycle)
在Case When语句的状态S3处,加入下面粗体字命令,将“指令寄存器”
(IR)截取高4位指令至TMP里
……
Elsif cp’event and cp=‘0’ then
……
when s2=>
……
When s3=>
nstate<=s4;
temp<=ir(7downto 4),
when s4=>
……
其余指令执行周期的命令,不放入CASE WHEN语句里,而改以IF-ELSE将状态S3~S5命令独立出来,这么做只是不希望CASE WHEN语句太过冗长。
changestatemode : process(cp,rst)
variable flag, F1:boolean;
Begin
If rst =‘1’ then
……
Elsif cp’event and cp=‘0’ then
If run=‘1’then
case pstate is
when s0=>
nstate<=s1;
……
end case;
pstate<=nstate;
End if;
If pstate =s3 then
If(tmp=“0000”)or(tmp=“0001”)or(tmp=“0010”)then
Mar<=ir(3 downto 0);
elsif tmp =“1110”then
outreg<=acc;
elsif tmp =“1111”then
run<=‘0’;
End if
Elsif pstate=s4 then
if tmp=“0000”then
acc<=databus;
elsif tmp=“0001”then
breg<=databus;
elsif tmp=“0010”then
breg<=databus;
end if;
Elsif pstate=s5 then
if tmp =“0001”and f1=ture then
Num <=unsigned(acc)+unsigend(breg);
Acc <=std_logic_vector(num);
F1:=false;
Elsif tmp=“0010” and f1 =true then
num <=unsigned(acc)-unsigned(breg);
Acc<=std_logic_vector(num);
F1:false;
End if;
End if;
End if;
End process changestatemode;
四、实验结果及仿真
4.1 软件仿真结果
4.2 硬件仿真结果
五、实验总结
如果要对程序运行的指令进行更改,需要改变s5中的计算
when s5=>next_state<=s0;
if temp="0001" and f1='1' then
ax<=ax&&bx; --执行位与指令,将结果存入ax
f1<='0';
elsif temp="0010" and f1='1' then
ax<=ax||bx; --执行或指令,将结果存入ax
f1<='0';
end if;