This repository was archived by the owner on Mar 24, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPLCPU.v
More file actions
373 lines (326 loc) · 11 KB
/
PLCPU.v
File metadata and controls
373 lines (326 loc) · 11 KB
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
`include "ctrl_encode_def.v"
module PLCPU(
input clk, // clock
input reset, // reset
input [31:0] inst_in, // instruction
input [31:0] Data_in, // data from data memory
output [31:0] PC_out, // PC address
output [31:0] Addr_out, // ALU output
output [31:0] Data_out, // data to data memory
output mem_w, // output: memory write signal
output mem_r, // output: memory read signal
);
wire RegWrite; // control signal to register write
wire [5:0] EXTOp; // control signal to signed extension
wire [4:0] ALUOp; // ALU opertion
wire [4:0] NPCOp; // next PC operation
wire [1:0] WDSel; // (register) write data selection
wire ALUSrc; // ALU source for B
wire Zero; // ALU ouput zero
wire [31:0] NPC; // next PC
wire [4:0] rs1; // rs
wire [4:0] rs2; // rt
wire [4:0] rd; // rd
wire [6:0] Op; // opcode
wire [6:0] Funct7; // funct7
wire [2:0] Funct3; // funct3
wire [11:0] Imm12; // 12-bit immediate
wire [31:0] Imm32; // 32-bit immediate
wire [19:0] IMM; // 20-bit immediate (address)
wire [4:0] A3; // register address for write
reg [31:0] WD; // register write data
reg [31:0] memdata_wr; // memory write data
wire [31:0] RD1,RD2; // register data specified by rs
wire [31:0] A; //operator for ALU A
wire [31:0] B; // operator for ALU B
wire [4:0] iimm_shamt;
wire [11:0] iimm,simm,bimm;
wire [19:0] uimm,jimm;
wire [31:0] immout;
//EX wires
wire [4:0] EX_rd;
wire [4:0] EX_rs1;
wire [4:0] EX_rs2;
wire [31:0] EX_immout;
wire [31:0] EX_RD1;
wire [31:0] EX_RD2;
wire EX_RegWrite;//RFWr
wire EX_MemWrite;//DMWr
wire EX_MemRead;//DMRe
wire [4:0] EX_ALUOp;
wire [4:0] EX_NPCOp;
wire EX_ALUSrc;
wire [1:0] EX_WDSel;
wire [31:0] EX_pc;
wire [6:0] EX_Opcode;
//MEM wires
wire [4:0] MEM_rd;
wire [4:0] MEM_rs2;
wire [31:0] MEM_RD2;
wire [31:0] MEM_aluout;
wire MEM_RegWrite;
wire MEM_MemWrite;
wire MEM_MemRead;
wire [1:0] MEM_WDSel;
assign mem_w = MEM_MemWrite;
assign mem_r = MEM_MemRead;
//WB wires
wire [4:0] WB_rd;
wire [31:0] WB_aluout;
wire [31:0] WB_MemData;
wire WB_RegWrite;
wire [1:0] WB_WDSel;
wire [31:0] WB_pc;
wire[31:0] aluout;
assign Addr_out = MEM_aluout;
assign Data_out = memdata_wr;
wire [31:0] instr;
assign iimm_shamt=instr[24:20];
assign iimm=instr[31:20];
assign simm={instr[31:25],instr[11:7]};
assign bimm={instr[31],instr[7],instr[30:25],instr[11:8]};
assign uimm=instr[31:12];
assign jimm={instr[31],instr[19:12],instr[20],instr[30:21]};
assign Op = instr[6:0]; // instruction
assign Funct7 = instr[31:25]; // funct7
assign Funct3 = instr[14:12]; // funct3
assign rs1 = instr[19:15]; // rs1
assign rs2 = instr[24:20]; // rs2
assign rd = instr[11:7]; // rd
assign Imm12 = instr[31:20];// 12-bit immediate
assign IMM = instr[31:12]; // 20-bit immediate
wire ID_MemWrite; // MemWrite from ctrl in ID
wire ID_MemRead; // MemRead from ctrl in ID
reg flaglu;
// instantiation of control unit
ctrl U_ctrl(
.Op(Op), .Funct7(Funct7), .Funct3(Funct3), .Zero(Zero),
.RegWrite(RegWrite), .MemWrite(ID_MemWrite), .MemRead(ID_MemRead),
.EXTOp(EXTOp), .ALUOp(ALUOp), .NPCOp(NPCOp),
.ALUSrc(ALUSrc), .WDSel(WDSel)
);
// instantiation of pc unit
PC U_PC(.clk(~clk), .rst(reset), .NPC((flaglu)?PC_out:NPC), .PC(PC_out) );
NPC U_NPC(.PC(PC_out), .NPCOp(EX_NPCOp),
.IMM(((EX_NPCOp==`NPC_JALR)?aluout:EX_immout)), .NPC(NPC));
always @(*) begin
// $write("A:0x%0h\n",A);
// $write("B:0x%0h\n",B);
// $write("PC:0x%0h\n",PC_out);
// $write("NPC:0x%0h\n",NPC);
// $write("aluout:0x%0h\n",aluout);
// $write("eximmout:0x%0h\n",EX_immout);
// $write("Zero:0x%0h\n",Zero);
end
EXT U_EXT(
.iimm(iimm), .simm(simm), .bimm(bimm), .uimm(uimm), .jimm(jimm),
.EXTOp(EXTOp), .immout(immout)
);
RF U_RF(
.clk(clk), .rst(reset),
.RFWr(WB_RegWrite),
.A1(rs1), .A2(rs2), .A3(WB_rd),
.WD(WD),
.RD1(RD1), .RD2(RD2)
);
// instantiation of alu unit
alu U_alu(.A(A), .B(B), .ALUOp(EX_ALUOp), .C(aluout), .Zero(Zero));
// always @(posedge clk) begin
// $write("0x%0h\n",aluout);
// $write("eximm:0x%0h\n",EX_immout);
// end
//please connnect the CPU by yourself
//WD MUX
always @(*)
begin
case(WB_WDSel)
`WDSel_FromALU: WD<=WB_aluout;
`WDSel_FromMEM: WD<=WB_MemData;
`WDSel_FromPC: WD<=WB_pc+4; //WB_pc????�u????��??4????J????????
endcase
end
// MUX Gate
reg [31:0] alu_in1;
reg [31:0] alu_in2;
wire AUIPC = ~EX_Opcode[6]&~EX_Opcode[5]&EX_Opcode[4]&~EX_Opcode[3]&EX_Opcode[2]&EX_Opcode[1]&EX_Opcode[0];
always @(*)
begin
// $write("EX_rs1:x%0d\tEX_rs2:x%0d\n",EX_rs1,EX_rs2);
if (AUIPC) begin
alu_in1 <= EX_pc;
end
else if (EX_rs1==0) begin
// $write("EX_rs1=0\n");
alu_in1 <= EX_RD1;
end
else if (EX_rs1==MEM_rd) begin
// $write("EX_rs1=MEM_rd(x%0d)\n",MEM_rd);
alu_in1 <= MEM_aluout;
end
else if (EX_rs1==WB_rd) begin
// $write("EX_rs1=WB_rd(x%0d)\n",WB_rd);
alu_in1 <= WB_aluout;
end
else begin
// $write("Other Th1\n");
alu_in1 <= EX_RD1; //from regfile
end
if (EX_rs2==0) begin
// $write("EX_rs2=0\n");
alu_in2 <= EX_RD2;
end
else if (EX_rs2==MEM_rd) begin
// $write("EX_rs2=MEM_rd(x%0d)\n",MEM_rd);
alu_in2 <= MEM_aluout;
end
else if (EX_rs2==WB_rd) begin
// $write("EX_rs2=WB_rd(x%0d) and Now MEM_rd(x%0d)\n",WB_rd, MEM_rd);
alu_in2 <= WB_aluout;
end
else begin
// $write("Other Th2\n");
alu_in2 <= EX_RD2; //from regfile
end
end
always @(*)
if (MEM_rs2==WB_rd)
memdata_wr <= WB_aluout;
else
memdata_wr <= MEM_RD2;//from MEM
assign A = alu_in1;
assign B = (EX_ALUSrc) ? EX_immout : alu_in2;//whether from EXT
// 【指令清除】ex判断跳转branch / jal / jalr 清除IF_ID,ID_EX段
reg flagpl;
always @(*) begin
case (EX_NPCOp)
`NPC_BRANCH: flagpl = 1;
`NPC_JUMP: flagpl = 1;
`NPC_JALR: flagpl = 1;
default: flagpl = 0;
endcase
end
// 数据旁路: MEM->EX WB->EX WB->MEM
// MEM -> EX
// addi x5,x0,1; addi x6,x5,1 rd,rs1,rs2
// MEM->EX EX_out.rs1 == MEM_out.rd || EX_out.rs2 == MEM_out.rd
// WB->MEM rs2,imm(rs1)
// addi x5,x0,1; sd x5,10(x0); / addi x5,x0,1; sd x5,10(x5) 这个情况划归到MEM->EX了 (?
// MEM_out.rs2 == WB_out.rd
// 跨双指令
// WB->EX EX_out.rs1 == WB_out.rd || EX_out.rs2 == WB_out.rd
// load-use harzard
always @(*) begin
if ((EX_rd==rs2 || EX_rd==rs1 || EX_rd==rd)&&(~EX_Opcode[6]&~EX_Opcode[5]&~EX_Opcode[4]&~EX_Opcode[3]&~EX_Opcode[2]&EX_Opcode[1]&EX_Opcode[0])) begin
// 检测EX段是否为LD指令,以及是否存在load-use
flaglu <= 1;
end
else
flaglu <= 0;
end
//-----pipe registers--------------
//IF_ID: [31:0] PC [31:0]instr
wire [64:0] IF_ID_in;
assign IF_ID_in[31:0] = PC_out;//original addr of the current ins in ID, not PC+4
assign IF_ID_in[63:32] = inst_in;
assign IF_ID_in[64] = flagpl | flaglu;
wire [64:0] IF_ID_out;
assign instr = IF_ID_out[63:32];
pl_reg #(.WIDTH(65))
IF_ID
(.clk(~clk), .rst(reset),
.in(IF_ID_in), .out(IF_ID_out));
//ID_EX
wire [194:0] ID_EX_in;
assign ID_EX_in[31:0] = IF_ID_out[31:0];//PC
assign ID_EX_in[36:32] = rd;
assign ID_EX_in[41:37] = rs1;
assign ID_EX_in[46:42] = rs2;
assign ID_EX_in[78:47] = immout;
assign ID_EX_in[110:79] = RD1;
assign ID_EX_in[142:111] = RD2;
assign ID_EX_in[143] = RegWrite;//RFWr
assign ID_EX_in[144] = ID_MemWrite;//DMWr
assign ID_EX_in[149:145] = ALUOp;
assign ID_EX_in[154:150] = NPCOp;
assign ID_EX_in[155] = ALUSrc;
assign ID_EX_in[158:156] = 3'b000; //nop, reserved for mem access
assign ID_EX_in[160:159] = WDSel;
assign ID_EX_in[161] = ID_MemRead;
assign ID_EX_in[193:162] = IF_ID_out[63:32];
assign ID_EX_in[194] = flagpl | flaglu;
wire [194:0] ID_EX_out;
//wire [31:0] EX_inst;
assign EX_rd = ID_EX_out[36:32];
assign EX_rs1 = ID_EX_out[41:37];
assign EX_rs2 = ID_EX_out[46:42];
assign EX_immout = ID_EX_out[78:47];
assign EX_RD1 = ID_EX_out[110:79];
assign EX_RD2 = ID_EX_out[142:111];
assign EX_RegWrite = ID_EX_out[143];//RFWr
assign EX_MemWrite = ID_EX_out[144];//DMWr
assign EX_ALUOp = ID_EX_out[149:145];
assign EX_NPCOp = {ID_EX_out[154:151], ID_EX_out[150] & Zero};
assign EX_ALUSrc = ID_EX_out[155];
assign EX_DMType = ID_EX_out[158:156];
assign EX_WDSel = ID_EX_out[160:159];
assign EX_MemRead = ID_EX_out[161];
assign EX_pc = ID_EX_out[31:0];
assign EX_Opcode = ID_EX_out[168:162];
//assign EX_inst = ID_EX_out[193:162];
pl_reg #(.WIDTH(195))
ID_EX
(.clk(~clk), .rst(reset),
.in(ID_EX_in), .out(ID_EX_out));
//EX_MEM
wire [146:0] EX_MEM_in;
assign EX_MEM_in[31:0] = ID_EX_out[31:0];//PC
assign EX_MEM_in[36:32] = EX_rd;//rd
assign EX_MEM_in[68:37] = alu_in2;//RD2 updated!!!
assign EX_MEM_in[100:69] = aluout;
assign EX_MEM_in[101] = EX_RegWrite;
assign EX_MEM_in[102] = EX_MemWrite;
assign EX_MEM_in[105:103] = EX_DMType;
assign EX_MEM_in[107:106] = EX_WDSel;
assign EX_MEM_in[112:108] = EX_rs2;
assign EX_MEM_in[113] = EX_MemRead;
assign EX_MEM_in[145:114] = ID_EX_out[193:162];
assign EX_MEM_in[146] = 0; // reserved for flush
wire [146:0] EX_MEM_out;
assign MEM_rd = EX_MEM_out[36:32];
assign MEM_RD2 = EX_MEM_out[68:37];
assign MEM_aluout = EX_MEM_out[100:69];
assign MEM_RegWrite = EX_MEM_out[101];
assign MEM_MemWrite = EX_MEM_out[102];
assign MEM_DMType = EX_MEM_out[105:103];
assign MEM_WDSel = EX_MEM_out[107:106];
assign MEM_rs2 = EX_MEM_out[112:108];
assign MEM_MemRead = EX_MEM_out[113];
//assign MEM_inst = EX_MEM_out[145:114];
pl_reg #(.WIDTH(147))
EX_MEM
(.clk(~clk), .rst(reset),
.in(EX_MEM_in), .out(EX_MEM_out));
//MEM_WB
wire [136:0] MEM_WB_in;
wire [31:0] WB_inst;
assign MEM_WB_in[31:0] = EX_MEM_out[31:0]; //PC
assign MEM_WB_in[36:32] = MEM_rd;
assign MEM_WB_in[68:37] = MEM_aluout;
assign MEM_WB_in[100:69] = Data_in; //data from dmem
assign MEM_WB_in[101] = MEM_RegWrite;
assign MEM_WB_in[103:102] = MEM_WDSel;
assign MEM_WB_in[135:104] = EX_MEM_out[145:114];
assign MEM_WB_in[136] = 0; // reserved for flush
wire [136:0] MEM_WB_out;
assign WB_pc = MEM_WB_out[31:0];
assign WB_rd = MEM_WB_out[36:32];
assign WB_aluout = MEM_WB_out[68:37];
assign WB_MemData = MEM_WB_out[100:69];
assign WB_RegWrite = MEM_WB_out[101];
assign WB_WDSel = MEM_WB_out[103:102];
assign WB_inst = MEM_WB_out[135:104];
pl_reg #(.WIDTH(137))
MEM_WB
(.clk(~clk), .rst(reset),
.in(MEM_WB_in), .out(MEM_WB_out));
endmodule