16 位实验 CPU 设计实例
开放式 CPU 指的是 CPU 在一片 FPGA 芯片中构成,它的指令系统和 CPU 内部结构可以由
使用者根据需要设计,并且能够在 TEC-CA 上进行调试的 CPU。实验 CPU 是学生为掌握计算
机的工作原理而设计的 CPU,主要针对基本原理而不强调完备性。这样的 CPU 可以复杂一些,
也可以简单一些,视学生水平而定。
本章中介绍的实验 CPU 实例是针对第 6 章计算机组成原理实验而设计的,使用者可在此
基础上根据自己的需要进行适当增减。
计算机组成原理实验除了进行计算机各部件的实验外,最重要的是使学生掌握计算机整
机的工作原理。我们力求通过这个实验 CPU 设计实例,使学生能够深入掌握计算机的整机工
作原理。
2.1 指令系统
设计 CPU 首先要设计指令系统。由于实验 CPU 采用 16 位字长,指令系统只有 15 条指令,
因此比 8 位 CPU 的指令系统设计容易得多。
2.1.1 指令系统
ADD DR,SR
指令编码:
DR
0000
SR
0000
0111
功能:DR ← DR + SR, 影响 C 和 Z 标志。PC ← PC + 1。
INC DR
指令编码:
DR
0001
SR
0000
0111
功能:DR ← DR + 1,影响 C 和 Z 标志。PC ← PC + 1。
SUB DR,SR
指令编码:
DR
0010
SR
0000
0111
功能:DR ← DR – SR,影响 C 和 Z 标志。PC ← PC + 1。
DEC DR
指令编码:
DR
0011
SR
0000
0111
功能:DR ← DR – 1,影响 C 和 Z 标志。PC ← PC + 1。
AND DR,SR
指令编码:
DR
0100
SR
0000
0011
功能:DR ← DR and SR,影响 Z 标志。PC ← PC + 1。
1
OR
DR,SR
指令编码:
DR
0101
SR
0000
0011
功能:DR ← DR or SR,影响 Z 标志。PC ← PC + 1。
NOT DR
指令编码:
DR
0110
SR
0000
0011
功能:DR ← not DR,影响 Z 标志。PC ← PC + 1。
MOV DR,SR
指令编码:
DR
0111
SR
0000
0001
功能:DR ← SR,不影响标志位。PC ← PC + 1。
JMP ADR
指令编码:
1000
0000
0000
0000
ADR
功能:PC ← ADR。
JNC ADR
????
指令编码:
1001
0000
ADR - @ -1
功能:如果 C=0,则 PC ← ADR;如果 C=1,则 PC ← PC + 1。
JNZ ADR
指令编码:
1010
0000
ADR - @ -1
功能:如果 Z=0,则 PC ← ADR;如果 Z=1,则 PC ← PC + 1。
MVRD
DR,DATA
指令编码:
1100
DR 00
0000
0000
DATA
功能:DR ← DATA。PC ← PC + 2。
LDR DR,SR
指令编码:
DR
1101
SR
0000
0001
功能:DR ← [SR]。PC ← PC + 1。
STR SR,DR
2
指令编码:
DR
1110
SR
0000
0000
功能:[DR] ← SR。PC ← PC + 1。
NOP
指令编码:
0111
0000
0000
0000
功能:PC ← PC + 1。
说明:
1. 本 CPU 中含有 4 个通用寄存器器,用 R0、R1、R2 和 R3 表示。源寄存器用 SR 表示,目
的寄存器用 DR 表示,因此 DR 和 SR 在指令编码中各用 2bit 编码。
2. 指令编码中的@代表该指令当前的 PC 值。
3. 从 汇 编 指 令 转 换 成 二 进 制 代 码 的 工 作 由 调 试 软 件 Debugcontroller 完 成 。 关 于
Debugcontroller 的用法,见第 5 章。
2.1.2 指令系统设计说明
设计指令系统时首要考虑的是指令要满足功能上的需求。这个指令系统除了 PUSH、POP、
CALL 和 RET 等少数指令没有包括外,其本上是齐全的。它包括了运算指令、转移指令和存
储指令等三类,有代表性。这三类指令根据 IR15—IR14 进行分类:
IR15 为 0 时运算指令;为 1 其他指令
IR15、IR14 为 10 时转移指令;
IR15、IR14 为 11 时存储指令。
除了要满足功能上的要求外,设计的指令格式要考虑指令译码方便,减少硬件资源的消
耗。本指令系统采取了如下措施:
(1)算术逻辑指令的 IR14—IR12 对应运算器 ALU 的 3 位运算操作码。
(2)当 IR0 = 1 时,本指令中有对 DR 的写操作。
(3)当 IR1 = 1 时,本指令影响标志位 Z。
(4)当 IR2 = 1 时,本指令影响标志位 C。
(5)NOP 指令实际上是一条“MOV R0,R0”指令,只是不改变目的寄存器的内容。
2.2 实验 CPU 总体设计方案
2.2.1 一条指令执行需要 3 拍时间
t1 取指。在 t2 的上升沿,将从存储器取出的指令写入指令寄存器 IR。
t2 根据指令寄存器 IR 的内容进行指令译码;根据指令译码得到的控制信号进行运算
和其它操作。
t3 存储器读、写操作;在 t3 的下降沿将运算结果写入目的寄存器,改变 C 标志和 Z 标
志;在 t3 的下降沿,改变 PC 的值,为取下一条指令做好准备。
由于取指阶段和存储器读写阶段都要访问存储器,速度较慢;而指令译码和运算都由
CPU 本身完成,因此取指阶段和存储器读写阶段各占一拍时间,指令译码和运算共占一拍
时间。
3
2.2.2 实验 CPU 的总体构成
实验 CPU 由 5 部分组成:取指部分 instru_fetch、指令译码部分 decoder_unit、执行
部分 exe_unit、存储器部分 memory_unit 和通用寄存器组 fegfile。另外,还有一个程序包
exe_cpu_components,将各低层设计实体作为元件存储,供各设计实体使用。顶层设计实体
exe_cpu 完成 5 个组成部分的连接。实验 CPU 总体框图见图 2-1。
4
图 2-1 实验 CPU 总体框图
5
1.通用寄存器组 regfile
通用寄存器组内包含 4 个 16 位寄存器。这是一个具有 1 个写入端口、2 个读出端口的
通用寄存器组。写入端口将指令执行后得到的目的寄存器的值在 t3 的下降沿写入目的寄存
器。只有具有写目的寄存器功能的指令执行结束时才写目的寄存器。有些指令,如 JMP 指令
等执行结束后不改变通用寄存器组的值。通用寄存器组的 2 个读出端口,一个是目的寄存器
读出端口,一个是源寄存器读出端口,从这 2 个端口读出的内容供执行部分 exe_unit 和存
储器部分 memory_unit 使用。
通用寄存器组内还有 2 个标志位:z_out 和 c_out,在 t3 的下降沿根据指令执行的结果
改变或者不改变它们的值。这 2 个标志位的值送执行部分 exe_unit 使用。
传统上通用寄存器组属运算器部分。
2.取指部分 instru_fetch
取指部分完成 4 项工作:
(1)产生时钟信号 t1、t2 和 t3,供实验 CPU 各部分使用。
(2)在复位信号 reset 为低时将 PC 复位为 0;在一条指令执行结束后,根据指令执行
的结果在 t3 的下降沿改变 PC 的值。
(3)将从存储器读出的指令的第一个字在 t2 的上升沿送指令寄存器 IR。
(4)计算 PC+1 的值 pc_inc,为双字指令取第二个指令字做准备。
传统上取指部分属控制器部分。
3. 指令译码部分 decoder_unit
源寄存器号(编址)。
目的寄存器号(编址)。
控制 ALU 进行 8 种运算操作的 3 位编码。
指令译码部分根据指令寄存器 IR 的值产生实验 CPU 所需要的各种控制信号和其他信号:
SR
DR
op_code
zj_instruct 为 1 表示本条指令是条“JNZ ADR”指令。
cj_instruct 为 1 表示本条指令是条“JNC ADR”指令。
lj_instruct 为 1 表示本条指令是条“JMP ADR”指令。
DRWr
Mem_Write
DW_intruct 为 1 表示本条指令是双字指令。
为 1 表示本条指令可能改变 z(结果为 0)标志。
change_z
为 1 表示本条指令本条指令可能改变 c(进位)标志。
change_c
sel_memdata 为 1 表示本条指令写入目的寄存器的值来自读存储器。
r_sjmp_addr 计算条件转移指令转移地址所需要的 16 位相对地址。它是由条件转移指
为 1 表示 在 t3 的下 降沿 将本 条指 令的 执行 结果 写入 目的 寄存 器。
为 1 表示本条指令有存储器写操作,存储器的地址是源寄存器的内容。
令中的 8 位相对地址经过符号扩展生成的。
从上述控制信号看,实验 CPU 的指令译码器是很简单的。指令译码器在传统上属于控制
器部分,是控制器的核心。所谓组合逻辑控制器是指指令译码器是由组合逻辑构成的,所谓
微程序控制器是指指令译码器主要由控制存储器 ROM 和少许组合逻辑构成的。
4. 执行部分 exe_unit
6
执行部分完成下列任务:
(1)8 种算术逻辑运算:加、加 1、减、减 1、与、或、非和数据传送,并临时将运算
结果存放在 result 中。根据运算结果产生进位标志,临时存放在 c_tmp 中;根据运算结果
产生结果为 0 标志,临时存放在 z_tmp 中。
(2)产生存储器读写所需要的存储器地址 Mem_Addr。存储器地址是根据下列情况决定
的:在 t1 节拍时选择 pc,在双字指令时选择 pc_inc,在 LDR 指令时选择 SR(源寄存器)
内容,在 STR 指令时选择 DR(目的寄存器)内容。
(3)产生条件转移指令(JNC 和 JNZ)所需要的转移标志 c_z_j_flag(为 1 表示转移)
和转移地址 sjmp_addr。
执行部分的核心传统上属于运算器,是运算器的核心。
5. 存储器部分 memory_unit
存储器部分主要完成对存储器的读写:
(1)它和 TEC—CA 实验台上存储器的接口部分。向实验台上的存储器送出 16 存储器地
址总线 Mem_addr,16 位双向数据总线 ob,读写信号 rw。当 rw 为 1 时,实验台上的存储器
作为读存储器信号处理;当 rw 信号为 0 时,实验台上的存储器作为读存储器信号处理。实
验台上的存储器由 2 片静态存储器 6116 和少量附加电路构成。(在 TEC—CA 实验台上具体实:
2 片 6116 并联构成 16 位字长的存储器,6116 所需的片选信号 cs 为低,读信号 oe 由 rw 反
相产生,写信号 we 直接选用 rw。)
(2)存储器地址 Mem_addr 来自执行部分,写信号 Mem_Write 由指令译码部分产生。当
Mem_Write 为 1 时在 t3 节拍完成写操作,其余情况下均进行读操作。
(3)在 t1 节拍中完成读指令的第 1 个字。
(4)对双字指令,在 t3 完成读指令的第 2 个字。
(5)对 JMP 指令,在 t3 读出转移地址,放在 data_read 中。
(6)对 MVRD 指令,在 t3 读出立即数 DATA,放在 data_read 中。
(7)对 LDR 指令,在 t3 读出存储器的值,放在 data_read 中。
(8)对 STR 指令,在 t3 将源寄存器的值写入存储器中。
(9)对在 t3 下降沿写入目的寄存器的值进行选择。在 LDR 指令中,选中读出的存储器
的值;在其他指令中,选中执行部分送来的运算结果 result。
实验 CPU 中存储器部分传统上属于控制器部分,实验台上的存储器属于计算机的存储器
部分。
6. 程序包 exp_cpu_components
程序包 exp_cpu_components 把实验 CPU 中除顶层设计实体 exp_cpu 以外的设计实体作
为元件(component)予以说明,供实验 CPU 中的其它设计实体作为元件予以引用。
7. 顶层设计实体 exp_cpu
顶层设计实体 exp_cpu 把 5 个二级设计实体 regfile、instru_fetch、decoder_unit、
exe_unit 和 memory_unit 作为元件引用,每个例化一次,用信号把它们连接起来,构成实
验 CPU。exp_cpu 同时也定义了实验 CPU 对外的接口:
clk
外部输入的时钟。
7
reset 外部输入的 CPU 复位信号,低电平有效。
AR
OB
WE
向外部输出的 16 位存储器地址总线。
16 位双向存储器数据总线。
向外部输出的存储器读写信号。当高电平时,对存储器进行读操作;当低电平
时,对存储器进行写操作。
在一个工程(project)中,较低层的设计实体其实相当于元件,与一块印制板上的电
路差不多;顶层设计实体对较低层设计实体每例化一次,相当于在印制板上上安放一个元件,
而顶层设计实体中的信号相当于印制板上的连线。因此,在一个工程中,如果有一个非顶层
设计实体从来没有被其他设计实体例化过,那么这个设计实体在这个工程中就是多余的,起
不到任何作用。顶层设计实体中除了由较低层设计实体构成的元件外,通常还有一些由
process 语句、信号赋值语句等构成的其他独立电路块,通过信号把元件和独立电路块互相
连接,最后形成了一个完整的电路设计。
2.3 指令流程表
实验 CPU 的指令流程表见表 2-1。
指令
表 2-1 实验 CPU 指令流程表
t1
微操作
t2
ADD DR,SR
Mem_Addr←pc
result←DR +
16 存储器地址总线/
SR
we←1
data_read←ob
generate
z_tmp
从存储器读出的指令
generate
INC DR
IR←data_read
pc_inc←pc +1
Mem_Addr←pc
we←1
data_read←ob
IR←data_read
pc_inc←pc +1
SUB DR,SR
Mem_Addr←pc
DEC DR
we←1
data_read←ob
IR←data_read
pc_inc←pc +1
Mem_Addr←pc
we←1
data_read←ob
IR←data_read
pc_inc←pc +1
8
c_tmp
result←DR +
1 generate
z_tmp
generate
c_tmp
result←DR -
SR generate
z_tmp
generate
c_tmp
result←DR -
1 generate
z_tmp
generate
c_tmp
t3
pc←pc_inc
DR←result
z_out←z_tmp
c_out←c_tmp
pc←pc_inc
DR←result
z_out←z_tmp
c_out←c_tmp
pc←pc_inc
DR←result
z_out←z_tmp
c_out←c_tmp
pc←pc_inc
DR←result
z_out←z_tmp
c_out←c_tmp