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

Subversion Repositories eco32

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

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

powered by: WebSVN 2.1.0

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