-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmips_cpu.v
334 lines (299 loc) · 11.9 KB
/
mips_cpu.v
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
`timescale 10ns / 1ns
module mycpu_top(
input resetn,
input clk,
output inst_sram_en,//TODO:韏?潘�餈�憭抒漲�詨�鈭��亦�inst_req_valid銋掩�
output [3:0] inst_sram_wen,
output [31:0] inst_sram_addr,
output [31:0] inst_sram_wdata,
input [31:0] inst_sram_rdata,
output data_sram_en,//TODO嚗��澆�賣��桅�
output [3:0] data_sram_wen,
output [31:0] data_sram_addr,
output [31:0] data_sram_wdata,
input [31:0] data_sram_rdata,
output reg [31:0] debug_wb_pc,//TODO嚗��潛���瘥�憟?迎��其�銝?銝芯縑�瑁”蝷箏�鈭B�嗆?��典����窒�湔嚗�瘝⊥�憟賜����?
output [3:0]debug_wb_rf_wen,
output [4:0] debug_wb_rf_wnum,
output [31:0] debug_wb_rf_wdata,
output [31:0] mips_perf_cnt_0//clk_counter
);
reg [31:0] PC;
assign inst_sram_wen = 0;
assign inst_sram_addr = PC;
assign inst_sram_wdata = 0;
assign debug_wb_rf_wen = {4{wen_reg_file}};//TODO嚗祗瘜�賣��桅�
assign debug_wb_rf_wnum = waddr;
assign debug_wb_rf_wdata = wdata;
//update inst and data
wire [2:0] next_state;
wire [31:0] inst;//�嫣�蝐餃�
assign inst=inst_sram_rdata;//TODO:�餅�鈭�縑�瘀����隞?銋��唳�隞歹��舐�仟ssign��
wire [31:0] data_from_mem;//�嫣�蝐餃�
assign data_from_mem=data_sram_rdata;//TODO:�餅�鈭�縑�瘀����隞?銋��唳�桀嚗�湔assign��
//define some simple signals (using extend)
wire [31:0] sign_extended_imm;
assign sign_extended_imm={{16{inst[15]}},inst[15:0]};
wire [25:0] instr_index;
assign instr_index=inst[25:0];
wire [27:0] instr_index_sl2;
assign instr_index_sl2={instr_index[25:0],2'b00};
wire [31:0] imm_sl16;
assign imm_sl16={inst[15:0],16'b0};
wire [31:0] zero_extended_imm;
assign zero_extended_imm={16'b0,inst[15:0]};
// define the signal related to main control
wire [5:0] behavior; //done
wire [31:0] Result; //done (used in 2 places)
wire [1:0] reg_dst;//signal for mux(where to write) //done
wire branch;//if the behavior is about branch //done
wire mem_read;//enable signal //done
wire [3:0] reg_write_value;//signal for mux(what to write) //done
wire [2:0] ALUop;//signal for ALU control //done
wire mem_write;//enable signal //done
wire [1:0] B_src;//signal for mux(what to compute) //done
wire reg_write;//enable signal //done
wire PC_enable;
wire bne; //done
wire beq; //done
wire j; //done
wire jal; //done
wire R_type;
wire regimm;
wire blez;
wire bgtz;
wire [2:0] mem_write_value;
wire writing_back;
wire in_delay_slot;
//add the control unit into the circuit
control_unit cpu_control_unit(.clk(clk),.resetn(resetn),.inst_sram_en(inst_sram_en),
.behavior(behavior),.Result(Result),
.reg_dst(reg_dst),.mem_read(mem_read),.reg_write_value(reg_write_value),
.ALUop(ALUop),.mem_write(mem_write),.B_src(B_src),.reg_write(reg_write),
.data_sram_wen(data_sram_wen),.mem_write_value(mem_write_value),
.PC_enable(PC_enable),
//decoding signal
.bne(bne),.beq(beq),.j(j),.jal(jal),.R_type(R_type),
.regimm(regimm),.blez(blez),.bgtz(bgtz),.writing_back(writing_back),
.in_delay_slot(in_delay_slot)
);
assign behavior=inst[31:26];
assign data_sram_en=mem_read | mem_write;//TODO嚗�賣��桅�
wire debug_wb_pc_update;
assign debug_wb_pc_update = writing_back | jal;
always@(posedge debug_wb_pc_update)
begin
debug_wb_pc <= PC;
end
//define the signal related to reg_file
wire clk_reg_file; //done
wire rst_reg_file; //done(not sure)
wire [4:0] waddr; //done
wire [4:0] raddr1; //done
wire [4:0] raddr2; //done
wire wen_reg_file; //done
wire [31:0] wdata; //done
wire [31:0] rdata1; //done
wire [31:0] rdata2; //done (used in 2 places)
//add the reg_flie into the circuit
reg_file cpu_reg_file(.clk(clk_reg_file),.resetn(rst_reg_file),.waddr(waddr),.raddr1(raddr1),
.raddr2(raddr2),.wen(wen_reg_file),.wdata(wdata),.rdata1(rdata1),.rdata2(rdata2));
assign clk_reg_file=clk;
assign raddr1=inst[25:21];
assign raddr2=inst[20:16];
assign wen_reg_file=(R_type==1 && inst[5:0]==6'b001011)?(rdata2!=32'b0):
(R_type==1 && inst[5:0]==6'b001010)?(rdata2==32'b0):
reg_write;//movn,movz
assign rst_reg_file=resetn;
//define the signal related to ALU
wire [31:0] A; //done
wire [31:0] B; //done
wire [3:0] ALUoperation; //done
wire Overflow;
wire CarryOut;
wire Zero; //done (used in pc_decider)
//add the ALU into the circuit
alu cpu_alu(.A(A),.B(B),.ALUop(ALUoperation),.Overflow(Overflow),.CarryOut(CarryOut),
.Zero(Zero),.Result(Result));
assign data_sram_addr=Result;
//add the ALU control unit into the circuit
ALU_control cpu_ALU_control(.func(inst[5:0]),.ALUop(ALUop),
.ALU_ctr(ALUoperation));
//MUX, what to write to memory
wire [31:0] write_data_sb;
wire [31:0] write_data_sh;
wire [31:0] write_data_swl;
wire [31:0] write_data_swr;
assign write_data_sb={4{rdata2[7:0]}}; //unify 4 situations of result
assign write_data_sh={2{rdata2[15:0]}}; //unify 4 situations of result
assign write_data_swl=(Result[1:0]==2'b00)?{24'b0,rdata2[31:14]}:
(Result[1:0]==2'b01)?{16'b0,rdata2[31:16]}:
(Result[1:0]==2'b10)?{8'b0,rdata2[31:8]}:
(Result[1:0]==2'b11)?rdata2:
32'b0;
assign write_data_swr=(Result[1:0]==2'b00)?rdata2:
(Result[1:0]==2'b01)?{rdata2[23:0],8'b0}:
(Result[1:0]==2'b10)?{rdata2[15:0],16'b0}:
(Result[1:0]==2'b11)?{rdata2[7:0],24'b0}:
32'b0;
assign data_sram_wdata=(mem_write_value==3'b000)?rdata2:
(mem_write_value==3'b001)?write_data_sb:
(mem_write_value==3'b010)?write_data_sh:
(mem_write_value==3'b011)?write_data_swl:
(mem_write_value==3'b100)?write_data_swr:
rdata2;
//MUX, where to write, decide 'waddr'
wire [4:0] waddr_option00;
wire [4:0] waddr_option01;
assign waddr_option00=inst[20:16];
assign waddr_option01=inst[15:11];
assign waddr=(reg_dst==2'b00)? waddr_option00:
(reg_dst==2'b01)? waddr_option01:
(reg_dst==2'b10)? 5'b11111:
5'b00000;
//MUX, what to compute, decide 'B'
wire [31:0] B_option00;
wire [31:0] B_option01;
wire [31:0] B_option10;
wire [31:0] B_option11;
assign B_option00=rdata2;
assign B_option01=sign_extended_imm;
assign B_option10=32'b0;
assign B_option11=zero_extended_imm;
assign B=(B_src==2'b00)? B_option00:
(B_src==2'b01)? B_option01:
(B_src==2'b10)? B_option10:
(B_src==2'b11)? B_option11:
rdata2;
//MUX,what to write to reg_flie, decide 'wdata'
wire [31:0] wdata_option0000;
wire [31:0] wdata_option0001;
wire [31:0] wdata_lb;
wire [31:0] wdata_lbu;
wire [31:0] wdata_lh;
wire [31:0] wdata_lhu;
wire [31:0] wdata_lwl;
wire [31:0] wdata_lwr;
assign wdata_option0000=Result;
assign wdata_option0001=data_from_mem;
assign wdata_lb=(Result[1:0]==2'b00)?{{24{data_from_mem[7]}},data_from_mem[7:0]}:
(Result[1:0]==2'b01)?{{24{data_from_mem[15]}},data_from_mem[15:8]}:
(Result[1:0]==2'b10)?{{24{data_from_mem[23]}},data_from_mem[23:16]}:
(Result[1:0]==2'b11)?{{24{data_from_mem[31]}},data_from_mem[31:24]}:
32'b0;
assign wdata_lbu=(Result[1:0]==2'b00)?{24'b0,data_from_mem[7:0]}:
(Result[1:0]==2'b01)?{24'b0,data_from_mem[15:8]}:
(Result[1:0]==2'b10)?{24'b0,data_from_mem[23:16]}:
(Result[1:0]==2'b11)?{24'b0,data_from_mem[31:24]}:
32'b0;
assign wdata_lh=(Result[1]==0)?{{16{data_from_mem[15]}},data_from_mem[15:0]}:
(Result[1]==1)?{{16{data_from_mem[31]}},data_from_mem[31:16]}:
32'b0;
assign wdata_lhu=(Result[1]==0)?{16'b0,data_from_mem[15:0]}:
(Result[1]==1)?{16'b0,data_from_mem[31:16]}:
32'b0;
assign wdata_lwl=(Result[1:0]==2'b00)?{data_from_mem[7:0],rdata2[23:0]}:
(Result[1:0]==2'b01)?{data_from_mem[15:0],rdata2[15:0]}:
(Result[1:0]==2'b10)?{data_from_mem[23:0],rdata2[7:0]}:
(Result[1:0]==2'b11)?data_from_mem[31:0]:
32'b0;
assign wdata_lwr=(Result[1:0]==2'b00)?data_from_mem[31:0]:
(Result[1:0]==2'b01)?{rdata2[31:24],data_from_mem[31:8]}:
(Result[1:0]==2'b10)?{rdata2[31:16],data_from_mem[31:16]}:
(Result[1:0]==2'b11)?{rdata2[31:8],data_from_mem[31:24]}:
32'b0;
assign wdata=(reg_write_value==4'b0000 &&(( inst[5:0]!=6'b001001 &&
inst[5:1]!=5'b00101 && inst[5:0]!=6'b100111 &&
inst[5:0]!=6'b101011)&&R_type==1 || R_type==0) )?wdata_option0000:
//unify movn and movz
//some R_type need handle
//seperately
(reg_write_value==4'b0001)?wdata_option0001:
(reg_write_value==4'b0010 ||
reg_write_value==4'b0000 && inst[5:0]==6'b001001 && R_type==1
)?(pc_next_option000+4):
//pc_next_option00 is defined below
(reg_write_value==4'b0011)?imm_sl16:
(reg_write_value==4'b0100 ||
reg_write_value==4'b0000 && inst[5:0]==6'b101011 && R_type==1
)?{31'b0,CarryOut}:
(reg_write_value==4'b0101)?wdata_lb: //lb
(reg_write_value==4'b0110)?wdata_lbu: //lbu
(reg_write_value==4'b0111)?wdata_lh: //lh
(reg_write_value==4'b1000)?wdata_lhu: //lhu
(reg_write_value==4'b1001)?wdata_lwl: //lwl
(reg_write_value==4'b1010)?wdata_lwr: //lwr
(reg_write_value==4'b0000 && inst[5:1]==5'b00101 && R_type==1)?rdata1:
//unify movn and movz
//note reg_write_value==4'b000 only represent shoult write
//result, can not imply it is R_type
(reg_write_value==4'b0000 && inst[5:0]==6'b100111 && R_type==1)?~Result:
4'b0000;
//MUX,when the option is shift using sa, let a equal to sa instead of rs
//controled by control unit and function field
wire [31:0] A_option0;
wire [31:0] A_option1;
assign A_option0=rdata1;
assign A_option1[4:0]=inst[10:6]; //only assign value to part of A_option1
assign A=(R_type==1 &&
(inst[5:0]==6'b000000 || inst[5:0]==6'b000011 ||
inst[5:0]==6'b000010)
)?A_option1:A_option0;
//PC
always @(posedge clk) begin
if(resetn==0) begin
PC<=32'Hbfc00000;//TODO嚗��仿�餈��啣�銵函內�寞�銵�銵?
end
else if(PC_enable)begin
PC<=pc_next;
end
//do not need PC<=PC
end
wire [31:0] pc_next;
wire [31:0] pc_next_option000;
wire [31:0] pc_next_option001;
wire [31:0] pc_next_option010;
wire [31:0] pc_next_option011;
reg [31:0] pc_next_option100;
wire [2:0] pc_decider;
assign pc_next_option000=PC+4; //directly +4
wire [31:0] offset;
assign offset={sign_extended_imm[29:0],2'b00};
assign pc_next_option001=pc_next_option000+offset; //beq,bne(pc+offset)
assign pc_next_option010={pc_next_option000[31:28],instr_index_sl2[27:0]};
assign pc_next_option011=rdata1;
always @(posedge clk)
begin
if(jal ==1)
begin
pc_next_option100<={pc_next_option000[31:28],instr_index_sl2[27:0]};
end
//TODO:otherwise pc_next_option100 dosen't change, how to code?
end
assign pc_decider=(Zero==0 && bne==1)?3'b001:
(Zero==1 && beq==1 ||
regimm==1 && inst[20:16]==5'b00001 && Result[0]==0 ||//bgez
blez==1 && (Result[0]==1 || rdata1==32'b0) ||//blez
bgtz==1 && (Result[0]==0 && rdata1!=32'b0) ||//bgtz
regimm==1 && inst[20:16]==5'b00000 && Result[0]==1)?3'b001://bltz
(j==1 /*|| jal==1 */)?3'b010:
(R_type==1 && inst[5:1]==5'b00100)?3'b011://unify jalr and jr
(in_delay_slot==1)?3'b100:
2'b00;
assign pc_next=(pc_decider==3'b000)?pc_next_option000:
(pc_decider==3'b001)?pc_next_option001:
(pc_decider==3'b010)?pc_next_option010:
(pc_decider==3'b011)?pc_next_option011:
(pc_decider==3'b100)?pc_next_option100:
0;
//mips_per_cnt_0 clk_counter
reg [31:0] clk_counter;
always @(posedge clk)
begin
if(resetn==0)
clk_counter<=1;
else
clk_counter<=clk_counter+32'b1;
end
assign mips_perf_cnt_0=clk_counter;
endmodule