关于用基本可编程逻辑器件应用搭建CPU

清华大学关于CPU芯片逻辑设计的经典资料,强烈推荐!!!
UID251364&帖子20916&精华0&积分783655&资产783655 信元&发贴收入412495 信元&推广收入10550 信元&附件收入243473 信元&下载支出1789 信元&阅读权限110&在线时间9908 小时&注册时间&最后登录&
清华大学关于CPU芯片逻辑设计的经典资料,强烈推荐!!!
本人以前在中国电子科技集团下面一个很牛X的研究所里面读研(名字就不说了,军工研究所,不便透露),呵呵,方向是硬件,导师是中科院毕业的博士,读研期间有幸接触到很多非常宝贵的第一手资料,很多都是各大EDA厂商来所里面做的培训和参考设计的视频、文档等资料,以后陆续和大家分享
这个资料是清华大学关于CPU芯片逻辑设计方面的经典资料,详细介绍CPU的逻辑电路设计方法并给出实际的逻辑电路以及功能模拟结果。首先从数字逻辑和CPU逻辑电路设计开始,以MIPS体系结构中比较典型的指令为样板,讨论了单周期和多周期的CPU设计技术;然后,讨论了系统控制协处理器的设计;最后讨论了较为复杂的存储管理设计技术、中断和例外管理设计技术和流水线CPU设计技术。书中还用MIPS汇编语言编写了用于CPU测试的简单程序,对所设计的CPU逻辑电路进行功能模拟,以验证CPU逻辑电路的正确性。这些电路和程序以及测试波形图均在资料中给出。
本资料为高清晰PDF格式,虽然文件有点大,98M,但是绝对物有所值,肯定会对您有所帮助,强烈推荐!!!!
下载次数:2165
下载需要消耗: 5 信元,如果是重复下载只需消耗: 1信元
下载次数:1942
下载需要消耗: 5 信元,如果是重复下载只需消耗: 1信元
下载次数:1589
下载需要消耗: 5 信元,如果是重复下载只需消耗: 1信元
下载次数:1853
下载需要消耗: 5 信元,如果是重复下载只需消耗: 1信元
下载次数:1677
下载需要消耗: 5 信元,如果是重复下载只需消耗: 1信元
下载次数:1964
下载需要消耗: 5 信元,如果是重复下载只需消耗: 1信元
下载次数:1259
下载需要消耗: 3 信元,如果是重复下载只需消耗: 1信元
UID900717&帖子46&精华0&积分56916&资产56916 信元&发贴收入260 信元&推广收入0 信元&附件收入6378 信元&下载支出253 信元&阅读权限90&在线时间252 小时&注册时间&最后登录&
很不错的资料,收下了,支持清华!!!
UID603405&帖子3&精华0&积分0&资产0 信元&发贴收入15 信元&推广收入0 信元&附件收入0 信元&下载支出65 信元&阅读权限10&在线时间3 小时&注册时间&最后登录&
呵呵,好东东,谢谢分享啦
UID242583&帖子464&精华2&积分32647&资产32647 信元&发贴收入2730 信元&推广收入0 信元&附件收入31328 信元&下载支出7899 信元&阅读权限80&在线时间421 小时&注册时间&最后登录&
是不是那本清华出的书&&CPU芯片逻辑设计技术 ,如果是就不要忽悠人了,贴点目录出来给大家看看。
CPU芯片逻辑设计技术
作者: 朱子玉 李亚民& &
出版社:清华大学出版社
上架时间:
出版日期:2005 年1月
开本:185×260
内容简介回到顶部↑   本书详细介绍CPU的逻辑电路设计方法并给出实际的逻辑电路以及功能模拟结果。全书共分十章,首先从数字逻辑和CPU逻辑电路设计开始,以MIPS体系结构中比较典型的指令为样板,讨论了单周期和多周期的CPU设计技术;然后,讨论了系统控制协处理器的设计;最后讨论了较为复杂的存储管理设计技术、中断和例外管理设计技术和流水线CPU设计技术。书中还用MIPS汇编语言编写了用于CPU测试的简单程序,对所设计的CPU逻辑电路进行功能模拟,以验证CPU逻辑电路的正确性。这些电路和程序以及测试波形图均在书中给出。
   本书可作为高等院校CPU逻辑设计课程的教材,也可以用做“计算机组成”课程的教学参考书。
