当前位置:   article > 正文

Verilog 简易单周期CPU_单周期cpu仿真文件如何编写

单周期cpu仿真文件如何编写

目录

 本实验包含:

 简易结构图:

各部件代码或实现:

控制器:

寄存器堆:

ALU:

数据存储器:

指令存储器:

CPU:

tp(仿真文件):

 仿真结果:

 单周期CPU压缩包下载


 本实验包含:

        指令存储器和数据存储器的ip核调用,控制器,寄存器堆,ALU,单周期CPU的实现。

 简易结构图:

各部件代码或实现:

控制器:

控制器有13条指令,需要可以再加,照着之前格式注释加就行了,对于同RAM相关的指令未测试

R:
 指令  [31:26]   [25:21]   [20:16]  [15:11] [10:6]  [5:0] 功能
add000000rsrtrd000000100000寄存器加
sub000000rsrtrd000000100010寄存器减
and000000rsrtrd000000100100寄存器与
or000000rsrtrd000000100101寄存器或
nor000000rsrtrd000000100111寄存器或非
sll000000rs000000rdsa000000逻辑左移
srl000000rs000000rdsa000010 逻辑右移
sra000000rs000000rdsa100111算术右移
I:
指令 [31:26] [25:21] [20:16] [15:0] 功能
addi001000rsrtimmediate立即数加
lw100011rsrtimmediate取字数据
sw101011rsrtimmediate存字数据
beq000100rsrtimmediate相等转移
J:
指令[31:26][25:21][20:16][15;0]功能
j0000100000000000immediate转移

