计算机组成实验五——简单的类MIPS单周期处理器实现生命科学技术学院5110809XXX大豆比目录1OVERVIEW (1)1.1实验名称 (1)1.2实验目的 (1)1.3实验范围 (1)1.4注意事项 (1)2实验描述 (2)2.1新建工程 (2)2.2顶层模块Top (5)2.2.1模块描述 (5)2.2.2新建模块源文件Top.v (5)2.2.3定义信号线 (5)2.2.4程序计数器PC (6)2.2.5RESET (6)2.2.6模块实例化,连接模块 (7)2.2.7连接其他信号线 (8)3仿真测试 (10)3.1编写二进制测试程序 (10)3.2初始化存储器 (10)3.3编辑testbench文件 (11)3.4仿真测试,观察波形 (11)4下载验证 (12)4.1修改Top.v中Top模块的输入输出端口 (12)4.2编辑管脚约束文件top.ucf (12)4.3时钟分频 (12)4.4指定输入输出端口的意义 (13)5实验感想与建议 (14)5.1实验感想 (14)5.2一些建议 (14)6实验程序源代码 (15)6.1Top.v (15)6.2Ctr.v (18)6.3Alu.v (21)6.4AluCtr.v (22)6.5data_memory.v (23)6.6register.v (25)6.7signext.v (27)6.8inst_memory.v (27)6.9timeDivider.v (28)1.OVERVIEW11.1实验名称简单的类MIPS单周期处理器实现-整体调试1.2实验目的完成单周期的类MIPS处理器1.3实验范围本次实验将覆盖以下范围1、ISE的使用2、Xilinx Spartan3E实验板的使用3、使用VerilogHDL进行逻辑设计4、仿真测试、下载验证1.4注意事项本实验的逻辑设计工具为Xilinx ISE13.4。
2.1新建工程1、启动ISE13.4;2、新建工程lab5;3、选择FPGA型号、综合和仿真工具、描述语言等配置;4、右键点击Hierarchy窗口,添加已有模块。
有:Ctr.v、Alu.v、AluCtr.v、data_memory.v、register.v、signext.v六个文件(之前两个实验完成)。
5、Adding Source Files...中,选中全部要添加的文件,保持默认项,点OK。
2.2顶层模块Top2.2.1模块描述MIPS单周期处理器原理图2.2.2新建模块源文件Top.v下图的例子是已经下载至板子验证过的,故输入和输出有1个时钟(mainClock)、4个开关([3:0]SWITCH)和8个LED灯([7:0]LED)。
2.2.3定义信号线给Top模块内的每一根连接的信号线命名,并在top模块中声明它们。
2.2.4程序计数器PC程序计数器是这个简单CPU能够跑起来的关键。
定义一个32位reg类型PC,在时钟上升沿做PC<=PC+4。
//定义PC//初始化PC为0//在时钟的上升沿根据不同情况对PC赋值2.2.5RESET当RESET为1时,PC置0,各寄存器清零。
要达成上述功能,就需要适当修改之前实验的各个模块,给模块添加reset信号。
以下以data_memory模块为例,演示reset信号的加入和功能实现。
1、在data_memory模块的定义中加入输入信号reset:2、在always模块中添加初始化代码在这一步中需要注意的是,对数据初始化的操作必须在原来数据赋值的always模块中进行,否则上板时会失败(不允许同一个变量在两个模块中赋值)。
2.2.6模块实例化,连接模块实例化前两次实验中编写的模块,实例化的过程中连接模块的端口。
本实验在实例化过程中采用的是如下方法:在连接时用“.”符号,表明原模块是定义时规定的端口名:模块模块名(.端口1(信号1),.端口2(信号2))下面是本工程文件所有实例化对象和端口连接的代码:2.2.7连接其他信号线MUXMux可以用一个三目运算符来实现。
2.实验描述9在Top.v中Mux的实现代码如下:OUT1:OUT2:OUT3:OUT4:OUT5:3.1编写二进制测试程序由于处理器是从指令内存inst_memory中读取指令,依次执行的,所以程序保存在指令内存中。
以下是测试程序的指令:00001000000000000000000000000100//j a00000000000000000000000000000000//nop00000000000000000000000000000000//nop00000000000000000000000000000000//nop10101100000001000000000000000000//sw$40($0)10101100000000110000000000000100//sw$34($0)10001100000000010000000000000100//lw$14($0)10001100000000100000000000000000//lw$20($0)00000000001000100001100000100000//add$3,$1,$200000000001000100010000000100010//sub$4,$1,$200001000000000000000000000000100//j a3.2初始化存储器$readmemb和$readmemh这两个系统任务用来从文件中读取数据到存储器中,代码编写放在存储器的initial初始化块中。
data_memory中:register中:inst_memory中:注意:在仿真测试时,初始化不完全并不会对波形造成影响,但是如果要上板子,则需对变量中的每一位进行赋值,否则会产生一个warning,提示你进行了部分初始化,系统默认会将你的初始化操作忽略从而产生错误。
3.3编辑testbench文件这里添加了时钟激励,200ns为一个时钟周期。
3.4仿真测试,观察波形对照自己的测试程序可知,波形正确,仿真成功。
4.1修改Top.v中Top模块的输入输出端口之前有提到过,上板子时,输入输出要做些变化。
如下图Top模块的输入输出直接被改为一个时钟、四个开关和八个LED灯。
4.2编辑管脚约束文件top.ucf将输入输出端口与物理管脚连接起来,如下:4.3时钟分频由于板子晶振提供的时钟频率速度较高,需要对时钟进行分频,所以自己定义了一个TimeDivider模块来实现,是由实验二中的TimeDivider模块做简单修改而来。
这里将buffer和clockOut做了一个初始化为0,是为了上板子的需要。
另外将clockOut<=&buffer改为clockOut<=buffer[24]可以使得到的时钟周期波形更加理想。
如不改,则clockOut在绝大多数时间为0,只有在1/225的时间才为1,做此修改后,clockOut为0和1的时间各占一半,波形较理想,易于观察。
4.4指定输入输出端口的意义前面4.1对Top模块的定义时,只有1个时钟、4个开关和8个LED灯,而没有指定他们分别表示什么。
所以接下来我们需要定义这4个开关和8个LED灯所对应的信号。
//开关3为reset信号//开关2,开关1,开关0的状态分别是关、关、开的时候即001时,LED灯显示第一个寄存器的后8位数据;//开关2,开关1,开关0的状态分别是关、开、关的时候即010时,LED灯显示第二个寄存器的后8位数据;//开关2,开关1,开关0的状态分别是关、开、开的时候即011时,LED灯显示第三个寄存器的后8位数据;//开关2,开关1,开关0的状态分别是开、关、关的时候即100时,LED灯显示第四个寄存器的后8位数据;//开关2,开关1,开关0的状态分别是关、关、开的时候即001时,LED灯显示指令寄存器的后8位数据;//开关2,开关1,开关0的状态是除上面说明的五种情况以外时,LED灯显示PC寄存器的后8位数据;4.5生成二进制流文件,下载至板子点击Generate Programming File,生成完成后,下载至板子验证。
经实际操作验证,程序有效,上板子成功!5.实验感想与建议145.1实验感想Lab5是对Lab3和Lab4的一个综合,通过新定义的模块Top来实现一个简单的类MIPS 单周期处理器。
在老师所给的实验指导书中,省略了很多细节,有很多细节代码需要自己去编写,需要自己对着原理图思考。
但是所幸前几个实验让我们对Verilog和FPGA有了一个粗浅的认识,使得自己拥有了初步自己思考和编写代码的能力。
窃以为这样一步一步走向深入的方法是非常不错的!比我们本专业的实验设计要合理得多!希望老师能够继续保持,实验课能够越办越好。
不得不提的是在板子上验证这一环节占用了我整个Lab5编写的大半时间,这主要是由于我之前对Verilog的代码编写只是依葫芦画瓢,而不得其要领所致。
花了很多的时间重新编写Lab5的代码部分,主要是因为阻塞赋值和非阻塞赋值的理解不够深刻,导致整个程序翻译成二进制流文件时一直报错。
之后通过百度,知道了对这两种赋值的一般处理方法,才解决了此问题。
总之,上板子遇到的问题要比仿真多得多……最后还是感谢老师让我将板子带回宿舍自行调试,我才最终完成了板子调试这部分的工作,也算了却我一个心结。
5.2一些建议本次实验结束,由于作为一名大四学生琐事缠身也无力进行下一个实验,虽然本人对下一个实验也是充满期待,在此也是表达一下遗憾之情。
以下就是本人关于计算机组成实验的一些建议:1、在实验初期时即说明板子可外借,其实本人Lab5波形仿真早已成功,只是板子验证实验花去过多时间而无法进行Lab6实验,直到老师借本人一个板子,才完成了板子验证实验。
2、实验指导文件中多一些要实现的功能的描述。
在本次实验中,本人就是一直纠结reset 要实现何种功能而耽误许多时间,也许这是本实验高度开放性的体现,但本人还是希望有一个较明确的目标比较容易实现。
在这几个星期的实验中,多谢老师的悉心指导和给予的宽松的实验环境。
谢谢老师!6.1Top.v////////////////////////////////////////////////////////////////////////////////// module Top(input mainClock,input[3:0]SWITCH,output reg[7:0]LED);reg[31:0]PC;wire clk,reset,REG_DST,JUMP,BRANCH,MEM_READ,MEM_TO_REG,MEM_WRITE,ALU_SRC,REG_WRITE,ZERO;wire[1:0]ALU_OP;wire[3:0]ALU_CTR;wire[31:0]INST;wire[31:0]ALU_RES;wire[31:0]DATA;wire[31:0]READ_DATA;wire[31:0]READ_DATA1;wire[31:0]READ_DATA2;wire[4:0]OUT1;wire[31:0]OUT2;wire[31:0]OUT3;wire[31:0]OUT4;wire[31:0]OUT5;wire[7:0]REG1;wire[7:0]REG2;wire[7:0]REG3;wire[7:0]REG4;initialbeginPC=0;endtimeDivider mainTimeDivider(.clockIn(mainClock),.clockOut(clk));Ctr mainCtr(.reset(reset),.opCode(INST[31:26]),.regDst(REG_DST),.jump(JUMP),.branch(BRANCH),.memRead(MEM_READ),.memToReg(MEM_TO_REG),.aluOp(ALU_OP),.memWrite(MEM_WRITE),.aluSrc(ALU_SRC),.regWrite(REG_WRITE));Alu mainAlu(.reset(reset),.input1(READ_DATA1),.input2(OUT2),.aluCtr(ALU_CTR),.zero(ZERO),.aluRes(ALU_RES));AluCtr mainALuCtr(.reset(reset),.aluOp(ALU_OP),.funct(INST[5:0]),.aluCtr(ALU_CTR));data_memory mainDataMemory(.clock_in(clk),.reset(reset),.address(ALU_RES),.writeData(READ_DATA2),.memWrite(MEM_WRITE),.memRead(MEM_READ),.readData(READ_DATA)); register mainRegister(.clock_in(clk),.reset(reset),.readReg1(INST[25:21]),.readReg2(INST[20:16]),.writeReg(OUT1),.writeData(OUT3),.regWrite(REG_WRITE),.readData1(READ_DATA1),.readData2(READ_DATA2),.register1(REG1),//.register2(REG2),//.register3(REG3),//.register4(REG4));//signext mainSignExt(.inst(INST[15:0]),.data(DATA),.reset(reset));inst_memory mainInstMemory(.reset(reset),.readAddress(PC),.inst(INST));assign OUT1=REG_DST?INST[15:11]:INST[20:16];assign OUT2=ALU_SRC?DATA:READ_DATA2;assign OUT3=MEM_TO_REG?READ_DATA:ALU_RES;assign OUT4=(ZERO&&BRANCH)?((DATA<<2)+PC+4):(PC+4);assign OUT5=JUMP?(PC+4)&32'b111100000000000000000000|(INST[25:0]<<2): OUT4;assign reset=SWITCH[3];//assign LED=(SWITCH[2]&&SWITCH[1]&&SWITCH[0])?INST[7:0]:PC[7:0];alwaysbegincase(SWITCH[2:0])3'b001:LED=REG1;3'b010:LED=REG2;3'b011:LED=REG3;3'b100:LED=REG4;3'b111:LED=INST[7:0];default:LED=PC[7:0];endcaseendalways@(posedge clk)beginif(reset)PC<=0;//else if(ZERO&BRANCH)PC<=OUT4;else if(JUMP)PC<=OUT5;elsePC<=PC+4;endendmodule6.2Ctr.v////////////////////////////////////////////////////////////////////////////////// module Ctr(input reset,input[5:0]opCode,output reg regDst,output reg aluSrc,output reg memToReg,output reg regWrite,output reg memRead,output reg memWrite,output reg branch,output reg[1:0]aluOp,output reg jump);always@(opCode or reset)beginif(reset)beginregDst=0;aluSrc=0;memToReg=0;regWrite=0;memRead=0;memWrite=0;branch=0;aluOp=2'b00;jump=0;endelsecase(opCode)6'b000010://jumpbeginregDst=0;aluSrc=0;memToReg=0;regWrite=0;memRead=0;memWrite=0;branch=0;aluOp=2'b00;jump=1;end6'b000000://R typebeginregDst=1;aluSrc=0;memToReg=0;regWrite=1;memRead=0;memWrite=0;branch=0;aluOp=2'b10;jump=0;end6'b100011://lwbeginregDst=0;aluSrc=1;memToReg=1;regWrite=1;memRead=1;memWrite=0;branch=0;aluOp=2'b00;jump=0;end6'b101011://sw beginregDst=1'bx;aluSrc=1;memToReg=1'bx;regWrite=0;memRead=0;memWrite=1;branch=0;aluOp=2'b00;jump=0;end6'b000100://beq beginregDst=1'bx;aluSrc=0;memToReg=1'bx;regWrite=0;memRead=0;memWrite=0;branch=1;aluOp=2'b00;jump=1;enddefault:beginregDst=0;aluSrc=0;memToReg=0;regWrite=0;memRead=0;memWrite=0;branch=0;aluOp=2'b00;jump=0;endendcaseendendmodule6.3Alu.v////////////////////////////////////////////////////////////////////////////////// module Alu(input reset,input[31:0]input1,input[31:0]input2,input[3:0]aluCtr,output reg zero,output reg[31:0]aluRes);always@(input1or input2or aluCtr or reset)////beginif(reset)////begin////zero=0;////aluRes=0;////end////else if(aluCtr==4'b0010)//addaluRes=input1+input2;else if(aluCtr==4'b0110)//subtractbeginaluRes=input1-input2;if(aluRes==0)zero=1;elsezero=0;endelse if(aluCtr==4'b0000)//andaluRes=input1&input2;else if(aluCtr==4'b0001)//oraluRes=input1|input2;else if(aluCtr==4'b0111)//sltbeginif(input1<input2)aluRes=1;elsealuRes=0;endelse if(aluCtr==4'b1100)//noraluRes=~(input1|input2);endendmodule6.4AluCtr.v////////////////////////////////////////////////////////////////////////////////// module AluCtr(input reset,////input[1:0]aluOp,input[5:0]funct,output reg[3:0]aluCtr);always@(aluOp or funct or reset)if(reset)////aluCtr=0;////else////begin////casex({aluOp,funct})8'b00xxxxxx://lw swaluCtr=4'b0010;8'b01xxxxxx://beqaluCtr=4'b0110;8'b10100000://R-type addaluCtr=4'b0010;8'b10100010://R-type subtractaluCtr=4'b0110;8'b10100100://R-type andaluCtr=4'b0000;8'b10100101://R-type oraluCtr=4'b0001;8'b10101010://R-type sltaluCtr=4'b0111;endcaseend////endmodule6.5data_memory.v//////////////////////////////////////////////////////////////////////////////////module data_memory(input clock_in,input reset,input[31:0]address,input[31:0]writeData,input memWrite,input memRead,output reg[31:0]readData);reg[31:0]memFile[15:0];//memory space:16*32bitsinitialbeginmemFile[0]=32'b00000000000000000000000000000000;memFile[1]=32'b00000000000000000000000000000001;memFile[2]=32'b00000000000000000000000000000010;memFile[3]=32'b00000000000000000000000000000011;memFile[4]=32'b00000000000000000000000000000100;memFile[5]=32'b00000000000000000000000000000101;memFile[6]=32'b00000000000000000000000000000110;memFile[7]=32'b00000000000000000000000000000111;memFile[8]=32'b00000000000000000000000000001000;memFile[9]=32'b00000000000000000000000000001001;memFile[10]=32'b00000000000000000000000000001010;memFile[11]=32'b00000000000000000000000000001011;memFile[12]=32'b00000000000000000000000000001100;memFile[13]=32'b00000000000000000000000000001101;memFile[14]=32'b00000000000000000000000000001110;memFile[15]=32'b00000000000000000000000000001111;//$readmemh("./src/mem_data.txt",memFile,10'h0);endalways@(memRead or address or reset)////beginif(reset)readData=0;else if(memRead)readData=memFile[address>>2];endalways@(negedge clock_in)beginif(reset)////beginmemFile[0]<=32'b00000000000000000000000000000000;memFile[1]<=32'b00000000000000000000000000000001;memFile[2]<=32'b00000000000000000000000000000010;memFile[3]<=32'b00000000000000000000000000000011;memFile[4]<=32'b00000000000000000000000000000100;memFile[5]<=32'b00000000000000000000000000000101;memFile[6]<=32'b00000000000000000000000000000110;memFile[7]<=32'b00000000000000000000000000000111;memFile[8]<=32'b00000000000000000000000000001000;memFile[9]<=32'b00000000000000000000000000001001;memFile[10]<=32'b00000000000000000000000000001010;memFile[11]<=32'b00000000000000000000000000001011;memFile[12]<=32'b00000000000000000000000000001100;memFile[13]<=32'b00000000000000000000000000001101;memFile[14]<=32'b00000000000000000000000000001110;memFile[15]<=32'b00000000000000000000000000001111;//$readmemh("./src/mem_data.txt",memFile,10'h0);endelse if(memWrite)memFile[address>>2]<=writeData;endendmodule6.6register.v//////////////////////////////////////////////////////////////////////////////////module register(input clock_in,input reset,/////////input[25:21]readReg1,input[20:16]readReg2,input[4:0]writeReg,input[31:0]writeData,input regWrite,output reg[31:0]readData1,output reg[31:0]readData2,output[7:0]register1,//output[7:0]register2,//output[7:0]register3,//output[7:0]register4//);reg[31:0]regFile[15:0];//register space:16*32bitsinitialbeginregFile[0]=32'b00000000000000000000000000000000;regFile[1]=32'b00000000000000000000000000000001;regFile[2]=32'b00000000000000000000000000000010;regFile[3]=32'b00000000000000000000000000000011;regFile[4]=32'b00000000000000000000000000000100;regFile[5]=32'b00000000000000000000000000000101;regFile[6]=32'b00000000000000000000000000000110;regFile[7]=32'b00000000000000000000000000000111;regFile[8]=32'b00000000000000000000000000001000;regFile[9]=32'b00000000000000000000000000001001;regFile[10]=32'b00000000000000000000000000001010;regFile[11]=32'b00000000000000000000000000001011;regFile[12]=32'b00000000000000000000000000001100;regFile[13]=32'b00000000000000000000000000001101;regFile[14]=32'b00000000000000000000000000001110;regFile[15]=32'b00000000000000000000000000001111;//$readmemh("./src/reg_file.txt",regFile,8'h0);endassign register1=regFile[1][7:0];///assign register2=regFile[2][7:0];///assign register3=regFile[3][7:0];///assign register4=regFile[4][7:0];///always@(readReg1or readReg2or writeReg or writeData or reset)/// beginif(reset)beginreadData1=0;readData2=0;endelsebeginreadData1=regFile[readReg1];readData2=regFile[readReg2];////endendalways@(negedge clock_in)beginif(reset)beginregFile[0]<=32'b00000000000000000000000000000000;regFile[1]<=32'b00000000000000000000000000000001;regFile[2]<=32'b00000000000000000000000000000010;regFile[3]<=32'b00000000000000000000000000000011;regFile[4]<=32'b00000000000000000000000000000100;regFile[5]<=32'b00000000000000000000000000000101;regFile[6]<=32'b00000000000000000000000000000110;regFile[7]<=32'b00000000000000000000000000000111;regFile[8]<=32'b00000000000000000000000000001000;regFile[9]<=32'b00000000000000000000000000001001;regFile[10]<=32'b00000000000000000000000000001010;regFile[11]<=32'b00000000000000000000000000001011;regFile[12]<=32'b00000000000000000000000000001100;regFile[13]<=32'b00000000000000000000000000001101;regFile[14]<=32'b00000000000000000000000000001110;regFile[15]<=32'b00000000000000000000000000001111;//$readmemh("./src/reg_file.txt",regFile,8'h0);/*readData1=0;readData2=0;*/endelsebeginif(regWrite)regFile[writeReg]<=writeData;endendendmodule6.7signext.v////////////////////////////////////////////////////////////////////////////////// module signext(input[15:0]inst,input reset,////output reg[31:0]data);always@(inst or reset)////beginif(reset)////data=0;////else if(inst[15]==1)////data={16'b1111111111111111,inst};elsedata={16'b0000000000000000,inst};endendmodule6.8inst_memory.v////////////////////////////////////////////////////////////////////////////////// module inst_memory(input reset,input[31:0]readAddress,output reg[31:0]inst);reg[31:0]instMemFile[0:15];//memory space:16*32bitsinitialbegininstMemFile[0]=32'b00001000000000000000000000000100;//j ainstMemFile[1]=32'b00000000000000000000000000000000;//nopinstMemFile[2]=32'b00000000000000000000000000000000;//nopinstMemFile[3]=32'b00000000000000000000000000000000;//nopinstMemFile[4]=32'b10101100000001000000000000000000;//sw$40($0)instMemFile[5]=32'b10101100000000110000000000000100;//sw$34($0)instMemFile[6]=32'b10001100000000010000000000000100;//lw$14($0)instMemFile[7]=32'b10001100000000100000000000000000;//lw$20($0)instMemFile[8]=32'b00000000001000100001100000100000;//add$3,$1,$2instMemFile[9]=32'b00000000001000100010000000100010;//sub$4,$1,$2instMemFile[10]=32'b00001000000000000000000000000100;//j ainstMemFile[11]=32'b00000000000000000000000000000000;//nopinstMemFile[12]=32'b00000000000000000000000000000000;//nopinstMemFile[13]=32'b00000000000000000000000000000000;//nopinstMemFile[14]=32'b00000000000000000000000000000000;//nopinstMemFile[15]=32'b00000000000000000000000000000000;//nop//$readmemb("./src/mem_inst.txt",instMemFile,32'b0);endalways@(readAddress or reset)beginif(reset)inst=0;elseinst=instMemFile[readAddress>>2];////readAddress/4endendmodule6.9timeDivider.v//////////////////////////////////////////////////////////////////////////////////module timeDivider(input clockIn,6.实验程序源代码29output reg clockOut);reg[24:0]buffer;////initial beginbuffer=0;clockOut=0;/////endalways@(posedge clockIn)beginbuffer<=buffer+1;clockOut<=buffer[24];endendmodule。