向明尚 张 强
(东北石油大学计算机与信息技术学院, 黑龙江 大庆 163318)
传统的计算机体系结构是指计算机的概念性结构,其作用是针对不同的层次分配软硬件功能和确定软硬件界面[1]。从存储程序和数据的角度,可将其分为冯·诺依曼结构和哈佛结构。冯·诺依曼结构也称普林斯顿结构,是将指令存储器和数据存储器合并在一起。哈佛结构是将指令存储器和数据存储器分开的一种并行存储器结构(见图1),其中程序和数据存储在不同的存储器中,可分别编址独立访问。
图1 哈佛结构示意图
模型机采用的是哈佛结构设计指令和数据存储器,指令存储器用于保存系统和用户程序,数据存储器用于保存操作数据、计算结果以及作为数据的交换空间。计算机系统通常由运算器、控制器、存储器、输入设备、输出设备五大功能部件组成[2]。其中,运算器用于算术逻辑运算;控制器用于控制程序和数据的输入、运行以及计算结果的输出;存储器用于保存程序和数据;输入设备用于输入程序和数据;输出设备用于输出计算机系统的计算结果及运行状态,通过显示器等设备予以显示。
计算机系统中采用数字化信息来表示数值与其他各种类型的信息,采用逻辑代数作为硬件设计的基本数学工具[3]。硬件电路的实现,可以通过现场可编程逻辑阵列(field-programmable gate array,FPGA)[4]和专用集成电路(application specific integrated circuit,ASIC)来完成[5]。ASIC通用性较差[6-8],因此本次研究采用FPGA实现哈佛结构模型机的设计。
针对计算机系统中各功能模块进行层次设计[9],设计的首要原则是简化原则。Dijkstra认为,系统的层次结构设计可以对系统验证和测试的简化带来巨大帮助[10]。完成各功能模块设计后,将其按照逻辑关系分层组织集成,构成模型机。采用自底向上的设计方法,依次设计ALU、程序存储器、数据存储器、译码器、累加器(Acc)、通用计数器(Ucnt)、程序计数器(PC)、堆栈计数器(SP)、时钟系统、指令系统等功能模块。验证后将各部件加入总线并予以测试,分层次组成不同的小系统。对小系统进行全面测试,通过测试后依次封装制作成系统模块,即集成单元电路芯片。
运算器小系统包括ALU、程序存储器、数据存储器等模块。一般情况下,能用数字化形式表示的信息,就可以归结为算术运算或逻辑运算类数据[11]。ALU是完成算术逻辑运算的单元电路,其功能结构如图2所示。ALU是一个多输入、多输出函数,表示为F=f(A,B,S)。其中,选择码用来确定2个运算数应该完成的运算类型,总运算数共有2k种。
图2 ALU功能结构示意图
对于程序和数据存储器,则应用FPGA中的存储器IP核进行设计,并配以相应的寄存器和存储器配置文件。验证通过后,加入总线构成一个运算器小系统(见图3),封装成Arithmetic_system模块。
图3 运算器小系统原理图
计数器小系统包括累加器、通用计数器、程序计数器、堆栈计数器等模块,以及添加封装后的Arithmetic_system模块和系统总线构成Counter_System模块,其工作原理如图4所示。累加器是计算机系统中工作比较频繁的功能部件,参与加减法、乘法、除法等多种运算以及数据传送,并具有判断数据正负和是否为零的功能。
图4 计数器小系统工作原理图
程序计数器PC,作为地址计数器指向程序存储器的一个存储单元,用来保存下一条将要执行的指令地址,并且具有计数值自动加1的功能。当指令执行时,首先根据PC中的地址,将一条指令由程序存储器中取出并放入到指令寄存器中,完成“取指令”的操作,即完成计算机系统的“取指”、“译码”、“执行”的第一个阶段。第一条指令执行完毕,PC计数值自动加1,然后准备取出下一条指令,最后完成所有指令的执行过程。
堆栈计数器,作为堆栈指针指向数据存储器的堆栈空间,采用后进先出的栈结构,由堆栈指针指向栈顶,可完成数据的进栈和出栈的操作。
堆栈计数器,其初值即栈顶的值,与计算机系统堆栈存储区的大小有关。本系统的堆栈存储器为8位数据存储器,其数据线、地址线都是8位,共有256个字节存储单元,存储单元地址从 0 到 255。因此,堆栈计数器采用的是 8 位计数器,可寻址 256 个存储单元。
寄存器是系统中的核心资源。为了节约芯片面积以降低成本,在保证功能和性能的基础上减少了芯片数量,并从结构上予以优化。在封装后的Counter_System模块基础上,分别添加指令寄存器、操作数寄存器、输出结果寄存器和系统总线等,从而构成寄存器小系统。寄存器小系统的工作原理如图5所示。指令寄存器用于保存由PC作为地址取出来的指令,以备送往指令译码器进行译码操作。其中,有2个操作数寄存器,用于保存参加算数逻辑运算的2个操作数;有1个输出结果寄存器,用于保存算数逻辑运算的结果。寄存器小系统封装成Register_system模块。
图5 寄存器小系统原理图
控制系统是模型机系统的核心,通过它才能使各个功能模块组织起完整的计算机系统,并根据指令系统的指令发出各种微操作指令,控制和完成各项系统工作。以Register_system模块为基础,添加译码器、节拍发生器、控制矩阵等构成一个控制系统。译码器在计算机中的系统应用较多:指令译码器,用于区分指令的功能,根据指令编码进行译码,执行指令相应的功能;地址译码器,用来区分存储器地址,寻找存储单元;状态译码器,用来区分设备的运行状态。译码器的设计与模型机的系统总线等有关,如作为存储器地址译码器,其输入、输出总线应与存储器地址相匹配。
节拍发生器由环形计数器和控制电路组成。模型机中的各种功能部件,都是在时钟信号的统一控制下按照设定顺序进行工作。为了协调各部件的工作,将时钟信号转换成机器节拍,使各部件按照节拍的顺序有条不紊地工作。
对于控制矩阵,需要根据计算机系统的体系结构、指令系统、译码系统、节拍发生器以及各种功能部件的特性进行综合设计,通过原理图和硬件描述语言相结合的方法来实现设计。
输入输出系统,其功能是控制模型机与外部数据的交换。输入系统由输入缓冲区计数器、缓冲区数据存储器、缓冲区控制单元、频率协调器等单元电路组成;输出系统由液晶显示器、七段数码管、LED二极管、蜂鸣器等单元电路组成。在上述小系统和控制系统的基础上,添加输入输出系统构成模型机系统模块Model_TOP,并以Alter DE0实验板为例添加I/O引脚配置和锁相环单元电路,构成完整的模型机系统。模型机的工作原理如图6所示。
图6 模型机原理图
计算机系统是时钟驱动的数字系统,必须具备可靠稳定的同步时钟系统。对于同步时钟系统,一般采用压控晶振(VCO) 频率锁相同步技术[12]和高精度晶振结合软件修正分频数同步技术[13]。本系统采用压控晶振频率锁相同步技术进行设计,系统的时钟周期设计为50 ns。DEO开发板上带有50 MHz的时钟源,可产生的时钟信号周期为20 ns,小于模型机的时钟周期,无法满足模型机的时钟要求。因此,采用FPGA内部的锁相环PLL来处理时钟信号,产生模型机所需的50 ns时钟信号周期。
指令系统是全部机器指令的集合,机器指令对应的是机器语言,而机器语言是由一条条语句构成,每一条语句又能准确表达某种语义[2]。在指令系统的设计中,既要考虑到功能性和实用性,又要考虑到实现的可能性和可靠性。模型机指令系统基于RISC理论采用单地址格式设计,指令由操作码和地址码组成。表1所示为模型机部分指令。
管理程序属于作业调度程序,采用指令系统的指令来编写。它能通过指令存储器配置文件直接提供给指令存储器,在系统开机后自动执行。管理系统可根据输入缓存区的情况读取用户程序和数据,将其分别保存到指令和数据存储器中。当用户程序和数据输入完毕后,自动调用并执行用户程序。管理程序清单如表2所示。指令存储器配置文件如图7所示。
管理程序可通过JEMP指令判断输入缓冲区是否为空:如果为空,则循环等待;如果不空,则调用输入子程序Input,将输入缓冲区的用户程序输入到模型机的指令存储器40号单元开始的存储单元中,将用户的数据输入到模型机的数据存储器中。JEND指令判断用户程序输入完毕则调用用户程序开始执行。
表1 模型机指令系统
表2 管理程序清单
图7 指令存储器配置文件结构示意图
用户程序按照指令系统中的指令编写。简单的用户程序,可以完成2个数的加法运算。如,3+5=8,计算结果8被送到7段数码管上显示。程序中指令的含义是,数据3送到Acc,Acc送到数据RAM的1号单元,即第一个加数保存在数据RAM的1号单元;接下来数据5送到Acc,Add指令将Acc的内容加上数据RAM的1号单元的内容3,得到的和是8,再将数据8保存到数据RAM的2号单元,最后输出数据RAM的2号单元的内容,即输出加法运算的和。
采用Verilog 语言编写微程序进行仿真测试。Verilog是硬件描述语言的一种,用于数字系统设计。可用它进行各种级别的逻辑设计,也可用它进行数字逻辑系统的仿真验证、时序分析、逻辑综合[14]。以运算器小系统为例介绍仿真测试过程。
首先,建立测试工程,其测试原理如图8所示。
图8 运算器小系统仿真测试原理图
其次,编写微程序测试文件并执行仿真,仿真波形如图9所示,部分测试文件代码如下。
第一段代码:
#100 d=0;dataMAL=1;clk=1;
#100 dataMAL=0;clk=0;
#100 d=9;dataMDL=1;clk=1;
#100 dataMDL=0;clk=0;
#100 dataMW=1;clk=1;
#100 dataMW=0;clk=0;
#100 dataME=1; clk=1;
#100 dataME=0; clk=0;
……
在上述代码段中,将数据9 写入数据RAM的0号单元,对应图9中的1、2、3处。
第二段代码:
#100 d=1;dataMAL=1; clk=1;
#100 dataMAL=0;clk=0;
#100 d=6;dataMDL=1; clk=1;
#100 dataMDL=0;clk=0;
#100 dataMW=1; clk=1;
#100 dataMW=0;clk=0;
#100 dataME=1; clk=1;
#100 dataME=0; clk=0;
……
上述代码段,将数据6写入数据 RAM的1号单元,其执行结果对应于图9中的4、5、6处。
第三段代码:
#100 add=0;clk=1;#100 clk=0; add =0
#100 d=0;dataMAL=1; clk=1;
#100 dataMAL=0;clk=0;
#100 dataME=1;clk=1;#100 clk=0;
#100 aL=1;clk=1;
#100 aL=0;dataME=0;clk=0;
……
上述代码段,将数据RAM的0号单元数据9输出到总线,同时,ALU的数据寄存器锁存数据9,其执行结果对应于图9中的7、8处。
第四段代码:
#100 d=1;dataMAL=1;clk=1;
#100 dataMAL=0;clk=0;
#100 dataME=1;clk=1;#100 clk=0;
#100 bL=1;clk=1;
#100 bL=0;dataME=0;clk=0;
……
上述代码段,将数据RAM的1号单元数据6输出到总线,同时,ALU的数据寄存器锁存数据6,其执行结果对应于图9中的9、10的处。
第五段代码:
#100 clk=1;addE=1;notE=0;orE=0;andE=0;
#100 clk=0;addE=0;
#100 clk=1;addE=0;notE=0;orE=0;andE=1;
#100 clk=0;andE=0;
#100 clk=1;addE=0;notE=0;orE=1;andE=0;
#100 clk=0;orE=0;
#100 clk=1;addE=0;notE=1;orE=0;andE=0;
#100 clk=0;notE=0;
……
上述代码段输出运算器小系统的算数逻辑运算和、与、或、非的结果:0f、00、0f、f6,其执行结果对应于图9中的11、12、13、14处。
图9 运算器小系统仿真波形图
按照图6配置输入输出引脚,将工程与开发板联系起来,编译工程生成开发板编程文件Model_TOP.pof,利用开发板的JTAG接口下载到开发板的Flash 中保存,开机后即可自动执行模型机系统。通过开发板上的按键,依次输入用户程序代码:06,03,05,01,06,05,01,01,05,02,02,02,F1。录入完毕按下复位键开始执行用户程序,即可在开发板的数码管上显示2个加数(数字3和5),以及求得的和(数字8)。用户程序执行结果正确,表明模型机系统设计正确。
模型机采用哈佛结构利用自底向上的方法进行设计。首先设计所需要的各种功能单元电路,依次分层封装成小系统,再生成电路元件并添加总线及控制电路,最后构成完整的模型机系统。单元电路的设计采用IP核、原理图和Verilog语言编程相结合的形式进行。原理图设计简洁直观,适合于逻辑边界清晰明确、功能相对简单的单元电路设计。对于逻辑边界不够清晰、功能比较复杂的单元电路,采用语言编程的方法更方便有效。系统设计的难点在于指令系统、时钟、节拍系统、控制矩阵等。对于系统设计的正确性,采用仿真波形分析和开发板下载相结合的方法进行验证。通过仿真分析对各个功能模块逐一验证,能够及时发现并纠正设计中存在的问题,加快设计进度。通过开发板下载运行所设计的工程文件,测试了模型机的功能和系统性能。测试验证结果表明,模型机的设计合理有效,其各项功能及性能符合要求。