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

Subversion Repositories eco32

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

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

powered by: WebSVN 2.1.0

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