飞道的博客

《自己动手写CPU》学习记录(3)——第4章/Part 1

354人阅读  评论(0)




目录

引言

致谢

平台

ori 指令

流水线结构建立

模型

简单的MIPS五级流水线结构

设计

宏定义

程序计数器

译码

通用寄存器

指令执行

内存访问

指令ROM

顶层文件

处理器顶层

SOPC顶层 

功能仿真

TestBench

仿真结果

执行时间

时序细节



引言

本篇学习书本的第四章,实现 ori 指令。

致谢

感谢书籍《自己动手写CPU》及其作者雷思磊。一并感谢开源精神。

平台

开发环境:Vivado IDE 2018.3

FPGA芯片型号:xc7a35tfgg484-2



ori 指令

指令格式:

指令用法:

ori rt, rs,immediate

其作用是将指令中的16位立即数进行无符号数扩展至 32 位,然后与索引号为 rt 的通用寄存器的值进行逻辑或运算,运算的结果保存到索引号为 rs 的寄存器内。

符号扩展示例:

此处书本有误

书本中给出的指令用法为:

 但是随后举的例子却是:

 所以正确的指令使用格式为:(上面写过了,再强调一遍)

ori rt, rs,immediate

流水线结构建立

模型

简单的MIPS五级流水线结构

设计

声明:

设计思路基本借鉴书本,但是具体的模块代码编写,与作者有较大不同

宏定义

