前言
继续来~~~~~~~~~~~~~~~~~~~~~~
图放好~~~~~~~~~~~~~~~~~~~~~~
指令解析
指令解析的过程就是Controller的编码过程,对于每一个指令,Controller需要将其拆解为具体的电路行为。
RD
继续来看下长指令,以RD指令为实例吧,为了防止忘记,我们再回顾下前两步要干什么~
1.处于S_fet1时,进行取值操作,完成后跳转至S_fet2:
- Sel_PC:Mux_1选择当前PC的输出到Bus_1总线,这个值就是我们要取得指令的地址;
- Sel_Bus_1:Mux_2选择Bus_1,也就是说把PC值加载到Bus_2上来了;
- Load_Add_R:把Bus_2总线上的数据写入到Add_R寄存器中,时序逻辑当拍拉高,下拍完成写入;
2.S_fet2状态下,将mem中的指令读出,之后进入S_dec译码:
- Sel_mem:Bus_2选择mem的输出数据,即把mem[Add_R]值加载到Bus_2总线上;
- Load_IR:将Bus_2上的值写入到IR内,实现了取值的功能;
- Inc_PC:取值完成了,PC先自加1,无论是长指令还是短指令,下一个要取的位置都在下一个Byte,除非解析出了跳转,那就一会跳一下好了;
3.S_dec状态下进行译码,此时IR内的指令已经稳定,opcode = IR.data_out[8 -1:4]为操作码,假设现在确认了操作码为RD,先复习下RD的行为~
RD | 0101 | 从长指令第二字节指定的存储单元中取出操作数,写入到目的寄存器 | dst = mem[addr] |
那么当识别到opcode为RD的话,需要进行如下解码操作:
- Sel_PC + Sel_Bus_1 + Load_Add_R:把现在已经自加1的PC值再次写入到Add_R中,准备读取下一个地址;
因此,下面一个状态就是S_rd1状态,来处理mem读出操作;
4.S_rd1状态,注意这个时候我们通过PC索引到的是一个8bit值,这个值是我们所需要的内容的地址!因此我们需要的是把这个8bit作为地址索引,读出需要的内容,如何把这8bit作为地址索引呢?
- Sel_mem:这样,mem的输出值加载到Bus_2总线上;
- Load_Add_R:把Bus_2总线的值加载到Add_R内;
- Inc_PC:处理完了后别忘记给PC自加1,PC值应该时刻指向下一个指令;
完成上述几步操作后,要读取的地址已经作用在mem接口上了,只需要在下一个状态S_rd2内将数据读出。
5.S_rd2状态,把长指令第二个字节索引地址内的内容写入dst寄存器中:
- Sel_mem:把mem的值加载到Bus_2总线;
- Load_R0/1/2/3:根据IR.data_out[2 -1:0],将Bus_2的数据写入到对应的目的寄存器中;
6.完美的完成了,这样继续跳会S_fet1继续取值就好了。
BR
1.长指令里再看一个BR跳转指令吧,前3步不多写了,从S_br1开始~
- Sel_mem:这样,mem的输出值加载到Bus_2总线上;
- Load_Add_R:把Bus_2总线的值加载到Add_R内;
S_br1与S_rd1的区别在哪里呢?就是少了Inc_PC,毕竟是要跳转,那自然就不需要PC自加1了呀;
2.S_br1之后就进入S_br2状态:
- Sel_mem:把mem的值加载到Bus_2总线;
- Load_PC:把Bus_2总线数据直接加载到PC就ok了;
好的,在需要跳转的地址直接加载到PC,那自然就完成了取值跳转。
Controller完整代码
经过上面的解析,实际上我们已经可以得到完整的Controller代码了,直接贴在这里,代码实现与书上的两段式状态机不一致,我更喜欢用三段状态机:
1. `ifndef CTRL_UNIT 2. `define CTRL_UNIT 3. 4. `define ASSIGN_ZERO begin \ 5. sel_PC = 'h0; \ 6. sel_R0 = 'h0; \ 7. sel_R1 = 'h0; \ 8. sel_R2 = 'h0; \ 9. sel_R3 = 'h0; \ 10. sel_ALU = 'h0; \ 11. sel_BUS1 = 'h0; \ 12. sel_MEM = 'h0; \ 13. load_add_R = 'h0; \ 14. load_reg_Y = 'h0; \ 15. load_reg_Z = 'h0; \ 16. load_IR = 'h0; \ 17. inc_PC = 'h0; \ 18. sel_R0 = 'h0; \ 19. sel_R1 = 'h0; \ 20. sel_R2 = 'h0; \ 21. sel_R3 = 'h0; \ 22. load_R0 = 'h0; \ 23. load_R1 = 'h0; \ 24. load_R2 = 'h0; \ 25. load_R3 = 'h0; \ 26. load_PC = 'h0; \ 27. sel_ALU = 'h0; \ 28. write = 'h0; \ 29. end 30. 31. 32. module ctrl_unit #( 33. `include "C:/Users/gaoji/Desktop/RISC_SPM/src/para_def.v" 34. )( 35. output reg load_R0, load_R1, load_R2, load_R3, 36. output reg load_PC, 37. output reg load_IR, 38. output reg load_reg_Y, 39. output reg load_reg_Z, 40. output reg load_add_R, 41. output reg inc_PC, 42. output reg [SEL1_WD -1:0] mux1_sel_to_bus1, 43. output reg [SEL2_WD -1:0] mux2_sel_to_bus2, 44. 45. output reg write, 46. 47. input [WORD_WD -1:0] instruction, 48. input zero_flag, 49. input clk, rst_n 50. ); 51. 52. reg [STATE_WD -1:0] state, next_state; 53. wire[OPCODE_WD -1:0] opcode; 54. wire[SRC_WD -1:0] src; 55. wire[DEST_WD -1:0] dest; 56. reg sel_R0, sel_R1, sel_R2, sel_R3, sel_PC; 57. reg sel_ALU, sel_BUS1, sel_MEM; 58. 59. assign opcode = instruction[(WORD_WD -1) : (WORD_WD -OPCODE_WD)]; 60. assign src = instruction[(SRC_WD +DEST_WD -1) : DEST_WD]; 61. assign dest = instruction[DEST_WD -1:0]; 62. 63. always @(*)begin 64. if(sel_R0) mux1_sel_to_bus1 = 0; 65. else if(sel_R1) mux1_sel_to_bus1 = 1; 66. else if(sel_R2) mux1_sel_to_bus1 = 2; 67. else if(sel_R3) mux1_sel_to_bus1 = 3; 68. else if(sel_PC) mux1_sel_to_bus1 = 4; 69. else mux1_sel_to_bus1 = 0; 70. end 71. 72. always @(*)begin 73. if(sel_ALU) mux2_sel_to_bus2 = 0; 74. else if(sel_BUS1) mux2_sel_to_bus2 = 1; 75. else if(sel_MEM) mux2_sel_to_bus2 = 2; 76. else mux2_sel_to_bus2 = 0; 77. end 78. 79. always @(posedge clk)begin 80. if(rst_n == 1'b0)begin 81. state <= 'h0; 82. end 83. else begin 84. state <= next_state; 85. end 86. end 87. 88. always @(*)begin 89. case(state) 90. S_IDLE: next_state = S_FET1; 91. S_FET1: next_state = S_FET2; 92. S_FET2: next_state = S_DEC; 93. S_DEC : begin 94. case(opcode) 95. NOP, NOT: next_state = S_FET1; 96. ADD, SUB, AND, NOT: next_state = S_EX1; 97. RD: next_state = S_RD1; 98. WR: next_state = S_WR1; 99. BR: next_state = S_BR1; 100. BRZ: if(zero_flag == 0) next_state = S_BR1; 101. default: next_state = S_FET1; 102. endcase 103. end 104. S_EX1 : next_state = S_FET1; 105. S_RD1 : next_state = S_RD2; 106. S_RD2 : next_state = S_FET1; 107. S_WR1 : next_state = S_WR2; 108. S_WR2 : next_state = S_FET1; 109. S_BR1 : next_state = S_BR2; 110. S_BR2 : next_state = S_FET1; 111. default:next_state = S_IDLE; 112. endcase 113. end 114. 115. always @(*)begin 116. `ASSIGN_ZERO 117. case(state) 118. S_IDLE: ; 119. S_FET1: begin 120. sel_PC = 'h1; 121. sel_BUS1 = 'h1; 122. load_add_R = 'h1; 123. end 124. S_FET2: begin 125. sel_MEM = 'h1; 126. load_IR = 'h1; 127. inc_PC = 'h1; 128. end 129. S_DEC: begin 130. case(opcode) 131. NOP: ; 132. ADD, SUB, AND: begin 133. case(src) 134. SEL_R0: sel_R0 = 'h1; 135. SEL_R1: sel_R1 = 'h1; 136. SEL_R2: sel_R2 = 'h1; 137. SEL_R3: sel_R3 = 'h1; 138. default:; 139. endcase 140. sel_BUS1 = 'h1; 141. load_reg_Y = 'h1; 142. end 143. NOT: begin 144. case(src) 145. SEL_R0: sel_R0 = 'h1; 146. SEL_R1: sel_R1 = 'h1; 147. SEL_R2: sel_R2 = 'h1; 148. SEL_R3: sel_R3 = 'h1; 149. default:; 150. endcase 151. case(dest) 152. SEL_R0: load_R0 = 'h1; 153. SEL_R1: load_R1 = 'h1; 154. SEL_R2: load_R2 = 'h1; 155. SEL_R3: load_R3 = 'h1; 156. default:; 157. endcase 158. load_reg_Z = 'h1; 159. sel_ALU = 'h1; 160. end 161. RD: begin 162. sel_PC = 'h1; 163. sel_BUS1 = 'h1; 164. load_add_R = 'h1; 165. end 166. WR: begin 167. sel_PC = 'h1; 168. sel_BUS1 = 'h1; 169. load_add_R = 'h1; 170. end 171. BR: begin 172. sel_PC = 'h1; 173. sel_BUS1 = 'h1; 174. load_add_R = 'h1; 175. end 176. default:; 177. endcase 178. end 179. S_EX1: begin 180. case(dest) 181. SEL_R0: begin sel_R0 = 'h1; load_R0 = 'h1; end 182. SEL_R1: begin sel_R1 = 'h1; load_R1 = 'h1; end 183. SEL_R2: begin sel_R2 = 'h1; load_R2 = 'h1; end 184. SEL_R3: begin sel_R3 = 'h1; load_R3 = 'h1; end 185. default:; 186. endcase 187. sel_ALU = 'h1; 188. load_reg_Z = 'h1; 189. end 190. S_RD1: begin 191. sel_MEM = 'h1; 192. load_add_R = 'h1; 193. inc_PC = 'h1; 194. end 195. S_RD2: begin 196. sel_MEM = 'h1; 197. case(dest) 198. SEL_R0: load_R0 = 'h1; 199. SEL_R1: load_R1 = 'h1; 200. SEL_R2: load_R2 = 'h1; 201. SEL_R3: load_R3 = 'h1; 202. default:; 203. endcase 204. end 205. S_WR1: begin 206. sel_MEM = 'h1; 207. load_add_R = 'h1; 208. inc_PC = 'h1; 209. end 210. S_WR2: begin 211. load_add_R = 'h1; 212. write = 'h1; 213. case(src) 214. SEL_R0: sel_R0 = 'h1; 215. SEL_R1: sel_R1 = 'h1; 216. SEL_R2: sel_R2 = 'h1; 217. SEL_R3: sel_R3 = 'h1; 218. default:; 219. endcase 220. end 221. S_BR1: begin 222. sel_MEM = 'h1; 223. load_add_R = 'h1; 224. end 225. S_BR2: begin 226. sel_MEM = 'h1; 227. load_PC = 'h1; 228. end 229. endcase 230. end 231. 232. endmodule 233. 234. `endif