06-Minisys-1单周期CPU控制器的设计
一、06-Minisys-1单周期CPU控制器的设计(1)
1.主要内容:
- 创建一个项目
- 单周期CPU控制器设计
项目初始文件http://www.njyangqs.com/soc/download/
2.创建一个项目
- 先确保初始文件包已安装在C盘的minisys1_classfiles目录下
- 打开vivado(2015.4),创建新项目,在C盘minisys1下
- 添加source files时,C盘-minisys1_classfiles-minisys,勾选copy。
4. 添加约束文件,xdc文件夹,勾上copy。
- 选择器件,Artix-7家族,fgg484封装,-1速度,选最下面的器件。
- 所有.v文件都不完整,需要补充完整
// ifetc32.v`timescale 1ns / 1ps
//
module Ifetc32(Instruction,PC_plus_4_out,Add_result,Read_data_1,Branch,nBranch,Jmp,Jal,Jrn,Zero,clock,reset,opcplus4);output[31:0] Instruction; // 输出指令output[31:0] PC_plus_4_out;input[31:0] Add_result;input[31:0] Read_data_1;input Branch;input nBranch;input Jmp;input Jal;input Jrn;input Zero;input clock,reset;output[31:0] opcplus4;wire[31:0] PC_plus_4;reg[31:0] PC;reg[31:0] next_PC; wire[31:0] Jpadr;reg[31:0] opcplus4;//分配64KB ROM,编译器实际只用 64KB ROMprgrom instmem(.clka(clock), // input wire clka.addra(PC[15:2]), // input wire [13 : 0] addra.douta(Jpadr) // output wire [31 : 0] douta);assign Instruction = Jpadr; // 取出指令always @* begin // beq $n ,$m if $n=$m branch bne if $n /=$m branch jrendalways @(negedge clock) beginend
endmodule
// idecode32.v
`timescale 1ns / 1ps
//module Idecode32(read_data_1,read_data_2,Instruction,read_data,ALU_result,Jal,RegWrite,MemtoReg,RegDst,Sign_extend,clock,reset,opcplus4,read_register_1_address);output[31:0] read_data_1;output[31:0] read_data_2;input[31:0] Instruction;input[31:0] read_data; // 从DATA RAM or I/O port取出的数据input[31:0] ALU_result; // 需要扩展立即数到32位input Jal; input RegWrite;input MemorIOtoReg;input RegDst;output[31:0] Sign_extend;input clock,reset;input[31:0] opcplus4; // 来自取指单元,JAL中用output[4:0] read_register_1_address;wire[31:0] read_data_1;wire[31:0] read_data_2;reg[31:0] register[0:31]; //寄存器组共32个32位寄存器reg[4:0] write_register_address;reg[31:0] write_data;wire[4:0] read_register_2_address;wire[4:0] write_register_address_1;wire[4:0] write_register_address_0;wire[15:0] Instruction_immediate_value;wire[5:0] opcode;wire sign;always @* begin //这个进程指定不同指令下的目标寄存器endalways @* begin //这个进程基本上是实现结构图中右下的多路选择器,准备要写的数据endinteger i;always @(posedge clock) begin // 本进程写目标寄存器if(reset==1) begin // 初始化寄存器组for(i=0;i<32;i=i+1) register[i] <= i;end else if(RegWrite==1) begin // 注意寄存器0恒等于0endend
endmodule
// control32.v`timescale 1ns / 1ps
//
module control32(Opcode,Function_opcode,Jrn,RegDST,ALUSrc,MemtoReg,RegWrite,MemWrite,Branch,nBranch,Jmp,Jal,I_format,Sftmd,ALUOp);input[5:0] Opcode; // 来自取指单元instruction[31..26]input[5:0] Function_opcode; // r-form instructions[5..0]output Jrn;output RegDST;output ALUSrc; // 决定第二个操作数是寄存器还是立即数output MemtoReg;output RegWrite;output MemWrite;output Branch;output nBranch;output Jmp;output Jal;output I_format;output Sftmd;output[1:0] ALUOp;wire Jmp,I_format,Jal,Branch,nBranch;wire R_format,Lw,Sw;assign R_format = (Opcode==6'b000000)? 1'b1:1'b0; //--00h assign RegDST = R_format; //说明目标是rd,否则是rtendmodule
// executs32.v`timescale 1ns / 1ps
//module Executs32(Read_data_1,Read_data_2,Sign_extend,Function_opcode,Exe_opcode,ALUOp,Shamt,ALUSrc,I_format,Zero,Sftmd,ALU_Result,Add_Result,PC_plus_4);input[31:0] Read_data_1; //r-form rsinput[31:0] Read_data_2; //r-form rtinput[31:0] Sign_extend; //i-forminput[5:0] Function_opcode; //r-form instructions[5..0]input[5:0] Exe_opcode; //op codeinput[1:0] ALUOp;input[4:0] Shamt;input Sftmd;input ALUSrc;input I_format;output Zero;output[31:0] ALU_Result;output[31:0] Add_Result; //pc op input[31:0] PC_plus_4;reg[31:0] ALU_Result;wire[31:0] Ainput,Binput;reg[31:0] Cinput,Dinput;reg[31:0] Einput,Finput;reg[31:0] Ginput,Hinput;reg[31:0] Sinput;reg[31:0] ALU_output_mux;wire[32:0] Branch_Add;wire[2:0] ALU_ctl;wire[5:0] Exe_code;wire[2:0] Sftm;wire Sftmd;reg s;assign Sftm = Function_opcode[2:0]; // 实际有用的只有低三位(移位指令)assign Exe_code = (I_format==0) ? Function_opcode : {3'b000,Exe_opcode[2:0]};assign Ainput = Read_data_1;assign Binput = (ALUSrc == 0) ? Read_data_2 : Sign_extend[31:0]; //R/LW,SW sft else的时候含LW和SWassign ALU_ctl[0] = (Exe_code[0] | Exe_code[3]) & ALUOp[1]; //24H AND assign ALU_ctl[1] = ((!Exe_code[2]) | (!ALUOp[1]));assign ALU_ctl[2] = (Exe_code[1] & ALUOp[1]) | ALUOp[0];always @* begin // 6种移位指令if(Sftmd)case(Sftm[2:0])3'b000:Sinput = //Sll rd,rt,shamt 000003'b010:Sinput = //Srl rd,rt,shamt 000103'b100:Sinput = //Sllv rd,rt,rs 0001003'b110:Sinput = //Srlv rd,rt,rs 0001103'b011:Sinput = //Sra rd,rt,shamt 000113'b111:Sinput = //Srav rd,rt,rs 00111default:Sinput = Binput;endcaseelse Sinput = Binput;endalways @* beginif(((ALU_ctl==3'b111) && (Exe_code[3]==1))||((ALU_ctl[2:1]==2'b11) && (I_format==1))) //slti(sub) 处理所有SLT类的问题ALU_Result = ;else if((ALU_ctl==3'b101) && (I_format==1)) ALU_Result[31:0] = ;else if(Sftmd==1) ALU_Result = ; else ALU_Result = ALU_output_mux[31:0]; //otherwiseendassign Branch_Add = PC_plus_4[31:2] + Sign_extend[31:0];assign Add_Result = Branch_Add[31:0]; //算出的下一个PC值已经做了除4处理,所以不需左移16位assign Zero = (ALU_output_mux[31:0]== 32'h00000000) ? 1'b1 : 1'b0;always @(ALU_ctl or Ainput or Binput) begincase(ALU_ctl)3'b000:ALU_output_mux = 3'b001:ALU_output_mux = 3'b010:ALU_output_mux = 3'b011:ALU_output_mux = 3'b100:ALU_output_mux = 3'b101:ALU_output_mux = 3'b110:ALU_output_mux = 3'b111:ALU_output_mux = default:ALU_output_mux = 32'h00000000;endcaseend
endmodule
//dmemory32.v`timescale 1ns / 1ps
//
module dmemory32(read_data,address,write_data,Memwrite,clock);output[31:0] read_data;input[31:0] address; //来自memorio模块,源头是来自执行单元算出的alu_resultinput[31:0] write_data; //来自译码单元的read_data2input Memwrite; //来自控制单元input clock;wire clk;assign clk = !clock; // 因为使用Cyclone芯片的固有延迟,RAM的地址线来不及在时钟上升沿准备好,// 使得时钟上升沿数据读出有误,所以采用反相时钟,使得读出数据比地址准// 备好要晚大约半个时钟,从而得到正确地址。//分配64KB RAM,编译器实际只用 64KB RAMendmodule
// memorio.v`timescale 1ns / 1ps
//module memorio(caddress,address,memread,memwrite,ioread,iowrite,mread_data,ioread_data,wdata,rdata,write_data,LEDCtrl,SwitchCtrl);input[31:0] caddress; // from alu_result in executs32input memread; // read memory, from control32input memwrite; // write memory, from control32input ioread; // read IO, from control32input iowrite; // write IO, from control32input[31:0] mread_data; // data from memoryinput[15:0] ioread_data; // data from ioinput[31:0] wdata; // the data from idecode32,that want to write memory or iooutput[31:0] rdata; // data from memory or IO that want to read in registeroutput[31:0] write_data; // data to memory or I/Ooutput[31:0] address; // address to mAddressoutput LEDCtrl; // LED CSoutput SwitchCtrl; // Switch CSreg[31:0] write_data;wire iorw;assign address = caddress;assign rdata = (memread==1) ? mread_data : {16'h0000,ioread_data[15:0]};assign iorw = (iowrite||ioread);assign LEDCtrl = ((iorw==1) && (caddress[31:0] == 32'hFFFFFC60)) ? 1'b1:1'b0;assign SwitchCtrl = ((iorw==1) && (caddress[31:0] == 32'hFFFFFC70)) ? 1'b1:1'b0;always @* beginif((memwrite==1)||(iowrite==1)) beginwrite_data = wdata;end else beginwrite_data = 32'hZZZZZZZZ;endend
endmodule
//ioread.v`timescale 1ns / 1ps
//module ioread(reset,clk,ior,switchctrl,ioread_data,ioread_data_switch);input reset,clk;input ior,switchctrl;input[15:0] ioread_data_switch;output[15:0] ioread_data;reg[15:0] ioread_data;always @* beginif(reset == 1)ioread_data = 16'b0000000000000000;else if(ior == 1) beginif(switchctrl == 1)ioread_data = ioread_data_switch;elseioread_data = ioread_data;endend
endmodule
// leds.v`timescale 1ns / 1ps
//module leds(led_clk,ledrst,ledwrite,ledaddrcs,ledwdata,ledout);input led_clk,ledrst;input ledwrite;input ledaddrcs;input[15:0] ledwdata;output[15:0] ledout;reg [15:0] ledout;always@(posedge led_clk or posedge ledrst) beginend
endmodule
// switchs.v`timescale 1ns / 1ps
//module switchs(switclk,switrst,switchread,switchaddrcs,switchrdata,switch_i);input switclk,switrst;input switchaddrcs,switchread;output [15:0] switchrdata;//拨码开关输入input [15:0] switch_i;reg [15:0] switchrdata;always@(negedge switclk or posedge switrst) beginend
endmodule
3.设计方法
- 考查每条指令在数据通路中的执行过程和涉及的控制信号的取值
- 根据列出的指令和控制信号之间的关系,写出每个控制信号的逻辑表达式
- 控制信号:
4.工程文件中control32.v
输入输出信号
控制单元输入信号来自于取值单元的指令码、以及指令中的功能码
控制单元的输出信号,各种控制信号,数据通路中一个个添加进来的
5.RegDST设计举例
1.将所有指令列表,OP值、操作码、RegDST取值
同类型可综合
2.RegDST数值
在I类型数据通路设计时,目标寄存器,R类型为rd,I类型为rt,需要选择为rd还是rt。二选一多路选择器的控制端为RegDST。
RegDST=1 -> rd
RegDST=0 -> rt
3.类型分析
ori addiu lw sw beq:I类型 (lw sw 存储器存储的指令)
jump J类型
R-format R类型
I类型RegDST取0,目标寄存器为rt;
R类型RegDST取1,目标寄存器为rd。
sw beq jump不写寄存器,只跳转/数据写存储器,RegDST取哪个无所谓。
4.RegDST = R-format
考察op
指令码OP code=0时,R-format为1,
二、06-Minisys-1单周期CPU控制器的设计(2)
1.RegWrite设计举例
1.写寄存器
I-format有些指令写寄存器,有些不写
jr不写寄存器
lw把存储器内容写寄存器,为1
sw无所谓,将寄存器的值写存储器中
jal跳转前把PC+4值写寄存器中
j跳转,不写
R-format写rd寄存器
2.练习1
3.在Minisys-1中哪些指令会使RegWrite为1,哪些指令会使RegWrite为0?
除beq、bne、lw、sw以外的I类型指令,以及R-format指令,还有jal指令,因此我们可以先定义I-format、lw、jal、jrn信号,再定义RegWrite。
4.练习2
2.ALU的控制电路
1.control32.v中发现有ALUop信号是输出出去的,输出给执行单元,告诉执行单元指令属于哪些类型。
ALU采用分级控制的方法(减轻控制器负担)。
在控制器中,只发出ALUop信号
2.约定:
3.这些指令到了运算/执行单元都要计算的。
LW、SW做加法得到最终地址,运算完成后当地址使用;
BEQ、BNE做减法,判断是否相等,运算完成后通过结果指导下一步工作;
R、I-format有各种运算,运算完成后即为最终结果。
4.如何实现
拼接运算,高位R-format或I-format成立,低位Branch或nBranch成立。
ALUop会送到执行单元,执行单元会根据ALUop或另外的控制信号确定做什么运算。
5.分级
对于执行单元来说,它的控制是分级的,一部分在控制单元中生成ALUop还有一部分在执行单元中生成更详细的控制信号。
6.练习3
完整地写出控制器模块。
3.ALU的控制电路仿真
- 在仿真前对设计的控制器的模块进行综合,看看有没有问题。control32-set as top做成顶层文件,对它进行综合。
- 看project summary,没有错误关闭当前窗口。
- 准备仿真,添加仿真文件,sim-control32_sim.v,并设置为顶层文件
- 查看control32_sim.v,所有输入都为reg,输出都为wire
- 对control32模块进行元件实例化
- 对control32产生一些输入信号检查输出是否正确,输入已有opcode和functioncode,每间隔200nm/250nm改变指令
- 进行行为仿真,双击波形图bar,选择3μs,reset-start,调整波形
- ADD要写寄存器,RegWrite为1;
- JR,Jrn信号为1;
- ADDI,ALUSrc为1,选择立即数,同时RegWrite为1要写寄存器;
- LW,从存储器中读数据给寄存器,MemtoReg为1,ALUSrc为1属于I类型;
- SW,MemWrite为高电平;
- BEQ,Branch高电平,nBranch低电平;
- BNE,Branch低电平,nBranch高电平;
- JMP,Jmp高电平;
- JAL,Jal高电平;
- SRL,移位指令,sftmd变为高电平
06-Minisys-1单周期CPU控制器的设计相关推荐
- 单周期CPU设计(Verilog)
2017/06/08: 当时单周期cpu写的比较仓促,没有深入的进行调试,我准备在放假的时候重构一下代码, 然后把博文改进一下,现在实在没有时间,很抱歉~ 不过多周期我有调试过的,所以有需要的可以移步 ...
- 【Computer Organization笔记10】单周期CPU设计:基于7条MIPS指令的数据通路
本次笔记内容: P19 计算机组成原理(19) P20 计算机组成原理(20) 本节课对应幻灯片: 组成原理24 singlecycle.pptx 基于上节课的7条MIPS指令的数据通路,分别针对7条 ...
- 单周期CPU设计【Verilog】
第一章 单周期CPU的设计原理 1.1 单周期CPU概述 1.2 CPU工作原理 第二章 单周期CPU的设计内容 2.1 指令系统的设计 2.1.1 概述 2.1.2 运算类指令的设计 2.1.3 传 ...
- 【中山大学计算机组成原理实验】单周期CPU设计与实现
实验一 : 单周期CPU设计与实现 一. 实验目的 (1) 掌握单周期CPU数据通路图的构成.原理及其设计方法: (2) 掌握单周期CPU的实现方法,代码实现方法: (3) 认识和掌握指令与CPU的关 ...
- (Verilog)单周期CPU设计
(Verilog)单周期CPU设计 首先是基础资料部分(借用学校资料): 一.实验内容 设计一个单周期CPU,该CPU至少能实现以下指令功能操作.需设计的指令与格式如下: ==> 算术运算指令 ...
- MIPS单周期CPU设计(24条指令)
MIPS单周期可执行24条指令CPU 实验要求 本实训项目帮助学生构建支持 24 条指令的 MIPS 单周期 CPU ,最终实现的处理器能运行 benchmark 测试程序.另外希望学有余力的同学能为 ...
- 31条指令单周期cpu设计(Verilog)-(十)上代码→顶层模块设计总结
说在前面 开发环境:Vivado 语言:Verilog cpu框架:Mips 控制器:组合逻辑 设计思路 按照预先设计好的数据通路图将各个模块连接起来 `timescale 1ns / 1ps mod ...
- 31条指令单周期cpu设计(Verilog)-(二)总体设计
目录 31条指令单周期cpu设计(Verilog)-(一)相关软件 31条指令单周期cpu设计(Verilog)-(二)总体设计 31条指令单周期cpu设计(Verilog)-(三)指令分析 ...
- 单周期CPU——verilog语言实现
单周期CPU的设计与实现 关于单周期CPU的设计问题,相信各位在课程上也有所学习,以下是个人的一些理解 整个项目的资源下载:这里写链接内容 实验内容 基本要求 PC和寄存器组写状态使用时钟触发,这是必 ...
最新文章
- 团队-科学技术器-模块测试过程
- matlab 由移相角如何产生移相脉冲,整流电路控制角移相范围是怎么确定的?
- 【debug】mount: unknown filesystem type ‘nfs’
- 今日头条、快手们疯狂招人是人工智能的失败?
- nmon安装为什么重启mysql_Centos7部署nmon监控工具
- [转]十个让你变成糟糕的程序员的行为
- Linux系统调用之open(), close() (转载)
- python dict()函数的奇异之处
- 已知圆上两点坐标和半径求圆心
- 服务器中的虚拟化是什么意思,虚拟化是什么意思
- oracle pdb与cdb区别,浅谈oracle 12C的新特性-CDB和PDB
- pig java api_Pig安装及入门案例
- INT8量化原理理解
- IPEmotion新增功能:交流电功率分析计算
- C语言简单编程案例——(五)
- 中国软件,从繁荣走向文明
- 多种JS刷新页面代码!
- 免费开源磁带机备份软件_服务器备份和还原过程| 免费和开源软件
- 宝塔使用心得--快速部署javaweb应用
- 字节(byte)、位(bit)、KB、B、字符之间关系以及编码占用位数