赞
踩
基本要求:利用Verilog HDL语言,基于Xilinx FPGA nexys4实验平台,设计一个能够执行以下MIPS指令集的单周期类MIPS处理器,要求完成所有支持指令的功能仿真,验证指令执行的正确性;
支持基本的算术逻辑运算如add,sub,and,or,slt, a n d i \textcolor{red}{andi} andi指令;
支持基本的内存操作如lw,sw指令;
支持基本的程序控制如beq,j指令。
根据单周期mipsCPU的结构分析知,可以将子模块分为数据存储器dram、指令存储器irom、寄存器文件RegFile、主控制译码MainCtr、ALU控制信号译码ALUCtr以及算术逻辑单元ALU,分别实现各个模块的功能;
再将控制信号等在mips的顶层模块中使用assign语句进行赋值,同时在顶层模块中进行其余子模块的实例化,使之与控制信号以及32位Instr等进行关联,对于不同的指令都有对应于各自的控制信号;
使用vivado的IPcore实现指令存储器irom的逻辑功能。在时钟上升沿到来时,读入PC信号的高五位,作为地址,输出相应的32位Instr指令,此处我们在vivado中导入text.coe到irom_IP中,其本质为16进制的32位机器码,机器码对照表如下:
ps:此处的起始地址应该为0x00000000,j指令也应该相应地跳回0x00000000.
使用vivado的IPcore实现数据存储器dram的逻辑功能。在时钟下降沿到来时,根据写数据的使能信号MenWr决定是否在输入的地址addr处写入输入的数据DataIn,除此之外还会输出存储在输入的地址addr处的数据到DataOut;
使用Verilog语言编写实现寄存器文件RegFile的逻辑功能。在时钟下降沿到来时,倘若写使能信号RegWr为高电平且复位信号reset为低电平,则将输入的数据DataIn写到地址为输入写地址WrAddr处的寄存器regs[WrAddr];倘若复位信号reset为高电平,则我们将regs的值设定为初始默认值regs[i]=i(按照要求也可将其写为学号的ASCII码)。模块中同时使用assign语句决定RsData和RtData的值是0或者地址为RsAddr或RtAddr的寄存器的值。
使用Verilog语言编写实现主控制译码MainCtr的逻辑功能。输入Instr的高六位,输出控制信号和ALUOp,根据每个指令调用的模块得到各个控制信号的状态,再将ALUOp输入到ALU控制信号译码ALUCtr中去。
使用Verilog语言编写实现ALU控制信号译码ALUCtr的逻辑功能。输入ALUOp和Instr的低六位Funct,输出各个指令相应的ALUCtr信号,并且输入到算术逻辑单元ALU中去,其中andi和and的ALUOp和Funct虽然不同,但ALUCtr是一致的。
使用Verilog语言编写算术逻辑单元ALU。输入符号数字In1和符号数In2,由输入的ALUCtr信号觉得要做的运算,事实上我们采用的编码让sw和lw在算术逻辑单元ALU中所做的运算为add,andi所做的为and,beq所做的为sub。并且Zero信号默认为0,只有在执行sub运算时有机会为1,当其为1时,BranchZ = B & Zero才有机会为1,让PC跳转到BranchPC = ImmL2 + SquencePC,即左移两位的立即数与PC加4后的和。
顶层模块的输入信号仅有时钟信号clk和复位信号reset,声明一系列中间信号,使用assign语句和子模块实例化实现指令功能的完成以及控制信号的传递,数据的读写运算等。除此之外,使用always语句实现PC信号的选择和PC的复位。
由于不同的指令需求,对于ALUCtr和MainCtr的编码不同,笔者在此处给出部分源码:
`timescale 1ns / 1ps module mips ( input clk, input reset ); wire [31:0] TempPC, JumpPC, MuxPC, SquencePC, BranchPC, Imm32, ImmL2, regWriteData, RsData, RtData, ALUin2, ALUres, memReadData, Instr; wire [4:0] regWriteAddr; wire [27:0] PsudeoPC; wire [1:0] ALUop; wire [3:0] ALUctr; wire BranchZ, regDst, ALUsrc, M2R, regWriteEn, zero, memWriteEn, B, J; reg [31:0] PC; assign PsudeoPC = {Instr[25:0], 2'b00}; assign JumpPC = {SquencePC[31:28], PsudeoPC}; assign TempPC = J ? JumpPC : MuxPC; assign MuxPC = BranchZ ? BranchPC : SquencePC; assign BranchPC = ImmL2 + SquencePC; assign ImmL2 = {Imm32[29:0], 2'b00}; assign Imm32 = {Instr[15] ? 16'hffff : 16'h0000, Instr[15:0]}; assign BranchZ = B & zero; assign regWriteAddr = regDst ? Instr[15:11] : Instr[20:16]; assign ALUin2 = ALUsrc ? Imm32 : RtData; assign regWriteData = M2R ? memReadData : ALUres; assign SquencePC = PC + 4; always @(negedge clk) begin if(reset) PC <= 32'h0; else PC <= TempPC; end ALU U0(RsData,ALUin2,ALUctr,ALUres,zero); //dram U1(memWriteEn,ALUres[6:2],memReadData,RtData); //irom U2(PC[6:2],Instr); dram_IP U1(~clk,memWriteEn,ALUres[6:2],RtData,memReadData); irom_IP U2(clk,PC[6:2],Instr); RegFile U3(~clk,reset,regWriteEn,Instr[25:21],Instr[20:16],regWriteAddr,regWriteData,RsData,RtData); MainCtr U4(Instr[31:26],regDst,ALUsrc,M2R,regWriteEn,memWriteEn,B,J,ALUop); ALUCtr U5(ALUop,Instr[5:0],ALUctr); endmodule
`timescale 1ns / 1ps module ALU ( input signed [31:0] In1, input signed [31:0] In2, input [3:0] ALUCtr, output reg [31:0] Res, output reg Zero ); always @(In1 or In2 or ALUCtr) begin case (ALUCtr) 4'b0110://sub begin Res = In1 - In2; Zero = (Res == 0) ? 1 : 0; // only sub needs Zero be 1 end 4'b0010://add begin Res = In1 + In2; Zero = 0; end 4'b0000://and begin Res = In1 & In2; Zero = 0; end 4'b0001://or begin Res = In1 | In2; Zero = 0; end 4'b0111://slt begin Res = (In1 < In2) ? 1 : 0; Zero = 0; end default: begin Res = 0; Zero = 0; end endcase end endmodule
`timescale 1ns / 1ps module RegFile ( input clk, input reset, input RegWr,//regWriteEn input [4:0] RsAddr, input [4:0] RtAddr, input [4:0] WrAddr,//regWriteAddr input [31:0] DataIn,//regWriteData output [31:0] RsData, output [31:0] RtData ); // 32 regs, for each one is 32 reg [31:0] regs[0:31]; assign RsData = (RsAddr == 5'b0) ? 32'b0 : regs[RsAddr]; assign RtData = (RtAddr == 5'b0) ? 32'b0 : regs[RtAddr]; integer i; always @(posedge clk) begin if(!reset & RegWr) begin regs[WrAddr] = DataIn; end else if(reset) begin for (i = 0; i < 32; i = i + 1) begin regs[i] = i; end end end endmodule
`timescale 1ns / 1ps module MainCtr ( input [5:0] OpCode,// Instr[31:26] output RegDst, output ALUSrc, output Mem2Reg, output RegWr, output MemWr, output B, output J, output [1:0] ALUOp ); reg [8:0] outputtemp; assign RegDst = outputtemp[8]; assign ALUSrc = outputtemp[7]; assign Mem2Reg = outputtemp[6]; assign RegWr = outputtemp[5]; assign MemWr = outputtemp[4]; assign B = outputtemp[3]; assign J = outputtemp[2]; assign ALUOp = outputtemp[1:0]; always @(OpCode) begin case (OpCode) 6'b000010: outputtemp = 9'bxxx0001xx;// j 6'b000000: outputtemp = 9'b100100010;// R 6'b100011: outputtemp = 9'b011100000;// lw 6'b101011: outputtemp = 9'bx1x010000;// sw 6'b000100: outputtemp = 9'bx0x001001;// beq 6'b001100: outputtemp = 9'b010100011;// andi default: outputtemp = 9'b000000000;// default endcase end endmodule
`timescale 1ns / 1ps module ALUCtr ( input [1:0] ALUOp, input [5:0] Funct, output reg [3:0] ALUCtr ); always @(ALUOp or Funct) begin casex ({ALUOp, Funct}) 8'b00xxxxxx: ALUCtr[3:0] = 4'b0010;// lw, sw 8'b01xxxxxx: ALUCtr[3:0] = 4'b0110;// beq 8'b10xx0000: ALUCtr[3:0] = 4'b0010;// add 8'b10xx0010: ALUCtr[3:0] = 4'b0110;// sub 8'b10xx0100: ALUCtr[3:0] = 4'b0000;// and 8'b10xx0101: ALUCtr[3:0] = 4'b0001;// or 8'b10xx1010: ALUCtr[3:0] = 4'b0111;// slt 8'b11xxxxxx: ALUCtr[3:0] = 4'b0000;// andi->and default: ALUCtr[3:0] = 4'b0000;// initial endcase end endmodule
`timescale 1ns / 1ps module ALU_sim( output [31:0] Res, output Zero ); reg [31:0] In1,In2; reg [3:0] ALUCtr; ALU S1(In1,In2,ALUCtr,Res, Zero); initial begin In1 = 32'hffff0000; In2 = 32'h00ffff00; ALUCtr=4'h2; #10 ALUCtr=4'h6; #10 ALUCtr=4'h0; #10 ALUCtr=4'h1; #10 ALUCtr=4'h7; end endmodule
`timescale 1ns/1ps module RegFile_sim ( output [31:0] RsData, output [31:0] RtData ); reg clk; reg reset; reg regWriteEn; reg [4:0] RsAddr; reg [4:0] RtAddr; reg [4:0] regWriteAddr; reg [31:0] regWriteData; parameter PERIOD = 10; always begin clk = 1'b0; #(PERIOD/2) clk = 1'b1; #(PERIOD/2) ; end initial begin reset = 1; RsAddr = 5'h0; RtAddr = 5'h0; #15 reset = 0; #30 regWriteEn = 1; regWriteAddr = 5'h03; regWriteData = 32'h5aa5; #20 RsAddr = 5'h03; RtAddr = 5'h03; end RegFile S2(clk,reset,regWriteEn,RsAddr,RtAddr,regWriteAddr,regWriteData,RsData,RtData); endmodule
module mips_sim ( ); reg clk; reg reset; mips U0(clk, reset); parameter PERIOD = 10; always begin clk = 1'b0; # (PERIOD/2) clk = ~clk; # (PERIOD/2) end initial begin reset = 1; #20 reset = 0; end endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。