目录回到顶部↑第1章 数字电路设计基础
1.1 布尔代数
1.2 逻辑表达式
1.2.1 真值表和逻辑化简
1.2.2 与或格式和或与格式
1.2.3 带有使能端的d触发器
1.3 逻辑门实现技术
1.3.1 晶体管开关
1.3.2 cmos逻辑门
1.3.3 负逻辑系统
1.4 数字电路的实现方法
1.4.1 标准器件
1.4.2 用户可编程逻辑芯片--pla,pal,cpld和fpga
1.4.3 客户全定制芯片
1.4.4 客户半定制芯片--标准单元和门阵列
1.5 数字电路的开发过程
1.6 max+plus的使用方法
1.6.1 逻辑图输入
1.6.2 编译
1.6.3 功能模拟
.1.6.4 生成电路的逻辑符号
1.7 ahdl,verilog hdl和vhdl举例
第2章 cpu逻辑电路设计概述
2.1 二进制数的大小及计算结果的溢出判断
2.2 数据在存储器中的存放和数据对齐
2.3 mips指令集简介
2.4 cpu逻辑电路设计简介
2.4.1 单周期cpu简介
2.4.2 多周期cpu简介
2.4.3 流水线cpu简介
2.5 存储器管理和tlb设计概述
2.5.1 虚拟地址到物理地址的转换
2.5.2 快速地址转换表tlb
2.6 高速缓存cache设计概述
2.6.1 cache映射
2.6.2 cache行替换
2.6.3 写策略
2.6.4 几种mips cpu的cache构成
2.7 几种典型的mips cpu
第3章 mips指令
3.1 mips寄存器堆
3.2 指令格式
3.3 cpu指令
3.3.1 计算指令
3.3.2 数据传送(load/store)指令
3.3.3 转移及分支指令
3.3.4 协处理器指令
3.3.5 其他指令
第4章 常用电路、算法及电路实现
4.1 逻辑运算器
4.1.1 逻辑与
4.1.2 逻辑或
4.1.3 逻辑或非
4.1.4 逻辑异或
4.2 常用电路
4.2.1 译码器
4.2.2 数据选择器
4.3 加减法器
4.3.1 32位加法器
4.3.2 32位减法器
4.3.3 32位加减法器
4.4 乘法器
4. 4. 1 32位无符号乘法器
4.4. 2 32位乘法器
4.4.3 乘法并行阵列
4.4.4 booth乘法算法
4.5 除法器
4.5.1 恢复余数法
4.5.2 不恢复余数法
4.5.3 有符号除法器
4.6 移位器
4.6.1 逻辑移位
4.6.2 算术移位
4.6.3 循环移位
4.7 首0/1计数器
4.7.1 首1计数器
4.7.2 首0计数器
4.8 比较器
4.9 alu设计
4.10 小结
第5章 单周期cpu设计
5.1 指令描述
5.2 设计思路
5.2.1 r类型指令
5.2.2 i类型指令
5.2.3 j类型指令
5.3 寄存器堆设计
5.4 单周期cup详细逻辑电路设计
5.4.1 取指令逻辑
5.4.2 指令译码逻辑
5.4.3 指令执行逻辑
5.4.4 存储器访问逻辑
5.4.5 结果写回逻辑
5.5 测试波形图
5.6 考虑延迟转移的单周期cpu设计
第6章 多周期cpu设计
6. 1 无延迟转移功能的cpu
6.1.1 设计思路及数据路径
6. 1. 2 cpu的控制信号
6.2 带有延迟转移功能的cpu
6.2.1 控制部件设计
6.2.2 数据路径设计
6.2.3 多周期cpu整体逻辑电路
6.2.4 功能模拟波形图
6.3 性能分析
第7章 系统控制协处理器的寄存器
7.1 cpo寄存器
7.2 cpo寄存器详细介绍
7.3 cpo寄存器实现
7.4 cpo寄存器堆读写
第8章 存储管理
8.1 mips虚拟地址空间分配
8.2 mipstlb概述
8.3 地址转换
8.3.1 固定地址转换
8.3.2 块地址转换
8.3.3 基于tlb的地址转换
8.4 tlb实现
8.4.1 输入输出信号
8.4.2 tlb条目实现
8.4.3 tlb实现
8.5 存储管理实现
8.5.1 数据虚拟地址转换
8.5.2 指令虚拟地址转换
第9章 中断和例外管理
9.1.1 rcset例外、softreset例外、nmi例外
9.1.2 普通外部中断
9.1.3 中断处理
9.2.1 例外向量
9.2.2 通用例外处理
9.2.3 reset例外处理
9.2.4 soft reset例外处理
9.2.5 nmi例外
9.2.6 mcheck例外
9.2.7 tlbrefill例外
9.2.8 tlbinvalid例外
9.2.9 tlb修改例外
9.2.10 整数溢出例外
9.2.11 systemcall例外
9.2.12 interrupt例外
9.3 例外处理流程实现
9.3.1 例外类型
9.3.2 例外处理
第10章 流水线cpu设计
10.1 流水线寄存器
10.2 流水线cpu的指令相关问题
10.2.1 指令相关的类型
10.2.2 指令相关的解决方法
10.3 流水线cpu实现
10.3.1 if阶段
10.3.2 id阶段
10.3.3 exe阶段
10.3.4 mem阶段
10.3.5 wb阶段
10.4 系统和测试
10.4.1 中断程序
10.4.2 测试程序及数据
10.4.3 测试结果
10.5 cache设计
10.5.1 cache的组成结构
10.5.2 cache操作
10.5.3 cache实现
10.5.4 带cache的流水线cpu设计
10.5.5 测试结果
10.6 小结
UID251364&帖子20916&精华0&积分783655&资产783655 信元&发贴收入412495 信元&推广收入10550 信元&附件收入243473 信元&下载支出1789 信元&阅读权限110&在线时间9908 小时&注册时间&最后登录&
这本书挺好的啊,有什么问题吗?
UID610249&帖子1021&精华0&积分1493&资产1493 信元&发贴收入5270 信元&推广收入0 信元&附件收入1042 信元&下载支出5014 信元&阅读权限30&在线时间504 小时&注册时间&最后登录&
很好,谢谢分享!
UID838562&帖子26&精华0&积分0&资产0 信元&发贴收入160 信元&推广收入0 信元&附件收入0 信元&下载支出607 信元&阅读权限10&在线时间4 小时&注册时间&最后登录&
UID838562&帖子26&精华0&积分0&资产0 信元&发贴收入160 信元&推广收入0 信元&附件收入0 信元&下载支出607 信元&阅读权限10&在线时间4 小时&注册时间&最后登录&
有点贵啊 求信元
UID838562&帖子26&精华0&积分0&资产0 信元&发贴收入160 信元&推广收入0 信元&附件收入0 信元&下载支出607 信元&阅读权限10&在线时间4 小时&注册时间&最后登录&
UID152084&帖子243&精华1&积分1935&资产1935 信元&发贴收入1390 信元&推广收入0 信元&附件收入3189 信元&下载支出7334 信元&阅读权限30&在线时间315 小时&注册时间&最后登录&
原来是一本书啊
[通过 QQ、MSN 分享给朋友]Nios2软核搭建_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
文档贡献者
评价文档:
Nios2软核搭建
大小:15.57MB
登录百度文库,专享文档复制特权,财富值每天免费拿!
你可能喜欢[text]前往评论0返回顶部[CPU自作入门]如何设计一个16位CPU模型?>&/&&/&
发布于&/&&
收藏:0&/&
我果然标题党了吗?不是转载那本日本人写的书啊!纯手打表诚意,希望猴子给过,第一次投稿各位大神帮帮忙。。。。。。
如何制作一个简单的16位CPU,首先我们要明确CPU是做什么的,想必各位都比我清楚,百度的资料也很全。。。。。
如果想要制作一个CPU,首先得明白下计算机的组成结构(或者计算机的替代品,因为并不是只有计算机有CPU,现在的电子产品都很先进,很多设备例如手机、洗衣机甚至电视和你家的汽车上面都得装一个CPU),数字电路基础,还最好有点编程的基础(当然,没有也没关系,这些知识都很容易获得,各种书上面都会提到,并且在接下来的过程中我会提到这些知识)
我们要实现的是一个RISC指令集的CPU,并且我们最后要自己为这个CPU设计指令并且编码。
首先我们来听个故事,关于CPU的诞生的故事:
日本客户希望英特尔帮助他们设计和生产八种专用集成电路芯片,用于实现桌面计算器。英特尔的工程师发现这样做有两个很大的问题。第一,英特尔已经在全力开发三种内存芯片了,没有人力再设计八种新的芯片。第二,用八种芯片实现计算器,将大大超出预算成本。英特尔的一个名叫特德&霍夫(Ted Hoff)的工程师仔细分析了日本同行的设计,他发现了一个现象。这八块芯片各实现一种特定的功能。当用户使用计算器时,这些功能并不是同时都需要的。比如,如果用户需要计算100个数的和,他会重复地输入一个数,再做一次加法,一共做100次,最后再打印出来。负责输入、加法和打印的电路并不同时工作。这样,当一块芯片在工作时,其他芯片可能是空闲的。
霍夫有了一个想法:为什么不能用一块通用的芯片加上程序来实现几块芯片的功能呢?当需要某种功能时,只需要把实现该功能的一段程序代码(称为子程序)加载到通用芯片上,其功能与专用芯片会完全一样。
经过几天的思考后,霍夫画出了计算器的新的体系结构图,其中包含4块芯片:一块通用处理器芯片,实现所有的计算和控制功能;一块可读写内存(RAM)芯片,用来存放数据;一块只读内存(ROM)芯片,用来存放程序;一块输入输出芯片,实现键入数据和操作命令、打印结果等等功能。
看完这个故事后,可以总结:CPU是一种用来代替专用集成电路的器件(这只是我的理解,不同人有不同理解,这个就智者见智了,我在接下来的例子中也会说明我的想法)
然后考虑如下这个例子:
repeat:inc eax
jmp repeat
int main()
unsigned int i = 0;
可以看到,以上三个例子都产生了一个从0不断增加的序列,而且前两个例子会一直加到溢出又从0开始(这个取决于计算机的字长也就是多少位的CPU,eax是32位寄存器所以必然是加到然后回0,而后面那个c程序则看不同编译器和不同平台不一样),后面那个例子则看你用的是什么样的加法器和多少个D触发器
那问题就来了,我假设要一个递减的序列怎么办呢?前两个例子很好解释,我直接改代码不就得了:
repeat:dec eax
jmp repeat
int main()
unsigned int i = 0;
你只需要轻轻敲击键盘,修改了代码之后,它就会如你所愿的执行。
但是后面那个例子怎么办呢?可能你已经想到办法了:如例2-3所示
问题就来了,你在键盘上敲两下可不能改变实际电路!上面(例1-3)中是个加法器,但是跑到这里却变成了减法器(例2-3)!
这样的话,你就得再做一个电路,一个用来算加法,一个用来算减法,可是两个电路代表你得用更多的电路和芯片,你花的钱就得更多,要是你不能同时使用这两个电路你就花了两份钱却只干了一件事!
这个问题能被解决吗?答案是能!
这个例子中使用了一个加法器一个减法器,没比上面的电路省(显然。。。。难道你想用减法器做加法器的功能?不可能吧!当然,加上一个负数的补码确实就是减去一个数,但是这里先不考虑这种问题),多了一组多路器,少了一组D触发器。总的来说,优势还是明显的(两块电路板和一块电路板的差别)。
而sel信号就是用来选择的(0是递增,1是递减)。
如果我们把sel信号看做&程序&的话,这个电路就像一个&CPU&能根据&程序&执行不同的&操作&,这样的话,通过&程序&(sel信号),这个电路就能够实现复用。
根据上面的结论,我认为(仅仅是个人认为啊~):程序就是硬件电路的延伸!
而CPU的基本思想,我认为就是这样的。
接下来我们就分析CPU的结构和各个部件,然后实现这个CPU。
什么是单周期CPU,什么是多周期CPU,什么是RISC,什么是CISC:
首先大家得有时钟的概念:
这个问题不好解释啊。。。。。。可以理解为家里面的机械钟,上上电池之后就会滴答滴答走,而它&滴答滴答&的速度就是频率,滴答一下用的时间就是周期,而人的工作,下班,吃饭和学习娱乐都是按照时钟的指示来进行的(熬夜的网瘾少年不算),一般来说,时钟信号都是由晶体振荡器产生的,0101交替的信号(低电平和高电平)
数字电路都需要一个&时钟&来驱动,就像演奏交响乐的时候需要一个指挥家在前面指挥一样,所有的人都会跟着指挥的拍子来演奏,就像数字电路中所有的部件都会跟着时钟节拍工作一样。
如下是一个理想的时钟信号:(注意是理想的)
当然,实际的时钟信号可能远没有这么理想,可能上升沿是斜的,而且占空比也可能不是50%,有抖动,有偏移(相对于两个器件),可能因为导线的寄生电容效应变得走形。
上面那段如果没听懂也没关系~~~反正就是告诉你,实际的时钟信号测出来肯定没这么标准
而cpu的工作频率,是外频与倍频的积(cpu究竟怎么算频率,其实这个我也不太清楚呵呵),因为cpu是通过外部的晶振产生一个时钟信号,然后再通过内部的电路(锁相环),倍频至需要的频率。当然,有人问,为什么要这么麻烦呢?直接在电路外边做个时钟晶振能产生那么高的时钟信号就可以了嘛,这个是可以的,在某些简单的系统上(例如51单片姬)就是这样的,但是计算姬的cpu比较复杂,因为一些原因所以必须要做到cpu内。
下面简单说一下CPU的两种指令集:CISC和RISC。
这个网址是百度知道的网友回答的CISC和RISC的差别
下面我来说下我的看法(个人看法,如有错误还请高手指正)
RISC是Reduced Instruction Set Computer,精简指令集计算机,典型例子是MIPS处理器
CISC是Complex Instruction Set Compute,复杂指令集计算机,典型例子是x86系列处理器(当然现在的x86指令还是当初cisc的指令,但是实际处理器的结构都已经变成了risc结构了,risc的结构实现流水线等特性比较容易,在计算机前的你如果用的是intel某系列的处理器,则它使用的指令集看上去还是像cisc的指令,但是实际上你的cpu的结构已经是risc的了)
一般CISC的处理器需要用微指令配合运行,而RISC全部是通过硬连线实现的,也就是说,当cisc的处理器在执行你的程序前,还得先从另外一个rom里面读出一些数据来&指导&处理器怎么处理你的命令,所以cisc效率比较低,而risc是完全通过部件和部件之间的连接实现某种功能,极大的提高了工作效率,而且为流水线结构的出现提供了基础。cisc的寄存器数量较少,指令能够实现一些比较特殊的功能,例如8086的一些寄存器:
ax,bx,cx,dx,si,di等;段寄存器有:cs,ds,es,ss等。相对的指令功能比较特殊,例如xlat将bx中的值作为基地址,al中的值作为偏移,在内存中寻址到的数据送到al当中(以ds为段寄存器)
而risc的处理器则通用寄存器比较多,而指令的功能可以稍微弱一点,例如:
以nios嵌入式处理器来说明,nios处理器有32个通用寄存器(r0~r31),而指令功能相对x86的弱一些,而且x86进行内存访问是直接使用mov指令,nios处理器读内存用的是load,写内存用的是store,
二者响应中断的方式也不一样,举一个典型的例子,x86的处理器将中断向量表放在了内存的最低地址(0-1023,每个中断向量占四个字节),能容纳256个中断(以实模式的8086举例)响应中断时,将中断号对应的地址上的cs和ip的值装入到cs和ip寄存器而将原来的地址保存,并且保存状态寄存器然后进入中断处理,请参见:
而risc则拥有一个共同的中断响应函数,这个函数会根据中断号找到程序向系统注册的函数的地址,并且调用这个函数。一般来说而是用的cisc指令的长度是不定的,例如x86的xor ax,bx对应机器码是0x31d8、而push ax是0x50、pop cx是0x59。而risc的指令确是定长的,例如32位。
如果还有不清楚的。。。。。自行百度,要理解这些概念需要一点时间
一个CPU的基本结构以及必要组件:
这个例子引用自DE2开发板套件带的光盘上的Lab Exercise 9,我们从图中可以看到,一个CPU包含了通用寄存器组R0~R7,一个ALU(算术逻辑单元),指令寄存器IR,控制器(一般这部分是一个有限状态机或者是用微指令实现),还有就是数据通路(图中的连线)。当然真正的CPU不可能只包含这么一点点组件,这是一个模型CPU,也就是说只是说明CPU的原理,真正复杂的CPU要涉及到很多复杂的结构和时序,例如虚拟模式需要使用一些特殊的寄存器、为了支持分页需要使用页表寄存器等,为了加速内存的访问需要使用TLB,加速数据和指令的访问而使用data cache和instruction cache等等。。。。。当然,那都是后面该考虑的,所以我们先从这个简单的部分开始讲起。
例子中能实现如下指令:
mv指令将Ry的数据转移到Rx中,mvi将立即数D转移到Rx当中,add将Rx和Ry的和放到Rx中,sub同上,不过执行的是减法。
首先来说明mv指令是如何执行的:mv指令将Ry的值移入Rx寄存器当中,这两个寄存器都是由一组D触发器构成,而D触发器的个数取决于寄存器的宽度,就像32位机、64位机这样,那他们的寄存器使用的D触发器的个数就是不一样的。当执行mv rx,ry时,中间的多路器(图中最大的那个multiplexer)选通Ry,让Ry寄存器驱动总线,这个时候Bus上的信号就是Ry的值;然后再看到R0~R7上分别有R0in~R7in信号,这个信号是使能信号,当这个信号有效时,在上升沿此触发器会将din的数据输入,所以说到这里大家一定想到了,这个时候Rx触发器上的Din信号就会变为有效,这样过了一个时钟周期后Ry的值就被送到了Rx当中。
与mv指令类似,mvi指令也将一个数据送入Rx当中,只不过这次的数据存在指令当中,是立即数,所以Rx的Din信号会变为有效,而多路器会选择IR中的数据,因为mvi指令的立即数存在指令当中。并且进行一定处理,例如扩展等。
add指令会让多路器先选择Rx,然后Ain信号有效,这样一个时钟周期后,Rx数据被送入Alu的A寄存器当中,这时多路器选择Ry,addsub信号为add以指示ALU进行加法操作,Gin有效让G寄存器存放运算结果,然后再过一个时钟周期G当中的数据就是Rx与Ry的和,这时多路器再选择Gin,Rx的Din有效,过了一个时钟周期后数据就被存放到Rx当中了。
sub的过程与add差不多,不过addsub信号是sub指示ALU进行减法。
下面我就将我做的CPU模型的RTL网表发出来,代码我会上传的,但是这个还只能进行仿真,因为设计的时候理念有问题,出现了异步设计,而且出现了将状态机的输出作为另一个器件的时钟端的错误,所以这个模型只能用于仿真。我用的synplify pro综合出的RTL,而状态转移图是用的Quartus的FSM Viewer截下来的。
首先是整个系统的概览:
这个比上面的那个简单模型复杂多了吧!但是别担心,其实这个只是上面的那个CPU变得稍微复杂了一点,这个和上面那个不同的地方还有:这个CPU是一个多周期CPU而上面的Lab Exercise是一个单周期的CPU
下图是程序计数器(PC),也就是常见x86处理器里面的ip(instruction poiniter):
红色部分就是pc了,后面是一个三态桥,连接到了总线上面,这里的数据有时候是要送到地址总线,用于寻内存中的数据,以便完成Instruction Fetch过程。
有时候又要送到通用寄存器的数据端,用于将pc的值送到其他寄存器。
下面这个是IR(Instruction Register),这个是多周期处理器的典型特征,因为处理器在第一个周期里面将机器码从内存取出,然后存放到这个寄存器里面,后面的几个状态都是通过这个寄存器里面的数据作为指示执行操作的。
下面介绍一下ALU,ALU是Arithmetic Logic Unit,即算术逻辑单元,这个装置的作用是进行算术操作和逻辑操作。典型的算术操作例如:1+1=2,11x23=253,而典型的逻辑操作例如:1 and 1=1,0 or 0 = 0,1&&3=8这种属于逻辑操作。
而从图中大家也看得到,ALU的输出用一根很长的线连接到了后面,参考整个CPU的图的话,会发现这些线连到了通用寄存器上面,这是为了让运算的结果存放回去,例如你用add eax,1的时候,eax的值被加上1然后放回eax,所以ALU的运算结果要用反馈送回到通用寄存器,而ALU的输入也应该有通用寄存器的输出。
下面再介绍ADDRMUX:
这个部件是用来选择地址的,右边的输出是CPU的地址总线,而CPU的地址总线就已经送出CPU了(也就是你能够在芯片的外表上看到引脚了),CPU的地址总线是送到存储器的地址端的,而现代的计算机系统实际上是相当复杂的,所以其实你家的计算机上CPU是通过北桥芯片访问内存的(当然也有将内存控制器做到CPU里面的)左边是地址的来源,地址的来源既有通用寄存器,也有程序计数器,还有一个是直接从IR里面送出,这是因为有的立即数里面也包含内存地址信息。
最后介绍通用寄存器:
通用寄存器的作用就是用来保存中间值或者用于运算,例如
相当于eax+2然后送回eax。
好马配好鞍,有了处理器,我们就得给它配上一个好的程序,下面我们就用自己设计的处理器进行求和,从1加到100,因为我们没有设计编译器,也没有设计汇编器,所以程序只能用机器码写出,示例程序如下:
我们不妨先写出程序的汇编代码:
mov [ADDR],r0;r0 = 0
mov r1,100
lop:add r2,r1
jmp r4(lop)
ext:mov [ADDR],r2
先将内存中存放数据的地址清零,这样才能存放等下送来的结果,然后将r1寄存器存入循环次数(也就是求和的上限)。然后再将r1的值加到r2中来,r2其实就是放求和的寄存器,最后我们会将r2中的值送到内存中的某个地址存放的。
然后将r1减去1,看看是否为0?如果为0则说明求和结束了,如果不是0则说明还要继续,结束后程序就跳到ext部分将结果存放到内存中某个地址(例子中给的是49152也就是二进制的0000b),最后jmp $是为了让程序停在这一行,防止程序跑飞(跑飞的程序危害很大!有可能把数据当代码或者把代码当数据!)
转换成VerilogHDL语言如下:
module memory
input [15:0] addr,
inout [15:0] data,
reg [15:0] data_ram[0:16'b11_1111];
initial begin
for (i = 0; i &= 16'b11_1111; i = i + 1)
data_ram[i] = $random();
data_ram[0] = 16'b0000; //mov [ADDR],r0;r0 = 0
data_ram[1] = 16'b0000; //ADDR
data_ram[2] = 16'b1000; //mov r1,100
data_ram[3] = 100; //100
//data_ram[2] = 16'b0000;
data_ram[4] = 16'b0001; //lop:add r2,r1
data_ram[5] = 16'b1000; //sub r1,1
data_ram[6] = 16'b0001; //1
data_ram[7] = 16'b1000; //cmp r1,0
data_ram[8] = 16'b0000; //0
data_ram[9] = 16'b0000; //jz ext
data_ram[10] = 16'b0011; //+3 offset(ext)
data_ram[11] = 16'b0000;//mov r4,4
data_ram[12] = 16'b0100;
data_ram[13] = 16'b0000;//jmp r4(lop)
data_ram[14] = 16'b0010;//ext:mov [ADDR],r2
data_ram[15] = 16'b0000;//ADDR
data_ram[16] = 16'b0000;//jmp $
data_ram[17] = 16'b1110;//-2 offset($)
/*data_ram[0] = 16'b0000; //mov r0,imm
data_ram[1] = 16'b1111; //imm
data_ram[2] = 16'b1000; //mov r7,r0
data_ram[3] = 16'b1000; //mov r3,0
data_ram[4] = 16'b0000;
data_ram[5] = 16'b0000; //mov r4,code of jmp r5
data_ram[6] = 16'b1000; //jmp r5
data_ram[7] = 16'b1100; //mov [r3],r4
data_ram[8] = 16'b0000; //mov r6,[0]
data_ram[9] = 16'b0000; //[0]
data_ram[10]= 16'b0110; //mov [255],r6
data_ram[11]= 16'b1111;
data_ram[12]= 16'b1000; //jmp r3
always @ (addr or rw or data)
data_ram[addr] =
assign data = rw ? 16'hzzzz : data_ram[addr];
设计中CPU外围还需要一个内存设备(Memory),我用HDL对其建模,初始化的时候每个内存地址上对应的数据都初始化为随机的,然后只有从0开始的一系列地址被初始化为我写的代码,而CPU在上电之后自动从0开始的地址取指令执行。
机器码对应的汇编指令在注释中已经给出。
然后是结果,结果应该是r2从0变化到+3+......+100=5050)
而r1则从100变化到0,变化到0后程序将进入死循环,停止在jmp $那一条。这是仿真开始的时候:
大家可以看到初始化后,d0~d7都变成了0,这是r0~r7寄存器的Q端,而state_current和state_next则是状态机的现态和状态机的次态,cpu的各个部件都通过这个状态机受到控制。状态名出现的顺序和上面的FSM Viewer的连线顺序是一样的。
而且大家可以看到,d2从0变化到了0x64也就是十进制100,说明已经执行了第一次加法了。
再来看看仿真结束:
这时候d1变化到了0而d2变化到了0x13ba(十进制的5050),说明程序已经在我们设计的处理器里面运行并且成功的得出了结果!
这个时候可能有人会问了,这个CPU怎么这么慢,算个1+....+100用了这么长的时间,上面的刻度都显示84100了,但是大家请注意,这个时间单位是ns
也就是说算完上述运算,这个处理器用了84100乘以10乘以-9次方秒,是人类所感觉不到的速度。
最后再提一下:
我是用synplify综合的电路,然后用debussy+modelsim仿真的,
相关资料请参考:
CPU逻辑设计,朱子玉,李亚民著
Lab Exercise 9出自DE2的开发光盘
如果有人想要代码,向我发邮件 我就会把代码发给你[CPU自作入门]如何设计一个16位CPU模型?该投稿暂无简介收藏0点赞0 dev urandom&/&如何设计一个简单的16位处理器模型,并且运行自己设计的程序,用debussy+modelsim仿真如何设计一个简单的16位处理器模型,并且运行自己设计的程序,用debussy+modelsim仿真[+展开简介]官方下载功能反馈

我要回帖

更多关于 可编程逻辑器件应用 的文章

 

随机推荐