verilog 设计流水线CPU

该博客围绕基于MIPS指令集的CPU实验展开,目的是掌握复杂系统设计和理解硬件原理。实验内容包括设计支持多种指令的CPU,实现5级流水线CPU并考虑数据和控制冒险。详细给出了实验代码、仿真结果,还介绍了调试时查看模块内变量值的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、实验目的

1 掌握复杂系统设计方法。

2 深刻理解计算机系统硬件原理。

二、实验内容

1)设计一个基于MIPS指令集的CPU,支持以下指令:{add, sub, addi,  lw, sw, beq, j, nop};

2)CPU需要包含寄存器组、RAM模块、ALU模块、指令译码模块;

3)该CPU能运行基本的汇编指令;(D~C+)

以下为可选内容:

4)实现多周期CPU(B-~B+);

5)实现以下高级功能之一(A-~A+):

(1)实现5级流水线CPU;

(2)实现超标量;

(3)实现4路组相联缓存;

可基于RISC V 、ARM指令集实现。

如发现代码为抄袭代码,成绩一律按不及格处理。

三、实验要求

编写相应测试程序,完成所有指令测试。

四、实验代码及结果

本实验所完成的内容为:实现5级流水线CPU。其中考虑到的冒险有:

数据冒险:

add和addi的冒险;R型指令与R型指令的冒险;add与lw的冒险;lw与sw的冒险。

控制冒险:

beq的冒险;j的冒险。

  1. 源代码

1.1 程序计数器PC

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

module PC(    

    input clk,    

    input Rst,

    input [31:0] PCin,    

    input [2:0] PCStall,

    output reg [31:0] PCout    

);    

      

    initial begin    

        PCout <= 0;   

    end  

        

    always@(posedge clk or posedge Rst) begin  

        if(Rst) begin

            PCout <= 0;

        end

        else if(PCStall) begin

        PCout <= PCout;

        end

        else   

        PCout = PCin;

         

    end  

        

endmodule    

1.2 指令寄存器Imem

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

`define DATA_WIDTH 32

module IMem(

    input [31:0] A,

    output [`DATA_WIDTH-1:0] RD

    );

    parameter IMEM_SIZE = 32;

     

    reg [31:0] RAM[31:0];

    

    initial

        $readmemb("D:/class/professtional class/ComputerStructure_experiments/experiment_6/memfile2.dat",RAM);

        //$readmemb("D:/ram_data_b.txt",RAM,0,1023) 读取二进制数据文件

        //$readmamh(D:/ram_data_b.txt",RAM,0,1023) 读取十六进制数据文件

    assign RD = RAM[A];

endmodule

1.3 控制单元Control_Unit

1.3.1 Control_unit

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

module Control_unit(

    input [5:0] Op, Funct,

    output MemToReg, MemWrite,

    output ALUSrc,

    output RegDst, RegWrite,

    output Jump,

    output [2:0] ALUControl,

    output Branch

    );

    

    wire [1:0] ALUOp;

    //Main Decoder

    MainDec2 MainDec_1(Op, MemToReg, MemWrite, Branch, ALUSrc, RegDst, RegWrite, Jump, ALUOp);

    //ALU Decoder

    ALUDec ALUDec_1(Funct, ALUOp, ALUControl);

    

    

endmodule

1.3.2 MainDec

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

module MainDec2(//主译码器

    input [5:0] Op,

    output MemToReg, MemWrite,

    output Branch ,ALUSrc,

    output RegDst, RegWrite,

    output Jump,

    output [1:0] ALUOp);

    

    reg [8:0] Controls;

    //

    

    assign {RegWrite, RegDst, ALUSrc, Branch, MemWrite,MemToReg, Jump, ALUOp} =Controls;

    

    always@(*)

        case(Op)

        6'b000000: Controls <=9'b110000010;// RTYPE or nop

        6'b100011: Controls <=9'b101001000;// LW:需要ALU计算 rs+ offset

        6'b101011: Controls <=9'b001010000; // SW:需要ALU 计算 rs + offset

        6'b000100: Controls <=9'b000100001;//BEQ

        6'b001000: Controls <=9'b101000000; //ADDI

        6'b000010: Controls <=9'b000000100;//J

        default:   Controls <=9'bxxxxxxxxx;// illegal Op

       endcase

endmodule

1.3.3 ALUDec

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

module ALUDec(//ALU泽码器

input [5:0] Funct,

input [1:0] ALUOp,

output reg [2:0] ALUControl);

    always@(*)

        case(ALUOp)

        2'b00: ALUControl<=3'b010;// add (for 1w/sw/addi)

        2'b01:ALUControl<=3'b110;// sub (for beq)

        default: case(Funct) // R-type Instructions

        6'b100000:ALUControl<=3'b010; // add

        6'b100010:ALUControl<=3'b110;// sub

        6'b100100:ALUControl<=3'b000;//and

        6'b100101:ALUControl<=3'b001;// or

        6'b101010:ALUControl<=3'b111;// slt

        default :ALUControl<=3'bxxx;//??? or nop

        endcase

        endcase

endmodule

1.4 寄存器RegFile

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

`define DATA_WIDTH 32

`define SIZE 32

