OpenCores
URL https://opencores.org/ocsvn/eco32/eco32/trunk

Subversion Repositories eco32

[/] [eco32/] [trunk/] [sim/] [cpu.c] - Blame information for rev 212

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 8 hellwig
/*
2
 * cpu.c -- CPU simulation
3
 */
4
 
5
 
6
#include <stdio.h>
7
#include <stdlib.h>
8
#include <string.h>
9
#include <setjmp.h>
10
 
11
#include "common.h"
12
#include "console.h"
13
#include "error.h"
14
#include "except.h"
15
#include "instr.h"
16
#include "cpu.h"
17
#include "mmu.h"
18
#include "timer.h"
19
 
20
 
21
/**************************************************************/
22
 
23
 
24
#define RR(n)           r[n]
25
#define WR(n,d)         ((void) ((n) != 0 ? r[n] = (d) : (d)))
26
 
27
#define V               (psw & PSW_V)
28
#define UM              (psw & PSW_UM)
29
#define PUM             (psw & PSW_PUM)
30
#define OUM             (psw & PSW_OUM)
31
#define IE              (psw & PSW_IE)
32
#define PIE             (psw & PSW_PIE)
33
#define OIE             (psw & PSW_OIE)
34
 
35
 
36
/**************************************************************/
37
 
38
 
39
static Bool debugIRQ = false;   /* set to true if debugging IRQs */
40
 
41
static Word pc;                 /* program counter */
42
static Word psw;                /* processor status word */
43
static Word r[32];              /* general purpose registers */
44
 
45
static unsigned irqPending;     /* one bit for each pending IRQ */
46
 
47
static Bool breakSet;           /* breakpoint set if true */
48
static Word breakAddr;          /* if breakSet, this is where */
49
 
50
static Word total;              /* counts total number of instrs */
51
 
52
static Bool run;                /* CPU runs continuously if true */
53
 
54
static Word startAddr;          /* start of ROM (or start of RAM, */
55
                                /* in case a program was loaded) */
56
 
57
 
58
/**************************************************************/
59
 
60
 
61
static void handleInterrupts(void) {
62
  unsigned irqMask;
63
  unsigned irqSeen;
64
  int priority;
65
 
66
  /* handle exceptions and interrupts */
67
  if (irqPending == 0) {
68
    /* no exception or interrupt pending */
69
    return;
70
  }
71
  /* at least one exception or interrupt is pending */
72
  irqMask = ~PSW_IRQ_MASK | (psw & PSW_IRQ_MASK);
73
  if (debugIRQ) {
74
    cPrintf("**** IRQ  = 0x%08X ****\n", irqPending);
75
    cPrintf("**** MASK = 0x%08X ****\n", irqMask);
76
  }
77
  irqSeen = irqPending & irqMask;
78
  if (irqSeen == 0) {
79
    /* none that gets through */
80
    return;
81
  }
82
  /* determine the one with the highest priority */
83
  for (priority = 31; priority >= 0; priority--) {
84
    if ((irqSeen & ((unsigned) 1 << priority)) != 0) {
85
      /* highest priority among visible ones found */
86
      break;
87
    }
88
  }
89
  /* acknowledge exception, or interrupt if enabled */
90
  if (priority >= 16 || IE != 0) {
91
    if (priority >= 16) {
92
      /* clear corresponding bit in irqPending vector */
93
      /* only done for exceptions, since interrupts are level-sensitive */
94
      irqPending &= ~((unsigned) 1 << priority);
95
    }
96
    /* copy and reset interrupt enable bit in PSW */
97
    if (PIE != 0) {
98
      psw |= PSW_OIE;
99
    } else {
100
      psw &= ~PSW_OIE;
101
    }
102
    if (IE != 0) {
103
      psw |= PSW_PIE;
104
    } else {
105
      psw &= ~PSW_PIE;
106
    }
107
    psw &= ~PSW_IE;
108
    /* copy and reset user mode enable bit in PSW */
109
    if (PUM != 0) {
110
      psw |= PSW_OUM;
111
    } else {
112
      psw &= ~PSW_OUM;
113
    }
114
    if (UM != 0) {
115
      psw |= PSW_PUM;
116
    } else {
117
      psw &= ~PSW_PUM;
118
    }
119
    psw &= ~PSW_UM;
120
    /* reflect priority in PSW */
121
    psw &= ~PSW_PRIO_MASK;
122
    psw |= priority << PSW_PRIO_SHFT;
123
    /* save interrupt return address and start service routine */
124
    WR(30, pc);
125
    if (V == 0) {
126
      /* exceptions and interrupts are vectored to ROM */
127
      pc = 0xC0000000 | ROM_BASE;
128
    } else {
129
      /* exceptions and interrupts are vectored to RAM */
130
      pc = 0xC0000000;
131
    }
132
    if (priority == EXC_TLB_MISS &&
133
        (mmuGetBadAddr() & 0x80000000) == 0) {
134
      /* user TLB miss exception */
135
      pc |= 0x00000008;
136
    } else {
137
      /* any other exception or interrupt */
138
      pc |= 0x00000004;
139
    }
140
  }
141
}
142
 
