summaryrefslogtreecommitdiff
path: root/verilog/datapath.v
blob: 1992e754290ddb4da088a44519e8994267775753 (plain) (blame)
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
`default_nettype none
`timescale 1ns/1ps

module datapath
(
	input wire clk, rst
);

// Pipeline Signals
wire stall_f;
wire stall_d;
wire flush_d;
wire flush_e;
wire [1:0] r1forward_e, r2forward_e;

// Fetch Signals
wire [31:0] pc_f;
wire [31:0] pc_4_f = pc_f + 4;
wire [31:0] pc_new = branch_pc ? pc_b_j : pc_4_f;

// Decode Signals
// From fetch
reg [31:0] instr_d;
reg [31:0] pc_d, pc_4_d;
// Controller Decode Signals
wire wb_pc_d, wb_mem_d;
wire wr_mem_d, wr_reg_d;
wire [4:0] alu_op_d;
wire alu_1_d, alu_2_d;
wire branch_d, jump_d, jump_r_d;
wire [3:0] i_b_j_u;
// Register Signals
wire [31:0] r1data_d, r2data_d;
wire [4:0] waddr_d = instr_d[11:7];
wire [4:0] r1addr_d = instr_d[19:15];
wire [4:0] r2addr_d = instr_d[24:20];
// Immediate Generation
wire [31:0] imm_d;

// Execute Signals
// PC and PC+4
reg [31:0] pc_e, pc_4_e;
// Control Signals
reg wb_pc_e, wb_mem_e;
reg wr_mem_e, wr_reg_e;
reg [4:0] alu_op_e;
reg alu_1_e, alu_2_e;
reg branch_e, jump_e, jump_r_e;
// Registers
reg [31:0] r1data_e, r2data_e;
reg [4:0] waddr_e, r1addr_e, r2addr_e;
//Immediate
reg [31:0] imm_e;
// ALU signals
wire [31:0] r1forward_reg_e = r1forward_e[1] ? reg_write_w : (r1forward_e[0] ? alu_out_m : r1data_e);
wire [31:0] r2forward_reg_e = r2forward_e[1] ? reg_write_w : (r2forward_e[0] ? alu_out_m : r2data_e);
wire [31:0] alu_in_1 = alu_1_e ? r1forward_reg_e : pc_e;
wire [31:0] alu_in_2 = alu_2_e ? r2forward_reg_e : imm_e;
wire [31:0] alu_out_e;
// Control flow signals
wire alu_branch;
wire branch_pc = jump_e | (branch_e & alu_branch);
wire [31:0] pc_b_j = imm_e + (jump_r_e ? r1data_e : pc_e);

// Memory Signals
// PC+4
reg [31:0] pc_4_m;
// Control Signals
reg wb_pc_m, wb_mem_m;
reg wr_mem_m, wr_reg_m;
//Registers
reg [31:0] r2data_m;
reg [4:0] waddr_m;
// ALU Out
reg [31:0] alu_out_m;

// WB signals
// Reg write back
reg wb_pc_w, wb_mem_w;
reg wr_reg_w;
reg [4:0] waddr_w;
reg [31:0] pc_4_w;
reg [31:0] alu_out_w, mem_out_w;
wire [31:0] reg_write_w = wb_pc_w ? pc_4_w : (wb_mem_w ? mem_out_w : alu_out_w);