module RegFile(CLK, WE3, RA1,RA2,WA3, WD3, RD1,RD2,Rst);

    parameter ADDR_SIZE = 5;

    input CLK,WE3;

    input [ADDR_SIZE-1:0] RA1, RA2, WA3;

    input Rst;

    input [`DATA_WIDTH-1:0] WD3;

    output [`DATA_WIDTH-1:0] RD1,RD2;

    reg [`DATA_WIDTH-1:0] rf[2 ** ADDR_SIZE-1:0];

    integer i;

    initial begin

    rf[1] <= 32'b0000_0000_0000_0000_0000_0000_0000_0101;

    rf[2] <= 32'b0000_0000_0000_0000_0000_0000_0000_0001; //用于测试复位功能

    end

    always @(posedge CLK or posedge Rst) begin

                   if(Rst) begin

                   for(i=0;i<`DATA_WIDTH;i=i+1) rf[i]=`SIZE'b0;

                   end

                   else if(WE3) begin

                       rf[WA3] <= WD3;

                   end

              

               end

    assign RD1 = (RA1 !=0)? rf[RA1]:0;

    assign RD2 = (RA2 !=0)? rf[RA2]:0;

endmodule

1.5 符号扩展 SigExt16_32

1

2

3

4

5

6

7

8

module SigExt16_32(In,Out);

input [15:0] In;

output [31:0] Out;

assign Out={{16{In[15]}},In[15:0]};

endmodule

1.6 算术逻辑单元 ALU

1.6.1 ALU

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

module ALU(F, ZF, A, B, OP);

    parameter SIZE = 32;

    output reg [SIZE-1:0] F;

    output reg ZF;

    input [SIZE-1:0] A, B;

    input [2:0] OP;

    wire CF;

    parameter ALU_AND = 3'b000;

    parameter ALU_ADD = 3'b010;

    parameter ALU_SUB = 3'b110;

    parameter ALU_SLT = 3'b111;

    

    parameter ALU_SLL = 3'b011;

    parameter ALU_OR = 3'b001;

    parameter ALU_XOR = 3'b100;

    parameter ALU_NOR = 3'b101;

    wire [7:0] EN;

    wire [SIZE-1:0] Fw, Fa;

    

    //数据流描述

    assign Fa = A & B;

    

    //行为描述

    always@(*) begin

    case(OP)

        ALU_AND: begin F <= Fa; end

        ALU_OR : begin F <= A|B; end

        ALU_XOR : begin F <= A^B; end

        ALU_NOR : begin F <= ~(A|B); end

        default: F = Fw;

    endcase

    

    //0标志位

    ZF = (F == 0);

    end

    

    //结构化描述

    //3-8编码,生成片选EN信号

    decoder_38 decoder(OP[2:0], EN);

    

    //算术加法

    ADD add1(Fw, CF, A,B,EN[2]);

    //算术减法

    SUB sub1(Fw, CF, A,B,EN[6]);

    //比较,若A<B, 则输出1,否则输出0.

    SLT slt1(Fw, A, B, EN[5]);

    

    //逻辑左移

    SLL sll1(Fw, A, B, EN[7]);

    

endmodule

1.6.2 decoder_38

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

module decoder_38(

    input wire [3:1] Y,

    output reg [7:0] I

);

always@(Y) begin

casex(Y)

    3'b000: I = 8'b0000_0001;

    3'b001: I = 8'b0000_0010;

    3'b010: I = 8'b0000_0100;

    3'b011: I = 8'b0000_1000;

    3'b100: I = 8'b0001_0000;

    3'b101: I = 8'b0010_0000;

    3'b110: I = 8'b0100_0000;

    3'b111: I = 8'b1000_0000;

    default: I = 8'b0000_0001;

endcase

end

endmodule

1.6.3 ADD
1.ADD top

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

module ADD(F, CF, A, B, EN);

parameter N = 32;

output  reg [N-1:0] F;

output  reg CF;

input [N-1:0] A,B;

input EN;

wire [N-1:0] F_temp;

wire CF_temp;

reg Cl=0;

adder_32bit t1(F_temp, CF_temp, A, B, Cl);

always@(EN,F_temp,CF_temp) begin

    if(EN == 0) begin

    F <= 32'bz;

    CF <= 1'bz;

    end

    else  begin

    F <= F_temp;

    CF <= CF_temp;

    end

end

endmodule

1.2 adder_32bit

1

2

3

4

5

6

7

8

9

module adder_32bit(S, Co, A, B, Cl);

    input [31:0] A, B;

    input Cl;

    output [31:0] S;

    output Co;

    wire C;

    adder_16bit  t0(S[15:0], C, A[15:0], B[15:0], Cl),

                 t1(S[31:16], Co, A[31:16], B[31:16], C);

endmodule

1.3 adder_16bit

1

2

3

4

5

6

7

8

9

module adder_16bit(S, Co, A, B, Cl);

    input [15:0] A, B;

    input Cl;

    output [15:0] S;

    output Co;

    wire C;

    adder_8bit  t0(S[7:0], C, A[7:0], B[7:0], Cl),

                t1(S[15:8], Co, A[15:8], B[15:8], C);

endmodule

1.4 adder_8bit

1

2

3

4

5

6

7

8

9

10

module adder_8bit(S, Co, A, B, Cl);

    input [7:0] A, B;

    input Cl;

    output [7:0] S;

    output Co;

    wire C;

    

    adder_4bit  t0(S[3:0], C, A[3:0], B[3:0], Cl),

                t1(S[7:4], Co, A[7:4], B[7:4], C);

endmodule

1.5 adder_4bit

1

2

3

4

5

6

7

8

9

10

module adder_4bit(S, Ch, A, B, Cl);

    input [3:0] A, B;

    input Cl;

    output [3:0] S;

    output Ch;

    wire C;

    

    adder_2bit  t0(S[1:0], C, A[1:0], B[1:0], Cl),

                t1(S[3:2], Ch, A[3:2], B[3:2], C);

endmodule

1.6 adder_2bit

1

2

3

4

5

6

7

8

9

10

module adder_2bit(S, Co, A, B, Ci);

    input [1:0] A, B;

    input Ci;

    output [1:0] S;

    output Co;

    wire C;

    full_adder  t0(S[0], C, A[0], B[0], Ci),

                t1(S[1], Co, A[1], B[1], C);

                

endmodule

1.7 full_adder

1

2

3

4

5

6

7

8

module full_adder(S, Co, A, B, Ci);

    output S, Co;

    input A, B, Ci;

    wire S1, D1, D2;

    half_adder HA1(S1, D1, A, B); //A + B ,进位为 D1, S1 为不计进位的加法结果

    half_adder HA2(S, D2, S1, Ci); //S1 + Ci ,进位为D2,

    or G1(Co, D2, D1);  // D2 和 D1 不会同时为 1,只要两个半加有一个进位,全加器就进位

endmodule

1.8 half_adder

1

2

3

4

5

6

7

module half_adder(

    output S,C,

    input A,B

    );

    xor(S,A,B);

    and(C,A,B);

endmodule

1.6.4 SUB

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

module SUB(F, CF, A, B, EN);

parameter N = 32;

output  reg [N-1:0] F;

output  reg CF;

input [N-1:0] A,B;

input EN;

always@(EN,A,B) begin

    if(EN == 0) begin

    F <= 32'bz;

    CF <=1'bz;

    end

    else begin

    if(A<B) CF <= 1;

    else CF <= 0;

    F <= A - B;

    end

end

endmodule

1.6.5 SLT

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

module SLT(F, A, B, EN);

 parameter N = 32;

 output reg [N-1:0] F;

 input [N-1:0] A,B;

 input EN;

 always@(A,B,EN) begin

 if(EN == 1) begin

 if(A < B) F <= 1;

 else F <= 0;

 end

 else F <= 32'bz;

 end

endmodule

1.6.6 SLL

1

2

3

4

5

6

7

8

9

10

module SLL(F,A,B,EN);

parameter N = 32;

output reg[N-1:0] F;

input [N-1:0] A,B;

input EN;

always@(A,B,EN) begin

if(EN == 1) F <= B << A;

else F <= 32'bz;

end

endmodule

1.7 内存 DataMemory

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

module DataMemory(

    input CLK,

    input [31:0] address,

    input [31:0] write_data,

    input mem_write,

    output [31:0] read_data

    );

    reg [31:0] memory [0:1023];

    initial begin

    memory[0] <= 32'b0000_0000_0000_0000_0000_0000_0000_0001;

    memory[1] <= 32'b0000_0000_0000_0000_0000_0000_0000_0011;

    end

    always@(posedge CLK) case(mem_write)

    1:memory[address]<=write_data;

    endcase

    assign read_data = memory[address];

endmodule

1.8 多路选择器

1.8.1 32位2选1多路选择器

1

2

3

4

5

6

7

8

9

10

module mux32_2 (

    input wire [31:0] a,

    input wire [31:0] b,

    input wire select,

    output wire [31:0] out

);

    assign out = (select) ? b : a;

endmodule

1.8.2 32位4选1多路选择器

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

module mux32_4(A0, A1, A2, A3, S, out);

 input [31:0] A0, A1, A2, A3;

 input [1:0] S;

 output [31:0] out;

 reg [31:0] select_value;

 always @(*) begin

 case(S)

 2'b00: select_value = A0;

 2'b01: select_value = A1;

 2'b10: select_value = A2;

 2'b11: select_value = A3;

 endcase

 end

 assign out = select_value;

endmodule

1.8 顶层模块(包含消除冒险部分)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288’

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

module CPU(

    input clk,

    input rst, //复位

    output  [31:0] result //输出结果

    );

    //输入指令

    wire [31:0] instr;   

   

    // ALU结果

    wire [31:0] alu_result;

    

    // 程序计数器

    reg [31:0] PCin;

    reg [31:0] PCin1,PCin2;

    reg [31:0] PCin3;

    wire [31:0] PCout;  //最终PC

    reg [2:0]   PCStall;

    //控制冒险用

    reg [4:0] rtI,rsI;

    reg [5:0] opcodeI;

    //控制单元相关变量

    wire  Branch;

    wire Zero;

    reg [5:0] opcode,Funct;

    reg [4:0] rs, rt, rd;

    wire MemtoReg, MemWrite;

    reg PCSrc;

    wire ALUSrc;

    wire RegDst, RegWrite;

    wire Jump;

    wire [2:0] ALUControl;

    wire [4:0] WriteReg;

    

    //寄存器相关变量

    wire [31:0] SrcA;

    wire [31:0] SrcB;

    wire [31:0] ReadData;

    wire [31:0] RD1;

    wire [31:0] RD2;

    wire [31:0] WD3;

    //符号扩展相关变量

    reg [15:0] imm;

    wire [31:0] SignImm;

    

    //流水线寄存器

     //IF_ID

      reg [31:0] NPCD;

      reg [31:0] IR;

      reg [2:0] IF_IDStall;

      //ID_EX

      reg RegWriteE,MemtoRegE,MemWriteE,BranchE;

      reg [2:0] ALUControlE;

      reg ALUSrcE,RegDstE;

      reg [4:0] rsE,rtE,rdE;

      reg [31:0] SignImmE,NPCE,WriteDataE;

      wire [4:0] WriteRegE;

      reg [31:0] RD1E,RD2E;

      wire [31:0] temp;

      reg [5:0]opcodeE;

      //EX_MA

      reg RegWriteM,MemtoRegM,MemWriteM,BranchM,ZeroM;

      reg [31:0] alu_resultM,WriteDataM,NPCM;

      reg [4:0] WriteRegM;

      reg PCSrcM;

      //MA_WB

      reg RegWriteW,MemtoRegW;

      reg [4:0] WriteRegW;

      reg [31:0] ReadDataW,alu_resultW;

    //前推解决数据冒险(当前指令位R型,后续指令R或I型,且当前指令的目的寄存器是后续指令的源寄存器

      reg [1:0] forward_rs,forward_rt;

      reg [1:0] forward_rs_2,forward_rt_2;

    

    

    //IF阶段

    PC pc(

    .clk(clk),

    .Rst(rst),

    .PCStall(PCStall),

    .PCin(PCin),

    .PCout(PCout)

    );

    

  

    always @(*) begin

    PCin1 = PCout + 1;  //自增

   

    if(PCSrcM == 1) PCin3 <= NPCM;

    else PCin3 <= PCin1;

    if(Jump) PCin <= SignImm;

    else PCin <= PCin3;

    end

    //立即数(j指令)或者 自增/beq增

    IMem imem(

    .A(PCout),

    .RD(instr)

    );

   

   //IF_ID

   always @(posedge clk or posedge rst) begin

       if(rst) begin

       NPCD <= 32'bx;

       IR <= 32'bx;

       IF_IDStall <= 0;

       PCStall <= 0;

       end

       //插入空指令

       else if(IF_IDStall) begin

       IR <= 32'bx;

       IF_IDStall <= IF_IDStall - 1;

       PCStall <= PCStall - 1;

       end

       else begin

       NPCD <= PCout+1;

       IR <= instr;

       end

   end

    always @(*) begin

    opcodeI <= instr[31:26];

    rtI <= instr[20:16];

    rsI <= instr[25:21];

    end

    //ID阶段

   

     

    always @* begin

        // 从指令中提取字段

        opcode = IR[31:26];

        rs = IR[25:21];

        rt = IR[20:16];

        rd = IR[15:11];

        Funct = IR[5:0];

        imm = IR[15:0];

     

    end

    

    //控制单元

    Control_unit cu(

    .Op(opcode),

    .Funct(Funct),

    .MemToReg(MemtoReg),

    .MemWrite(MemWrite),

    .ALUSrc(ALUSrc),

    .RegDst(RegDst),

    .RegWrite(RegWrite),

    .Jump(Jump),

    .ALUControl(ALUControl),

    .Branch(Branch)

    );

  

    //寄存器

    RegFile rf(

    .Rst(rst),

    .CLK(clk),

    .WE3(RegWriteW),

    .RA1(rs),

    .RA2(rt),

    .WA3(WriteRegW),

    .WD3(result),

    .RD1(RD1),

    .RD2(RD2)

    );

    

  

    //符号扩展

    SigExt16_32 sigext(

    .In(imm),

    .Out(SignImm)

    );

    //ID_EX  

    always @(posedge clk or posedge rst) begin

        if(rst) begin

         RegWriteE <=0;

         MemtoRegE <=0;

         MemWriteE <=0;

         BranchE <=0;

         ALUControlE  <=0;

         ALUSrcE <=0;

         RegDstE <=0;

         rsE <=0;

         rtE <=0;

         rdE <=0;

         SignImmE <=0;

         NPCE <=0;

         RD1E <=0; RD2E <=0;

         opcodeE <= 0;

        end

        else begin

         RegWriteE <= RegWrite;

         MemtoRegE <= MemtoReg;

         MemWriteE <= MemWrite;

         BranchE <= Branch;

         ALUControlE  <= ALUControl;

         ALUSrcE <= ALUSrc;

         RegDstE <= RegDst;

         rsE <= rs;

         rtE <= rt;

         rdE <= rd;

         SignImmE <= SignImm;

         NPCE <= NPCD;

         RD1E <= RD1; RD2E<= RD2;

         opcodeE <= opcode;

         end

    end

    

    //EX阶段

  

     //前推解决数据冒险

     always@(*) begin

     //当前指令为R型指令,后续指令为R型或I型,前一个的rd是后续指令的rs/rt

     if(opcodeE == 6'b000000 )begin

         if(rdE == rs) begin

             forward_rs <= 2'b01;

         end

         else forward_rs <= 2'b00;

         if(rdE == rt) begin

             forward_rt <= 2'b01;

         end

         else begin

             forward_rt <= 2'b00;

         end

     end

     //当前指令为addi指令,后续指令为R型或addi,当前的目的寄存器rt是后一个的rs

     else if(opcodeE == 6'b001000) begin

          if(rtE == rs) begin

             forward_rs <= 2'b01;

          end

          else begin

            forward_rs <= 2'b00;

          end

          if(rtE == rt) begin

            forward_rt <= 2'b01;

          end

          else begin

            forward_rt <= 2'b00;

          end

     end

     

     //当前指令为sw指令,后续指令为lw指令:

     else if(opcodeE == 6'b101011) begin

     if(opcode == 6'b100011) begin

     //sw的rs + offset 等于了 lw 的 rs + offset   

     if(alu_result == alu_resultM) begin

     

     end

     end

     //

     end

     

     //当前指令为lw指令,后续指令为R型指令,且lw的rt 等于了 R型指令的rs/rt

     else if(opcodeE == 6'b100011 && opcode == 6'b000000) begin

        if( rtE == rs ) begin

        forward_rs <= 2'b10;

        forward_rt <= 2'b00;

        end

        else if ( rtE == rt) begin

        forward_rs <= 2'b00;

        forward_rt <= 2'b10;

        end

        else begin

        forward_rs <= 2'b00;

        forward_rt <= 2'b00;

        end

     end

     else begin

        forward_rs <= 2'b00;

        forward_rt <= 2'b00;

     end

      //插入1个空指令解决诸如指令1addi的rt 等于 指令3add的 rs/rt(如果从指令1取指算作第一个周期,那么指令1完成在第六个周期,但是add在第二个周期就从寄存器取值了

    /* if(opcodeE ==  6'b001000 & opcodeI == 6'b000000)begin

         if( rtE == rtI || rtE == rsI) begin

         IF_IDStall <= 1;

         PCStall <= 1;

         end

     end

     */

     end

     //forward信号需要延迟一个clk周期赋值

     always @(posedge clk) begin

     forward_rs_2 <= forward_rs;

     forward_rt_2 <= forward_rt;

     end

     

     //分支预测解决控制冒险

     //j 指令 跳转地址在 译码阶段就可以得出,流水线只需停顿一个周期。

     always @(*) begin

     if(opcodeI == 6'b000010) begin

     IF_IDStall <= 1;

     PCStall <= 1;

     end

     // beq 指令 跳转地址 在MA阶段才能得出(后续进入了3条指令,流水线需要把IF_ID,ID_EX的寄存器清清零(只需要控制住不往内存或寄存器里写即可)

     if(PCSrcM == 1) begin

     RegWriteE = 0; MemWriteE = 0;

     RegWriteM = 0; MemWriteM = 0;

     end

     end

     //SrcBE RD2为rt内值,SignImm为立即数

     mux32_4 mux_SrcA(

     .A0(RD1E),

     .A1(alu_resultM),

     .A2(ReadData),

     .A3(),

     .S(forward_rs_2),

     .out(SrcA)

     );

      mux32_4 mux_SrcB_WriteData(

      .A0(RD2E),

      .A1(alu_resultM),

      .A2(ReadData),

      .A3(),

      .S(forward_rt_2),

      .out(temp)

      );

      mux32_2 mux32_21(

      .a(temp),

      .b(SignImmE),

      .select(ALUSrcE),

      .out(SrcB)

      );

      

    ALU alu(

    .F(alu_result),

    .ZF(Zero),

    .A(SrcA),

    .B(SrcB),

    .OP(ALUControlE)

    );

    

    //WriteReg选择写入的寄存器 RegDst=0 选rt,1选rd

        mux5_2 mux5_21(

        .a(rtE),

        .b(rdE),

        .select(RegDstE),

        .out(WriteRegE)

        );  

        

    //EX_MA

    always @(posedge clk or posedge rst) begin

        if(rst) begin

         RegWriteM <= 0;

         MemtoRegM <= 0;

         MemWriteM <= 0;

         BranchM <= 0;

         ZeroM <= 0;

         alu_resultM <= 0;

         WriteDataM <= 0;

         WriteRegM <= 0;

         NPCM <= 0;

        end

        else begin

          RegWriteM <= RegWriteE;

          MemtoRegM <= MemtoRegE;

          MemWriteM <= MemWriteE;

          BranchM <= BranchE;

          ZeroM <= Zero;

          alu_resultM <= alu_result;

          WriteDataM <= WriteDataE; //

          WriteRegM <= WriteRegE; //

          NPCM <= NPCE + SignImmE;

        end

    end

    always @(*) begin

    PCSrcM = BranchM & ZeroM;

    WriteDataE = temp;

    end

    //MA阶段

    DataMemory dm(

    .CLK(clk),

    .address(alu_resultM),

    .write_data(WriteDataM), //RD2为rt寄存器内容

    .mem_write(MemWriteM),

    .read_data(ReadData)

    );    

    

    //MA_WB

       always @(posedge clk or posedge rst) begin

            if(rst) begin

             RegWriteW <= 0;

             MemtoRegW <= 0;

             WriteRegW <= 0;

             alu_resultW <= 0;

             ReadDataW <= 0;

            end

            else begin

              RegWriteW <= RegWriteM;

              MemtoRegW <= MemtoRegM;

              WriteRegW <= WriteRegM;

              alu_resultW <= alu_resultM;

              ReadDataW <= ReadData;

            end

        end

    //WB阶段

    //选择写入寄存器的数据,ALU运算结果或者内存读入的数据(lw)

    mux32_2 mux32_22(

    .a(alu_resultW),

    .b(ReadDataW),

    .select(MemtoRegW),

    .out(result)

    );  

    

endmodule

2.仿真代码

1

2

3

4

5

6

7

8

9

10

11

12

module cpu_sim;

    reg clk;

    reg rst;

  

    initial begin

    clk = 1;rst = 0;

    #5 rst = 1;

    #5 rst = 0;

    end

    always #20 clk=~clk;

    CPU t1(.clk(clk),.rst(rst));

endmodule

测试文档:

指令

opcode  rs      rt     rd    shamt      Funct

31:26 25:21 20:16 15:11 10:6 5:0

// 001000 00011 00001 00000 00000 010000 //0.addi rs=3(0) + imm=16存放到rt = 1

 // 001000 00011 00010 00000 00000 001000 //1.addi rs=3(0) + imm=8存放到rt = 2

// 000000 00010 00010 00011 00000 100000 //2.add rs=2(8) + rt=2(8),存放到rd=3(16) //数据冒险1 与 指令 1

// 000000 00011 00011 00100 00000 100000 //3.add rs=3(16) + rt=3(16),存放到rd=4 //数据冒险2,rs=上一个rd

 // 000000 00001 00010 00101 00000 100010 //4.sub rs=1(16) - rt=2(8) ,存放到 rd = 5

 // 100011 00000 00110 00000 00000 000001 //5.lw rs=0, rt=6, offset=1 将地址为 rs + offset =1(3)的内存中的值加载到 rt=6 寄存器中。

// 000000 00110 00010 00111 00000 100000 //6.add rs=6(3) + rt=2(8)=11,存放到rd=7 //数据冒险3,与lw

 // 101011 00000 00001 00000 00000 000100 //7.sw rs=0 rt=1, offset=4 将 rt=1 寄存器中的值(8)存储到地址为 rs + offset=4 的内存中。

 // 100011 00000 01000 00000 00000 000100 //8.lw rs=0, rt=8, offset=4 将地址为 rs + offset =4(16)的内存中的值加载到 rt=8 寄存器中。  //与上一个指令产生数据冒险4

 // 000100 00011 00010 00000 00000 000100 //9.beq 相等转移 如果 rs 和 rt 寄存器中的值相等,则跳转到当前指令地址加上 offset 的地址。(这里为不相等,不跳转)

 // 000000 00000 00000 00000 00000 000000 //10.nop 空指令

 // 000100 00001 00001 00000 00000 000100 //11.beq 相等转移 如果 rs 和 rt 寄存器中的值相等,则跳转到当前指令地址加上 offset=4 的地址。

 // 000000 00000 00000 00000 00000 000000 //12.nop 空指令

 // 000000 00000 00000 00000 00000 000000 //13.nop 空指令

 // 000000 00000 00000 00000 00000 000000 //14.nop 空指令

 // 000000 00000 00000 00000 00000 000000 //15.nop 空指令

 // 000010 00000 00000 00000 00000 000000 //16.j 无条件跳转到目标地址(绝对地址=0)。

2.结果

2.1 复位

5ns时触发复位信号上升沿,rf内所有数据置为0.

2.2 0.addi rs=3(0) + imm=16存放到rt = 1

1.取指(0-40ns)

从指令寄存器中取出指令,并使用加法器修正PC值。

// 001000 00011 00001 00000 00000 010000 //0.addi rs=3(0) + imm=16存放到rt = 1

并暂存指令和PC

2.译码(40-80ns)

根据IR的指令,经过控制单元获得相应的控制信号,暂存入级间寄存器中,并从寄存器堆中读出数据RD1=0

3.执行(80-120ns)

ALU根据SrcA(0),SrcB(16)和 ALUOP 进行运算,并把结果存入寄存器中。

4.访存(120-160ns)

此指令无访存操作。

5.写回(160-200ns)

将运算结果result=16写回寄存器中。

200ns时写回完成,rf[1]=16

2.3 addi rs=3(0) + imm=8存放到rt = 2

1.取指(40-80ns)

从指令寄存器中取出指令,并使用加法器修正PC值。

// 001000 00011 00010 00000 00000 001000 //1.addi rs=3(0) + imm=8存放到rt = 2

并暂存指令和PC

2.译码(80-120ns)

根据IR的指令,经过控制单元获得相应的控制信号,暂存入级间寄存器中,并从寄存器堆中读出数据RD1=0

3.执行(120-160ns)

ALU根据SrcA(0),SrcB8) ALUOP 进行运算,并把结果存入寄存器中。

4.访存(160-200ns)

此指令无访存操作。

5.写回(200-240ns)

将运算结果result=8写回寄存器中。

240ns时写回完成,rf[2]=8.

.

2.4 add rs=2(8) + rt=2(8),存放到rd=3(16) //数据冒险1 与 指令 2.3

1.取指(80-120ns)

从指令寄存器中取出指令,并使用加法器修正PC值。

// 000000 00010 00010 00011 00000 100000 //2.add rs=2(8) + rt=2(8),存放到rd=3(16) //数据冒险1 与 指令 1

并暂存指令和PC

2.译码(120-160ns)

根据IR的指令获得相应的控制信号,暂存入寄存器中。

此时根据上一个指令的操作码和rd,和本指令的操作码、rs、rt,检测到了rs和rt的数据冒险,于是将前推信号forward_rs和forward_rt置为1.

3.执行(160-200ns)

根据前推信号forward_rs_2和forward_rt_2,SrcA,SrcB等于上一个指令执行阶段的结果8.

ALU根据SrcA8),SrcB8)和 ALUOP 进行运算,并把结果存入寄存器中。

4.访存(200-240ns)

此指令无访存操作。

5.写回(240-280ns)

将运算结果result=16写回寄存器中。

280ns时写回完成,rf[3]=16.

2.5 add rs=3(16) + rt=3(16),存放到rd=4 //数据冒险2,rs=上一个rd

1.取指(120-160ns)

从指令寄存器中取出指令,并使用加法器修正PC值。

// 000000 00011 00011 00100 00000 100000 //3.add rs=3(16) + rt=3(16),存放到rd=4 //数据冒险2,rs=上一个rd

并暂存指令和PC

2.译码(160-200ns)

根据IR的指令获得相应的控制信号,暂存入寄存器中。

此时根据上一个指令的操作码和rd,和本指令的操作码、rs、rt,检测到了rs、rt的数据冒险,于是将前推信号forward_rs 、forward_rt置为1.

3.执行(200-240ns)

根据前推信号forward_rs_2和forward_rt_2,SrcA,SrcB等于上一个指令执行阶段的结果16.

ALU根据SrcA16),SrcB16)和 ALUOP 进行运算,并把结果存入寄存器中。

4.访存(240-280ns)

此指令无访存操作。

5.写回(280-320ns)

将运算结果result=32写回寄存器中。

320ns时写回完成,rf[3]=32.

2.6 sub rs=1(16) - rt=1(16) ,存放到 rd = 5

1.取指(160-200ns)

从指令寄存器中取出指令,并使用加法器修正PC值。

// 000000 00001 00001 00101 00000 100010 //4.sub rs=1(16) - rt=1(16) ,存放到 rd = 5

并暂存指令和PC

2.译码(200-240ns)

根据IR的指令,经过控制单元获得相应的控制信号,暂存入级间寄存器中,并从寄存器堆中读出数据RD1=16,RD2=16

3.执行(240-280ns)

ALU根据SrcA16),SrcB(16)和 ALUOP 进行运算,并把结果存入寄存器中。

4.访存(280-320ns)

此指令无访存操作。

5.写回(320-360ns)

将运算结果result=0写回寄存器中。

360ns时写回完成,rf[5] = 0.

2.7 lw rs=0, rt=6, offset=1 将地址为 rs + offset =1(3)的内存中的值(16加载到 rt=6 寄存器中。

1.取指(200-240ns)

从指令寄存器中取出指令,并使用加法器修正PC值。

// 100011 00000 00110 00000 00000 000001 //5.lw rs=0, rt=6, offset=1 将地址为 rs + offset =1(3)的内存中的值加载到 rt=6 寄存器中。

并暂存指令和PC

2.译码(240-280ns)

根据IR的指令,经过控制单元获得相应的控制信号,暂存入级间寄存器中。

3.执行(280-320ns)

ALU根据SrcA0),SrcB1)和 ALUOP 进行运算,并把结果存入寄存器中,传递给DataMemory模块的address,作读取内存的地址(1)。

4.访存(320-360ns)

根据地址address,读出内存中的数据,存入ReadData(3)中。

5.写回(360-400ns)

将ReadData=3写回寄存器中。

400ns时写入完成,rf[6]=3.

2.8 add rs=6(3) + rt=2(8)=11,存放到rd=7 //数据冒险3,与lw

1.取指(240-280ns)

从指令寄存器中取出指令,并使用加法器修正PC值。

// 000000 00110 00010 00111 00000 100000 //6.add rs=6(3) + rt=2(8)=11,存放到rd=7 //数据冒险3,与lw

并暂存指令和PC

2.译码(280-320ns)

根据IR的指令获得相应的控制信号,暂存入寄存器中。

此时根据上一个指令的操作码和rt,和本指令的操作码、rs,检测到了rs的数据冒险,于是将前推信号forward_rs置为2.

并从寄存器堆中读出数据RD2=8

3.执行(320-360ns)

根据前推信号forward_rs_2,SrcA等于上一个指令执行阶段的ReadData(3).

ALU根据SrcA3),SrcB8)和 ALUOP 进行运算,并把结果存入寄存器中。

4.访存(360-400ns)

此指令无访存操作。

5.写回(400-440ns)

将运算结果result=11写回寄存器中。

440ns时写回完成,rf[7] = 11.

2.9 sw rs=0 rt=1, offset=4 将 rt=1 寄存器中的值(16)存储到地址为 rs + offset=4 的内存中。

1.取指(280-320ns)

从指令寄存器中取出指令,并使用加法器修正PC值。

// 101011 00000 00001 00000 00000 000100 //7.sw rs=0 rt=1, offset=4 将 rt=1 寄存器中的值(16)存储到地址为 rs + offset=4 的内存中。

并暂存指令和PC

2.译码(320-360ns)

根据IR的指令,经过控制单元获得相应的控制信号,暂存入级间寄存器中,并从寄存器堆中读出数据RD2=16作写入内存的值。

3.执行(360-400ns)

ALU根据SrcA0),SrcB1)和 ALUOP 进行运算,并把结果存入寄存器中,传递给DataMemory模块的address,作写入内存的地址(1)。

4.访存(400-440ns)

根据地址address和控制信号MemWriteM,将值16写入内存中。

440ns时写入完成,memory[4]=16.

5.写回(440-480ns)

此指令无写回操作。

2.10 lw rs=0, rt=8, offset=4 将地址为 rs + offset =4(16)的内存中的值加载到 rt=8 寄存器中。  //与上一个指令产生数据冒险4

1.取指(320-360ns)

从指令寄存器中取出指令,并使用加法器修正PC值。

// 100011 00000 01000 00000 00000 000100 //8.lw rs=0, rt=8, offset=4 将地址为 rs + offset =4(16)的内存中的值加载到 rt=8 寄存器中。  //与上一个指令产生数据冒险4

并暂存指令和PC

2.译码(360-400ns)

根据IR的指令,经过控制单元获得相应的控制信号,暂存入级间寄存器中。

3.执行(440-440ns)

ALU根据SrcA0),SrcB4)和 ALUOP 进行运算,并把结果存入寄存器中,传递给DataMemory模块的address,作读取内存的地址(4)。

4.访存(440-480ns)

根据地址address,读出内存中的数据,存入ReadData(16)中。

5.写回(480-520ns)

将ReadData=16写回寄存器中。

520ns时写入完成,rf[8]=16.

2.11 beq 相等转移 如果 rs=3 和 rt =2寄存器中的值相等,则跳转到当前指令地址加上 offset 的地址。(这里为不相等,不跳转)

1.取指(360-400ns)

从指令寄存器中取出指令,并使用加法器修正PC值。

// 000100 00011 00010 00000 00000 000100 //9.beq 相等转移 如果 rs 和 rt 寄存器中的值相等,则跳转到当前指令地址加上 offset 的地址。(这里为不相等,不跳转)

并暂存指令和PC

2.译码(400-440ns)

根据IR的指令获得相应的控制信号,暂存入寄存器中。

并从寄存器堆中读出数据RD1=16,RD2=8

3.执行(440-480ns)

ALU根据SrcA16),SrcB8)和 ALUOP 进行(SUB)运算,并把结果存入寄存器中。

结果不为0,Zero信号=0PCSrc=0,不跳转。

4.访存(480-520ns)

此指令无访存操作。

5.写回(520-560ns)

此指令无写回操作。

2.12 nop 空指令

1.取指(400-440ns)

从指令寄存器中取出指令,并使用加法器修正PC值。

// 000000 00000 00000 00000 00000 000000 //10.nop 空指令

并暂存指令和PC

2.译码(440-480ns)

根据IR的指令获得相应的控制信号,暂存入寄存器中。

3.执行(480-520ns)

此指令该阶段无操作。

4.访存(520-560ns)

此指令无访存操作。

5.写回(560-600ns)

此指令无写回操作。

2.13 beq 相等转移 如果 rs 和 rt 寄存器中的值相等,则跳转到当前指令地址加上 offset=4 的地址。

1.取指(400-440ns)

从指令寄存器中取出指令,并使用加法器修正PC值。

// 000100 00001 00001 00000 00000 000100 //11.beq 相等转移 如果 rs 和 rt 寄存器中的值相等,则跳转到当前指令地址加上 offset=4 的地址。

并暂存指令和PC

2.译码(440-480ns)

根据IR的指令获得相应的控制信号,暂存入寄存器中。

并从寄存器堆中读出数据RD1=16,RD2=16

3.执行(480-520ns)

ALU根据SrcA16),SrcB16)和 ALUOP 进行(SUB)运算,并把结果存入寄存器中。

结果不为0,Zero信号=1PCSrc=Zero & Branch = 1,需要跳转。此时将与寄存器,内存写入相关的控制变量全部置0:RegWriteE = 0; MemWriteE = 0;  RegWriteM = 0; MemWriteM = 0,避免beq后续的流水向寄存器和内存写入值,然后下一个PC根据PCSrc=1,为跳转地址NPCM(16)。

4.访存(520-560ns)

此指令无访存操作。

5.写回(560-600ns)

此指令无写回操作。

2.14 j 无条件跳转到目标地址(绝对地址=0)

1.取指(600-640ns)

从指令寄存器中取出指令,并使用加法器修正PC值。

// 000010 00000 00000 00000 00000 000000 //16.j 无条件跳转到目标地址(绝对地址=0)。

并暂存指令和PC

跳转地址在 译码阶段就可以得出,流水线只需停顿一个周期。所以将流水线停滞一个周期(640-680),避免后续指令进入流水线。

2.译码(640-680ns)

根据IR的指令获得相应的控制信号Jump=1和立即数SignImm=0,更新此时的PCin=0.

在680时便从地址为0开始取指令。

五、调试和心得体会

1.在Run Simulation时,如果想要查看所调用模块内变量的值,可以先在Simulation Settings 里,找到 Simulation,勾选xsim_simulate,log.all_signals*,就可以在仿真的时候,拖动变量进入图标即可查看其值。

如,想查看ALUSrc,就将其拖动值右侧变量列中,便可查看

五段流水线CPU verilog是指一种基于Verilog语言的五段流水线处理器设计。五段流水线是指将指令执行过程拆分为五个步骤,分别是指令获取、指令译码、执行操作、访问存储和写回结果。每个步骤之间通过流水线寄存器相连,实现指令的并行执行,提高CPU的效率。下面就来详细介绍一下五段流水线CPU verilog的相关内容。 五段流水线CPU verilog设计主要包括指令集、寄存器堆、流水线、ALU和控制单元等组成部分。首先是指令集设计,可以基于MIPS或ARM等指令集设计,实现CPU对不同类型的指令的识别和执行。其次是寄存器堆设计,用于储存CPU的数据和状态。每个寄存器都有一个唯一的地址,可以通过地址访问寄存器储存的数据。然后是流水线设计流水线主要由五个阶段组成,通过流水线寄存器连接各个阶段,实现指令的流水线执行。其次是ALU的设计,ALU用于执行CPU的算术逻辑运算和位运算,支持加、减、与、或、移位等运算。最后是控制单元的设计,控制单元用于控制流水线的各个阶段的启动和停止,以及判断和处理异常情况。 五段流水线CPU verilog设计优化要点包括减少流水线延迟、解决数据冒险和控制冒险等问题。流水线延迟可以通过增加指令预取、指令重排等技术实现。数据冒险是指指令执行时需要使用前面指令的结果,但是前一条指令的结果还没有写回到寄存器中,为了解决这个问题可以采用数据前推的技术。控制冒险是指一个指令的控制信息影响另一个指令的执行结果,可以通过控制转移指令的识别和分支预测等技术进行解决。 总之,五段流水线CPU verilog设计是一项需要综合考虑指令集、流水线、寄存器堆、ALU和控制单元等多个方面的复杂任务。只有在充分考虑到各个方面的因素,并进行优化设计,才能实现高效、稳定的CPU设计
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值