143
 
144
static void execNextInstruction(void) {
145
  Word instr;
146
  Word next;
147
  int op, reg1, reg2, reg3;
148
  Half immed;
149
  Word offset;
150
  int scnt;
151
  Word smsk;
152
  Word aux;
153
 
154
  /* count the instruction */
155
  total++;
156
  /* fetch the instruction */
157
  instr = mmuReadWord(pc, UM);
158
  /* decode the instruction */
159
  op = (instr >> 26) & 0x3F;
160
  reg1 = (instr >> 21) & 0x1F;
161
  reg2 = (instr >> 16) & 0x1F;
162
  reg3 = (instr >> 11) & 0x1F;
163
  immed = instr & 0x0000FFFF;
164
  offset = instr & 0x03FFFFFF;
165
  next = pc + 4;
166
  /* execute the instruction */
167
  switch (op) {
168
    case OP_ADD:
169
      WR(reg3, (signed int) RR(reg1) + (signed int) RR(reg2));
170
      break;
171
    case OP_ADDI:
172
      WR(reg2, (signed int) RR(reg1) + (signed int) SEXT16(immed));
173
      break;
174
    case OP_SUB:
175
      WR(reg3, (signed int) RR(reg1) - (signed int) RR(reg2));
176
      break;
177
    case OP_SUBI:
178
      WR(reg2, (signed int) RR(reg1) - (signed int) SEXT16(immed));
179
      break;
180
    case OP_MUL:
181
      WR(reg3, (signed int) RR(reg1) * (signed int) RR(reg2));
182
      break;
183
    case OP_MULI:
184
      WR(reg2, (signed int) RR(reg1) * (signed int) SEXT16(immed));
185
      break;
186
    case OP_MULU:
187
      WR(reg3, RR(reg1) * RR(reg2));
188
      break;
189
    case OP_MULUI:
190
      WR(reg2, RR(reg1) * ZEXT16(immed));
191
      break;
192
    case OP_DIV:
193
      if (RR(reg2) == 0) {
194
        throwException(EXC_DIVIDE);
195
      }
196
      WR(reg3, (signed int) RR(reg1) / (signed int) RR(reg2));
197
      break;
198
    case OP_DIVI:
199
      if (SEXT16(immed) == 0) {
200
        throwException(EXC_DIVIDE);
201
      }
202
      WR(reg2, (signed int) RR(reg1) / (signed int) SEXT16(immed));
203
      break;
204
    case OP_DIVU:
205
      if (RR(reg2) == 0) {
206
        throwException(EXC_DIVIDE);
207
      }
208
      WR(reg3, RR(reg1) / RR(reg2));
209
      break;
210
    case OP_DIVUI:
211
      if (SEXT16(immed) == 0) {
212
        throwException(EXC_DIVIDE);
213
      }
214
      WR(reg2, RR(reg1) / ZEXT16(immed));
215
      break;
216
    case OP_REM:
217
      if (RR(reg2) == 0) {
218
        throwException(EXC_DIVIDE);
219
      }
220
      WR(reg3, (signed int) RR(reg1) % (signed int) RR(reg2));
221
      break;
222
    case OP_REMI:
223
      if (SEXT16(immed) == 0) {
224
        throwException(EXC_DIVIDE);
225
      }
226
      WR(reg2, (signed int) RR(reg1) % (signed int) SEXT16(immed));
227
      break;
228
    case OP_REMU:
229
      if (RR(reg2) == 0) {
230
        throwException(EXC_DIVIDE);
231
      }
232
      WR(reg3, RR(reg1) % RR(reg2));
233
      break;
234
    case OP_REMUI:
235
      if (SEXT16(immed) == 0) {
236
        throwException(EXC_DIVIDE);
237
      }
238
      WR(reg2, RR(reg1) % ZEXT16(immed));
239
      break;
240
    case OP_AND:
241
      WR(reg3, RR(reg1) & RR(reg2));
242
      break;
243
    case OP_ANDI:
244
      WR(reg2, RR(reg1) & ZEXT16(immed));
245
      break;
246
    case OP_OR:
247
      WR(reg3, RR(reg1) | RR(reg2));
248
      break;
249
    case OP_ORI:
250
      WR(reg2, RR(reg1) | ZEXT16(immed));
251
      break;
252
    case OP_XOR:
253
      WR(reg3, RR(reg1) ^ RR(reg2));
254
      break;
255
    case OP_XORI:
256
      WR(reg2, RR(reg1) ^ ZEXT16(immed));
257
      break;
258
    case OP_XNOR:
259
      WR(reg3, ~(RR(reg1) ^ RR(reg2)));
260
      break;
261
    case OP_XNORI:
262
      WR(reg2, ~(RR(reg1) ^ ZEXT16(immed)));
263
      break;
264
    case OP_SLL:
265
      scnt = RR(reg2) & 0x1F;
266
      WR(reg3, RR(reg1) << scnt);
267
      break;
268
    case OP_SLLI:
269
      scnt = immed & 0x1F;
270
      WR(reg2, RR(reg1) << scnt);
271
      break;
272
    case OP_SLR:
273
      scnt = RR(reg2) & 0x1F;
274
      WR(reg3, RR(reg1) >> scnt);
275
      break;
276
    case OP_SLRI:
277
      scnt = immed & 0x1F;
278
      WR(reg2, RR(reg1) >> scnt);
279
      break;
280
    case OP_SAR:
281
      scnt = RR(reg2) & 0x1F;
282
      smsk = (RR(reg1) & 0x80000000 ? ~(((Word) 0xFFFFFFFF) >> scnt) : 0);
283
      WR(reg3, smsk | (RR(reg1) >> scnt));
284
      break;
285
    case OP_SARI:
286
      scnt = immed & 0x1F;
287
      smsk = (RR(reg1) & 0x80000000 ? ~(((Word) 0xFFFFFFFF) >> scnt) : 0);
288
      WR(reg2, smsk | (RR(reg1) >> scnt));
289
      break;
290
    case OP_LDHI:
291
      WR(reg2, ZEXT16(immed) << 16);
292
      break;
293
    case OP_BEQ:
294
      if (RR(reg1) == RR(reg2)) {
295
        next += SEXT16(immed) << 2;
296
      }
297
      break;
298
    case OP_BNE:
299
      if (RR(reg1) != RR(reg2)) {
300
        next += SEXT16(immed) << 2;
301
      }
302
      break;
303
    case OP_BLE:
304
      if ((signed int) RR(reg1) <= (signed int) RR(reg2)) {
305
        next += SEXT16(immed) << 2;
306
      }
307
      break;
308
    case OP_BLEU:
309
      if (RR(reg1) <= RR(reg2)) {
310
        next += SEXT16(immed) << 2;
311
      }
312
      break;
313
    case OP_BLT:
314
      if ((signed int) RR(reg1) < (signed int) RR(reg2)) {
315
        next += SEXT16(immed) << 2;
316
      }
317
      break;
318
    case OP_BLTU:
319
      if (RR(reg1) < RR(reg2)) {
320
        next += SEXT16(immed) << 2;
321
      }
322
      break;
323
    case OP_BGE:
324
      if ((signed int) RR(reg1) >= (signed int) RR(reg2)) {
325
        next += SEXT16(immed) << 2;
326
      }
327
      break;
328
    case OP_BGEU:
329
      if (RR(reg1) >= RR(reg2)) {
330
        next += SEXT16(immed) << 2;
331
      }
332
      break;
333
    case OP_BGT:
334
      if ((signed int) RR(reg1) > (signed int) RR(reg2)) {
335
        next += SEXT16(immed) << 2;
336
      }
337
      break;
338
    case OP_BGTU:
339
      if (RR(reg1) > RR(reg2)) {
340
        next += SEXT16(immed) << 2;
341
      }
342
      break;
343
    case OP_J:
344
      next += SEXT26(offset) << 2;
345
      break;
346
    case OP_JR:
347
      next = RR(reg1);
348
      break;
349
    case OP_JAL:
350
      WR(31, next);
351
      next += SEXT26(offset) << 2;
352
      break;
353
    case OP_JALR:
354
      aux = RR(reg1);
355
      WR(31, next);
356
      next = aux;
357
      break;
358
    case OP_TRAP:
359
      throwException(EXC_TRAP);
360
      break;
361
    case OP_RFX:
362
      if (UM != 0) {
363
        throwException(EXC_PRV_INSTRCT);
364
      }
365
      if (PIE != 0) {
366
        psw |= PSW_IE;
367
      } else {
368
        psw &= ~PSW_IE;
369
      }
370
      if (OIE != 0) {
371
        psw |= PSW_PIE;
372
      } else {
373
        psw &= ~PSW_PIE;
374
      }
375
      if (PUM != 0) {
376
        psw |= PSW_UM;
377
      } else {
378
        psw &= ~PSW_UM;
379
      }
380
      if (OUM != 0) {
381
        psw |= PSW_PUM;
382
      } else {
383
        psw &= ~PSW_PUM;
384
      }
385
      next = RR(30);
386
      break;
387
    case OP_LDW:
388
      WR(reg2, mmuReadWord(RR(reg1) + SEXT16(immed), UM));
389
      break;
390
    case OP_LDH:
391
      WR(reg2, (signed int) (signed short)
392
               mmuReadHalf(RR(reg1) + SEXT16(immed), UM));
393
      break;
394
    case OP_LDHU:
395
      WR(reg2, mmuReadHalf(RR(reg1) + SEXT16(immed), UM));
396
      break;
397
    case OP_LDB:
398
      WR(reg2, (signed int) (signed char)
399
               mmuReadByte(RR(reg1) + SEXT16(immed), UM));
400
      break;
401
    case OP_LDBU:
402
      WR(reg2, mmuReadByte(RR(reg1) + SEXT16(immed), UM));
403
      break;
404
    case OP_STW:
405
      mmuWriteWord(RR(reg1) + SEXT16(immed), RR(reg2), UM);
406
      break;
407
    case OP_STH:
408
      mmuWriteHalf(RR(reg1) + SEXT16(immed), RR(reg2), UM);
409
      break;
410
    case OP_STB:
411
      mmuWriteByte(RR(reg1) + SEXT16(immed), RR(reg2), UM);
412
      break;
413
    case OP_MVFS:
414
      switch (immed) {
415
        case 0:
416
          WR(reg2, psw);
417
          break;
418
        case 1:
419
          WR(reg2, mmuGetIndex());
420
          break;
421
        case 2:
422
          WR(reg2, mmuGetEntryHi());
423
          break;
424
        case 3:
425
          WR(reg2, mmuGetEntryLo());
426
          break;
427
        case 4:
428
          WR(reg2, mmuGetBadAddr());
429
          break;
430 168 hellwig
        case 5:
431
          WR(reg2, mmuGetBadAccs());
432
          break;
433 8 hellwig
        default:
434
          throwException(EXC_ILL_INSTRCT);
435
          break;
436
      }
437
      break;
438
    case OP_MVTS:
439
      if (UM != 0) {
440
        throwException(EXC_PRV_INSTRCT);
441
      }
442
      switch (immed) {
443
        case 0:
444
          psw = RR(reg2);
445
          break;
446
        case 1:
447
          mmuSetIndex(RR(reg2));
448
          break;
449
        case 2:
450
          mmuSetEntryHi(RR(reg2));
451
          break;
452
        case 3:
453
          mmuSetEntryLo(RR(reg2));
454
          break;
455
        case 4:
456
          mmuSetBadAddr(RR(reg2));
457
          break;
458 168 hellwig
        case 5:
459
          mmuSetBadAccs(RR(reg2));
460
          break;
461 8 hellwig
        default:
462
          throwException(EXC_ILL_INSTRCT);
463
          break;
464
      }
465
      break;
466
    case OP_TBS:
467
      if (UM != 0) {
468
        throwException(EXC_PRV_INSTRCT);
469
      }
470
      mmuTbs();
471
      break;
472
    case OP_TBWR:
473
      if (UM != 0) {
474
        throwException(EXC_PRV_INSTRCT);
475
      }
476
      mmuTbwr();
477
      break;
478
    case OP_TBRI:
479
      if (UM != 0) {
480
        throwException(EXC_PRV_INSTRCT);
481
      }
482
      mmuTbri();
483
      break;
484
    case OP_TBWI:
485
      if (UM != 0) {
486
        throwException(EXC_PRV_INSTRCT);
487
      }
488
      mmuTbwi();
489
      break;
490
    default:
491
      throwException(EXC_ILL_INSTRCT);
492
      break;
493
  }
494
  /* update PC */
495
  pc = next;
496
}
497
 