输入:op,func
输出:MemtoReg,MemWrite,Branch,ALUOP,ALUSrc,RegWrite,RegDst

  1. //
  2. //创建日期:2022/12/19 10:46:36
  3. //设计名称:控制器
  4. //课程名称:Controler
  5. //说明:
  6. //输入:op,func
  7. //输出:MemtoReg,MemWrite,Branch,ALUOP,ALUSrc,RegWrite,RegDst
  8. //依赖项:
  9. //
  10. //版次:
  11. //版本0.01-文件已创建
  12. //其他注释:
  13. //
  14. //
  15. module Controler(op,func,MemtoReg,MemWrite,Branch,ALUOP,ALUSrc,RegWrite,RegDst);
  16. input [5:0] op;
  17. input [5:0] func;
  18. output MemtoReg;
  19. output MemWrite;
  20. output Branch;
  21. output [11:0] ALUOP;
  22. output ALUSrc;
  23. output RegWrite;
  24. output RegDst;
  25. reg MemtoReg,MemWrite,Branch,ALUSrc,RegWrite,RegDst;
  26. reg [11:0] ALUOP;
  27. // R:
  28. // 指令 [31:26] [25:21] [20:16] [15:11] [10:6] [5:0] 功能
  29. // add 000000 rs rt rd 000000 100000 寄存器加
  30. // sub 000000 rs rt rd 000000 100010 寄存器减
  31. // and 000000 rs rt rd 000000 100100 寄存器与
  32. // or 000000 rs rt rd 000000 100101 寄存器或
  33. // nor 000000 rs rt rd 000000 100111 寄存器或非
  34. // sll 000000 rs 000000 rd sa 000000 逻辑左移
  35. // srl 000000 rs 000000 rd sa 000010 逻辑右移
  36. // sra 000000 rs 000000 rd sa 000011 算术右移
  37. //I:
  38. // 指令 [31:26] [25:21] [20:16] [15:0] 功能
  39. // addi 001000 rs rt immediate 立即数加
  40. // lw 100011 rs rt immediate 取字数据
  41. // sw 101011 rs rt immediate 存字数据
  42. // beq 000100 rs rt immediate 相等转移
  43. //J:
  44. // 指令 [31:26] [25:21] [20:16] [15:0] 功能
  45. // j 000010 00000 00000 immediate 转移
  46. always @(*)
  47. begin
  48. case(op)
  49. 6'b000000://寄存器操作
  50. begin
  51. MemtoReg=0;//输出ALU的输出
  52. MemWrite=0;//数据存储器不写入
  53. Branch=0;//正常PC
  54. ALUSrc=0;//ALU输入2选择寄存器输出
  55. RegWrite=1;//寄存器写入
  56. RegDst=1;//有rd
  57. case(func) //控制ALU操作
  58. 6'b100000:// 寄存器加
  59. ALUOP=12'b010000000000;
  60. 6'b100010:// 寄存器减
  61. ALUOP=12'b100000000000;
  62. 6'b100100:// 寄存器与
  63. ALUOP=12'b000010000000;
  64. 6'b100101:// 寄存器或
  65. ALUOP=12'b000000100000;
  66. 6'b100111:// 寄存器或非
  67. ALUOP=12'b000001000000;
  68. 6'b100100:// 逻辑左移
  69. ALUOP=12'b000000001000;
  70. 6'b100101:// 逻辑右移
  71. ALUOP=12'b000000000100;
  72. 6'b100111:// 算术右移
  73. ALUOP=12'b000000000010;
  74. default:ALUOP=12'b010000000000;
  75. endcase
  76. end
  77. 6'b001000:// 立即数加
  78. begin
  79. MemtoReg=0;//输出ALU结果
  80. MemWrite=0;//数据存储器不写入
  81. Branch=0;//正常PC
  82. ALUOP=12'b010000000000;//ALU加操作
  83. ALUSrc=1;//数据2选择立即数输出
  84. RegWrite=1;//寄存器写入
  85. RegDst=0;//rd选择rt
  86. end
  87. 6'b100011:// 取字数据
  88. begin
  89. MemtoReg=1;//输出数据存储器结果
  90. MemWrite=0;//数据存储器不写入
  91. Branch=0;//正常PC
  92. ALUOP=12'b000000000000;//ALU无操作,输出第一个输入
  93. ALUSrc=1;//数据2随意
  94. RegWrite=1;//寄存器写入
  95. RegDst=0;//rd选择rt
  96. end
  97. 6'b101011:// 存字数据
  98. begin
  99. MemtoReg=1;//输出随意
  100. MemWrite=1;//数据存储器写入
  101. Branch=0;//正常PC
  102. ALUOP=12'b000000000000;//ALU无操作,输出第一个输入
  103. ALUSrc=1;//数据2随意
  104. RegWrite=0;//寄存器不写入
  105. RegDst=0;//不写入随意
  106. end
  107. 6'b000100:// 相等转移
  108. begin
  109. MemtoReg=1;//输出随意
  110. MemWrite=0;//数据存储器不写入
  111. Branch=1;//PC可能改变
  112. ALUOP=12'b000000000000;//ALU无操作,输出第一个输入
  113. ALUSrc=0;//ALU输入2选择寄存器输出
  114. RegWrite=0;//寄存器不写入
  115. RegDst=0;//不写入随意
  116. end
  117. 6'b000010://跳转
  118. begin
  119. MemtoReg=1;//输出随意
  120. MemWrite=0;//数据存储器不写入
  121. Branch=1;//PC可能改变
  122. ALUOP=12'b000000000000;//ALU无操作,输出第一个输入
  123. ALUSrc=0;//数据2选择寄存器输出
  124. RegWrite=0;//寄存器不写入
  125. RegDst=0;//不写入随意
  126. end
  127. default:
  128. begin
  129. MemtoReg=0;
  130. MemWrite=0;
  131. Branch=0;
  132. ALUOP = 12'b000000000000;//ALU无操作,输出第一个输入
  133. ALUSrc=0;
  134. RegWrite=1;
  135. RegDst=1;
  136. end
  137. endcase
  138. end
  139. endmodule

寄存器堆:

