-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProcessor.java
More file actions
598 lines (593 loc) · 21.9 KB
/
Processor.java
File metadata and controls
598 lines (593 loc) · 21.9 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
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
public class Processor {
// UNCHANGED VALS
private static final Bit T = new Bit(true);
private static final Bit F = new Bit(false);
private static final Word32 BLANK = new Word32();
private static final Word32 ONE = new Word32(new Bit[]{F, F, F, F, F, F, F, F, F, F,F, F, F, F, F, F, F, F, F, F,F, F, F, F, F, F, F, F, F, F,F,T});
private static final Word32 EIGHT = new Word32(new Bit[]{F, F, F, F, F, F, F, F, F, F,F, F, F, F, F, F, F, F, F, F,F, F, F, F, F, F, F, F, T, F,F,F});
private static final Word16 RETURN = new Word16(new Bit[]{F,T,F,T,F});
private static final Word16 LOAD = new Word16(new Bit[]{T,F,F,T,F});
private static final Word16 SYSCALL = new Word16(new Bit[]{F,T,F,F,F});
private static final Word16 MULTIPLY = new Word16(new Bit[]{F,F,F,T,T});
private static final Word16 BNE = new Word16(new Bit[]{T,F,F,F,T});
private static final Word16 CALL = new Word16(new Bit[]{F,T,F,F,T});
private static final Word16 COPY = new Word16(new Bit[]{T,F,T,F,F});
private static final Word16 STORE = new Word16(new Bit[]{T,F,F,T,T});
private static final LinkedList<String>OpCodesFormat = new LinkedList<>(Arrays.asList(
"f,f,f,f,t", // add
"f,f,f,t,f", // and
"f,f,f,t,t", // multiply
"f,f,t,f,f", // leftshift
"f,f,t,f,t", // subtract
"f,f,t,t,f", // or
"f,f,t,t,t", // rightshift
"f,t,f,t,t" // compare
));
private static final LinkedList<String>NONALUOpCodesFormat = new LinkedList<>(Arrays.asList(
"t,f,f,t,f", // load
"t,f,f,t,t", // store
"t,f,t,f,f" // copy
));
// Memory class
private Memory mem;
// Read only l1 cache
private InstructionCache l1 = new InstructionCache();
// Read/Write only l2 cache
private L2Cache l2 = new L2Cache();
// ALU class
private ALU alu = new ALU();
// Storage for registers
private LinkedList<Word32> Registers = new LinkedList<>();
// Storage for instructions
private LinkedList<Word16> Instructions = new LinkedList<Word16>();
private LinkedList<Word32> Saved_Addr = new LinkedList<Word32>();
// Storage for output
public List<String> output = new LinkedList<>();
// PC keeps track of instructions present
private Word32 PC = new Word32();
// Instruction keeps track of current instruction
private Word16 Instruction = new Word16();
// OP1 & OP2 used for various op formatted instructs.
private Word32 OP1 = new Word32();
private Word32 OP2 = new Word32();
// CURR_ADDR used to store the current address in memory
private Word32 CURR_ADDR = new Word32();
// CallReturnVal used for various CallReturn formatted instructs
private Word32 CallReturnVal = new Word32();
// isHalt used to pause program
private boolean isHalt = false;
// is2R checks to see the format of the instruction
private boolean is2R = false;
// skipIteration skips the current iteration if need be
private boolean skipIteration = false;
// isReturn checks if return is called.
private boolean isReturn = false;
// Clock cycle tracker
private int CURRENT_CLOCK_CYCLE = 0;
// Constructor for Processor
public Processor(Memory m) {
// Set up memory
mem = m;
// Set up Registers
for(int i = 0; i < 32; i++)
Registers.add(new Word32());
}
public void run() {
// Clear mem.address in case it still has stuff in it
BLANK.copy(mem.address);
while(!isHalt){
// If PC is even, then call fetch
fetch();
// While instructions, and no other booleans are true, iterate thru loop,
// go thru decode execute & store as normally.
while(!Instructions.isEmpty() && !skipIteration && !isReturn) {
// Pop instruction from instructions stack.
Instruction = Instructions.pop();
decode();
// if halt, then break
if (isHalt)
break;
// if isReturn, then clear instructions and break
else if(isReturn){
EmptyInstructions();
break;
}
execute();
// Breaks if skipIteration is true
if(skipIteration){
EmptyInstructions();
break;
}
store();
}
// if not skipping, att one to PC
if(!skipIteration && !isReturn){
Word32 PCCopy = new Word32();
PC.copy(PCCopy);
Adder.add(PCCopy, ONE, PC);
}
// if isReturn, then remove the first of the saved addresses and copy it to pc
// read mem afterwards for proper fetching.
if(isReturn){
Saved_Addr.remove(0).copy(PC);
PC.copy(mem.address);
}
skipIteration = false;
isReturn = false;
}
}
private void fetch() {
Word32 instructs = new Word32();
// If mem.address is not in l1 range, check l2 range
if(!l1.checkIfInRange(mem.address)){
// If l2 addr range fails, send mem to l2
if(!l2.checkIfInAddr(getBaseNumber(mem.address))){
SendMemValsToL2(mem.address);
CURRENT_CLOCK_CYCLE += 350;
}
// Send l2 to l1 to fetch instructions faster
SendL2ValsToL1(mem.address);
CURRENT_CLOCK_CYCLE += 50;
CURRENT_CLOCK_CYCLE += 20;
}
else
CURRENT_CLOCK_CYCLE += 10;
// Reads memory.
mem.address.copy(l1.address);
l1.read();
l1.value.copy(instructs);
// Get both instructions from word
Word16 getInstruct1 = new Word16();
Word16 getInstruct2 = new Word16();
instructs.getTopHalf(getInstruct1);
instructs.getBottomHalf(getInstruct2);
// Add both instructions to linkedList
Instructions.add(getInstruct1);
Instructions.add(getInstruct2);
// Add 1 to memory address to read from next address
Word32 memCpy = new Word32();
mem.address.copy(memCpy);
Adder.add(memCpy, ONE, mem.address);
}
private void decode() {
// fullInstruct & instruct to keep track of instructions.
String fullInstruct = Instruction.toString();
String instruct = fullInstruct.substring(0,9);
BLANK.copy(OP1);
BLANK.copy(OP2);
// Checks if halt
if(Instruction.equals(new Word16(), 5))
isHalt = true;
// Checks for return, if true then address to saved address
else if(Instruction.equals(RETURN, 5)){
Word32 newAddr = new Word32();
PC.copy(newAddr);
Saved_Addr.add(newAddr);
isReturn = true;
}
else{
// Checks if format 2R/Immediate or Call/Return
if(OpCodesFormat.contains(instruct) || NONALUOpCodesFormat.contains(fullInstruct.substring(0,9))){
is2R = true;
Bit b = new Bit(false);
Instruction.getBitN(5, b);
// Checks if format is immediate
if(b.getValue() == Bit.boolValues.TRUE){
GenerateImmediateVal(Instruction).copy(OP1);
RetrieveValFromRegister(Instruction, 1).copy(OP2);
}
// Else check if 2r.
else{
RetrieveValFromRegister(Instruction, 0).copy(OP1);
RetrieveValFromRegister(Instruction, 1).copy(OP2);
}
}
// If call/return format
else{
is2R = false;
GenerateCallReturnValue(Instruction).copy(CallReturnVal);
}
}
}
private void execute() {
String fullInstruct = Instruction.toString();
String instruct = fullInstruct.substring(0,9);
// If format is 2R
if(is2R){
// If instruction is in ALU
if(OpCodesFormat.contains(instruct)){
Instruction.copy(alu.instruction);
OP2.copy(alu.op1);
OP1.copy(alu.op2);
if(Instruction.equals(MULTIPLY, 5))
CURRENT_CLOCK_CYCLE += 10;
else
CURRENT_CLOCK_CYCLE += 2;
//
alu.doInstruction();
}
// if load
else if(Instruction.equals(LOAD, 5))
RetrieveVal(OP1, OP2);
}
else{
// If equals syscall
if(Instruction.equals(SYSCALL, 5)){
Bit b = new Bit(false);
CallReturnVal.getBitN(31, b);
SendAllL2ValsToMem();
if(b.getValue() == Bit.boolValues.TRUE){
printMem();
}
else
printReg();
}
// If equals bne
else if(Instruction.equals(BNE, 5)){
// If immediate, then check msb, make necessary changes to address (by adding or subtracting),
// then modify and adjust PC while updating the new memory value.
if(alu.equal.getValue() == Bit.boolValues.FALSE){
Word32 res = new Word32();
Bit msb = new Bit(false);
CallReturnVal.getBitN(0,msb);
if(msb.getValue() == Bit.boolValues.TRUE){
Word32 Positive = new Word32();
CallReturnVal.not(Positive);
Word32 AddOne = new Word32();
Adder.add(Positive, ONE, AddOne);
Adder.subtract(PC, AddOne, res);
}
else
Adder.add(PC, CallReturnVal, res);
res.copy(PC);
PC.copy(mem.address);
skipIteration = true;
}
}
// call
else if(Instruction.equals(CALL ,5)){
pushAddr(CallReturnVal);
}
}
}
private void printReg() {
for (int i = 0; i < 32; i++) {
var line = "r"+ i + ":" + Registers.get(i);
output.add(line);
System.out.println(line);
}
System.out.println("Total clock cycles: " + CURRENT_CLOCK_CYCLE);
}
private void printMem() {
for (int i = 0; i < 350; i++) {
Word32 addr = new Word32();
Word32 value = new Word32();
int n = i;
int k = 31;
while(n > 0){
if(n % 2 != 0)
addr.setBitN(k, new Bit(true));
else
addr.setBitN(k, new Bit(false));
n /= 2;
k--;
}
addr.copy(mem.address);
mem.read();
mem.value.copy(value);
var line = i + ":" + value;
output.add(line);
System.out.println(line);
}
System.out.println("Total clock cycles: " + CURRENT_CLOCK_CYCLE);
}
private void store() {
String fullInstruct = Instruction.toString();
if(is2R){
// If calculation is complete, send to register with ALU result.
if(OpCodesFormat.contains(fullInstruct.substring(0,9)) && !Instruction.equals(ALU.COMPARE, 5))
SendValToRegister(Instruction, alu.result);
// If copy, then send value in 2r or immediate formatting.
else if(Instruction.equals(COPY, 5)){
Bit b = new Bit(false);
Instruction.getBitN(5, b);
if(b.getValue() == Bit.boolValues.TRUE)
SendValToRegister(Instruction, OP1);
else
SendAlternateValToRegister(OP1);
}
// Send val to memory if store.
else if(Instruction.equals(STORE, 5)){
SendVal(Instruction);
}
}
}
// Helper methods:
// Generate an immediate value as a word32 for input.
private Word32 GenerateImmediateVal(Word16 inp){
Word32 FIN_VAL = new Word32();
Bit signBit = new Bit(false);
inp.getBitN(6, signBit);
for(int i = 0; i < 5; i++){
Bit B = new Bit(false);
inp.getBitN(10 - i, B);
FIN_VAL.setBitN(31 - i, B);
}
if(signBit.getValue() == Bit.boolValues.TRUE){
for(int i = 0; i < 27; i++)
FIN_VAL.setBitN(i, new Bit(true));
}
return FIN_VAL;
}
// Retrieve value from register, depending on the choice it can depend
// on the index in which the user wants (first or second).
private Word32 RetrieveValFromRegister(Word16 inp, int choice){
int start = 10;
if(choice == 1 || choice == 2)
start = 15;
int end = start - 5;
return Registers.get(generateIndex(inp, start, end));
}
// Generate Index creates a index generated in the WOrd16 instruction.
private int generateIndex(Word16 inp, int start, int end){
Word32 num = new Word32();
Bit b = new Bit(false);
int i = 0;
while(end < start){
inp.getBitN(start, b);
num.setBitN(31-i, b);
i++;
start--;
}
Word32 iterator = new Word32();
int fin = 0;
while(!iterator.equals(num)) {
Word32 temp = new Word32();
iterator.copy(temp);
fin++;
Adder.add(temp, ONE, iterator);
}
return fin;
}
// sendVal to register takes the value of a word and sends it to a register address.
private void SendValToRegister(Word16 addr, Word32 val){
int start = 15;
val.copy(Registers.get(generateIndex(addr, start, start-5)));
}
// In cases where an address val is being sent to another address val, this
// is done instead. It simply takes the instruction address and uses it inplace
// to then send it to the value.
private void SendAlternateValToRegister(Word32 op1){
int start = 15;
Word16 Bot = new Word16();
Instruction.copy(Bot);
op1.copy(Registers.get(generateIndex(Bot, start, start-5)));
}
// GenerateCallReturnValue simply generates a call return value depending on input.
private Word32 GenerateCallReturnValue(Word16 inp){
Word32 FIN_VAL = new Word32();
Bit signBit = new Bit(false);
inp.getBitN(6, signBit);
Bit C = new Bit(false);
int n = 0;
for(int i = 15; i > 5; i--){
inp.getBitN(i,C);
FIN_VAL.setBitN(31-n,C);
n++;
}
if(signBit.getValue() == Bit.boolValues.TRUE){
for(int i = 0; i < 22; i++)
FIN_VAL.setBitN(i, new Bit(true));
}
return FIN_VAL;
}
// pushAddr takes the address and pushes the next address into saved addresses.
// it then reacts from memory the current address.
private void pushAddr(Word32 dest){
Word32 cp = new Word32();
PC.copy(cp);
Word32 S_ADD = new Word32();
Adder.add(cp, ONE, S_ADD);
Saved_Addr.add(S_ADD);
Word32 res = new Word32();
Adder.add(PC, dest, res);
res.copy(PC);
PC.copy(mem.address);
skipIteration = true;
}
// Empties out instructions.
public void EmptyInstructions(){
while(!Instructions.isEmpty())
Instructions.pop();
}
// ASSIGNMENT 6 METHODS
private Word32 getBaseNumber(Word32 inp){
Word32 cp = new Word32();
inp.copy(cp);
Word32 curr = new Word32();
cp.copy(curr);
while(!curr.checkLast3(BLANK)){
Adder.subtract(cp, ONE, curr);
curr.copy(cp);
}
return cp;
}
// SendL2Vals to L1 copies l2 at address input. Creates an array of Word32 and then inputs it to instructionCache.
public void SendL2ValsToL1(Word32 address){
Word32 base = new Word32();
getBaseNumber(address).copy(base);
base.copy(l1.baseAddress);
base.copy(l2.baseAddress);
Word32[] arr = new Word32[8];
for(int i = 0; i < 8; i++)
arr[i] = new Word32();
Word32 start = new Word32();
base.copy(start);
Word32 end = new Word32();
Adder.add(start, EIGHT, end);
Word32 cp = new Word32();
start.copy(cp);
int i = 0;
while(!start.equals(end)){
start.copy(l2.address);
l2.read();
l2.value.copy(arr[i]);
Adder.add(start, ONE, cp);
cp.copy(start);
i++;
}
l1.configureL1(arr);
}
// SendMemValsToL2 inputs address to mem, gets base address, and then gets the 8 addresses afterwards into l2 from mem.
public void SendMemValsToL2(Word32 address){
Word32 base = new Word32();
getBaseNumber(address).copy(base);
l2.addAddr(base);
base.copy(l2.baseAddress);
mem.address.copy(CURR_ADDR);
Word32[] arr = new Word32[8];
for(int i = 0; i < 8; i++)
arr[i] = new Word32();
Word32 start = new Word32();
base.copy(start);
Word32 end = new Word32();
Adder.add(start, EIGHT, end);
Word32 cp = new Word32();
start.copy(cp);
int i = 0;
while(!start.equals(end)){
start.copy(mem.address);
mem.read();
mem.value.copy(arr[i]);
Adder.add(start, ONE, cp);
cp.copy(start);
i++;
}
l2.configureL2(base, arr);
CURR_ADDR.copy(mem.address);
}
// RetrieveVal adds op1 and op2 then takes it from l2, it will then retrieve it from mem if a miss occurs.
private void RetrieveVal(Word32 OP1, Word32 OP2){
CURRENT_CLOCK_CYCLE += 20;
Word32 addr = new Word32();
Word32 o1C = new Word32();
Word32 o2C = new Word32();
OP1.copy(o1C);
OP2.copy(o2C);
Bit MSB = new Bit(false);
OP1.getBitN(0, MSB);
if(MSB.getValue() == Bit.boolValues.FALSE)
Adder.add(o1C, o2C, addr);
else {
Word32 subtract = new Word32();
OP1.not(subtract);
Word32 positive = new Word32();
Adder.add(subtract, ONE, positive);
Adder.subtract(o2C,positive ,addr);
}
// Retrieve from L2
Word32 base = new Word32();
getBaseNumber(addr).copy(base);
// If not in L2, call Retrieve from mem to L2
if(!l2.checkIfInAddr(base)){
SendMemValsToL2(addr);
CURRENT_CLOCK_CYCLE += 350;
}
if(checkIfDegraded(base)){
SendL2ValsToMem(addr);
CURRENT_CLOCK_CYCLE += 50;
}
// Retrieve from L2
base.copy(l2.baseAddress);
addr.copy(l2.address);
l2.read();
l2.value.copy(Registers.get(generateIndex(Instruction, 15, 10)));
}
// Check if degraded checks if there's any differences between l2 cache and mem based on a base address.
public boolean checkIfDegraded(Word32 baseAddress){
if(baseAddress.equals(l2.NEGONE)){
return false;
}
mem.address.copy(CURR_ADDR);
Word32 start = new Word32();
Word32 end = new Word32();
Word32 cp = new Word32();
baseAddress.copy(start);
baseAddress.copy(cp);
baseAddress.copy(l2.baseAddress);
Adder.add(start, EIGHT, end);
while(!start.equals(end)){
start.copy(mem.address);
start.copy(l2.address);
mem.read();
l2.read();
if(!mem.value.equals(l2.value)){
CURR_ADDR.copy(mem.address);
return true;
}
Adder.add(start, ONE, cp);
cp.copy(start);
}
CURR_ADDR.copy(mem.address);
return false;
}
// SendVal checks if l2 is full, evicts an edited value, and then edits the cache within l2.
public void SendVal(Word16 inp){
CURRENT_CLOCK_CYCLE += 20;
if(l2.isFull())
SendFirstL2ValToMem();
Registers.get(generateIndex(inp,15,10)).copy(l2.address);
Word32 base = new Word32();
getBaseNumber(l2.address).copy(base);
base.copy(l2.baseAddress);
if(!l2.checkIfInAddr(base)){
l2.addAddr(base);
SendMemValsToL2(base);
CURRENT_CLOCK_CYCLE += 350;
}
OP1.copy(l2.value);
l2.write();
CURRENT_CLOCK_CYCLE += 50;
}
// SendL2Vals to mem gets the base address, generates an array of Word32's, and then writes to mem.
public void SendL2ValsToMem(Word32 addr){
Word32 base = new Word32();
getBaseNumber(addr).copy(base);
Word32[] vals = l2.getValuesBy(base);
mem.address.copy(CURR_ADDR);
Word32 cp = new Word32();
base.copy(cp);
for(int i = 0; i < vals.length; i++){
base.copy(mem.address);
vals[i].copy(mem.value);
mem.write();
Adder.add(base, ONE, cp);
cp.copy(base);
}
CURR_ADDR.copy(mem.address);
}
// Method which sends all values from l2 to mem at the end of the program.
public void SendAllL2ValsToMem(){
Word32 base = new Word32();
for(int i = 0; i < 4; i++){
l2.getBaseBy(i).copy(base);
if(checkIfDegraded(base))
SendL2ValsToMem(base);
}
}
// Sends the first L2 val list to memory. Used for cache eviction
public int SendFirstL2ValToMem(){
Word32 base = new Word32();
for(int i = 0; i < 4; i++){
l2.getBaseBy(i).copy(base);
if(checkIfDegraded(base)){
SendL2ValsToMem(base);
return i;
}
}
return -1;
}
}