1
|
---------------------------------------------------------------------
|
2
|
-- TITLE: Controller / Opcode Decoder
|
3
|
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com)
|
4
|
-- DATE CREATED: 2/8/01
|
5
|
-- FILENAME: control.vhd
|
6
|
-- PROJECT: Plasma CPU core
|
7
|
-- COPYRIGHT: Software placed into the public domain by the author.
|
8
|
-- Software 'as is' without warranty. Author liable for nothing.
|
9
|
-- NOTE: MIPS(tm) is a registered trademark of MIPS Technologies.
|
10
|
-- MIPS Technologies does not endorse and is not associated with
|
11
|
-- this project.
|
12
|
-- DESCRIPTION:
|
13
|
-- Controls the CPU by decoding the opcode and generating control
|
14
|
-- signals to the rest of the CPU.
|
15
|
-- This entity decodes the MIPS(tm) opcode into a
|
16
|
-- Very-Long-Word-Instruction.
|
17
|
-- The 32-bit opcode is converted to a
|
18
|
-- 6+6+6+16+4+2+4+3+2+2+3+2+4 = 60 bit VLWI opcode.
|
19
|
-- Based on information found in:
|
20
|
-- "MIPS RISC Architecture" by Gerry Kane and Joe Heinrich
|
21
|
-- and "The Designer's Guide to VHDL" by Peter J. Ashenden
|
22
|
---------------------------------------------------------------------
|
23
|
library ieee;
|
24
|
use ieee.std_logic_1164.all;
|
25
|
use work.mlite_pack.all;
|
26
|
|
27
|
entity control is
|
28
|
port(opcode : in std_logic_vector(31 downto 0);
|
29
|
intr_signal : in std_logic;
|
30
|
rs_index : out std_logic_vector(5 downto 0);
|
31
|
rt_index : out std_logic_vector(5 downto 0);
|
32
|
rd_index : out std_logic_vector(5 downto 0);
|
33
|
imm_out : out std_logic_vector(15 downto 0);
|
34
|
alu_func : out alu_function_type;
|
35
|
shift_func : out shift_function_type;
|
36
|
mult_func : out mult_function_type;
|
37
|
branch_func : out branch_function_type;
|
38
|
a_source_out : out a_source_type;
|
39
|
b_source_out : out b_source_type;
|
40
|
c_source_out : out c_source_type;
|
41
|
pc_source_out: out pc_source_type;
|
42
|
mem_source_out:out mem_source_type;
|
43
|
exception_out: out std_logic);
|
44
|
end; --entity control
|
45
|
|
46
|
architecture logic of control is
|
47
|
begin
|
48
|
|
49
|
control_proc: process(opcode, intr_signal)
|
50
|
variable op, func : std_logic_vector(5 downto 0);
|
51
|
variable rs, rt, rd : std_logic_vector(5 downto 0);
|
52
|
variable rtx : std_logic_vector(4 downto 0);
|
53
|
variable imm : std_logic_vector(15 downto 0);
|
54
|
variable alu_function : alu_function_type;
|
55
|
variable shift_function : shift_function_type;
|
56
|
variable mult_function : mult_function_type;
|
57
|
variable a_source : a_source_type;
|
58
|
variable b_source : b_source_type;
|
59
|
variable c_source : c_source_type;
|
60
|
variable pc_source : pc_source_type;
|
61
|
variable branch_function: branch_function_type;
|
62
|
variable mem_source : mem_source_type;
|
63
|
variable is_syscall : std_logic;
|
64
|
begin
|
65
|
alu_function := ALU_NOTHING;
|
66
|
shift_function := SHIFT_NOTHING;
|
67
|
mult_function := MULT_NOTHING;
|
68
|
a_source := A_FROM_REG_SOURCE;
|
69
|
b_source := B_FROM_REG_TARGET;
|
70
|
c_source := C_FROM_NULL;
|
71
|
pc_source := FROM_INC4;
|
72
|
branch_function := BRANCH_EQ;
|
73
|
mem_source := MEM_FETCH;
|
74
|
op := opcode(31 downto 26);
|
75
|
rs := '0' & opcode(25 downto 21);
|
76
|
rt := '0' & opcode(20 downto 16);
|
77
|
rtx := opcode(20 downto 16);
|
78
|
rd := '0' & opcode(15 downto 11);
|
79
|
func := opcode(5 downto 0);
|
80
|
imm := opcode(15 downto 0);
|
81
|
is_syscall := '0';
|
82
|
|
83
|
case op is
|
84
|
when "000000" => --SPECIAL
|
85
|
case func is
|
86
|
when "000000" => --SLL r[rd]=r[rt]<<re;
|
87
|
a_source := A_FROM_IMM10_6;
|
88
|
c_source := C_FROM_SHIFT;
|
89
|
shift_function := SHIFT_LEFT_UNSIGNED;
|
90
|
|
91
|
when "000010" => --SRL r[rd]=u[rt]>>re;
|
92
|
a_source := A_FROM_IMM10_6;
|
93
|
c_source := C_FROM_shift;
|
94
|
shift_function := SHIFT_RIGHT_UNSIGNED;
|
95
|
|
96
|
when "000011" => --SRA r[rd]=r[rt]>>re;
|
97
|
a_source := A_FROM_IMM10_6;
|
98
|
c_source := C_FROM_SHIFT;
|
99
|
shift_function := SHIFT_RIGHT_SIGNED;
|
100
|
|
101
|
when "000100" => --SLLV r[rd]=r[rt]<<r[rs];
|
102
|
c_source := C_FROM_SHIFT;
|
103
|
shift_function := SHIFT_LEFT_UNSIGNED;
|
104
|
|
105
|
when "000110" => --SRLV r[rd]=u[rt]>>r[rs];
|
106
|
c_source := C_FROM_SHIFT;
|
107
|
shift_function := SHIFT_RIGHT_UNSIGNED;
|
108
|
|
109
|
when "000111" => --SRAV r[rd]=r[rt]>>r[rs];
|
110
|
c_source := C_FROM_SHIFT;
|
111
|
shift_function := SHIFT_RIGHT_SIGNED;
|
112
|
|
113
|
when "001000" => --JR s->pc_next=r[rs];
|
114
|
pc_source := FROM_BRANCH;
|
115
|
alu_function := ALU_ADD;
|
116
|
branch_function := BRANCH_YES;
|
117
|
|
118
|
when "001001" => --JALR r[rd]=s->pc_next; s->pc_next=r[rs];
|
119
|
c_source := C_FROM_PC_PLUS4;
|
120
|
pc_source := FROM_BRANCH;
|
121
|
alu_function := ALU_ADD;
|
122
|
branch_function := BRANCH_YES;
|
123
|
|
124
|
--when "001010" => --MOVZ if(!r[rt]) r[rd]=r[rs]; /*IV*/
|
125
|
--when "001011" => --MOVN if(r[rt]) r[rd]=r[rs]; /*IV*/
|
126
|
|
127
|
when "001100" => --SYSCALL
|
128
|
is_syscall := '1';
|
129
|
|
130
|
when "001101" => --BREAK s->wakeup=1;
|
131
|
is_syscall := '1';
|
132
|
|
133
|
--when "001111" => --SYNC s->wakeup=1;
|
134
|
|
135
|
when "010000" => --MFHI r[rd]=s->hi;
|
136
|
c_source := C_FROM_MULT;
|
137
|
mult_function := MULT_READ_HI;
|
138
|
|
139
|
when "010001" => --MTHI s->hi=r[rs];
|
140
|
mult_function := MULT_WRITE_HI;
|
141
|
|
142
|
when "010010" => --MFLO r[rd]=s->lo;
|
143
|
c_source := C_FROM_MULT;
|
144
|
mult_function := MULT_READ_LO;
|
145
|
|
146
|
when "010011" => --MTLO s->lo=r[rs];
|
147
|
mult_function := MULT_WRITE_LO;
|
148
|
|
149
|
when "011000" => --MULT s->lo=r[rs]*r[rt]; s->hi=0;
|
150
|
mult_function := MULT_SIGNED_MULT;
|
151
|
|
152
|
when "011001" => --MULTU s->lo=r[rs]*r[rt]; s->hi=0;
|
153
|
mult_function := MULT_MULT;
|
154
|
|
155
|
when "011010" => --DIV s->lo=r[rs]/r[rt]; s->hi=r[rs]%r[rt];
|
156
|
mult_function := MULT_SIGNED_DIVIDE;
|
157
|
|
158
|
when "011011" => --DIVU s->lo=r[rs]/r[rt]; s->hi=r[rs]%r[rt];
|
159
|
mult_function := MULT_DIVIDE;
|
160
|
|
161
|
when "100000" => --ADD r[rd]=r[rs]+r[rt];
|
162
|
c_source := C_FROM_ALU;
|
163
|
alu_function := ALU_ADD;
|
164
|
|
165
|
when "100001" => --ADDU r[rd]=r[rs]+r[rt];
|
166
|
c_source := C_FROM_ALU;
|
167
|
alu_function := ALU_ADD;
|
168
|
|
169
|
when "100010" => --SUB r[rd]=r[rs]-r[rt];
|
170
|
c_source := C_FROM_ALU;
|
171
|
alu_function := ALU_SUBTRACT;
|
172
|
|
173
|
when "100011" => --SUBU r[rd]=r[rs]-r[rt];
|
174
|
c_source := C_FROM_ALU;
|
175
|
alu_function := ALU_SUBTRACT;
|
176
|
|
177
|
when "100100" => --AND r[rd]=r[rs]&r[rt];
|
178
|
c_source := C_FROM_ALU;
|
179
|
alu_function := ALU_AND;
|
180
|
|
181
|
when "100101" => --OR r[rd]=r[rs]|r[rt];
|
182
|
c_source := C_FROM_ALU;
|
183
|
alu_function := ALU_OR;
|
184
|
|
185
|
when "100110" => --XOR r[rd]=r[rs]^r[rt];
|
186
|
c_source := C_FROM_ALU;
|
187
|
alu_function := ALU_XOR;
|
188
|
|
189
|
when "100111" => --NOR r[rd]=~(r[rs]|r[rt]);
|
190
|
c_source := C_FROM_ALU;
|
191
|
alu_function := ALU_NOR;
|
192
|
|
193
|
when "101010" => --SLT r[rd]=r[rs]<r[rt];
|
194
|
c_source := C_FROM_ALU;
|
195
|
alu_function := ALU_LESS_THAN_SIGNED;
|
196
|
|
197
|
when "101011" => --SLTU r[rd]=u[rs]<u[rt];
|
198
|
c_source := C_FROM_ALU;
|
199
|
alu_function := ALU_LESS_THAN;
|
200
|
|
201
|
when "101101" => --DADDU r[rd]=r[rs]+u[rt];
|
202
|
c_source := C_FROM_ALU;
|
203
|
alu_function := ALU_ADD;
|
204
|
|
205
|
--when "110001" => --TGEU
|
206
|
--when "110010" => --TLT
|
207
|
--when "110011" => --TLTU
|
208
|
--when "110100" => --TEQ
|
209
|
--when "110110" => --TNE
|
210
|
when others =>
|
211
|
end case;
|
212
|
|
213
|
when "000001" => --REGIMM
|
214
|
rt := "000000";
|
215
|
rd := "011111";
|
216
|
a_source := A_FROM_PC;
|
217
|
b_source := B_FROM_IMMX4;
|
218
|
alu_function := ALU_ADD;
|
219
|
pc_source := FROM_BRANCH;
|
220
|
branch_function := BRANCH_GTZ;
|
221
|
--if(test) pc=pc+imm*4
|
222
|
|
223
|
case rtx is
|
224
|
when "10000" => --BLTZAL r[31]=s->pc_next; branch=r[rs]<0;
|
225
|
c_source := C_FROM_PC_PLUS4;
|
226
|
branch_function := BRANCH_LTZ;
|
227
|
|
228
|
when "00000" => --BLTZ branch=r[rs]<0;
|
229
|
branch_function := BRANCH_LTZ;
|
230
|
|
231
|
when "10001" => --BGEZAL r[31]=s->pc_next; branch=r[rs]>=0;
|
232
|
c_source := C_FROM_PC_PLUS4;
|
233
|
branch_function := BRANCH_GEZ;
|
234
|
|
235
|
when "00001" => --BGEZ branch=r[rs]>=0;
|
236
|
branch_function := BRANCH_GEZ;
|
237
|
|
238
|
--when "10010" => --BLTZALL r[31]=s->pc_next; lbranch=r[rs]<0;
|
239
|
--when "00010" => --BLTZL lbranch=r[rs]<0;
|
240
|
--when "10011" => --BGEZALL r[31]=s->pc_next; lbranch=r[rs]>=0;
|
241
|
--when "00011" => --BGEZL lbranch=r[rs]>=0;
|
242
|
|
243
|
when others =>
|
244
|
end case;
|
245
|
|
246
|
when "000011" => --JAL r[31]=s->pc_next; s->pc_next=(s->pc&0xf0000000)|target;
|
247
|
c_source := C_FROM_PC_PLUS4;
|
248
|
rd := "011111";
|
249
|
pc_source := FROM_OPCODE25_0;
|
250
|
|
251
|
when "000010" => --J s->pc_next=(s->pc&0xf0000000)|target;
|
252
|
pc_source := FROM_OPCODE25_0;
|
253
|
|
254
|
when "000100" => --BEQ branch=r[rs]==r[rt];
|
255
|
a_source := A_FROM_PC;
|
256
|
b_source := B_FROM_IMMX4;
|
257
|
alu_function := ALU_ADD;
|
258
|
pc_source := FROM_BRANCH;
|
259
|
branch_function := BRANCH_EQ;
|
260
|
|
261
|
when "000101" => --BNE branch=r[rs]!=r[rt];
|
262
|
a_source := A_FROM_PC;
|
263
|
b_source := B_FROM_IMMX4;
|
264
|
alu_function := ALU_ADD;
|
265
|
pc_source := FROM_BRANCH;
|
266
|
branch_function := BRANCH_NE;
|
267
|
|
268
|
when "000110" => --BLEZ branch=r[rs]<=0;
|
269
|
a_source := A_FROM_PC;
|
270
|
b_source := b_FROM_IMMX4;
|
271
|
alu_function := ALU_ADD;
|
272
|
pc_source := FROM_BRANCH;
|
273
|
branch_function := BRANCH_LEZ;
|
274
|
|
275
|
when "000111" => --BGTZ branch=r[rs]>0;
|
276
|
a_source := A_FROM_PC;
|
277
|
b_source := B_FROM_IMMX4;
|
278
|
alu_function := ALU_ADD;
|
279
|
pc_source := FROM_BRANCH;
|
280
|
branch_function := BRANCH_GTZ;
|
281
|
|
282
|
when "001000" => --ADDI r[rt]=r[rs]+(short)imm;
|
283
|
b_source := B_FROM_SIGNED_IMM;
|
284
|
c_source := C_FROM_ALU;
|
285
|
rd := rt;
|
286
|
alu_function := ALU_ADD;
|
287
|
|
288
|
when "001001" => --ADDIU u[rt]=u[rs]+(short)imm;
|
289
|
b_source := B_FROM_SIGNED_IMM;
|
290
|
c_source := C_FROM_ALU;
|
291
|
rd := rt;
|
292
|
alu_function := ALU_ADD;
|
293
|
|
294
|
when "001010" => --SLTI r[rt]=r[rs]<(short)imm;
|
295
|
b_source := B_FROM_SIGNED_IMM;
|
296
|
c_source := C_FROM_ALU;
|
297
|
rd := rt;
|
298
|
alu_function := ALU_LESS_THAN_SIGNED;
|
299
|
|
300
|
when "001011" => --SLTIU u[rt]=u[rs]<(unsigned long)(short)imm;
|
301
|
b_source := B_FROM_SIGNED_IMM;
|
302
|
c_source := C_FROM_ALU;
|
303
|
rd := rt;
|
304
|
alu_function := ALU_LESS_THAN;
|
305
|
|
306
|
when "001100" => --ANDI r[rt]=r[rs]&imm;
|
307
|
b_source := B_FROM_IMM;
|
308
|
c_source := C_FROM_ALU;
|
309
|
rd := rt;
|
310
|
alu_function := ALU_AND;
|
311
|
|
312
|
when "001101" => --ORI r[rt]=r[rs]|imm;
|
313
|
b_source := B_FROM_IMM;
|
314
|
c_source := C_FROM_ALU;
|
315
|
rd := rt;
|
316
|
alu_function := ALU_OR;
|
317
|
|
318
|
when "001110" => --XORI r[rt]=r[rs]^imm;
|
319
|
b_source := B_FROM_IMM;
|
320
|
c_source := C_FROM_ALU;
|
321
|
rd := rt;
|
322
|
alu_function := ALU_XOR;
|
323
|
|
324
|
when "001111" => --LUI r[rt]=(imm<<16);
|
325
|
c_source := C_FROM_IMM_SHIFT16;
|
326
|
rd := rt;
|
327
|
|
328
|
when "010000" => --COP0
|
329
|
alu_function := ALU_OR;
|
330
|
c_source := C_FROM_ALU;
|
331
|
if opcode(23) = '0' then --move from CP0
|
332
|
rs := '1' & opcode(15 downto 11);
|
333
|
rt := "000000";
|
334
|
rd := '0' & opcode(20 downto 16);
|
335
|
else --move to CP0
|
336
|
rs := "000000";
|
337
|
rd(5) := '1';
|
338
|
pc_source := FROM_BRANCH; --delay possible interrupt
|
339
|
branch_function := BRANCH_NO;
|
340
|
end if;
|
341
|
|
342
|
--when "010001" => --COP1
|
343
|
--when "010010" => --COP2
|
344
|
--when "010011" => --COP3
|
345
|
--when "010100" => --BEQL lbranch=r[rs]==r[rt];
|
346
|
--when "010101" => --BNEL lbranch=r[rs]!=r[rt];
|
347
|
--when "010110" => --BLEZL lbranch=r[rs]<=0;
|
348
|
--when "010111" => --BGTZL lbranch=r[rs]>0;
|
349
|
|
350
|
when "100000" => --LB r[rt]=*(signed char*)ptr;
|
351
|
a_source := A_FROM_REG_SOURCE;
|
352
|
b_source := B_FROM_SIGNED_IMM;
|
353
|
alu_function := ALU_ADD;
|
354
|
rd := rt;
|
355
|
c_source := C_FROM_MEMORY;
|
356
|
mem_source := MEM_READ8S; --address=(short)imm+r[rs];
|
357
|
|
358
|
when "100001" => --LH r[rt]=*(signed short*)ptr;
|
359
|
a_source := A_FROM_REG_SOURCE;
|
360
|
b_source := B_FROM_SIGNED_IMM;
|
361
|
alu_function := ALU_ADD;
|
362
|
rd := rt;
|
363
|
c_source := C_FROM_MEMORY;
|
364
|
mem_source := MEM_READ16S; --address=(short)imm+r[rs];
|
365
|
|
366
|
when "100010" => --LWL //Not Implemented
|
367
|
a_source := A_FROM_REG_SOURCE;
|
368
|
b_source := B_FROM_SIGNED_IMM;
|
369
|
alu_function := ALU_ADD;
|
370
|
rd := rt;
|
371
|
c_source := C_FROM_MEMORY;
|
372
|
mem_source := MEM_READ32;
|
373
|
|
374
|
when "100011" => --LW r[rt]=*(long*)ptr;
|
375
|
a_source := A_FROM_REG_SOURCE;
|
376
|
b_source := B_FROM_SIGNED_IMM;
|
377
|
alu_function := ALU_ADD;
|
378
|
rd := rt;
|
379
|
c_source := C_FROM_MEMORY;
|
380
|
mem_source := MEM_READ32;
|
381
|
|
382
|
when "100100" => --LBU r[rt]=*(unsigned char*)ptr;
|
383
|
a_source := A_FROM_REG_SOURCE;
|
384
|
b_source := B_FROM_SIGNED_IMM;
|
385
|
alu_function := ALU_ADD;
|
386
|
rd := rt;
|
387
|
c_source := C_FROM_MEMORY;
|
388
|
mem_source := MEM_READ8; --address=(short)imm+r[rs];
|
389
|
|
390
|
when "100101" => --LHU r[rt]=*(unsigned short*)ptr;
|
391
|
a_source := A_FROM_REG_SOURCE;
|
392
|
b_source := B_FROM_SIGNED_IMM;
|
393
|
alu_function := ALU_ADD;
|
394
|
rd := rt;
|
395
|
c_source := C_FROM_MEMORY;
|
396
|
mem_source := MEM_READ16; --address=(short)imm+r[rs];
|
397
|
|
398
|
--when "100110" => --LWR //Not Implemented
|
399
|
|
400
|
when "101000" => --SB *(char*)ptr=(char)r[rt];
|
401
|
a_source := A_FROM_REG_SOURCE;
|
402
|
b_source := B_FROM_SIGNED_IMM;
|
403
|
alu_function := ALU_ADD;
|
404
|
mem_source := MEM_WRITE8; --address=(short)imm+r[rs];
|
405
|
|
406
|
when "101001" => --SH *(short*)ptr=(short)r[rt];
|
407
|
a_source := A_FROM_REG_SOURCE;
|
408
|
b_source := B_FROM_SIGNED_IMM;
|
409
|
alu_function := ALU_ADD;
|
410
|
mem_source := MEM_WRITE16;
|
411
|
|
412
|
when "101010" => --SWL //Not Implemented
|
413
|
a_source := A_FROM_REG_SOURCE;
|
414
|
b_source := B_FROM_SIGNED_IMM;
|
415
|
alu_function := ALU_ADD;
|
416
|
mem_source := MEM_WRITE32; --address=(short)imm+r[rs];
|
417
|
|
418
|
when "101011" => --SW *(long*)ptr=r[rt];
|
419
|
a_source := A_FROM_REG_SOURCE;
|
420
|
b_source := B_FROM_SIGNED_IMM;
|
421
|
alu_function := ALU_ADD;
|
422
|
mem_source := MEM_WRITE32; --address=(short)imm+r[rs];
|
423
|
|
424
|
--when "101110" => --SWR //Not Implemented
|
425
|
--when "101111" => --CACHE
|
426
|
--when "110000" => --LL r[rt]=*(long*)ptr;
|
427
|
--when "110001" => --LWC1
|
428
|
--when "110010" => --LWC2
|
429
|
--when "110011" => --LWC3
|
430
|
--when "110101" => --LDC1
|
431
|
--when "110110" => --LDC2
|
432
|
--when "110111" => --LDC3
|
433
|
--when "111000" => --SC *(long*)ptr=r[rt]; r[rt]=1;
|
434
|
--when "111001" => --SWC1
|
435
|
--when "111010" => --SWC2
|
436
|
--when "111011" => --SWC3
|
437
|
--when "111101" => --SDC1
|
438
|
--when "111110" => --SDC2
|
439
|
--when "111111" => --SDC3
|
440
|
when others =>
|
441
|
end case;
|
442
|
|
443
|
if c_source = C_FROM_NULL then
|
444
|
rd := "000000";
|
445
|
end if;
|
446
|
|
447
|
if intr_signal = '1' or is_syscall = '1' then
|
448
|
rs := "111111"; --interrupt vector
|
449
|
rt := "000000";
|
450
|
rd := "101110"; --save PC in EPC
|
451
|
alu_function := ALU_OR;
|
452
|
shift_function := SHIFT_NOTHING;
|
453
|
mult_function := MULT_NOTHING;
|
454
|
branch_function := BRANCH_YES;
|
455
|
a_source := A_FROM_REG_SOURCE;
|
456
|
b_source := B_FROM_REG_TARGET;
|
457
|
c_source := C_FROM_PC;
|
458
|
pc_source := FROM_LBRANCH;
|
459
|
mem_source := MEM_FETCH;
|
460
|
exception_out <= '1';
|
461
|
else
|
462
|
exception_out <= '0';
|
463
|
end if;
|
464
|
|
465
|
rs_index <= rs;
|
466
|
rt_index <= rt;
|
467
|
rd_index <= rd;
|
468
|
imm_out <= imm;
|
469
|
alu_func <= alu_function;
|
470
|
shift_func <= shift_function;
|
471
|
mult_func <= mult_function;
|
472
|
branch_func <= branch_function;
|
473
|
a_source_out <= a_source;
|
474
|
b_source_out <= b_source;
|
475
|
c_source_out <= c_source;
|
476
|
pc_source_out <= pc_source;
|
477
|
mem_source_out <= mem_source;
|
478
|
|
479
|
end process;
|
480
|
|
481
|
end; --logic
|
482
|
|