本节博客主要是进行一个简单科普,介绍一下实验要求以及对本系列博客进行一个简单介绍。如果你是数字IC设计小白,建议通篇阅读;如果你基础比较扎实且时间较紧,可以直接跳到第二部分开始正文。
本实验是在完成《数字集成系统设计》课程大作业时实现的,由于在实现过程中可以比较深刻的体会到处理器的设计流程,故分享出来给初学者提供一个简单参考。
当然,作为一个大作业,难度并不太高,没有实现太多的指令,暂时也没有冒险检测,也没有实现多发射等操作,只是一个简单的处理器。此外,本人水平也有限,代码质量可能不是太高,也没有进行优化,仅限于完成操作,故可能有较多不足,还请大佬批评指正。
对于初学者,希望可以通过这一系列博客,培养出你们数字IC设计的一些基本的能力:对问题的思考方式、编程习惯、从软件到硬件设计的思维转变,工具的使用…
如果在你看完这些博客之后能够有所收获(而不仅仅是完成了作业),就够了,希望你能在IC设计的道路上越走越远。
阅读本博客的同学建议有一些处理器设计基础以及Verilog设计基础,但没有也没关系,文中将尽可能阐述清楚涉及到的知识。本系列博客主要基于:《MK.Computer.Organization.and.Design.The.Hardware.Software.Interface.ARM.Edition》,后续简称“本书”,有处理器设计需求的同学,建议仔细阅读该书,它写的很详细,可以帮你快速入门。有条件最好买一本来仔细研读,并尽可能动手实践;没有条件购买或暂时不需购买的同学可以从本博客中下载到该书电子版(ARM中英版本、RISC-V版本及答案、MIPS中文版)。建议阅读英文原版,遇到生词随时记录下来,既可以提升词汇量,又可以锻炼英语阅读速度。
当然,书中或多或少会有一些错误,博主猜测是因为这个书的一系列版本大部分都是从同一版复制粘贴过来的,修改的时候难免会漏掉一些,所以请大家读的时候擦亮眼睛。
链接:https://pan.baidu.com/s/1dtpFTsJ5fdEmnPDyX66U1Q
提取码:b26b
本博客在书写过程中将尽可能把遇到的知识通过超链接插入进来,方便读者快速跳转进行学习,也请大家不要烦躁,耐心学习这些知识,最好形成笔记,这样更有助于你的理解。
此外,博客中用到的代码都提供github源码下载。
ARM是Advanced RISC Machine的缩写,即进阶精简指令集机器。arm更早称为Acorn RISC Machine,是一个32位精简指令集(RISC)处理器架构。ARM处理器是典型的RISC架构,具有性能高、成本低和能耗省的特点,在智能手机、平板电脑、嵌入控制、多媒体数字等处理器领域拥有主导地位。同时ARM也在向桌面机、服务器和超级计算机领域发展。在后PC时代,ARM具有巨大的生态系统和应用领域。因此,了解这一体系结构对于我们理解计算机的组成原理与设计实践具有重要的意义。
ARM处理器更详细的介绍请参考:ARM架构版本及处理器系列详细介绍
当然,这只是宏观方面的学习,后面几章将开始详细介绍处理器相关的知识,包括指令介绍、寄存器介绍等。
ARMv8比MIPS庞大得多(ARMv8指令集参考手册多达5400页),但是本书只挑选了ARMv8指令集的一个子集,这个子集在指令数量和特性上都与以前版本所采用的MIPS相似。为了避免混淆,本书将这个子集称为LEGv8。所以,本书基于ARMv8撰写了LEGv8版。
本次实验主要是基于LEGv8指令集来实现一个简单的ARM处理器:
从教材第二章图2‐20(或下图1)的LEGv8指令集中挑选部分指令,使其至少能够完成阶乘和冒泡法排序两个程序(参见下面程序)。将这些指令按照图2‐20的编码组合成一个新的指令集(命名为DISD指令集)。
图1 LEGv8指令编码
阶乘的C语言程序为:
long long int fact(long long int n)
{
if(n < 1) return 1;
else return n * fact(n - 1);
}
该程序的实现很简单,fact为factorial的缩写,即阶乘;传入的形参为int类型的n,当n大于1时,直接返回1;否则进行递归调用。
冒泡算法的C语言程序可以分为两部分,子函数为交换函数swap(),用于交换数组元素,C代码为:
void swap(long long int v[], long long int k)
{
long long int temp;
temp = v[k];
v[k] = v[k+1];
v[k+1] = temp;
}
该函数也比较简单,传入的形参有两个,一个是要进行交换的数组地址v[],另一个是要进行交换的元素k。
另一个函数是排序函数sort(),用于排序数组元素,C代码为:
void sort(long long int v[], size_t n)
{
size_t i, j;
for(i = 0; i < n; i += 1)
{
for(j = i - 1; j >= 0 && v[j] > v[j+1]; j -= 1)
{
swap(v, j);
}
}
}
排序算法有很多种,此处采用的是冒泡排序(Bubble Sort)。虽然冒泡排序算法不是最快的,但却是最简单的。
有些同学注意到,上述的代码里采用的都是long long int和size_t类型,而不是常见的int类型,这是为什么呢?
下图为比较流行的规定:
尽管每个编译器都有多种选择,但一般而言,同一种操作系统上的编译器选择相同的解决方案。为简化起见,本书假设所有指针都是64位,并定义C寄存器都是双长整型,以便与指针的大小保持一致。本书也遵循C99标准,将索引数组的变量声明为size_t,size_t是标准C库中定义的,在64位系统中为long long unsigned int,非64位系统中为long unsigned int。这保证了该变量能与数组的大小匹配,索引值的声明一般和长整型相同。
参考教材第四章的内容,采用Verilog语言设计一个ARM处理器(通过单周期指令以及流水线两种方式),实现上述DISD指令集。
测试程序,分别测试阶乘和排序两种程序在上述微处理器中的运行情况。请关注可实现的最大阶乘数是多少,以及可实现对多少个正整数进行排序。
好的,本节就先讲到这里,如果你有收获且乐意的话,麻烦点个赞哦,收藏也可以哇( ̄▽ ̄)~*
本系列博客共分为5篇:
第一篇对一些处理器基础知识进行简单讲解,并讲清楚实验要求。
第二篇从指令、寄存器、汇编器的角度对设计处理器所需要的基础知识进行较为详细的讲解,并对实验所需汇编程序进行了分析。
第三篇讲解数字IC设计所需要的一些工具以及使用方法,并讲解了一些编程规范。
第四篇主要是针对单周期CPU的基础理论和模块设计进行讲解,在讲Verilog实现的时候,顺带讲了很多编程规范。
lijyhh/LEGv8
链接:https://pan.baidu.com/s/1dtpFTsJ5fdEmnPDyX66U1Q
提取码:b26b