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

Subversion Repositories eco32

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

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
        default:
431
          throwException(EXC_ILL_INSTRCT);
432
          break;
433
      }
434
      break;
435
    case OP_MVTS:
436
      if (UM != 0) {
437
        throwException(EXC_PRV_INSTRCT);
438
      }
439
      switch (immed) {
440
        case 0:
441
          psw = RR(reg2);
442
          break;
443
        case 1:
444
          mmuSetIndex(RR(reg2));
445
          break;
446
        case 2:
447
          mmuSetEntryHi(RR(reg2));
448
          break;
449
        case 3:
450
          mmuSetEntryLo(RR(reg2));
451
          break;
452
        case 4:
453
          mmuSetBadAddr(RR(reg2));
454
          break;
455
        default:
456
          throwException(EXC_ILL_INSTRCT);
457
          break;
458
      }
459
      break;
460
    case OP_TBS:
461
      if (UM != 0) {
462
        throwException(EXC_PRV_INSTRCT);
463
      }
464
      mmuTbs();
465
      break;
466
    case OP_TBWR:
467
      if (UM != 0) {
468
        throwException(EXC_PRV_INSTRCT);
469
      }
470
      mmuTbwr();
471
      break;
472
    case OP_TBRI:
473
      if (UM != 0) {
474
        throwException(EXC_PRV_INSTRCT);
475
      }
476
      mmuTbri();
477
      break;
478
    case OP_TBWI:
479
      if (UM != 0) {
480
        throwException(EXC_PRV_INSTRCT);
481
      }
482
      mmuTbwi();
483
      break;
484
    default:
485
      throwException(EXC_ILL_INSTRCT);
486
      break;
487
  }
488
  /* update PC */
489
  pc = next;
490
}
491
 
492
 
493
/**************************************************************/
494
 
495
 
496
Word cpuGetPC(void) {
497
  return pc;
498
}
499
 
500
 
501
void cpuSetPC(Word addr) {
502
  pc = addr;
503
}
504
 
505
 
506
Word cpuGetReg(int regnum) {
507
  return RR(regnum & 0x1F);
508
}
509
 
510
 
511
void cpuSetReg(int regnum, Word value) {
512
  WR(regnum & 0x1F, value);
513
}
514
 
515
 
516
Word cpuGetPSW(void) {
517
  return psw;
518
}
519
 
520
 
521
void cpuSetPSW(Word value) {
522
  psw = value;
523
}
524
 
525
 
526
Word cpuGetIRQ(void) {
527
  return irqPending;
528
}
529
 
530
 
531
Bool cpuTestBreak(void) {
532
  return breakSet;
533
}
534
 
535
 
536
Word cpuGetBreak(void) {
537
  return breakAddr;
538
}
539
 
540
 
541
void cpuSetBreak(Word addr) {
542
  breakAddr = addr;
543
  breakSet = true;
544
}
545
 
546
 
547
void cpuResetBreak(void) {
548
  breakSet = false;
549
}
550
 
551
 
552
Word cpuGetTotal(void) {
553
  return total;
554
}
555
 
556
 
557
void cpuStep(void) {
558
  jmp_buf myEnvironment;
559
  int exception;
560
 
561
  exception = setjmp(myEnvironment);
562
  if (exception == 0) {
563
    /* initialization */
564
    pushEnvironment(&myEnvironment);
565 25 hellwig
    timerTick();
566 8 hellwig
    execNextInstruction();
567
    handleInterrupts();
568
  } else {
569
    /* an exception was thrown */
570
    cpuSetInterrupt(exception);
571
    handleInterrupts();
572
  }
573
  popEnvironment();
574
}
575
 
576
 
577
void cpuRun(void) {
578
  jmp_buf myEnvironment;
579
  int exception;
580
 
581
  run = true;
582
  exception = setjmp(myEnvironment);
583
  if (exception == 0) {
584
    /* initialization */
585
    pushEnvironment(&myEnvironment);
586
  } else {
587
    /* an exception was thrown */
588
    cpuSetInterrupt(exception);
589
    handleInterrupts();
590
    if (breakSet && pc == breakAddr) {
591
      run = false;
592
    }
593
  }
594
  while (run) {
595 25 hellwig
    timerTick();
596 8 hellwig
    execNextInstruction();
597
    handleInterrupts();
598
    if (breakSet && pc == breakAddr) {
599
      run = false;
600
    }
601
  }
602
  popEnvironment();
603
}
604
 
605
 
606
void cpuHalt(void) {
607
  run = false;
608
}
609
 
610
 
611
void cpuSetInterrupt(int priority) {
612
  irqPending |= ((unsigned) 1 << priority);
613
}
614
 
615
 
616
void cpuResetInterrupt(int priority) {
617
  irqPending &= ~((unsigned) 1 << priority);
618
}
619
 
620
 
621
void cpuReset(void) {
622
  int i;
623
 
624
  cPrintf("Resetting CPU...\n");
625
  /* most registers are in a random state */
626
  for (i = 1; i < 32; i++) {
627
    r[i] = rand();
628
  }
629
  /* but not all */
630
  pc = startAddr;
631
  r[0] = 0;
632
  psw = 0;
633
  /* reset simulator control variables */
634
  irqPending = 0;
635
  total = 0;
636
}
637
 
638
 
639
void cpuInit(Word initialPC) {
640
  startAddr = initialPC;
641
  cpuReset();
642
}
643
 
644
 
645
void cpuExit(void) {
646
}

powered by: WebSVN 2.1.0

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