498
 
499
/**************************************************************/
500
 
501
 
502
Word cpuGetPC(void) {
503
  return pc;
504
}
505
 
506
 
507
void cpuSetPC(Word addr) {
508
  pc = addr;
509
}
510
 
511
 
512
Word cpuGetReg(int regnum) {
513
  return RR(regnum & 0x1F);
514
}
515
 
516
 
517
void cpuSetReg(int regnum, Word value) {
518
  WR(regnum & 0x1F, value);
519
}
520
 
521
 
522
Word cpuGetPSW(void) {
523
  return psw;
524
}
525
 
526
 
527
void cpuSetPSW(Word value) {
528
  psw = value;
529
}
530
 
531
 
532
Word cpuGetIRQ(void) {
533
  return irqPending;
534
}
535
 
536
 
537
Bool cpuTestBreak(void) {
538
  return breakSet;
539
}
540
 
541
 
542
Word cpuGetBreak(void) {
543
  return breakAddr;
544
}
545
 
546
 
547
void cpuSetBreak(Word addr) {
548
  breakAddr = addr;
549
  breakSet = true;
550
}
551
 
552
 
553
void cpuResetBreak(void) {
554
  breakSet = false;
555
}
556
 
557
 
558
Word cpuGetTotal(void) {
559
  return total;
560
}
561
 
