-
Notifications
You must be signed in to change notification settings - Fork 0
/
processor.v
263 lines (243 loc) · 8.06 KB
/
processor.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
`include "config.v"
/**
* READ THIS DESCRIPTION!
*
* The processor takes in several inputs from a skeleton file.
*
* Inputs
* clock: this is the clock for your processor at 50 MHz
* reset: we should be able to assert a reset to start your pc from 0 (sync or
* async is fine)
*
* Imem: input data from imem
* Dmem: input data from dmem
* Regfile: input data from regfile
*
* Outputs
* Imem: output control signals to interface with imem
* Dmem: output control signals and data to interface with dmem
* Regfile: output control signals and data to interface with regfile
*
* Notes
*
* Ultimately, your processor will be tested by subsituting a master skeleton, imem, dmem, so the
* testbench can see which controls signal you active when. Therefore, there needs to be a way to
* "inject" imem, dmem, and regfile interfaces from some external controller module. The skeleton
* file acts as a small wrapper around your processor for this purpose.
*
* You will need to figure out how to instantiate two memory elements, called
* "syncram," in Quartus: one for imem and one for dmem. Each should take in a
* 12-bit address and allow for storing a 32-bit value at each address. Each
* should have a single clock.
*
* Each memory element should have a corresponding .mif file that initializes
* the memory element to certain value on start up. These should be named
* imem.mif and dmem.mif respectively.
*
* Importantly, these .mif files should be placed at the top level, i.e. there
* should be an imem.mif and a dmem.mif at the same level as process.v. You
* should figure out how to point your generated imem.v and dmem.v files at
* these MIF files.
*
* imem
* Inputs: 12-bit address, 1-bit clock enable, and a clock
* Outputs: 32-bit instruction
*
* dmem
* Inputs: 12-bit address, 1-bit clock, 32-bit data, 1-bit write enable
* Outputs: 32-bit data at the given address
*
*/
module processor(clock,
reset, // I: A reset signal
address_imem, // O: The address of the data to get from imem
q_imem, // I: The data from imem
address_dmem, // O: The address of the data to get or put from/to dmem
data, // O: The data to write to dmem
wren, // O: Write enable for dmem
q_dmem, // I: The data from dmem
ctrl_writeEnable, // O: Write enable for regfile
ctrl_writeReg, // O: Register to write to in regfile
ctrl_readRegA, // O: Register to read from port A of regfile
ctrl_readRegB, // O: Register to read from port B of regfile
data_writeReg, // O: Data to write to for regfile
data_readRegA, // I: Data from port A of regfile
data_readRegB, // I: Data from port B of regfile
//addr_pcin//For testing
);
// Control signals
input clock, reset;
// Imem
output [11:0] address_imem;
input [31:0] q_imem;
// Dmem
output [11:0] address_dmem;
output [31:0] data;
output wren;
input [31:0] q_dmem;
// Regfile
output ctrl_writeEnable;
output [4:0] ctrl_writeReg, ctrl_readRegA, ctrl_readRegB;
output [31:0] data_writeReg;
input [31:0] data_readRegA, data_readRegB;
/* YOUR CODE STARTS HERE */
wire clk, rst;
assign clk = clock;
assign rst = reset;
//==>> Instruction Fetch <<==
wire ctrl_branch;
wire [31:0] addr_pcin;
//output [31:0] addr_pcin;//for testing
wire [31:0] addr_branch;
wire [31:0] addr_pcout;
wire [31:0] addr_nxtpc;
wire [31:0] inst;
assign addr_nxtpc = addr_pcout + 32'h00000001;
assign addr_pcin = ctrl_branch ? addr_branch : addr_nxtpc;
dffe_wers pc(
.we(1'b1),
.din(addr_pcin),
.qout(addr_pcout),
.clk(clk),
.rst(rst)
);
assign address_imem = addr_pcout[11:0];
assign inst = q_imem;
//==>> Instruction Decode & Regfile <<==
// instruction fields
wire ctrl_ex;
wire [4:0] inst_opcode;
wire [4:0] inst_rd;
wire [4:0] inst_rs;
wire [4:0] inst_rt;
wire [4:0] inst_shamt;
wire [4:0] inst_aluop;
wire [16:0] inst_simm17;
wire [26:0] inst_uimm27;
// decoder output
wire [`W_RANDLOGIC-1:0] ctrl_datapath;
// immgen output
wire [31:0] data_simm17x;
wire [31:0] data_uimm27x;
// regfile
assign ctrl_writeEnable = ctrl_datapath[`REGWE];
assign ctrl_writeReg =
(ctrl_ex | ctrl_datapath[`SETX]) ?
`RSTATUS
:
ctrl_datapath[`JAL] ?
`RRETADDR
:
inst_rd;
assign ctrl_readRegA =
ctrl_datapath[`BEX] ?
`RZERO
:
ctrl_datapath[`JR] ?
inst_rd
:
ctrl_datapath[`CONDB] ?
inst_rd
:
inst_rs;
assign ctrl_readRegB =
ctrl_datapath[`BEX] ?
`RSTATUS
:
ctrl_datapath[`SW] ?
inst_rd
:
ctrl_datapath[`CONDB] ?
inst_rs
:
inst_rt;
assign inst_opcode = inst[31:27];
// random logic (decoder)
assign inst_opcode = inst[31:27];
assign inst_rd = inst[26:22];
assign inst_rs = inst[21:17];
assign inst_rt = inst[16:12];
assign inst_shamt = inst[11:7];
assign inst_aluop = inst[6:2];
assign inst_simm17 = inst[16:0];
assign inst_uimm27 = inst[26:0];
randlogic u_randlogic(
.inst_opcode(inst_opcode),
.ctrl_out(ctrl_datapath)
);
// immediate number generator
assign data_simm17x = {{15{inst_simm17[16]}}, inst_simm17};
assign data_uimm27x = {5'h00, inst_uimm27};
//==>> Execution and Branch Address Calculation <<==
wire [31:0] data_operanda;
wire [31:0] data_operandb;
wire [4:0] ctrl_aluop;
wire [31:0] data_aluout;
wire ctrl_ne;
wire ctrl_lt;
wire ctrl_ovf;
wire ctrl_condbr;
wire ctrl_immjmp;
wire [31:0] data_excode;
assign ctrl_aluop =
ctrl_datapath[`IMMADD] ?
`ALUADD
:
ctrl_datapath[`CONDB] ?
`ALUSUB
:
inst_aluop;
assign data_operanda = data_readRegA;
assign data_operandb = ctrl_datapath[`IMM2ALU] ? data_simm17x : data_readRegB;
alu u_alu(
.data_operandA(data_operanda),
.data_operandB(data_operandb),
.ctrl_ALUopcode(ctrl_aluop),
.ctrl_shiftamt(inst_shamt),
.data_result(data_aluout),
.isNotEqual(ctrl_ne),
.isLessThan(ctrl_lt),
.overflow(ctrl_ovf));
assign ctrl_condbr = (ctrl_datapath[`BNE] & ctrl_ne) | (ctrl_datapath[`BLT] & ctrl_lt);
assign ctrl_immjmp = ctrl_datapath[`IMM2PC] | (ctrl_datapath[`BEX] & ctrl_ne);
assign ctrl_branch = ctrl_immjmp |
ctrl_datapath[`REG2PC] |
ctrl_condbr;
assign addr_branch =
ctrl_condbr ?
addr_nxtpc + data_simm17x
:
ctrl_immjmp ?
data_uimm27x
:
data_operanda;
exception_gen u_exception_gen(
.ctrl_alu(ctrl_datapath[`ALU]),
.ctrl_addi(ctrl_datapath[`ADDI]),
.ovf(ctrl_ovf),
.aluop(ctrl_aluop),
.ctrl_ex(ctrl_ex),
.data_excode(data_excode)
);
//==>> Data Memory Operation <<==
wire [31:0] data_dmem;
assign address_dmem = data_aluout[11:0];
assign data = data_readRegB;
assign wren = ctrl_datapath[`MEMWE];
assign data_dmem = q_dmem;
//==>> Register Write Back <<==
assign data_writeReg =
ctrl_ex ?
data_excode
:
ctrl_datapath[`SETX]?
data_uimm27x
:
ctrl_datapath[`PC2RD] ?
addr_nxtpc
:
ctrl_datapath[`MEM2REG] ?
data_dmem
:
data_aluout;
endmodule