此文件主要定义了一些与设计相关的宏,当设计的参数需要更改时,在此文件修改即可,不需要改动内部设计文件。方便代码维护,也增强了代码的可读性。


  
  1. // |------------------------------ ================================== ------------------------------
  2. // |============================== MIPS32 CPU SYSTEM ALL MACRO DEFINE ==============================
  3. // |------------------------------ ================================== ------------------------------
  4. // |Create Date : 2022-12-06
  5. // |Finish Date : 2022-
  6. // |Edited by : Xu Y. B. (CSDN USER NAME :在路上,正出发)
  7. // |Reference : 《自己动手写CPU》——第4章
  8. // |
  9. // |
  10. // |------------------------------------------------------------------------------------------------
  11. // |Change History:
  12. // |
  13. // |-------------------------------------- 系统级全局宏定义 --------------------------------------
  14. // |------------------------------------------------------------------------------------------------
  15. // | 0字
  16. `define DEF_ZERO_WORD 32 'd0 // 0字
  17. // | 关于译码
  18. `define DEF_ALU_OPR_BUS 7: 0 // 译码输出 O_ALU_OPR 总线
  19. `define DEF_ALU_SEL_BUS 2: 0 // 译码输出 O_ALU_SEL 总线
  20. // | 逻辑 0 1
  21. `define DEF_LOG_TRUE 1 'b1 // 逻辑 真
  22. `define DEF_LOG_FALSE 1 'b0 // 逻辑 假
  23. // | 芯片使能
  24. `define DEF_CHIP_EN 1 'b1 // 芯片使能
  25. `define DEF_CHIP_DIS 1 'b0 // 芯片不使能
  26. // |-------------------------------------- 指令相关的宏定义 --------------------------------------
  27. // |------------------------------------------------------------------------------------------------
  28. // | 指令码
  29. `define DEF_ISTC_ORI 6 'b001101 // ori
  30. `define DEF_ISTC_NOP 6 'd0 // nop
  31. // | ALU操作码
  32. `define DEF_ALU_OR_OPR 8 'b00100101 // ALU 或 操作码
  33. `define DEF_ALU_NOP_OPR 8 'd0 // ALU 空 操作码
  34. // | ALU 选择
  35. `define DEF_ALU_SEL_LOGIC 3 'b001
  36. `define DEF_ALU_SEL_NOP 3 'b000
  37. // | 操作数
  38. `define DEF_SRC_OPR_DATA_BUS 31: 0
  39. `define DEF_IMM_DATA_BUS 15: 0
  40. // |-------------------------------------- 指令存储器宏定义 --------------------------------------
  41. // |------------------------------------------------------------------------------------------------
  42. `define DEF_ISTC_ADDR_BUS 31: 0 // 地址线总线
  43. `define DEF_ISTC_DATA_BUS 31: 0 // 数据线总线
  44. `define DEF_ISTC_CACH_DEPTH 2** 17- 1 // 缓存深度/地址最大值
  45. `define DEF_ISTC_ADDR_WIDTH_ACTUAL 17 // 实际使用的缓存地址线宽度
  46. // |-------------------------------------- 通用寄存器宏定义 --------------------------------------
  47. // |------------------------------------------------------------------------------------------------
  48. `define DEF_GPR_ADDR_WIDTH 5 // 通用寄存器地址位宽(32个)
  49. `define DEF_GPR_DATA_WIDTH 32 // 通用寄存器数据位宽
  50. `define DEF_GPR_NUM 32 // 通用寄存器数目
  51. `define DEF_GPR_ADDR_NOP 5 'd0 // 空操作 GPR 地址

程序计数器

该模块在时钟节拍下,给出程序指令寄存器要读取的地址,以及读使能信号。输出接口对接指令存储器ROM模块。


  
  1. // |------------------------------ ================================== ------------------------------
  2. // |============================== 程序计数寄存器模块 ==============================
  3. // |------------------------------ ================================== ------------------------------
  4. // |Create Date : 2022-12-06
  5. // |Finish Date : 2022-12-06
  6. // |Edited by : Xu Y. B. (CSDN USER NAME :在路上,正出发)
  7. // |Reference : 《自己动手写CPU》——第4章
  8. // |
  9. // |
  10. // |------------------------------------------------------------------------------------------------
  11. // |Change History:
  12. // |
  13. `include "MIPS_SYS_DEFINES.v"
  14. `timescale 1ns / 1ps
  15. module PC_REG_MDL(
  16. // |-------------------------------------- 输入输出端口声明 --------------------------------------
  17. // |------------------------------------------------------------------------------------------------
  18. input I_CPU_CLK,
  19. input I_CPU_RSTN,
  20. output reg [` DEF_ISTC_ADDR_BUS] O_PC,
  21. output reg O_ISTC_ROM_CE
  22. );
  23. // |-------------------------------------- 模块内部逻辑设计 --------------------------------------
  24. // |------------------------------------------------------------------------------------------------
  25. // CE
  26. always @ (posedge I_CPU_CLK)
  27. begin
  28. if(~ I_CPU_RSTN)
  29. begin
  30. O_ISTC_ROM_CE <= ` DEF_CHIP_DIS;
  31. end
  32. else
  33. begin
  34. O_ISTC_ROM_CE <= ` DEF_CHIP_EN;
  35. end
  36. end
  37. // PC
  38. always @ (posedge I_CPU_CLK)
  39. begin
  40. if( O_ISTC_ROM_CE == ` DEF_CHIP_DIS)
  41. begin
  42. O_PC <= 32'd0;
  43. end
  44. else
  45. begin
  46. O_PC <= O_PC + 32'd4;
  47. end
  48. end
  49. endmodule

译码

此模块主要接收来自指令存储器ROM模块输出的指令,并且按照指令编码规则进行指令译码,为后续的指令执行模块提供必要的计算信息。


  
  1. // |------------------------------ ================================== ------------------------------
  2. // |============================== 指令-译码模块 ==============================
  3. // |------------------------------ ================================== ------------------------------
  4. // |Create Date : 2022-12-07
  5. // |Finish Date : 2022-12-07
  6. // |Edited by : Xu Y. B. (CSDN USER NAME :在路上,正出发)
  7. // |Reference : 《自己动手写CPU》——第4章
  8. // |
  9. // |
  10. // |------------------------------------------------------------------------------------------------
  11. // |Change History:
  12. // |
  13. `include "MIPS_SYS_DEFINES.v"
  14. `timescale 1ns / 1ps
  15. module ID_MDL(
  16. // |-------------------------------------- 输入输出端口声明 --------------------------------------
  17. // |------------------------------------------------------------------------------------------------
  18. // | 时钟、复位
  19. input I_CPU_CLK,
  20. input I_CPU_RSTN,
  21. // | 指令
  22. input [` DEF_ISTC_DATA_BUS] I_ISTC,
  23. // | GPR读写控制
  24. output reg O_GPR_RD_EN_A,
  25. output reg [` DEF_GPR_ADDR_WIDTH -1: 0] O_GPR_RD_ADDR_A,
  26. input [` DEF_GPR_DATA_WIDTH -1: 0] I_GPR_RD_DATA_A,
  27. output reg O_GPR_RD_EN_B,
  28. output reg [` DEF_GPR_ADDR_WIDTH -1: 0] O_GPR_RD_ADDR_B,
  29. input [` DEF_GPR_DATA_WIDTH -1: 0] I_GPR_RD_DATA_B,
  30. // | 译码输出相关 对接 ALU 运算单元
  31. // output reg [`DEF_ALU_SEL_BUS] O_ALU_SEL,
  32. output reg [` DEF_ALU_OPR_BUS] O_ALU_OP_TYPE,
  33. output reg [` DEF_SRC_OPR_DATA_BUS] O_SRC_OPR_DATA_A,
  34. output reg [` DEF_SRC_OPR_DATA_BUS] O_SRC_OPR_DATA_B,
  35. output reg O_DST_GPR_WR_EN,
  36. output reg [` DEF_GPR_ADDR_WIDTH -1: 0] O_DST_GPR_WR_ADDR
  37. );
  38. // |-------------------------------------- 模块内部信号声明 --------------------------------------
  39. // |------------------------------------------------------------------------------------------------
  40. // | 指令分解相关
  41. wire [ 5: 0] W_ISTC_TYPE;
  42. wire [` DEF_GPR_ADDR_WIDTH -1: 0] W_SRC_GPR_ADDR;
  43. wire [` DEF_GPR_ADDR_WIDTH -1: 0] W_DST_GPR_ADDR;
  44. wire [` DEF_IMM_DATA_BUS] W_ISTC_IMM_DATA;
  45. // | 32位立即数
  46. reg [ 31: 0] R_IMM_DATA_32BIT;
  47. // | 指令有效信号
  48. reg R_ISTC_VAL;
  49. // |-------------------------------------- 模块内部逻辑设计 --------------------------------------
  50. // |------------------------------------------------------------------------------------------------
  51. // | 指令分解相关
  52. assign W_ISTC_TYPE = I_ISTC[ 31: 26];
  53. assign W_SRC_GPR_ADDR = I_ISTC[ 25: 21];
  54. assign W_DST_GPR_ADDR = I_ISTC[ 20: 16];
  55. assign W_ISTC_IMM_DATA = I_ISTC[ 15: 0] ;
  56. // | 指令译码
  57. always @ (posedge I_CPU_CLK)
  58. begin
  59. if(~ I_CPU_RSTN)
  60. begin
  61. O_GPR_RD_EN_A <= 1'b0;
  62. O_GPR_RD_ADDR_A <= ` DEF_GPR_ADDR_NOP;
  63. O_GPR_RD_EN_B <= 1'b0;
  64. O_GPR_RD_ADDR_B <= ` DEF_GPR_ADDR_NOP;
  65. O_ALU_OP_TYPE <= ` DEF_ALU_NOP_OPR;
  66. // O_ALU_SEL <= `DEF_ALU_SEL_NOP;
  67. O_DST_GPR_WR_EN <= 1'b0;
  68. O_DST_GPR_WR_ADDR <= ` DEF_GPR_ADDR_NOP;
  69. R_ISTC_VAL <= 1'b0;
  70. R_IMM_DATA_32BIT <= 32'd0;
  71. end
  72. else
  73. begin
  74. case( W_ISTC_TYPE)
  75. ` DEF_ISTC_ORI: // ori指令
  76. begin
  77. O_GPR_RD_EN_A <= 1'b1;
  78. O_GPR_RD_ADDR_A <= W_SRC_GPR_ADDR;
  79. O_GPR_RD_EN_B <= 1'b0;
  80. O_GPR_RD_ADDR_B <= ` DEF_GPR_ADDR_NOP;
  81. O_ALU_OP_TYPE <= ` DEF_ALU_OR_OPR;
  82. // O_ALU_SEL <= `DEF_ALU_SEL_LOGIC;
  83. O_DST_GPR_WR_EN <= 1'b1;
  84. O_DST_GPR_WR_ADDR <= W_DST_GPR_ADDR;
  85. R_ISTC_VAL <= 1'b1;
  86. R_IMM_DATA_32BIT <= { 16'd0, W_ISTC_IMM_DATA};
  87. end
  88. default:
  89. begin
  90. O_GPR_RD_EN_A <= 1'b0;
  91. O_GPR_RD_ADDR_A <= ` DEF_GPR_ADDR_NOP;
  92. O_GPR_RD_EN_B <= 1'b0;
  93. O_GPR_RD_ADDR_B <= ` DEF_GPR_ADDR_NOP;
  94. O_ALU_OP_TYPE <= ` DEF_ALU_NOP_OPR;
  95. // O_ALU_SEL <= `DEF_ALU_SEL_NOP;
  96. O_DST_GPR_WR_EN <= 1'b0;
  97. O_DST_GPR_WR_ADDR <= ` DEF_GPR_ADDR_NOP;
  98. R_ISTC_VAL <= 1'b0;
  99. R_IMM_DATA_32BIT <= 32'd0;
  100. end
  101. endcase
  102. end
  103. end
  104. // | 数据输出
  105. always @ (posedge I_CPU_CLK)
  106. begin
  107. if(~ I_CPU_RSTN)
  108. begin
  109. O_SRC_OPR_DATA_A <= ` DEF_ZERO_WORD;
  110. end
  111. else if( O_GPR_RD_EN_A)
  112. begin
  113. O_SRC_OPR_DATA_A <= I_GPR_RD_DATA_A;
  114. end
  115. else if(~ O_GPR_RD_EN_A)
  116. begin
  117. O_SRC_OPR_DATA_A <= R_IMM_DATA_32BIT;
  118. end
  119. else
  120. begin
  121. O_SRC_OPR_DATA_A <= ` DEF_ZERO_WORD;
  122. end
  123. end
  124. always @ (posedge I_CPU_CLK)
  125. begin
  126. if(~ I_CPU_RSTN)
  127. begin
  128. O_SRC_OPR_DATA_B <= ` DEF_ZERO_WORD;
  129. end
  130. else if( O_GPR_RD_EN_B)
  131. begin
  132. O_SRC_OPR_DATA_B <= I_GPR_RD_DATA_B;
  133. end
  134. else if(~ O_GPR_RD_EN_B)
  135. begin
  136. O_SRC_OPR_DATA_B <= R_IMM_DATA_32BIT;
  137. end
  138. else
  139. begin
  140. O_SRC_OPR_DATA_B <= ` DEF_ZERO_WORD;
  141. end
  142. end
  143. endmodule

通用寄存器

此模块主要负责32位通用寄存器的初始化、读写等操作。可当作RAM理解。


  
  1. // |------------------------------ ================================== ------------------------------
  2. // |============================== 取指-译码接口模块 ==============================
  3. // |------------------------------ ================================== ------------------------------
  4. // |Create Date : 2022-12-06
  5. // |Finish Date : 2022-12-06
  6. // |Edited by : Xu Y. B. (CSDN USER NAME :在路上,正出发)
  7. // |Reference : 《自己动手写CPU》——第4章
  8. // |
  9. // |
  10. // |------------------------------------------------------------------------------------------------
  11. // |Change History:
  12. // |
  13. `include "MIPS_SYS_DEFINES.v"
  14. `timescale 1ns / 1ps
  15. module GPR_WR_RD_MDL(
  16. // |-------------------------------------- 输入输出端口声明 --------------------------------------
  17. // |------------------------------------------------------------------------------------------------
  18. // | 时钟、复位
  19. input I_CPU_CLK,
  20. input I_CPU_RSTN,
  21. // | 写
  22. input I_GPR_WR_EN,
  23. input [` DEF_GPR_ADDR_WIDTH -1: 0] I_GPR_WR_ADDR,
  24. input [` DEF_GPR_DATA_WIDTH -1: 0] I_GPR_WR_DATA,
  25. // |读
  26. input I_GPR_RD_EN_A,
  27. input [` DEF_GPR_ADDR_WIDTH -1: 0] I_GPR_RD_ADDR_A,
  28. output reg [` DEF_GPR_DATA_WIDTH -1: 0] O_GPR_RD_DATA_A,
  29. input I_GPR_RD_EN_B,
  30. input [` DEF_GPR_ADDR_WIDTH -1: 0] I_GPR_RD_ADDR_B,
  31. output reg [` DEF_GPR_DATA_WIDTH -1: 0] O_GPR_RD_DATA_B
  32. );
  33. // |-------------------------------------- GPR-寄存器组定义 --------------------------------------
  34. // |------------------------------------------------------------------------------------------------
  35. reg [` DEF_GPR_DATA_WIDTH -1: 0] R_GPR [` DEF_GPR_NUM -1: 0];
  36. // |-------------------------------------- GPR-寄存器初始化 --------------------------------------
  37. // |------------------------------------------------------------------------------------------------
  38. initial $readmemh( "D:/VIVADO_WORK_SPACE/CPU_MIPS32/DATA_FILE/GPR_INIT.txt", R_GPR);
  39. // |-------------------------------------- GPR-寄存器写操作 --------------------------------------
  40. // |------------------------------------------------------------------------------------------------
  41. always @ (posedge I_CPU_CLK)
  42. begin
  43. if( I_CPU_RSTN)
  44. begin
  45. if( I_GPR_WR_EN && I_GPR_WR_ADDR != ` DEF_GPR_ADDR_WIDTH'd0)
  46. begin
  47. R_GPR[ I_GPR_WR_ADDR] <= I_GPR_WR_DATA;
  48. end
  49. end
  50. end
  51. // |-------------------------------------- PORT A 读操作 --------------------------------------
  52. // |------------------------------------------------------------------------------------------------
  53. always @ (*)
  54. begin
  55. if(~ I_CPU_RSTN)
  56. begin
  57. O_GPR_RD_DATA_A = ` DEF_ZERO_WORD;
  58. end
  59. else if( I_GPR_WR_EN && I_GPR_RD_EN_A && ( I_GPR_RD_ADDR_A == I_GPR_WR_ADDR))
  60. begin
  61. O_GPR_RD_DATA_A = I_GPR_WR_DATA;
  62. end
  63. else if( I_GPR_RD_EN_A)
  64. begin
  65. O_GPR_RD_DATA_A = R_GPR[ I_GPR_RD_ADDR_A];
  66. end
  67. else
  68. begin
  69. O_GPR_RD_DATA_A = ` DEF_ZERO_WORD;
  70. end
  71. end
  72. // |-------------------------------------- PORT B 读操作 --------------------------------------
  73. // |------------------------------------------------------------------------------------------------
  74. always @ (*)
  75. begin
  76. if(~ I_CPU_RSTN)
  77. begin
  78. O_GPR_RD_DATA_B = ` DEF_ZERO_WORD;
  79. end
  80. else if( I_GPR_WR_EN && I_GPR_RD_EN_B && ( I_GPR_RD_ADDR_B == I_GPR_WR_ADDR))
  81. begin
  82. O_GPR_RD_DATA_B = I_GPR_WR_DATA;
  83. end
  84. else if( I_GPR_RD_EN_B)
  85. begin
  86. O_GPR_RD_DATA_B = R_GPR[ I_GPR_RD_ADDR_B];
  87. end
  88. else
  89. begin
  90. O_GPR_RD_DATA_B = ` DEF_ZERO_WORD;
  91. end
  92. end
  93. endmodule

初始化文件:

说明:此处文中的示例代码存在如下问题:

1、模块输出一般不选择组合逻辑输出;

2、always快描述组合逻辑时,要用阻塞赋值 “=”

指令执行

此模块是CPU的核心运算模块,将译码阶段传递的运算指令执行,并且完成数据的写请求。


  
  1. // |------------------------------ ================================== ------------------------------
  2. // |============================== 指令-执行模块 ==============================
  3. // |------------------------------ ================================== ------------------------------
  4. // |Create Date : 2022-12-07
  5. // |Finish Date : 2022-12-07
  6. // |Edited by : Xu Y. B. (CSDN USER NAME :在路上,正出发)
  7. // |Reference : 《自己动手写CPU》——第4章
  8. // |
  9. // |
  10. // |------------------------------------------------------------------------------------------------
  11. // |Change History:
  12. // |
  13. `include "MIPS_SYS_DEFINES.v"
  14. `timescale 1ns / 1ps
  15. module EXE_MDL(
  16. // |-------------------------------------- 输入输出端口声明 --------------------------------------
  17. // |------------------------------------------------------------------------------------------------
  18. // | 时钟、复位
  19. input I_CPU_CLK,
  20. input I_CPU_RSTN,
  21. // | 操作指令
  22. // input [`DEF_ALU_SEL_BUS] I_ALU_SEL,
  23. input [` DEF_ALU_OPR_BUS] I_ALU_OP_TYPE,
  24. // | 源操作数
  25. input [` DEF_SRC_OPR_DATA_BUS] I_SRC_OPR_DATA_A,
  26. input [` DEF_SRC_OPR_DATA_BUS] I_SRC_OPR_DATA_B,
  27. // | 目的寄存器写
  28. input I_DST_GPR_WR_EN,
  29. input [` DEF_GPR_ADDR_WIDTH -1: 0] I_DST_GPR_WR_ADDR,
  30. // | 输出
  31. output reg O_DST_GPR_WR_EN, //输入打一拍
  32. output reg [` DEF_GPR_ADDR_WIDTH -1: 0] O_DST_GPR_WR_ADDR, //输入打一拍
  33. output reg [` DEF_GPR_DATA_WIDTH -1: 0] O_DST_GPR_WR_DATA
  34. );
  35. // |-------------------------------------- 模块内部信号声明 --------------------------------------
  36. // |------------------------------------------------------------------------------------------------
  37. // | I_ALU_OP_TYPE 打拍
  38. reg [` DEF_ALU_OPR_BUS] R_I_ALU_OP_TYPE;
  39. reg R_I_DST_GPR_WR_EN;
  40. reg [` DEF_GPR_ADDR_WIDTH -1: 0] R_I_DST_GPR_WR_ADDR;
  41. // |-------------------------------------- 模块内部逻辑设计 --------------------------------------
  42. // |------------------------------------------------------------------------------------------------
  43. // | I_ALU_OP_TYPE 打拍对齐时序
  44. always @ (posedge I_CPU_CLK)
  45. begin
  46. if(~ I_CPU_RSTN)
  47. begin
  48. R_I_ALU_OP_TYPE <= 0;
  49. end
  50. else
  51. begin
  52. R_I_ALU_OP_TYPE <= I_ALU_OP_TYPE;
  53. end
  54. end
  55. // | 计算单元
  56. always @ (posedge I_CPU_CLK)
  57. begin
  58. if(~ I_CPU_RSTN)
  59. begin
  60. O_DST_GPR_WR_DATA <= ` DEF_ZERO_WORD;
  61. end
  62. else
  63. begin
  64. case( R_I_ALU_OP_TYPE)
  65. ` DEF_ALU_OR_OPR:
  66. begin
  67. O_DST_GPR_WR_DATA <= I_SRC_OPR_DATA_A | I_SRC_OPR_DATA_B;
  68. end
  69. default:
  70. begin
  71. O_DST_GPR_WR_DATA <= ` DEF_ZERO_WORD;
  72. end
  73. endcase
  74. end
  75. end
  76. // | 写操作打拍
  77. always @ (posedge I_CPU_CLK)
  78. begin
  79. if(~ I_CPU_RSTN)
  80. begin
  81. O_DST_GPR_WR_EN <= 1'b0;
  82. O_DST_GPR_WR_ADDR <= 5'd0;
  83. R_I_DST_GPR_WR_EN <= 1'b0;
  84. R_I_DST_GPR_WR_ADDR <= 5'd0;
  85. end
  86. else
  87. begin
  88. R_I_DST_GPR_WR_EN <= I_DST_GPR_WR_EN;
  89. R_I_DST_GPR_WR_ADDR <= I_DST_GPR_WR_ADDR;
  90. O_DST_GPR_WR_EN <= R_I_DST_GPR_WR_EN;
  91. O_DST_GPR_WR_ADDR <= R_I_DST_GPR_WR_ADDR;
  92. end
  93. end
  94. endmodule

内存访问

此模块主要是一些内存访问的操作,由于 ori 指令暂时不需要访存,所以该模块目前只有写使能传递功能。


  
  1. // |------------------------------ ================================== ------------------------------
  2. // |============================== -执行模块 ==============================
  3. // |------------------------------ ================================== ------------------------------
  4. // |Create Date : 2022-12-07
  5. // |Finish Date : 2022-12-07
  6. // |Edited by : Xu Y. B. (CSDN USER NAME :在路上,正出发)
  7. // |Reference : 《自己动手写CPU》——第4章
  8. // |
  9. // |
  10. // |------------------------------------------------------------------------------------------------
  11. // |Change History:
  12. // |
  13. `include "MIPS_SYS_DEFINES.v"
  14. `timescale 1ns / 1ps
  15. module MEM_ACS_MDL(
  16. // |-------------------------------------- 输入输出端口声明 --------------------------------------
  17. // |------------------------------------------------------------------------------------------------
  18. // | 时钟、复位
  19. input I_CPU_CLK,
  20. input I_CPU_RSTN,
  21. // | 前接指令执行模块输出
  22. input I_DST_GPR_WR_EN,
  23. input [` DEF_GPR_ADDR_WIDTH -1: 0] I_DST_GPR_WR_ADDR,
  24. input [` DEF_GPR_DATA_WIDTH -1: 0] I_DST_GPR_WR_DATA,
  25. // | 后接写回模块
  26. output reg O_DST_GPR_WR_EN,
  27. output reg [` DEF_GPR_ADDR_WIDTH -1: 0] O_DST_GPR_WR_ADDR,
  28. output reg [` DEF_GPR_DATA_WIDTH -1: 0] O_DST_GPR_WR_DATA
  29. );
  30. // |-------------------------------------- 模块内部逻辑设计 --------------------------------------
  31. // |------------------------------------------------------------------------------------------------
  32. // | 目的寄存器写操作传递/打拍
  33. always @ (posedge I_CPU_CLK)
  34. begin
  35. if(~ I_CPU_RSTN)
  36. begin
  37. O_DST_GPR_WR_EN <= 1'b0;
  38. O_DST_GPR_WR_ADDR <= 5'd0;
  39. O_DST_GPR_WR_DATA <= 32'd0;
  40. end
  41. else
  42. begin
  43. O_DST_GPR_WR_EN <= I_DST_GPR_WR_EN ;
  44. O_DST_GPR_WR_ADDR <= I_DST_GPR_WR_ADDR;
  45. O_DST_GPR_WR_DATA <= I_DST_GPR_WR_DATA;
  46. end
  47. end
  48. endmodule

指令ROM

此模块存放程序指令。


  
  1. // |------------------------------ ================================== ------------------------------
  2. // |============================== 程序计数寄存器模块 ==============================
  3. // |------------------------------ ================================== ------------------------------
  4. // |Create Date : 2022-12-08
  5. // |Finish Date : 2022-12-08
  6. // |Edited by : Xu Y. B. (CSDN USER NAME :在路上,正出发)
  7. // |Reference : 《自己动手写CPU》——第4章
  8. // |
  9. // |
  10. // |------------------------------------------------------------------------------------------------
  11. // |Change History:
  12. // |
  13. `include "MIPS_SYS_DEFINES.v"
  14. `timescale 1ns / 1ps
  15. module ROM_ISTC_MDL(
  16. // |-------------------------------------- 输入输出端口声明 --------------------------------------
  17. // |------------------------------------------------------------------------------------------------
  18. input I_CPU_CLK,
  19. input I_CPU_RSTN,
  20. input I_RD_EN,
  21. input [` DEF_ISTC_ADDR_BUS] I_RD_ADDR,
  22. output reg [` DEF_ISTC_DATA_BUS] O_ISTC
  23. );
  24. // |-------------------------------------- 模块内部信号声明 --------------------------------------
  25. // |------------------------------------------------------------------------------------------------
  26. // | ROM空间开辟
  27. reg [` DEF_ISTC_DATA_BUS] R_ROM_DATA [` DEF_ISTC_CACH_DEPTH: 0];
  28. // |-------------------------------------- 模块内部逻辑设计 --------------------------------------
  29. // |------------------------------------------------------------------------------------------------
  30. // | ROM初始化
  31. initial $readmemh( "D:/VIVADO_WORK_SPACE/CPU_MIPS32/DATA_FILE/ISTC_ROM.txt", R_ROM_DATA);
  32. // | 数据读取
  33. always @ (posedge I_CPU_CLK)
  34. begin
  35. if(~ I_CPU_RSTN)
  36. begin
  37. O_ISTC <= ` DEF_ZERO_WORD;
  38. end
  39. else
  40. begin
  41. if( I_RD_EN)
  42. begin
  43. O_ISTC <= R_ROM_DATA[ I_RD_ADDR[` DEF_ISTC_ADDR_WIDTH_ACTUAL+ 1: 2]];
  44. end
  45. else
  46. begin
  47. O_ISTC <= ` DEF_ZERO_WORD;
  48. end
  49. end
  50. end
  51. endmodule

程序代码示例:(此处借鉴书本的方法,仅为了完成仿真)

顶层文件

处理器顶层


  
  1. // |------------------------------ ================================== ------------------------------
  2. // |============================== 指令-执行模块 ==============================
  3. // |------------------------------ ================================== ------------------------------
  4. // |Create Date : 2022-12-07
  5. // |Finish Date : 2022-12-07
  6. // |Edited by : Xu Y. B. (CSDN USER NAME :在路上,正出发)
  7. // |Reference : 《自己动手写CPU》——第4章
  8. // |
  9. // |
  10. // |------------------------------------------------------------------------------------------------
  11. // |Change History:
  12. // |
  13. `include "MIPS_SYS_DEFINES.v"
  14. `timescale 1ns / 1 ps
  15. module TOP_MIPS32 (
  16. // |-------------------------------------- 输入输出端口声明 --------------------------------------
  17. // |------------------------------------------------------------------------------------------------
  18. // | 时钟、复位
  19. input I_CPU_CLK,
  20. input I_CPU_RSTN,
  21. // | 指令取
  22. input [`DEF_ISTC_DATA_BUS] I_ISTC_FROM_ROM,
  23. output [`DEF_ISTC_ADDR_BUS] O_ISTC_ADDR_2_ROM,
  24. // | 指令存储器使能
  25. output O_ISTC_ROM_CE
  26. );
  27. // |-------------------------------------- 模块内部信号声明 --------------------------------------
  28. // |------------------------------------------------------------------------------------------------
  29. // | PC_REG_MDL 输出
  30. wire [`DEF_ISTC_ADDR_BUS] W_PC;
  31. // | IF_ID_MDL 输出
  32. wire [`DEF_ISTC_ADDR_BUS] W_ID_ADDR;
  33. wire [`DEF_ISTC_DATA_BUS] W_ID_DATA;
  34. // ID_MDL 端口信号(GPR相关)
  35. wire W_GPR_RD_EN_A;
  36. wire [`DEF_GPR_ADDR_WIDTH -1: 0] W_GPR_RD_ADDR_A;
  37. wire [`DEF_GPR_DATA_WIDTH -1: 0] W_GPR_RD_DATA_A;
  38. wire W_GPR_RD_EN_B;
  39. wire [`DEF_GPR_ADDR_WIDTH -1: 0] W_GPR_RD_ADDR_B;
  40. wire [`DEF_GPR_DATA_WIDTH -1: 0] W_GPR_RD_DATA_B;
  41. // ID_MDL 端口信号(EXE 相关)
  42. wire [`DEF_ALU_OPR_BUS] W_ALU_OP_TYPE;
  43. wire [`DEF_SRC_OPR_DATA_BUS] W_SRC_OPR_DATA_A;
  44. wire [`DEF_SRC_OPR_DATA_BUS] W_SRC_OPR_DATA_B;
  45. // GPR_WR_RD_MDL 写操作端口(EXE 相关)
  46. wire W_DST_GPR_WR_EN_EXE_MDL_IN;
  47. wire [`DEF_GPR_ADDR_WIDTH -1: 0] W_DST_GPR_WR_ADDR_EXE_MDL_IN;
  48. // GPR_WR_RD_MDL 写操作端口(MEM 相关)
  49. wire W_DST_GPR_WR_EN_MEM_MDL_IN;
  50. wire [`DEF_GPR_ADDR_WIDTH -1: 0] W_DST_GPR_WR_ADDR_MEM_MDL_IN;
  51. wire [`DEF_GPR_DATA_WIDTH -1: 0] W_DST_GPR_WR_DATA_MEM_MDL_IN;
  52. // GPR_WR_RD_MDL 写操作端口(GPR 相关)
  53. wire W_DST_GPR_WR_EN_GPR_MDL_IN;
  54. wire [`DEF_GPR_ADDR_WIDTH -1: 0] W_DST_GPR_WR_ADDR_GPR_MDL_IN;
  55. wire [`DEF_GPR_DATA_WIDTH -1: 0] W_DST_GPR_WR_DATA_GPR_MDL_IN;
  56. // |-------------------------------------- 模块内部逻辑设计 --------------------------------------
  57. // |------------------------------------------------------------------------------------------------
  58. // | 输出
  59. assign O_ISTC_ADDR_2_ROM = W_PC;
  60. // |-------------------------------------- 子模块例化 --------------------------------------
  61. // |------------------------------------------------------------------------------------------------
  62. // | 程序计数器模块
  63. PC_REG_MDL INST_PC_REG_MDL
  64. (
  65. .I_CPU_CLK (I_CPU_CLK),
  66. .I_CPU_RSTN (I_CPU_RSTN),
  67. .O_PC (W_PC),
  68. .O_ISTC_ROM_CE (O_ISTC_ROM_CE)
  69. );
  70. // | 译码模块例化
  71. ID_MDL INST_ID_MDL
  72. (
  73. .I_CPU_CLK (I_CPU_CLK),
  74. .I_CPU_RSTN (I_CPU_RSTN),
  75. .I_ISTC (I_ISTC_FROM_ROM),
  76. .O_GPR_RD_EN_A (W_GPR_RD_EN_A),
  77. .O_GPR_RD_ADDR_A (W_GPR_RD_ADDR_A),
  78. .I_GPR_RD_DATA_A (W_GPR_RD_DATA_A),
  79. .O_GPR_RD_EN_B (W_GPR_RD_EN_B),
  80. .O_GPR_RD_ADDR_B (W_GPR_RD_ADDR_B),
  81. .I_GPR_RD_DATA_B (W_GPR_RD_DATA_B),
  82. .O_ALU_OP_TYPE (W_ALU_OP_TYPE),
  83. .O_SRC_OPR_DATA_A (W_SRC_OPR_DATA_A),
  84. .O_SRC_OPR_DATA_B (W_SRC_OPR_DATA_B),
  85. .O_DST_GPR_WR_EN (W_DST_GPR_WR_EN_EXE_MDL_IN),
  86. .O_DST_GPR_WR_ADDR (W_DST_GPR_WR_ADDR_EXE_MDL_IN)
  87. );
  88. // | 通用寄存器模块例化
  89. GPR_WR_RD_MDL INST_GPR_WR_RD_MDL
  90. (
  91. .I_CPU_CLK (I_CPU_CLK),
  92. .I_CPU_RSTN (I_CPU_RSTN),
  93. .I_GPR_WR_EN (W_DST_GPR_WR_EN_GPR_MDL_IN),
  94. .I_GPR_WR_ADDR (W_DST_GPR_WR_ADDR_GPR_MDL_IN),
  95. .I_GPR_WR_DATA (W_DST_GPR_WR_DATA_GPR_MDL_IN),
  96. .I_GPR_RD_EN_A (W_GPR_RD_EN_A),
  97. .I_GPR_RD_ADDR_A (W_GPR_RD_ADDR_A),
  98. .O_GPR_RD_DATA_A (W_GPR_RD_DATA_A),
  99. .I_GPR_RD_EN_B (W_GPR_RD_EN_B),
  100. .I_GPR_RD_ADDR_B (W_GPR_RD_ADDR_B),
  101. .O_GPR_RD_DATA_B (W_GPR_RD_DATA_B)
  102. );
  103. // | 执行模块例化
  104. EXE_MDL INST_EXE_MDL
  105. (
  106. .I_CPU_CLK (I_CPU_CLK),
  107. .I_CPU_RSTN (I_CPU_RSTN),
  108. .I_ALU_OP_TYPE (W_ALU_OP_TYPE),
  109. .I_SRC_OPR_DATA_A (W_SRC_OPR_DATA_A),
  110. .I_SRC_OPR_DATA_B (W_SRC_OPR_DATA_B),
  111. .I_DST_GPR_WR_EN (W_DST_GPR_WR_EN_EXE_MDL_IN),
  112. .I_DST_GPR_WR_ADDR (W_DST_GPR_WR_ADDR_EXE_MDL_IN),
  113. .O_DST_GPR_WR_EN (W_DST_GPR_WR_EN_MEM_MDL_IN),
  114. .O_DST_GPR_WR_ADDR (W_DST_GPR_WR_ADDR_MEM_MDL_IN),
  115. .O_DST_GPR_WR_DATA (W_DST_GPR_WR_DATA_MEM_MDL_IN)
  116. );
  117. // | 存储器存取模块例化
  118. MEM_ACS_MDL INST_MEM_ACS_MDL
  119. (
  120. .I_CPU_CLK (I_CPU_CLK),
  121. .I_CPU_RSTN (I_CPU_RSTN),
  122. .I_DST_GPR_WR_EN (W_DST_GPR_WR_EN_MEM_MDL_IN),
  123. .I_DST_GPR_WR_ADDR (W_DST_GPR_WR_ADDR_MEM_MDL_IN),
  124. .I_DST_GPR_WR_DATA (W_DST_GPR_WR_DATA_MEM_MDL_IN),
  125. .O_DST_GPR_WR_EN (W_DST_GPR_WR_EN_GPR_MDL_IN),
  126. .O_DST_GPR_WR_ADDR (W_DST_GPR_WR_ADDR_GPR_MDL_IN),
  127. .O_DST_GPR_WR_DATA (W_DST_GPR_WR_DATA_GPR_MDL_IN)
  128. );
  129. endmodule

SOPC顶层 


  
  1. // |------------------------------ ================================== ------------------------------
  2. // |============================== MIPS32 SOPC 系统 ==============================
  3. // |------------------------------ ================================== ------------------------------
  4. // |Create Date : 2022-12-07
  5. // |Finish Date : 2022-12-07
  6. // |Edited by : Xu Y. B. (CSDN USER NAME :在路上,正出发)
  7. // |Reference : 《自己动手写CPU》——第4章
  8. // |
  9. // |
  10. // |------------------------------------------------------------------------------------------------
  11. // |Change History:
  12. // |
  13. `include "MIPS_SYS_DEFINES.v"
  14. `timescale 1ns / 1 ps
  15. module TOP_MIPS32_SOPC (
  16. // |-------------------------------------- 输入输出端口声明 --------------------------------------
  17. // |------------------------------------------------------------------------------------------------
  18. // | 时钟、复位
  19. input I_CPU_CLK,
  20. input I_CPU_RSTN
  21. );
  22. // |-------------------------------------- 模块内部信号声明 --------------------------------------
  23. // |------------------------------------------------------------------------------------------------
  24. // | TOP_MIPS32 模块端口
  25. // | 指令取
  26. wire [`DEF_ISTC_DATA_BUS] W_ISTC_FROM_ROM;
  27. wire [`DEF_ISTC_ADDR_BUS] W_ISTC_ADDR_2_ROM;
  28. // | 指令存储器使能
  29. wire W_ISTC_ROM_CE;
  30. // |-------------------------------------- 子模块例化 --------------------------------------
  31. // |------------------------------------------------------------------------------------------------
  32. // | 处理器模块
  33. TOP_MIPS32 INST_TOP_MIPS32
  34. (
  35. .I_CPU_CLK (I_CPU_CLK),
  36. .I_CPU_RSTN (I_CPU_RSTN),
  37. .I_ISTC_FROM_ROM (W_ISTC_FROM_ROM),
  38. .O_ISTC_ADDR_2_ROM (W_ISTC_ADDR_2_ROM),
  39. .O_ISTC_ROM_CE (W_ISTC_ROM_CE)
  40. );
  41. // | 指令存储模块
  42. ROM_ISTC_MDL INST_ROM_ISTC_MDL
  43. (
  44. .I_CPU_CLK (I_CPU_CLK),
  45. .I_CPU_RSTN (I_CPU_RSTN),
  46. .I_RD_EN (W_ISTC_ROM_CE),
  47. .I_RD_ADDR (W_ISTC_ADDR_2_ROM),
  48. .O_ISTC (W_ISTC_FROM_ROM)
  49. );
  50. endmodule

功能仿真

TestBench


  
  1. // |------------------------------ ================================== ------------------------------
  2. // |============================== 顶层模块仿真平台 ==============================
  3. // |------------------------------ ================================== ------------------------------
  4. // |Create Date : 2022-12-08
  5. // |Finish Date : 2022-12-08
  6. // |Edited by : Xu Y. B. (CSDN USER NAME :在路上,正出发)
  7. // |Reference : 《自己动手写CPU》——第4章
  8. // |
  9. // |
  10. // |------------------------------------------------------------------------------------------------
  11. // |Change History:
  12. // |
  13. `timescale 1ns / 1ps
  14. `define CLK_PERIOD 20
  15. module TB_TOP_MIPS32();
  16. reg I_CPU_CLK;
  17. reg I_CPU_RSTN;
  18. // 产生时钟
  19. initial I_CPU_CLK = 0;
  20. always #(`CLK_PERIOD/2) I_CPU_CLK = ~I_CPU_CLK;
  21. // 产生复位
  22. initial
  23. begin
  24. I_CPU_RSTN <= 0;
  25. #(`CLK_PERIOD*3);
  26. @(posedge I_CPU_CLK);
  27. I_CPU_RSTN <= 1;
  28. #(`CLK_PERIOD*10);
  29. $finish;
  30. end
  31. // 顶层例化
  32. TOP_MIPS32_SOPC INST_TOP_MIPS32_SOPC
  33. (.I_CPU_CLK(I_CPU_CLK),
  34. .I_CPU_RSTN(I_CPU_RSTN)
  35. );
  36. endmodule

仿真结果

执行时间

从取到第一条指令,到第一条指令完成并写入寄存器,共耗费100纳秒=5个时钟周期。

时序细节




转载:https://blog.csdn.net/qq_43045275/article/details/128209440
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场