562
 
563
void cpuStep(void) {
564
  jmp_buf myEnvironment;
565
  int exception;
566
 
567
  exception = setjmp(myEnvironment);
568
  if (exception == 0) {
569
    /* initialization */
570
    pushEnvironment(&myEnvironment);
571 25 hellwig
    timerTick();
572 8 hellwig
    execNextInstruction();
573
    handleInterrupts();
574
  } else {
575
    /* an exception was thrown */
576
    cpuSetInterrupt(exception);
577
    handleInterrupts();
578
  }
579
  popEnvironment();
580
}
581
 
582
 
583
void cpuRun(void) {
584
  jmp_buf myEnvironment;
585
  int exception;
586
 
587
  run = true;
588
  exception = setjmp(myEnvironment);
589
  if (exception == 0) {
590
    /* initialization */
591
    pushEnvironment(&myEnvironment);
592
  } else {
593
    /* an exception was thrown */
594
    cpuSetInterrupt(exception);
595
    handleInterrupts();
596
    if (breakSet && pc == breakAddr) {
597
      run = false;
598
    }
599
  }
600
  while (run) {
601 25 hellwig
    timerTick();
602 8 hellwig
    execNextInstruction();
603
    handleInterrupts();
604
    if (breakSet && pc == breakAddr) {
605
      run = false;
606
    }
607
  }
608
  popEnvironment();
609
}
610
 
611
 
612
void cpuHalt(void) {
613
  run = false;
614
}
615
 
616
 
617
void cpuSetInterrupt(int priority) {
618
  irqPending |= ((unsigned) 1 << priority);
619
}
620
 
621
 
622
void cpuResetInterrupt(int priority) {
623
  irqPending &= ~((unsigned) 1 << priority);
624
}
625
 
626
 
627
void cpuReset(void) {
628
  int i;
629
 
630
  cPrintf("Resetting CPU...\n");
631
  /* most registers are in a random state */
632
  for (i = 1; i < 32; i++) {
633
    r[i] = rand();
634
  }
635
  /* but not all */
636
  pc = startAddr;
637
  r[0] = 0;
638
  psw = 0;
639
  /* reset simulator control variables */
640
  irqPending = 0;
641
  total = 0;
642
}
643
 
644
 
645
void cpuInit(Word initialPC) {
646
  startAddr = initialPC;
647
  cpuReset();
648
}
649
 
650
 
651
void cpuExit(void) {
652
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.