always @ (posedge clk) begin

	// IF/ID Pipeline Stage
	if (flush_d) begin
		// Insert NOP
		instr_d <= 32'b0000000000000000000000010011;
		pc_d    <= 32'hXXXXXXXX;
		pc_4_d  <= 32'hXXXXXXXX;
	end
	else if (stall_d) begin
		instr_d <= instr_d;
		pc_d    <= pc_d;
		pc_4_d  <= pc_4_d;
	end
	else begin
		pc_d    <= pc_f;
		pc_4_d  <= pc_4_f;
	end
	
	// ID/IE stage
	// These Control signals don't affect arch state if left alone
	// So don't need to be flushed
	pc_e <= pc_d;
	pc_4_e <= pc_4_d;
	wb_pc_e <= wb_pc_d;
	wb_mem_e <= wb_mem_d;
	alu_op_e <= alu_op_d;
	alu_1_e <= alu_1_d;
	alu_2_e <= alu_2_d;
	r1data_e <= r1data_d;
	r2data_e <= r2data_d;
	r1addr_e <= r1addr_d;
	r2addr_e <= r2addr_d;
	waddr_e <= waddr_d;
	imm_e <= imm_d;
	if (flush_e) begin

		wr_mem_e <= 1'b0;
		wr_reg_e <= 1'b0;
		branch_e <= 1'b0;
		jump_e <= 1'b0;
		jump_r_e <= 1'b0;
	end
	else begin
		wr_mem_e <= wr_mem_d;
		wr_reg_e <= wr_reg_d;
		branch_e <= branch_d;
		jump_e <= jump_d;
		jump_r_e <= jump_r_d;
	end

	// IE/M Stage
	// Never flushed or stalled
	pc_4_m <= pc_4_e;
	wb_pc_m <= wb_pc_e;
	wb_mem_m <= wb_mem_e;
	wr_reg_m <= wr_reg_e;
	wr_mem_m <= wr_mem_e;
	waddr_m <= waddr_e;
	r2data_m <= r2forward_reg_e; 
	alu_out_m <= alu_out_e;

	// M/W Stage
	// Never flushed or stalled
	pc_4_w <= pc_4_m;
	wb_pc_w <= wb_pc_m;
	wb_mem_w <= wb_mem_m;
	wr_reg_w <= wr_reg_m;
	waddr_w <= waddr_m;
	alu_out_w <= alu_out_m;
end


// Pipeline Control
hazard hazard0
(
	.r1addr_e(r1addr_e), .r2addr_e(r2addr_e),
	.waddr_e(waddr_e), .waddr_m(waddr_m), .waddr_w(waddr_w),
	.wr_reg_m(wr_reg_m), .wr_reg_w(wr_reg_w),
	.r1forward_e(r1forward_e), .r2forward_e(r2forward_e),
	.r1addr_d(r1addr_d), .r2addr_d(r2addr_d),
	.wb_mem_e(wb_mem_e),
	.stall_f(stall_f), .stall_d(stall_d), .flush_e(flush_e), .flush_d(flush_d),
	.branch_pc(branch_pc)
);

// FETCH STAGE

pc pc0(
	.clk(clk), .we(~stall_f), .rst(rst),
	.pc_new(pc_new), .pc(pc_f)
);

memory #(.ADDR_WIDTH(8), .FILE_NAME("instr_mem.mem")) instr_mem
(
	.clk(clk), .we(1'b0),
	.be(4'b1111),
	.addr(pc_f[7:0]),
	.din(32'b0),
	.dout(instr_d)
);

// DECODE STAGE

decode dec0
(
	.opcode(instr_d[6:2]), .func3(instr_d[14:12]), .func7(instr_d[31]),
	.wb_pc_d(wb_pc_d), .wb_mem_d(wb_mem_d),
	.wr_mem_d(wr_mem_d), .wr_reg_d(wr_reg_d),
	.alu_op_d(alu_op_d), .alu_1_d(alu_1_d), .alu_2_d(alu_2_d),
	.branch_d(branch_d), .jump_d(jump_d), .jump_r_d(jump_r_d),
	.i_b_j_u(i_b_j_u)
);

regfile reg0
(
	.clk(clk), .we(wr_reg_w),
	.waddr(waddr_w), .wdata(reg_write_w),
	.r1addr(r1addr_d), .r2addr(r2addr_d), .r1data(r1data_d), .r2data(r2data_d)
);

immediate imm0
(
	.instr(instr_d[31:7]),
	.i(i_b_j_u[3]), .b(i_b_j_u[2]), .j(i_b_j_u[1]), .u(i_b_j_u[0]),
	.imm(imm_d)
);

// EXECUTE STAGE

alu alu0
(
	.A(alu_in_1),
	.B(alu_in_2),
	.C(alu_out_e),
	.OP(alu_op_e),
	.Branch(alu_branch)
);

// MEMORY STAGE
memory #(.ADDR_WIDTH(8), .FILE_NAME("data_mem.mem")) data_mem
(
	.clk(clk), .we(wr_mem_m),
	.be(4'b1111), // TODO Add support for smaller byte writes
	.addr(alu_out_m[7:0]),
	.din(r2data_m),
	.dout(mem_out_w)
);

// WB Stage has no modules only a mux


// Debug Waveforms
`ifdef verilator

initial begin
	$dumpfile("./log_datapath/datapath.vcd");
	$dumpvars(0, datapath);
end

`endif

endmodule