采用之前的寄存器堆(短版)代码,没有初始化,不影响使用,需要的话加上就行

  1. //
  2. //
  3. //创建日期:2022/10/16 21:37:00
  4. //设计名称:寄存器堆
  5. //课程名称:regfile
  6. //说明:
  7. // 实现 32 个寄存器, 其中 0 号寄存器读出的值恒为 0
  8. // 寄存器堆为异步读同步写,
  9. // 共有 1 个写端口和 2 个读端口
  10. //依赖项:
  11. //
  12. //版次:
  13. //版本0.01-文件已创建
  14. //其他注释:
  15. //
  16. module regfile(
  17. input clk, // 时钟
  18. input wen, // 写使能
  19. input [4 :0] raddr1, // 读地址1
  20. input [4 :0] raddr2, // 读地址2
  21. input [4 :0] waddr, // 写地址
  22. input [31:0] wdata, // 写数据
  23. output reg [31:0] rdata1, // 读到的数据1
  24. output reg [31:0] rdata2, // 读到的数据2
  25. input [4 :0] test_addr, // 测试读端口
  26. output reg [31:0] test_data // 测试输出
  27. );
  28. reg [31:0] rf[31:0]; // 定义3232位的寄存器
  29. always @(posedge clk) // 时钟上升沿
  30. begin
  31. if (wen) // 如果写使能wen为1则写入寄存器
  32. begin
  33. rf[waddr] <= wdata;
  34. end
  35. end
  36. //读端口 1
  37. always @(*)
  38. begin
  39. if (raddr1==5'd0)
  40. rdata1 <= 32'd0;
  41. else
  42. rdata1 <= rf[raddr1];
  43. end
  44. //读端口 2
  45. always @(*)
  46. begin
  47. if (raddr2==5'd0)
  48. rdata2 <= 32'd0;
  49. else
  50. rdata2 <= rf[raddr2];
  51. end
  52. //测试读端口
  53. always @(*)
  54. begin
  55. if (test_addr==5'd0)
  56. test_data <= 32'd0;
  57. else
  58. test_data <= rf[test_addr];
  59. end
  60. endmodule

ALU

对照之前的ALU增加了比较相等的输出,用于PC的跳转,采用独热编码,相当于13种简易运算。

  1. //
  2. //创建日期:2022/11/6 20:06:00
  3. //设计名称:ALU算术逻辑单元
  4. //课程名称:alu
  5. //说明:
  6. //输入: [11:0] alu_control; // ALU控制信号
  7. // [31:0] alu_src1; // ALU操作数1
  8. // [31:0] alu_src2; // ALU操作数2
  9. //输出: [31:0] alu_result; // ALU结果
  10. // Equal 两个输入是否相等
  11. //依赖项:
  12. //
  13. //版次:
  14. //版本0.01-文件已创建
  15. //其他注释:
  16. //
  17. //
  18. module alu(alu_control,alu_src1,alu_src2,alu_result,Equal);
  19. input [11:0] alu_control; // ALU控制信号
  20. input [31:0] alu_src1; // ALU操作数1
  21. input [31:0] alu_src2; // ALU操作数2
  22. output [31:0] alu_result; // ALU结果
  23. output Equal; //相等
  24. wire Equal;
  25. reg [31:0] alu_result;
  26. // 控制信号为独热编码
  27. assign Equal = alu_src1==alu_src2;
  28. always @(*)
  29. begin
  30. case(alu_control) // 下面的12指操作数1,操作数2
  31. 12'b000000000001:alu_result<=alu_src1<<16; // 高位加载 1
  32. 12'b000000000010:alu_result<=alu_src1>>>alu_src2; // 算术右移 2
  33. 12'b000000000100:alu_result<=alu_src1>>alu_src2; // 逻辑右移 4
  34. 12'b000000001000:alu_result<=alu_src1<<alu_src2; // 逻辑左移 8
  35. 12'b000000010000:alu_result<=alu_src1^alu_src2; // 按位异或 16
  36. 12'b000000100000:alu_result<=alu_src1|alu_src2;// 按位或 32
  37. 12'b000001000000:alu_result<=~(alu_src1|alu_src2); // 按位或非 64
  38. 12'b000010000000:alu_result<=alu_src1&alu_src2; // 按位与 128
  39. 12'b000100000000:alu_result<=alu_src1<alu_src2?32'd1:32'd0;// 无符号比较,小于置位 256
  40. 12'b001000000000:alu_result<=$signed(alu_src1)<$signed(alu_src2)?32'd1:32'd0;// 有符号比较,小于置位 512
  41. 12'b010000000000:alu_result<=alu_src1+alu_src2;// 1加 1024
  42. 12'b100000000000:alu_result<=alu_src1-alu_src2;// 12048
  43. default: alu_result<=alu_src1;
  44. endcase
  45. end
  46. endmodule

数据存储器:

采用IP核实现:

没有测试,功能或许有问题

         

 

指令存储器:

采用IP核实现:

 

 

 

 第四张图的ROM.coe数据如下:

  1. memory_initialization_radix=2;
  2. memory_initialization_vector=
  3. 00100000000000010000000000001000
  4. 00100000000000100000000000000010
  5. 00100000000000110000000000000000
  6. 00000000010000110001100000100000
  7. 00010000001000110000000000000111
  8. 00001000000000000000000000000011

这是一段测试用的指令段,具体功能在tp文件种有注释

这个文件什么名字和位置都可以,后缀是.coe就行。

CPU:

  1. //
  2. //创建日期:2022/12/19 16:32:56
  3. //设计名称:CPU
  4. //课程名称:CPU
  5. //说明:
  6. //调用各个部件,进行运算
  7. //依赖项:
  8. // 控制器,寄存器,ALU
  9. //版次:
  10. //版本0.01-文件已创建
  11. //其他注释:
  12. module CPU(clk);
  13. input clk;
  14. // PC
  15. reg [7:0] PC=8'd0;//PC从第0条指令开始
  16. wire[31:0] SignImm;//指令后16位扩展结果
  17. wire PCSrc;//是否跳转
  18. always@(posedge clk)//上升沿
  19. begin
  20. if (PCSrc == 0)
  21. PC = PC+1;
  22. else
  23. PC = SignImm[7:0];
  24. end
  25. // 指令存储器
  26. wire [31:0] instructions;//指令存储器输出
  27. ROM_D IROM(
  28. .a(PC),//地址
  29. .spo(instructions));//指令输出
  30. wire[5:0] op,func;//控制器输入
  31. wire[4:0] rs,rt,rd;//三个寄存器地址
  32. assign op = instructions[31:26];
  33. assign func = instructions[5:0];
  34. assign rs = instructions[25:21];
  35. assign rt = instructions[20:16];
  36. assign rd = instructions[15:11];
  37. assign SignImm = {{(16){instructions[15]}},instructions[15:0]};
  38. // 控制器
  39. wire MemtoReg,MemWrite,Branch,ALUSrc,RegWrite,RegDst;//控制器输出控制信号
  40. wire[11:0] ALUOP;//ALU所做的操作
  41. Controler Contr(op,func,MemtoReg,MemWrite,Branch,ALUOP,ALUSrc,RegWrite,RegDst);
  42. // 寄存器堆
  43. wire[31:0] R1,R2,WriteBackData;//寄存器输出和数据输入
  44. wire[4:0] reg_w;//寄存器写地址
  45. assign reg_w = RegDst?rd:rt;
  46. regfile regfile_(clk,RegWrite,rs,rt,reg_w,WriteBackData,R1,R2);
  47. // ALU
  48. wire[31:0] srcB,ALUResult;//ALU第二个数据输入和数据输出
  49. wire Equal;//输入是否相等
  50. assign srcB = ALUSrc?SignImm:R2;
  51. alu ALU(ALUOP,R1,srcB,ALUResult,Equal);
  52. assign PCSrc = Branch&Equal;
  53. // 数据存储器
  54. wire [31:0] ReadData;//数据存储器输出
  55. data_RAM DRM(
  56. .clka (clk ),
  57. .wea (MemWrite ),
  58. .addra (ALUResult[7:0]),
  59. .dina (R2 ),
  60. .douta (ReadData ));
  61. assign WriteBackData = MemWrite?ReadData:ALUResult;
  62. endmodule

tp(仿真文件):

就一个clk和CPU的调用,所用指令段的注释。

  1. `timescale 1ns / 1ps
  2. //001000 00000 00001 00000000000010000个寄存器和8相加存入第1个寄存器
  3. //001000 00000 00010 00000000000000100个寄存器和2相加存入第2个寄存器
  4. //001000 00000 00011 00000000000000000个寄存器和0相加存入第3个寄存器
  5. //000000 00010 00011 00011 00000 1000003个寄存器和第2个寄存器相加,结果存入第3个寄存器
  6. //000100 00001 00011 00000000000001111个寄存器和第3个相等转移到7
  7. //000010 00000 00000 0000000000000011 转移到3
  8. //相当于以下程序:
  9. // reg[1] = 8
  10. // reg[2] = 2
  11. // reg[3] = 0
  12. //M: reg[3] = reg[3]+reg[2]
  13. // if reg[1] == reg[3]: goto N
  14. // goto M
  15. //N:
  16. module tp;
  17. reg clk=0;
  18. CPU cpu_(clk);
  19. always #10 clk = ~clk;
  20. endmodule

 仿真结果:

 

 

 

 

 单周期CPU压缩包下载

开了动态调分,初始积分是0.

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/696283
推荐阅读
相关标签
  

闽ICP备14008679号