暑期实训CPU设计(四)
基于MIPS指令集的简单CPU设计(20条指令)代码及注释
数据通路图:
自底向下,一个模块一个模块来
ALU:
alu.v
module alu (a,b,aluc,r,z);
input [31:0] a,b; //源操作数
input [3:0] aluc; //操作控制码
output [31:0] r; //零标志位
output z;
wire [31:0] d_and = a & b; //x 0 0 1 AND
wire [31:0] d_or = a | b; //x 1 0 1 0R
wire [31:0] d_xor = a ^ b; //x 0 1 0 XOR
wire [31:0] d_lui = {b[15:0],16'h0}; //x 1 1 0 LUI 高16是所给数据b得低16位,低16位补零
wire [31:0] d_and_or = aluc[2]?d_or : d_and; //选择获取按位与还是按位或运算
wire [31:0] d_xor_1ui= aluc[2]?d_lui : d_xor; //选择获取异或还是LUI运算
wire [31:0] d_as,d_sh;
addsub32 as32 (a,b,aluc[2],d_as); //x 0 0 0 ADD //x 1 0 0 SUB
shift shifter (b,a[4:0],aluc[2],aluc[3],d_sh) ; //0 0 1 1 SLL//0 1 1 1 SRL//1 1 1 1 SRA
mux4x32 se1ect (d_as,d_and_or, d_xor_1ui, d_sh, aluc[1:0],r);
assign z = ~|r;
endmodule
//alu运算逻辑单元
addsub32.v
module addsub32(a,b,sub,s);input [31:0] a,b;input sub;output [31:0] s;cla32 as32 (a,b^{32{sub}},sub,s);
endmodule//减法相当于加上一个负数
//加减法运算模块,加减取决于sub,加法运算0,减法运算1
//若sub为0, 任何-一个数b异或0为本身, 此时b" {32 {sub}=b, 加法;
//若sub为1, 任何一个数b异或I为其取反,此时b^ {32{sub}=~b, 减法。
cla32.v
//先行进位加法器,能够快速产生进位位,用到了一种树形进位产生算法//产生32位加法结果和进位输出
module cla32 (a,b,ci,s,co);input [31:0] a,b;input ci;output [31:0] s;output co;wire g_out,p_out;cla_32 cla (a,b, ci,g_out,p_out, s); assign co = g_out| p_out & ci;
endmodule//一位加法器的代码
//g为进位产生函数,p为进位传递函数
module add(a,b,c,g,p,s);input a,b,c;output g,p,s;assign s = a^b^c;assign g = a & b;assign p = a | b;
endmodule//gp生成器
module g_p (g,p,c_in,g_out,p_out,c_out);
input [1:0] g,p;
input c_in;
output g_out, p_out, c_out;
assign g_out = g[1]|p[1] & g[0];
assign p_out = p[1] & p[0];
assign c_out = g[0] | p[0] & c_in;
endmodule//2位先行进位加法器,用了两个一位加法器和一个GP生成器
module cla_2 (a,b,c_in,g_out,p_out,s) ;
input [1:0] a,b;
input c_in;
output g_out, p_out;
output [1:0] s;
wire [1:0] g,p;
wire c_out;
add add0 (a[0],b[0],c_in, g[0],p[0],s[0]);
add add1 (a[1],b[1],c_out, g[1],p[1],s[1]);
g_p g_p0 (g,p,c_in, g_out,p_out,c_out);
endmodulemodule cla_4 (a,b, c_in,g_out,p_out,s);
input [3:0] a,b;
input c_in;
output g_out, p_out;
output [3:0] s;
wire [1:0] g,p;
wire c_out;
cla_2 cla0 (a[1:0],b[1:0],c_in, g[0],p[0],s[1:0]);
cla_2 clal (a[3:2],b[3:2],c_out,g[1],p[1],s[3:2]);
g_p g_p0 (g,p,c_in, g_out,p_out,c_out);
endmodulemodule cla_8 (a,b, c_in,g_out,p_out, s);
input [7:0] a,b;
input c_in;
output g_out, p_out;
output [7:0] s;
wire [1:0] g,p;
wire c_out;
cla_4 cla0 (a[3:0],b[3:0],c_in, g[0],p[0],s[3:0]);
cla_4 c1a1 (a[7:4],b[7:4],c_out,g[1],p[1],s[7:4]);
g_p g_p0 (g,p,c_in, g_out,p_out,c_out);
endmodulemodule cla_16 (a,b, c_in,g_out,p_out, s);
input [15:0] a,b;
input c_in;
output g_out, p_out;
output [15:0] s;
wire [1:0] g,p;
wire c_out;
cla_8 cla0 (a[7:0],b[7:0],c_in,g[0],p[0],s[7:0]);
cla_8 cla1 (a[15:8],b[15:8],c_out,g[1],p[1],s[15:8]);
g_p g_p0 (g,p,c_in, g_out,p_out,c_out);
endmodulemodule cla_32 (a,b,c_in,g_out,p_out, s);
input [31:0] a,b;
input c_in;
output g_out, p_out;
output [31:0] s;
wire [1:0] g,p;
wire c_out;
cla_16 c1a0 (a[15:0],b[15:0],c_in,g[0],p[0],s[15:0]);
cla_16 c1a1 (a[31:16],b[31:16],c_out,g[1],p[1],s[31:16]);
g_p g_p0 (g,p,c_in, g_out,p_out,c_out);
endmodule
shifi.v
module shift (d,sa,right,arith,sh);
input [31:0] d; //目的操作数
input [4:0] sa; //所移位数
input right,arith; //左移右移
output [31:0] sh;
reg [31:0] sh; //目的操作数
always @* beginif (!right) begin //左移sh = d << sa;end else if (!arith) begin //逻辑右移sh = d >> sa;end else begin //算数右移sh = $signed(d) >>> sa;end
end
endmodule//算数移位 逻辑移位模块
mux4x32.v
module mux4x32 (a0,a1,a2,a3,s,y);input [31:0] a0,a1,a2,a3;input [1:0] s;output [31:0] y;function [31:0] select;input [31:0] a0,a1,a2,a3;input [1:0] s;case (s)2'b00: select = a0;2'b01: select = a1;2'b10: select = a2;2'b11: select = a3;endcaseendfunctionassign y = select(a0,a1,a2,a3,s);
endmodule//32位4选1多路选择器
//加减法;或与运算;异或lui;移位运算
//选哪一个作为输出由s决定
//s由控制器决定
寄存器堆:
redfile.v
module regfile (rna, rnb, d, wn,we, clk, clrn, qa, qb);
input [4:0] rna,rnb,wn; //写地址
input [31:0] d; //准备写入寄存器中的数据
input we, clk, clrn; //写使能;时钟;复位
output [31:0] qa,qb;
reg [31:0] register [1:31]; // 31 x 32-bit regs// 2 read ports
assign qa = (rna == 0) ? 0 : register[rna]; //读出rna指定的寄存器的值,并输出到qa端口
assign qb = (rnb == 0) ? 0 : register[rnb];// 1 write port
always @(posedge clk or negedge clrn)
begin
if (clrn==0)
begininteger i;for(i=1;i<32;i=i+1)register[i] <= 0;
end
else if((wn!=0)&&we)
register[wn] <= d; //把d写入Wn指定的寄存器
end
endmodule
控制器的设计
sccu_flow.v
module sccu_dataflow (op,func,z,wmem,wreg,regrt,m2reg,aluc,shift,aluimm,pcsource,jal,sext);input [5:0] op,func;//操作码input z; //零标志位output wreg,regrt,jal,m2reg,shift,aluimm,sext,wmem;//8个一位控制信号output [3:0] aluc;//4位alu运算控制信号output [1:0] pcsource;//2位PC寻址控制信号wire r_type = ~|op;wire i_add = r_type&func[5]&~func[4]&~func[3]&~func[2]&~func[1]&~func[0];wire i_sub = r_type&func[5]&~func[4]&~func[3]&~func[2]&func[1]&~func[0];wire i_and = r_type&func[5]&~func[4]&~func[3]&func[2]&~func[1]&~func[0];wire i_or = r_type&func[5]&~func[4]&~func[3]&func[2]&~func[1]&func[0];wire i_xor = r_type&func[5]&~func[4]&~func[3]&func[2]&func[1]&~func[0];wire i_sll = r_type&~func[5]&~func[4]&~func[3]&~func[2]&~func[1]&~func[0];wire i_srl = r_type&~func[5]&~func[4]&~func[3]&~func[2]&func[1]&~func[0];wire i_sra = r_type&~func[5]&~func[4]&~func[3]&~func[2]&func[1]&func[0];wire i_jr = r_type&~func[5]&~func[4]&func[3]&~func[2]&~func[1]&~func[0];wire i_addi = ~op[5]&~op[4]&op[3]&~op[2]&~op[1]&~op[0];wire i_andi = ~op[5]&~op[4]&op[3]&op[2]&~op[1]&~op[0];wire i_ori = ~op[5]&~op[4]&op[3]&op[2]&~op[1]&op[0];wire i_xori = ~op[5]&~op[4]&op[3]&op[2]&op[1]&~op[0];wire i_lw = op[5]&~op[4]&~op[3]&~op[2]&op[1]&op[0];wire i_sw = op[5]&~op[4]&op[3]&~op[2]&op[1]&op[0];wire i_beq = ~op[5]&~op[4]&~op[3]&op[2]&~op[1]&~op[0];wire i_bne = ~op[5]&~op[4]&~op[3]&op[2]&~op[1]&op[0];wire i_lui = ~op[5]&~op[4]&op[3]&op[2]&op[1]&op[0];wire i_j = ~op[5]&~op[4]&~op[3]&~op[2]&op[1]&~op[0];wire i_jal = ~op[5]&~op[4]&~op[3]&~op[2]&op[1]&op[0];//20条wire语句对应了20条指令集,前十条是R型指令,通过func判断是那一条R型指令//后十条通过op判断是哪一条mips指令//判断完进行译码,由下面的assign语句给出控制信号assign wreg = i_add|i_sub|i_and|i_or|i_xor|i_sll|i_srl|i_sra|i_addi|i_andi|i_ori|i_xori|i_lw|i_lui|i_jal;assign regrt= i_addi|i_andi|i_ori|i_xori|i_lw|i_lui;assign jal= i_jal;assign m2reg= i_lw;assign shift=i_sll|i_srl|i_sra;assign aluimm=i_addi|i_andi|i_ori|i_xori|i_lw|i_lui|i_sw;assign sext =i_addi|i_lw|i_sw|i_beq|i_bne;assign aluc[3]=i_sra;assign aluc[2]=i_sub|i_or|i_srl|i_sra|i_ori|i_lui;assign aluc[1]=i_xor|i_sll|i_sra|i_xori|i_beq|i_bne|i_lui;assign aluc[0]=i_and|i_or|i_sll|i_srl|i_sra|i_andi|i_ori;assign wmem = i_sw;assign pcsource[1]=i_jr|i_j|i_jal;assign pcsource[0]=i_beq&z|i_bne&~z|i_j|i_jal;//两条pcsource赋值语句用于告诉四选一选择器判断到底是用哪一条数据来源进行对pc值(下一条待执行的代码段地址)的修改。//控制信号和数据通路图对应着看
endmodule
数据存储器:
scdatamem.v
module scdatamem (clk,dataout,datain,addr,we,inclk,outclk);
input [31:0] datain;//存储器输入的数据
input [31:0] addr ;//数据输入地址输出地址
input clk, we, inclk, outclk;//时钟信号;写使能
output [31:0] dataout;
reg [31:0] ram [0:31];
assign dataout =ram[addr[6:2]];
always @ (posedge clk) beginif (we) ram[addr[6:2]] = datain;//有写使能信号时,addr指定相应的32位寄存器,并将输入的数据datain写入数据存储器内的相应的ram部分
end
integer i;
initial beginfor (i = 0;i < 32;i = i + 1)ram[i] = 0;ram[5'h14] = 32'h000000a3;ram[5'h15] = 32'h00000027;ram[5'h16] = 32'h00000079;ram[5'h17] = 32'h00000115;
end
endmodule
指令存储器:
scinstmem.v
module scinstmem (a,inst); input [31:0] a; // a用于存放本指令周期内寄存器pc的值output [31:0] inst; //存放下一条指令所在寄存器的编号wire [31:0] rom [0:31];assign rom[5'h00] = 32'h3c010000; // (00) main: lui r1,0assign rom[5'h01] = 32'h34240050; // (04) ori r4,r1,80assign rom[5'h02] = 32'h20050004; // (08) addi r5,r0, 4assign rom[5'h03] = 32'h0c000018; // (0c)call: jal sumassign rom[5'h04] = 32'hac820000; // (10) sw r2,0(r4)assign rom[5'h05] = 32'h8c890000; // (14) lw r9, 0(r4)assign rom[5'h06] = 32'h01244022; // (18) sub r8, r9. r4assign rom[5'h07] = 32'h20050003; // (lc) addi r5, r0. 3assign rom[5'h08] = 32'h20a5ffff; // (20) loop2: addi r5, r5, -1assign rom[5'h09] = 32'h34a8ffff; // (24) ori r8, r5, 0xffffassign rom[5'h0A] = 32'h39085555; // (28) xori r8. r8, 0x5555assign rom[5'h0B] = 32'h2009ffff; // (2c) addi r9, rO, -1assign rom[5'h0C] = 32'h312affff; // (30) andi rlO, r9, 0xffffassign rom[5'h0D] = 32'h01493025; // (34) or r6. rlO, r9assign rom[5'h0E] = 32'h01494026; // (38) xor r8, rlO, r9assign rom[5'h0F] = 32'h01463824; // (3c) and r7, rlO, r6assign rom[5'h10] = 32'h10a00001; // (40) beq r5, r0, shiftassign rom[5'h11] = 32'h08000008; // (44) j loop2 assign rom[5'h12] = 32'h2005ffff; // (48) shift: addi r5. r0, -1assign rom[5'h13] = 32'h000543c0; // (4c) sll r8. r5. 15assign rom[5'h14] = 32'h00084400; // (50) sll r8, r8, 16assign rom[5'h15] = 32'h00084403; // (54) sra r8, r8, 16assign rom[5'h16] = 32'h000843c2; // (58) srl r8. r8. 15assign rom[5'h17] = 32'h08000017; // (5c) finish: j finish assign rom[5'h18] = 32'h00004020; // (60) sum: add r8, r0, r0assign rom[5'h19] = 32'h8c890000; // (64) loop: lw r9, (r4)assign rom[5'h1A] = 32'h20840004; // (68) addi r4, r4, 4assign rom[5'h1B] = 32'h01094020; // (6c) add r8, r8, r9assign rom[5'h1C] = 32'h20a5ffff; // (70) addi r5, r5, -1assign rom[5'h1D] = 32'h14a0fffb; // (74) bne rS, r0, loopassign rom[5'h1E] = 32'h00081000; // (78) sll r2f r8f 0assign rom[5'h1F] = 32'h03e00008; // (7c) jr r31 assign inst = rom[a[6:2]];//更新PCendmodule//每一个寄存器存储一条指令 每一条机器指令后面的注释是它的汇编格式
顶层设计:
sccmop_dataflow.v
module sccmop_dataflow(clock, resetn, inst, pc, aluout, memout,mem_clk);
input clock, resetn,mem_clk;
output [31:0] inst,pc, aluout,memout;
wire [31:0] data;
wire wmem;
sccpu_dataflow s (clock, resetn, inst,memout,pc, wmem, aluout, data);
//描述数据通路中所有的部件,以及部件之间如何传递数据的关系的模块调用代码
scinstmem imem (pc,inst);
//指令存储器模块
scdatamem dmem (clock, memout, data, aluout, wmem, mem_clk, mem_clk);
//数据存储器模块
endmodule
sccpu_dataflow.v
//描述数据通路中所有的部件,以及部件之间如何传递数据的关系的模块调用代码
module sccpu_dataflow(clock, resetn, inst,mem,pc, wmem,alu,data);
input [31:0] inst,mem;
input clock,resetn;
output [31:0] pc,alu,data;output wmem;
wire [31:0] p4 , bpc, npc, adr, ra, alua, alub, res, alu_mem;
wire [3:0] aluc;
wire [4:0] reg_dest, wn;
wire [1:0] pcsource;
wire zero, wmem, wreg, regrt, m2reg, shift, aluimm, jal, sext;
wire [31:0] sa = {27'b0,inst[10:6]};
wire [31:0] offset = {imm[13:0],inst[15:0],2'b00};
sccu_dataflow cu (inst[31:26] , inst[5:0] , zero, wmem,wreg,regrt,m2reg, aluc, shift, aluimm,pcsource, jal, sext);
wire e = sext & inst[15];
wire [15:0] imm = {16{e}};
wire [31:0] immediate = {imm,inst[15:0]};
dff32 ip (npc,clock,resetn,pc); //32位D触发器
cla32 pcplus4 (pc,32'h4,1'b0,p4); //PC+4
cla32 br_adr (p4,offset,1'b0, adr);
wire [31:0] jpc = {p4[31:28],inst[25:0],2'b00}; //4+28拼接
mux2x32 alu_b (data, immediate,aluimm, alub) ;
mux2x32 alu_a (ra,sa,shift,alua);
mux2x32 result (alu,mem,m2reg,alu_mem);
mux2x32 link (alu_mem,p4,jal,res);
mux2x5 reg_wn (inst[15:11], inst[20: 16] , regrt, reg_dest);
assign wn = reg_dest | {5{jal}}; //ja1: r31 <-- p4;
mux4x32 nextpc (p4,adr,ra, jpc,pcsource,npc);
regfile rf (inst[25:21] ,inst[20:16] ,res,wn,wreg,clock,resetn,ra,data);
alu al_unit (alua,alub,aluc,alu, zero);
endmodule
mux2x32.v
module mux2x32 (a0,a1,s,y);input [31:0] a0,a1;input s;output [31:0] y;assign y = s?a1:a0;
endmodule
//32位2选1多路选择器
mux2x5.v
module mux2x5 (a0,a1,s,y);input [4:0] a0,a1;input s;output [4:0] y;assign y = s?a1:a0;
endmodule
//5位2选1多路选择器
dff32.v
module dff32(d,clk,clrn,q);input [31:0] d;input clk,clrn;output [31:0] q;reg [31:0] q;always @ (negedge clrn or posedge clk)if (clrn == 0) begin q <= 0;end else beginq <= d;end
endmodule
//32位寄存器,当有清零信号来临时就清零,否则寄存器内就存入输入的32位数据q。
暑期实训CPU设计(四)相关推荐
- 暑期实训总结_李小倩
暑期实训总结 姓名:李小倩 学号:111307105 班级:CSDN-java班 年级:2011级 转眼间实训已经结束有些时间了,我想这个实训对于我们参与的每一个人来说都是一段美好快乐的记忆.记得距 ...
- 暑期实训心得及总结_史国旭
暑期实训心得及总结 姓名:史国旭 学号:111307168 班级:CSDN-java 年级:2011级 转眼间实训已经结束4天了,我想这个实训对于我们参与的每 ...
- 计算机暑期实训报告,计算机专业暑期实训报告总结范文
<计算机专业暑期实训报告总结范文>由会员分享,可在线阅读,更多相关<计算机专业暑期实训报告总结范文(4页珍藏版)>请在人人文库网上搜索. 1.计算机专业暑期实训报告总结范文 计 ...
- web前端大三实训网页设计:餐饮网站设计——烧烤美食山庄(7个页面) HTML+CSS+JavaScript
web前端大三实训网页设计:餐饮网站设计--烧烤美食山庄(7个页面) HTML+CSS+JavaScript 临近期末, 你还在为HTML网页设计结课作业,老师的作业要求感到头大?HTML网页作业无从 ...
- 【百家稷学】深度学习计算机视觉生产实习(山西农业大学暑期实训)
继续咱们百家稷学专题,本次是有三AI在山西农业大学开设的为期10天的正式暑期专业课程.百家稷学专题的目标,是走进100所高校和企业进行学习与分享. 本次主题 本次实训是在山西农业大学进行,主题是< ...
- 爱尚实训html入门基础篇,爱尚实训网页设计与网页制作的区别
爱尚实训网页设计与网页制作的区别 网页设计是将策划案中的内容.网站的主题模式,以及结合自己的认识通过艺术的手法表现出来而网页制作通常就是将网页设计师所设计出来的设计稿,按照W3C规范用html语言将其 ...
- 山东大学暑期实训-饮食健康管理系统设计与实现(一)
山东大学暑期实训-饮食健康管理系统设计与实现(一) 环境配置篇(一) python环境配置 环境配置篇(一) python环境配置 使用Anaconda配置python环境,Python环境选择3.8 ...
- 暑期实训21组第一周个人工作总结
2022.6.21 参加暑期实训开题会议 下午13:30,参加由队长主持的队内的第一次全体线上会议,主要明确项目的内容.要点.技术.人员.分工等问题: 下午15:00,参加由英特尔的指导老师主持的答疑 ...
- Java暑期实训任务二——单词检测程序
实训内容:模仿"百词斩"手机App,设计并用Java语言实现一个"百词斩"图形界面程序(根据自己的能力,可以适当地增加或删除部分功能). 最低要求: (1)事先 ...
最新文章
- 对Transformer、XLNet、 ALBERT、 CRF等技术仍然一知半解?再不学习就OUT了!
- SSH-Struts第四弹:Struts2学习过程中遇到的问题
- zookeeper中展示所有节点_zookeeper工作原理与节点使用
- 若依如何配置允许跨域访问?
- IDEA 中创建多级目录
- matlab晶闸管整流电路,基于Matlab GUI的整流电路仿真
- 数字电视的格式(BT.601 BT.709 BT.2020)和接口(BT.656 BT.1120 BT.2077)
- pyqt QTableView详细用法
- Js日期格式化 年月日时分秒
- 【PS】证件照修改尺寸
- MQTT QoS(服务质量)介绍
- 聚宽macd底背离_MACD背离技术分析(图解)
- lempel ziv matlab,1.9 Lempel-Ziv算法
- 福师《计算机应用基础》在线作业一,福师《计算机应用基础》在线作业一答案...
- 如何备战 CCNP 考试
- 刷酸记录(迪维维A酸乳膏)20190905
- 计算机语言学笔记(二)现代汉语切分研究
- elasticsearch系列四:搜索详解(搜索API、Query DSL)
- 圣斗士星矢ol外国服务器网站,国外粉丝狂热支持《圣斗士星矢ol》
- php 单选默认,html单选按钮默认选中怎么做?input标签的单选按钮用法实例