Root/plasma/tools/mlite.c

1/*-------------------------------------------------------------------
2-- TITLE: Plasma CPU in software. Executes MIPS(tm) opcodes.
3-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com)
4-- DATE CREATED: 1/31/01
5-- FILENAME: mlite.c
6-- PROJECT: Plasma CPU core
7-- COPYRIGHT: Software placed into the public domain by the author.
8-- Software 'as is' without warranty. Author liable for nothing.
9-- DESCRIPTION:
10-- Plasma CPU simulator in C code.
11-- This file served as the starting point for the VHDL code.
12-- Assumes running on a little endian PC.
13--------------------------------------------------------------------*/
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <ctype.h>
18#include <assert.h>
19
20//#define ENABLE_CACHE
21#define SIMPLE_CACHE
22
23#define MEM_SIZE (1024*1024*2)
24#define ntohs(A) ( ((A)>>8) | (((A)&0xff)<<8) )
25#define htons(A) ntohs(A)
26#define ntohl(A) ( ((A)>>24) | (((A)&0xff0000)>>8) | (((A)&0xff00)<<8) | ((A)<<24) )
27#define htonl(A) ntohl(A)
28
29#ifndef WIN32
30//Support for Linux
31#define putch putchar
32#include <termios.h>
33#include <unistd.h>
34
35void Sleep(unsigned int value)
36{
37   usleep(value * 1000);
38}
39
40int kbhit(void)
41{
42   struct termios oldt, newt;
43   struct timeval tv;
44   fd_set read_fd;
45
46   tcgetattr(STDIN_FILENO, &oldt);
47   newt = oldt;
48   newt.c_lflag &= ~(ICANON | ECHO);
49   tcsetattr(STDIN_FILENO, TCSANOW, &newt);
50   tv.tv_sec=0;
51   tv.tv_usec=0;
52   FD_ZERO(&read_fd);
53   FD_SET(0,&read_fd);
54   if(select(1, &read_fd, NULL, NULL, &tv) == -1)
55      return 0;
56   //tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
57   if(FD_ISSET(0,&read_fd))
58      return 1;
59   return 0;
60}
61
62int getch(void)
63{
64   struct termios oldt, newt;
65   int ch;
66
67   tcgetattr(STDIN_FILENO, &oldt);
68   newt = oldt;
69   newt.c_lflag &= ~(ICANON | ECHO);
70   tcsetattr(STDIN_FILENO, TCSANOW, &newt);
71   ch = getchar();
72   //tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
73   return ch;
74}
75#else
76//Support for Windows
77#include <conio.h>
78extern void __stdcall Sleep(unsigned long value);
79#endif
80
81#define UART_WRITE 0x20000000
82#define UART_READ 0x20000000
83#define IRQ_MASK 0x20000010
84#define IRQ_STATUS 0x20000020
85#define CONFIG_REG 0x20000070
86#define MMU_PROCESS_ID 0x20000080
87#define MMU_FAULT_ADDR 0x20000090
88#define MMU_TLB 0x200000a0
89
90#define IRQ_UART_READ_AVAILABLE 0x001
91#define IRQ_UART_WRITE_AVAILABLE 0x002
92#define IRQ_COUNTER18_NOT 0x004
93#define IRQ_COUNTER18 0x008
94#define IRQ_MMU 0x200
95
96#define MMU_ENTRIES 4
97#define MMU_MASK (1024*4-1)
98
99typedef struct
100{
101   unsigned int virtualAddress;
102   unsigned int physicalAddress;
103} MmuEntry;
104
105typedef struct {
106   int r[32];
107   int pc, pc_next, epc;
108   unsigned int hi;
109   unsigned int lo;
110   int status;
111   int userMode;
112   int processId;
113   int exceptionId;
114   int faultAddr;
115   int irqStatus;
116   int skip;
117   unsigned char *mem;
118   int wakeup;
119   int big_endian;
120   MmuEntry mmuEntry[MMU_ENTRIES];
121} State;
122
123static char *opcode_string[]={
124   "SPECIAL","REGIMM","J","JAL","BEQ","BNE","BLEZ","BGTZ",
125   "ADDI","ADDIU","SLTI","SLTIU","ANDI","ORI","XORI","LUI",
126   "COP0","COP1","COP2","COP3","BEQL","BNEL","BLEZL","BGTZL",
127   "?","?","?","?","?","?","?","?",
128   "LB","LH","LWL","LW","LBU","LHU","LWR","?",
129   "SB","SH","SWL","SW","?","?","SWR","CACHE",
130   "LL","LWC1","LWC2","LWC3","?","LDC1","LDC2","LDC3"
131   "SC","SWC1","SWC2","SWC3","?","SDC1","SDC2","SDC3"
132};
133
134static char *special_string[]={
135   "SLL","?","SRL","SRA","SLLV","?","SRLV","SRAV",
136   "JR","JALR","MOVZ","MOVN","SYSCALL","BREAK","?","SYNC",
137   "MFHI","MTHI","MFLO","MTLO","?","?","?","?",
138   "MULT","MULTU","DIV","DIVU","?","?","?","?",
139   "ADD","ADDU","SUB","SUBU","AND","OR","XOR","NOR",
140   "?","?","SLT","SLTU","?","DADDU","?","?",
141   "TGE","TGEU","TLT","TLTU","TEQ","?","TNE","?",
142   "?","?","?","?","?","?","?","?"
143};
144
145static char *regimm_string[]={
146   "BLTZ","BGEZ","BLTZL","BGEZL","?","?","?","?",
147   "TGEI","TGEIU","TLTI","TLTIU","TEQI","?","TNEI","?",
148   "BLTZAL","BEQZAL","BLTZALL","BGEZALL","?","?","?","?",
149   "?","?","?","?","?","?","?","?"
150};
151
152static unsigned int HWMemory[8];
153
154
155static int mem_read(State *s, int size, unsigned int address)
156{
157   unsigned int value=0, ptr;
158
159   s->irqStatus |= IRQ_UART_WRITE_AVAILABLE;
160   switch(address)
161   {
162      case UART_READ:
163         if(kbhit())
164            HWMemory[0] = getch();
165         s->irqStatus &= ~IRQ_UART_READ_AVAILABLE; //clear bit
166         return HWMemory[0];
167      case IRQ_MASK:
168         return HWMemory[1];
169      case IRQ_MASK + 4:
170         Sleep(10);
171         return 0;
172      case IRQ_STATUS:
173         if(kbhit())
174            s->irqStatus |= IRQ_UART_READ_AVAILABLE;
175         return s->irqStatus;
176      case MMU_PROCESS_ID:
177         return s->processId;
178      case MMU_FAULT_ADDR:
179         return s->faultAddr;
180   }
181
182   ptr = (unsigned int)s->mem + (address % MEM_SIZE);
183
184   if(0x10000000 <= address && address < 0x10000000 + 1024*1024)
185      ptr += 1024*1024;
186
187   switch(size)
188   {
189      case 4:
190         if(address & 3)
191            printf("Unaligned access PC=0x%x address=0x%x\n", (int)s->pc, (int)address);
192         assert((address & 3) == 0);
193         value = *(int*)ptr;
194         if(s->big_endian)
195            value = ntohl(value);
196         break;
197      case 2:
198         assert((address & 1) == 0);
199         value = *(unsigned short*)ptr;
200         if(s->big_endian)
201            value = ntohs((unsigned short)value);
202         break;
203      case 1:
204         value = *(unsigned char*)ptr;
205         break;
206      default:
207         printf("ERROR");
208   }
209   return(value);
210}
211
212static void mem_write(State *s, int size, int unsigned address, unsigned int value)
213{
214   unsigned int ptr;
215
216   switch(address)
217   {
218      case UART_WRITE:
219         putch(value);
220         fflush(stdout);
221         return;
222      case IRQ_MASK:
223         HWMemory[1] = value;
224         return;
225      case IRQ_STATUS:
226         s->irqStatus = value;
227         return;
228      case CONFIG_REG:
229         return;
230      case MMU_PROCESS_ID:
231         //printf("processId=%d\n", value);
232         s->processId = value;
233         return;
234   }
235
236   if(MMU_TLB <= address && address <= MMU_TLB+MMU_ENTRIES * 8)
237   {
238      //printf("TLB 0x%x 0x%x\n", address - MMU_TLB, value);
239      ptr = (unsigned int)s->mmuEntry + address - MMU_TLB;
240      *(int*)ptr = value;
241      s->irqStatus &= ~IRQ_MMU;
242      return;
243   }
244
245   ptr = (unsigned int)s->mem + (address % MEM_SIZE);
246
247   if(0x10000000 <= address && address < 0x10000000 + 1024*1024)
248      ptr += 1024*1024;
249
250   switch(size)
251   {
252      case 4:
253         assert((address & 3) == 0);
254         if(s->big_endian)
255            value = htonl(value);
256         *(int*)ptr = value;
257         break;
258      case 2:
259         assert((address & 1) == 0);
260         if(s->big_endian)
261            value = htons((unsigned short)value);
262         *(short*)ptr = (unsigned short)value;
263         break;
264      case 1:
265         *(char*)ptr = (unsigned char)value;
266         break;
267      default:
268         printf("ERROR");
269   }
270}
271
272#ifdef ENABLE_CACHE
273/************* Optional MMU and cache implementation *************/
274/* TAG = VirtualAddress | ProcessId | WriteableBit */
275unsigned int mmu_lookup(State *s, unsigned int processId,
276                         unsigned int address, int write)
277{
278   int i;
279   unsigned int compare, tag;
280
281   if(processId == 0 || s->userMode == 0)
282      return address;
283   //if(address < 0x30000000)
284   // return address;
285   compare = (address & ~MMU_MASK) | (processId << 1);
286   for(i = 0; i < MMU_ENTRIES; ++i)
287   {
288      tag = s->mmuEntry[i].virtualAddress;
289      if((tag & ~1) == compare && (write == 0 || (tag & 1)))
290         return s->mmuEntry[i].physicalAddress | (address & MMU_MASK);
291   }
292   //printf("\nMMUTlbMiss 0x%x PC=0x%x w=%d pid=%d user=%d\n",
293   // address, s->pc, write, processId, s->userMode);
294   //printf("m");
295   s->exceptionId = 1;
296   s->faultAddr = address & ~MMU_MASK;
297   s->irqStatus |= IRQ_MMU;
298   return address;
299}
300
301
302#define CACHE_SET_ASSOC_LN2 0
303#define CACHE_SET_ASSOC (1 << CACHE_SET_ASSOC_LN2)
304#define CACHE_SIZE_LN2 (13 - CACHE_SET_ASSOC_LN2) //8 KB
305#define CACHE_SIZE (1 << CACHE_SIZE_LN2)
306#define CACHE_LINE_SIZE_LN2 2 //4 bytes
307#define CACHE_LINE_SIZE (1 << CACHE_LINE_SIZE_LN2)
308
309static int cacheData[CACHE_SET_ASSOC][CACHE_SIZE/sizeof(int)];
310static int cacheAddr[CACHE_SET_ASSOC][CACHE_SIZE/CACHE_LINE_SIZE];
311static int cacheSetNext;
312static int cacheMiss, cacheWriteBack, cacheCount;
313
314static void cache_init(void)
315{
316   int set, i;
317   for(set = 0; set < CACHE_SET_ASSOC; ++set)
318   {
319      for(i = 0; i < CACHE_SIZE/CACHE_LINE_SIZE; ++i)
320         cacheAddr[set][i] = 0xffff0000;
321   }
322}
323
324/* Write-back cache memory tagged by virtual address and processId */
325/* TAG = virtualAddress | processId | dirtyBit */
326static int cache_load(State *s, unsigned int address, int write)
327{
328   int set, i, pid, miss, offsetAddr, offsetData, offsetMem;
329   unsigned int addrTagMatch, addrPrevMatch=0;
330   unsigned int addrPrev;
331   unsigned int addressPhysical, tag;
332
333   ++cacheCount;
334   addrTagMatch = address & ~(CACHE_SIZE-1);
335   offsetAddr = (address & (CACHE_SIZE-1)) >> CACHE_LINE_SIZE_LN2;
336
337   /* Find match */
338   miss = 1;
339   for(set = 0; set < CACHE_SET_ASSOC; ++set)
340   {
341      addrPrevMatch = cacheAddr[set][offsetAddr] & ~(CACHE_SIZE-1);
342      if(addrPrevMatch == addrTagMatch)
343      {
344         miss = 0;
345         break;
346      }
347   }
348
349   /* Cache miss? */
350   if(miss)
351   {
352      ++cacheMiss;
353      set = cacheSetNext;
354      cacheSetNext = (cacheSetNext + 1) & (CACHE_SET_ASSOC-1);
355   }
356   //else if(write || (address >> 28) != 0x1)
357   //{
358   // tag = cacheAddr[set][offsetAddr];
359   // pid = (tag & (CACHE_SIZE-1)) >> 1;
360   // if(pid != s->processId)
361   // miss = 1;
362   //}
363
364   if(miss)
365   {
366      offsetData = address & (CACHE_SIZE-1) & ~(CACHE_LINE_SIZE-1);
367
368      /* Cache line dirty? */
369      if(cacheAddr[set][offsetAddr] & 1)
370      {
371         /* Write back cache line */
372         tag = cacheAddr[set][offsetAddr];
373         addrPrev = tag & ~(CACHE_SIZE-1);
374         addrPrev |= address & (CACHE_SIZE-1);
375         pid = (tag & (CACHE_SIZE-1)) >> 1;
376         addressPhysical = mmu_lookup(s, pid, addrPrev, 1); //virtual->physical
377         if(s->exceptionId)
378            return 0;
379         offsetMem = addressPhysical & ~(CACHE_LINE_SIZE-1);
380         for(i = 0; i < CACHE_LINE_SIZE; i += 4)
381            mem_write(s, 4, offsetMem + i, cacheData[set][(offsetData + i) >> 2]);
382         ++cacheWriteBack;
383      }
384
385      /* Read cache line */
386      addressPhysical = mmu_lookup(s, s->processId, address, write); //virtual->physical
387      if(s->exceptionId)
388         return 0;
389      offsetMem = addressPhysical & ~(CACHE_LINE_SIZE-1);
390      cacheAddr[set][offsetAddr] = addrTagMatch;
391      for(i = 0; i < CACHE_LINE_SIZE; i += 4)
392         cacheData[set][(offsetData + i) >> 2] = mem_read(s, 4, offsetMem + i);
393   }
394   cacheAddr[set][offsetAddr] |= write;
395   return set;
396}
397
398static int cache_read(State *s, int size, unsigned int address)
399{
400   int set, offset;
401   int value;
402
403   if((address & 0xfe000000) != 0x10000000)
404      return mem_read(s, size, address);
405
406   set = cache_load(s, address, 0);
407   if(s->exceptionId)
408      return 0;
409   offset = (address & (CACHE_SIZE-1)) >> 2;
410   value = cacheData[set][offset];
411   if(s->big_endian)
412      address ^= 3;
413   switch(size)
414   {
415      case 2:
416         value = (value >> ((address & 2) << 3)) & 0xffff;
417         break;
418      case 1:
419         value = (value >> ((address & 3) << 3)) & 0xff;
420         break;
421   }
422   return value;
423}
424
425static void cache_write(State *s, int size, int unsigned address, unsigned int value)
426{
427   int set, offset;
428   unsigned int mask;
429
430   if((address >> 28) != 0x1) // && (s->processId == 0 || s->userMode == 0))
431   {
432      mem_write(s, size, address, value);
433      return;
434   }
435
436   set = cache_load(s, address, 1);
437   if(s->exceptionId)
438      return;
439   offset = (address & (CACHE_SIZE-1)) >> 2;
440   if(s->big_endian)
441      address ^= 3;
442   switch(size)
443   {
444      case 2:
445         value &= 0xffff;
446         value |= value << 16;
447         mask = 0xffff << ((address & 2) << 3);
448         break;
449      case 1:
450         value &= 0xff;
451         value |= (value << 8) | (value << 16) | (value << 24);
452         mask = 0xff << ((address & 3) << 3);
453         break;
454      case 4:
455      default:
456         mask = 0xffffffff;
457         break;
458   }
459   cacheData[set][offset] = (value & mask) | (cacheData[set][offset] & ~mask);
460}
461
462#define mem_read cache_read
463#define mem_write cache_write
464
465#else
466static void cache_init(void) {}
467#endif
468
469
470#ifdef SIMPLE_CACHE
471
472//Write through direct mapped 4KB cache
473#define CACHE_MISS 0x1ff
474static unsigned int cacheData[1024];
475static unsigned int cacheAddr[1024]; //9-bit addresses
476static int cacheTry, cacheMiss, cacheInit;
477
478static int cache_read(State *s, int size, unsigned int address)
479{
480   int offset;
481   unsigned int value, value2, address2=address;
482
483   if(cacheInit == 0)
484   {
485      cacheInit = 1;
486      for(offset = 0; offset < 1024; ++offset)
487         cacheAddr[offset] = CACHE_MISS;
488   }
489
490   offset = address >> 20;
491   if(offset != 0x100 && offset != 0x101)
492      return mem_read(s, size, address);
493
494   ++cacheTry;
495   offset = (address >> 2) & 0x3ff;
496   if(cacheAddr[offset] != (address >> 12) || cacheAddr[offset] == CACHE_MISS)
497   {
498      ++cacheMiss;
499      cacheAddr[offset] = address >> 12;
500      cacheData[offset] = mem_read(s, 4, address & ~3);
501   }
502   value = cacheData[offset];
503   if(s->big_endian)
504      address ^= 3;
505   switch(size)
506   {
507      case 2:
508         value = (value >> ((address & 2) << 3)) & 0xffff;
509         break;
510      case 1:
511         value = (value >> ((address & 3) << 3)) & 0xff;
512         break;
513   }
514
515   //Debug testing
516   value2 = mem_read(s, size, address2);
517   if(value != value2)
518      printf("miss match\n");
519   //if((cacheTry & 0xffff) == 0) printf("\n***cache(%d,%d)\n ", cacheMiss, cacheTry);
520   return value;
521}
522
523static void cache_write(State *s, int size, int unsigned address, unsigned int value)
524{
525   int offset;
526
527   mem_write(s, size, address, value);
528
529   offset = address >> 20;
530   if(offset != 0x100 && offset != 0x101)
531      return;
532
533   offset = (address >> 2) & 0x3ff;
534   if(size != 4)
535   {
536      cacheAddr[offset] = CACHE_MISS;
537      return;
538   }
539   cacheAddr[offset] = address >> 12;
540   cacheData[offset] = value;
541}
542
543#define mem_read cache_read
544#define mem_write cache_write
545#endif //SIMPLE_CACHE
546/************* End optional cache implementation *************/
547
548
549void mult_big(unsigned int a,
550              unsigned int b,
551              unsigned int *hi,
552              unsigned int *lo)
553{
554   unsigned int ahi, alo, bhi, blo;
555   unsigned int c0, c1, c2;
556   unsigned int c1_a, c1_b;
557
558   ahi = a >> 16;
559   alo = a & 0xffff;
560   bhi = b >> 16;
561   blo = b & 0xffff;
562
563   c0 = alo * blo;
564   c1_a = ahi * blo;
565   c1_b = alo * bhi;
566   c2 = ahi * bhi;
567
568   c2 += (c1_a >> 16) + (c1_b >> 16);
569   c1 = (c1_a & 0xffff) + (c1_b & 0xffff) + (c0 >> 16);
570   c2 += (c1 >> 16);
571   c0 = (c1 << 16) + (c0 & 0xffff);
572   *hi = c2;
573   *lo = c0;
574}
575
576void mult_big_signed(int a,
577                     int b,
578                     unsigned int *hi,
579                     unsigned int *lo)
580{
581   unsigned int ahi, alo, bhi, blo;
582   unsigned int c0, c1, c2;
583   unsigned int c1_a, c1_b;
584
585   ahi = a >> 16;
586   alo = a & 0xffff;
587   bhi = b >> 16;
588   blo = b & 0xffff;
589
590   c0 = alo * blo;
591   c1_a = ahi * blo;
592   c1_b = alo * bhi;
593   c2 = ahi * bhi;
594
595   c2 += (c1_a >> 16) + (c1_b >> 16);
596   c1 = (c1_a & 0xffff) + (c1_b & 0xffff) + (c0 >> 16);
597   c2 += (c1 >> 16);
598   c0 = (c1 << 16) + (c0 & 0xffff);
599   *hi = c2;
600   *lo = c0;
601}
602
603//execute one cycle of a Plasma CPU
604void cycle(State *s, int show_mode)
605{
606   unsigned int opcode;
607   unsigned int op, rs, rt, rd, re, func, imm, target;
608   int imm_shift, branch=0, lbranch=2, skip2=0;
609   int *r=s->r;
610   unsigned int *u=(unsigned int*)s->r;
611   unsigned int ptr, epc, rSave;
612
613   opcode = mem_read(s, 4, s->pc);
614   op = (opcode >> 26) & 0x3f;
615   rs = (opcode >> 21) & 0x1f;
616   rt = (opcode >> 16) & 0x1f;
617   rd = (opcode >> 11) & 0x1f;
618   re = (opcode >> 6) & 0x1f;
619   func = opcode & 0x3f;
620   imm = opcode & 0xffff;
621   imm_shift = (((int)(short)imm) << 2) - 4;
622   target = (opcode << 6) >> 4;
623   ptr = (short)imm + r[rs];
624   r[0] = 0;
625   if(show_mode)
626   {
627      printf("%8.8x %8.8x ", s->pc, opcode);
628      if(op == 0)
629         printf("%8s ", special_string[func]);
630      else if(op == 1)
631         printf("%8s ", regimm_string[rt]);
632      else
633         printf("%8s ", opcode_string[op]);
634      printf("$%2.2d $%2.2d $%2.2d $%2.2d ", rs, rt, rd, re);
635      printf("%4.4x", imm);
636      if(show_mode == 1)
637         printf(" r[%2.2d]=%8.8x r[%2.2d]=%8.8x", rs, r[rs], rt, r[rt]);
638      printf("\n");
639   }
640   if(show_mode > 5)
641      return;
642   epc = s->pc + 4;
643   if(s->pc_next != s->pc + 4)
644      epc |= 2; //branch delay slot
645   s->pc = s->pc_next;
646   s->pc_next = s->pc_next + 4;
647   if(s->skip)
648   {
649      s->skip = 0;
650      return;
651   }
652   rSave = r[rt];
653   switch(op)
654   {
655      case 0x00:/*SPECIAL*/
656         switch(func)
657         {
658            case 0x00:/*SLL*/ r[rd]=r[rt]<<re; break;
659            case 0x02:/*SRL*/ r[rd]=u[rt]>>re; break;
660            case 0x03:/*SRA*/ r[rd]=r[rt]>>re; break;
661            case 0x04:/*SLLV*/ r[rd]=r[rt]<<r[rs]; break;
662            case 0x06:/*SRLV*/ r[rd]=u[rt]>>r[rs]; break;
663            case 0x07:/*SRAV*/ r[rd]=r[rt]>>r[rs]; break;
664            case 0x08:/*JR*/ s->pc_next=r[rs]; break;
665            case 0x09:/*JALR*/ r[rd]=s->pc_next; s->pc_next=r[rs]; break;
666            case 0x0a:/*MOVZ*/ if(!r[rt]) r[rd]=r[rs]; break; /*IV*/
667            case 0x0b:/*MOVN*/ if(r[rt]) r[rd]=r[rs]; break; /*IV*/
668            case 0x0c:/*SYSCALL*/ epc|=1; s->exceptionId=1; break;
669            case 0x0d:/*BREAK*/ epc|=1; s->exceptionId=1; break;
670            case 0x0f:/*SYNC*/ s->wakeup=1; break;
671            case 0x10:/*MFHI*/ r[rd]=s->hi; break;
672            case 0x11:/*FTHI*/ s->hi=r[rs]; break;
673            case 0x12:/*MFLO*/ r[rd]=s->lo; break;
674            case 0x13:/*MTLO*/ s->lo=r[rs]; break;
675            case 0x18:/*MULT*/ mult_big_signed(r[rs],r[rt],&s->hi,&s->lo); break;
676            case 0x19:/*MULTU*/ mult_big(r[rs],r[rt],&s->hi,&s->lo); break;
677            case 0x1a:/*DIV*/ s->lo=r[rs]/r[rt]; s->hi=r[rs]%r[rt]; break;
678            case 0x1b:/*DIVU*/ s->lo=u[rs]/u[rt]; s->hi=u[rs]%u[rt]; break;
679            case 0x20:/*ADD*/ r[rd]=r[rs]+r[rt]; break;
680            case 0x21:/*ADDU*/ r[rd]=r[rs]+r[rt]; break;
681            case 0x22:/*SUB*/ r[rd]=r[rs]-r[rt]; break;
682            case 0x23:/*SUBU*/ r[rd]=r[rs]-r[rt]; break;
683            case 0x24:/*AND*/ r[rd]=r[rs]&r[rt]; break;
684            case 0x25:/*OR*/ r[rd]=r[rs]|r[rt]; break;
685            case 0x26:/*XOR*/ r[rd]=r[rs]^r[rt]; break;
686            case 0x27:/*NOR*/ r[rd]=~(r[rs]|r[rt]); break;
687            case 0x2a:/*SLT*/ r[rd]=r[rs]<r[rt]; break;
688            case 0x2b:/*SLTU*/ r[rd]=u[rs]<u[rt]; break;
689            case 0x2d:/*DADDU*/r[rd]=r[rs]+u[rt]; break;
690            case 0x31:/*TGEU*/ break;
691            case 0x32:/*TLT*/ break;
692            case 0x33:/*TLTU*/ break;
693            case 0x34:/*TEQ*/ break;
694            case 0x36:/*TNE*/ break;
695            default: printf("ERROR0(*0x%x~0x%x)\n", s->pc, opcode);
696               s->wakeup=1;
697         }
698         break;
699      case 0x01:/*REGIMM*/
700         switch(rt) {
701            case 0x10:/*BLTZAL*/ r[31]=s->pc_next;
702            case 0x00:/*BLTZ*/ branch=r[rs]<0; break;
703            case 0x11:/*BGEZAL*/ r[31]=s->pc_next;
704            case 0x01:/*BGEZ*/ branch=r[rs]>=0; break;
705            case 0x12:/*BLTZALL*/r[31]=s->pc_next;
706            case 0x02:/*BLTZL*/ lbranch=r[rs]<0; break;
707            case 0x13:/*BGEZALL*/r[31]=s->pc_next;
708            case 0x03:/*BGEZL*/ lbranch=r[rs]>=0; break;
709            default: printf("ERROR1\n"); s->wakeup=1;
710          }
711         break;
712      case 0x03:/*JAL*/ r[31]=s->pc_next;
713      case 0x02:/*J*/ s->pc_next=(s->pc&0xf0000000)|target; break;
714      case 0x04:/*BEQ*/ branch=r[rs]==r[rt]; break;
715      case 0x05:/*BNE*/ branch=r[rs]!=r[rt]; break;
716      case 0x06:/*BLEZ*/ branch=r[rs]<=0; break;
717      case 0x07:/*BGTZ*/ branch=r[rs]>0; break;
718      case 0x08:/*ADDI*/ r[rt]=r[rs]+(short)imm; break;
719      case 0x09:/*ADDIU*/ u[rt]=u[rs]+(short)imm; break;
720      case 0x0a:/*SLTI*/ r[rt]=r[rs]<(short)imm; break;
721      case 0x0b:/*SLTIU*/ u[rt]=u[rs]<(unsigned int)(short)imm; break;
722      case 0x0c:/*ANDI*/ r[rt]=r[rs]&imm; break;
723      case 0x0d:/*ORI*/ r[rt]=r[rs]|imm; break;
724      case 0x0e:/*XORI*/ r[rt]=r[rs]^imm; break;
725      case 0x0f:/*LUI*/ r[rt]=(imm<<16); break;
726      case 0x10:/*COP0*/
727         if((opcode & (1<<23)) == 0) //move from CP0
728         {
729            if(rd == 12)
730               r[rt]=s->status;
731            else
732               r[rt]=s->epc;
733         }
734         else //move to CP0
735         {
736            s->status=r[rt]&1;
737            if(s->processId && (r[rt]&2))
738            {
739               s->userMode|=r[rt]&2;
740               //printf("CpuStatus=%d %d %d\n", r[rt], s->status, s->userMode);
741               //s->wakeup = 1;
742               //printf("pc=0x%x\n", epc);
743            }
744         }
745         break;
746// case 0x11:/*COP1*/ break;
747// case 0x12:/*COP2*/ break;
748// case 0x13:/*COP3*/ break;
749      case 0x14:/*BEQL*/ lbranch=r[rs]==r[rt]; break;
750      case 0x15:/*BNEL*/ lbranch=r[rs]!=r[rt]; break;
751      case 0x16:/*BLEZL*/ lbranch=r[rs]<=0; break;
752      case 0x17:/*BGTZL*/ lbranch=r[rs]>0; break;
753// case 0x1c:/*MAD*/ break; /*IV*/
754      case 0x20:/*LB*/ r[rt]=(signed char)mem_read(s,1,ptr); break;
755      case 0x21:/*LH*/ r[rt]=(signed short)mem_read(s,2,ptr); break;
756      case 0x22:/*LWL*/
757                         //target=8*(ptr&3);
758                         //r[rt]=(r[rt]&~(0xffffffff<<target))|
759                         // (mem_read(s,4,ptr&~3)<<target); break;
760      case 0x23:/*LW*/ r[rt]=mem_read(s,4,ptr); break;
761      case 0x24:/*LBU*/ r[rt]=(unsigned char)mem_read(s,1,ptr); break;
762      case 0x25:/*LHU*/ r[rt]=(unsigned short)mem_read(s,2,ptr); break;
763      case 0x26:/*LWR*/
764                         //target=32-8*(ptr&3);
765                         //r[rt]=(r[rt]&~((unsigned int)0xffffffff>>target))|
766                         //((unsigned int)mem_read(s,4,ptr&~3)>>target);
767                         break;
768      case 0x28:/*SB*/ mem_write(s,1,ptr,r[rt]); break;
769      case 0x29:/*SH*/ mem_write(s,2,ptr,r[rt]); break;
770      case 0x2a:/*SWL*/
771                         //mem_write(s,1,ptr,r[rt]>>24);
772                         //mem_write(s,1,ptr+1,r[rt]>>16);
773                         //mem_write(s,1,ptr+2,r[rt]>>8);
774                         //mem_write(s,1,ptr+3,r[rt]); break;
775      case 0x2b:/*SW*/ mem_write(s,4,ptr,r[rt]); break;
776      case 0x2e:/*SWR*/ break; //fixme
777      case 0x2f:/*CACHE*/break;
778      case 0x30:/*LL*/ r[rt]=mem_read(s,4,ptr); break;
779// case 0x31:/*LWC1*/ break;
780// case 0x32:/*LWC2*/ break;
781// case 0x33:/*LWC3*/ break;
782// case 0x35:/*LDC1*/ break;
783// case 0x36:/*LDC2*/ break;
784// case 0x37:/*LDC3*/ break;
785// case 0x38:/*SC*/ *(int*)ptr=r[rt]; r[rt]=1; break;
786      case 0x38:/*SC*/ mem_write(s,4,ptr,r[rt]); r[rt]=1; break;
787// case 0x39:/*SWC1*/ break;
788// case 0x3a:/*SWC2*/ break;
789// case 0x3b:/*SWC3*/ break;
790// case 0x3d:/*SDC1*/ break;
791// case 0x3e:/*SDC2*/ break;
792// case 0x3f:/*SDC3*/ break;
793      default: printf("ERROR2 address=0x%x opcode=0x%x\n", s->pc, opcode);
794         s->wakeup=1;
795   }
796   s->pc_next += (branch || lbranch == 1) ? imm_shift : 0;
797   s->pc_next &= ~3;
798   s->skip = (lbranch == 0) | skip2;
799
800   if(s->exceptionId)
801   {
802      r[rt] = rSave;
803      s->epc = epc;
804      s->pc_next = 0x3c;
805      s->skip = 1;
806      s->exceptionId = 0;
807      s->userMode = 0;
808      //s->wakeup = 1;
809      return;
810   }
811}
812
813void show_state(State *s)
814{
815   int i,j;
816   printf("pid=%d userMode=%d, epc=0x%x\n", s->processId, s->userMode, s->epc);
817   for(i = 0; i < 4; ++i)
818   {
819      printf("%2.2d ", i * 8);
820      for(j = 0; j < 8; ++j)
821      {
822         printf("%8.8x ", s->r[i*8+j]);
823      }
824      printf("\n");
825   }
826   //printf("%8.8lx %8.8lx %8.8lx %8.8lx\n", s->pc, s->pc_next, s->hi, s->lo);
827   j = s->pc;
828   for(i = -4; i <= 8; ++i)
829   {
830      printf("%c", i==0 ? '*' : ' ');
831      s->pc = j + i * 4;
832      cycle(s, 10);
833   }
834   s->pc = j;
835}
836
837void do_debug(State *s)
838{
839   int ch;
840   int i, j=0, watch=0, addr;
841   s->pc_next = s->pc + 4;
842   s->skip = 0;
843   s->wakeup = 0;
844   show_state(s);
845   ch = ' ';
846   for(;;)
847   {
848      if(ch != 'n')
849      {
850         if(watch)
851            printf("0x%8.8x=0x%8.8x\n", watch, mem_read(s, 4, watch));
852         printf("1=Debug 2=Trace 3=Step 4=BreakPt 5=Go 6=Memory ");
853         printf("7=Watch 8=Jump 9=Quit> ");
854      }
855      ch = getch();
856      if(ch != 'n')
857         printf("\n");
858      switch(ch)
859      {
860      case '1': case 'd': case ' ':
861         cycle(s, 0); show_state(s); break;
862      case 'n':
863         cycle(s, 1); break;
864      case '2': case 't':
865         cycle(s, 0); printf("*"); cycle(s, 10); break;
866      case '3': case 's':
867         printf("Count> ");
868         scanf("%d", &j);
869         for(i = 0; i < j; ++i)
870            cycle(s, 1);
871         show_state(s);
872         break;
873      case '4': case 'b':
874         printf("Line> ");
875         scanf("%x", &j);
876         printf("break point=0x%x\n", j);
877         break;
878      case '5': case 'g':
879         s->wakeup = 0;
880         cycle(s, 0);
881         while(s->wakeup == 0)
882         {
883            if(s->pc == j)
884               break;
885            cycle(s, 0);
886         }
887         show_state(s);
888         break;
889      case 'G':
890         s->wakeup = 0;
891         cycle(s, 1);
892         while(s->wakeup == 0)
893         {
894            if(s->pc == j)
895               break;
896            cycle(s, 1);
897         }
898         show_state(s);
899         break;
900      case '6': case 'm':
901         printf("Memory> ");
902         scanf("%x", &j);
903         for(i = 0; i < 8; ++i)
904         {
905            printf("%8.8x ", mem_read(s, 4, j+i*4));
906         }
907         printf("\n");
908         break;
909      case '7': case 'w':
910         printf("Watch> ");
911         scanf("%x", &watch);
912         break;
913      case '8': case 'j':
914         printf("Jump> ");
915         scanf("%x", &addr);
916         s->pc = addr;
917         s->pc_next = addr + 4;
918         show_state(s);
919         break;
920      case '9': case 'q':
921         return;
922      }
923   }
924}
925/************************************************************/
926
927int main(int argc,char *argv[])
928{
929   State state, *s=&state;
930   FILE *in;
931   int bytes, index;
932   printf("Plasma emulator\n");
933   memset(s, 0, sizeof(State));
934   s->big_endian = 1;
935   s->mem = (unsigned char*)malloc(MEM_SIZE);
936   memset(s->mem, 0, MEM_SIZE);
937   if(argc <= 1)
938   {
939      printf(" Usage: mlite file.exe\n");
940      printf(" mlite file.exe B {for big_endian}\n");
941      printf(" mlite file.exe L {for little_endian}\n");
942      printf(" mlite file.exe BD {disassemble big_endian}\n");
943      printf(" mlite file.exe LD {disassemble little_endian}\n");
944
945      return 0;
946   }
947   in = fopen(argv[1], "rb");
948   if(in == NULL)
949   {
950      printf("Can't open file %s!\n",argv[1]);
951      getch();
952      return(0);
953   }
954   bytes = fread(s->mem, 1, MEM_SIZE, in);
955   fclose(in);
956   memcpy(s->mem + 1024*1024, s->mem, 1024*1024); //internal 8KB SRAM
957   printf("Read %d bytes.\n", bytes);
958   cache_init();
959   if(argc == 3 && argv[2][0] == 'B')
960   {
961      printf("Big Endian\n");
962      s->big_endian = 1;
963   }
964   if(argc == 3 && argv[2][0] == 'L')
965   {
966      printf("Big Endian\n");
967      s->big_endian = 0;
968   }
969   s->processId = 0;
970   if(argc == 3 && argv[2][0] == 'S')
971   { /*make big endian*/
972      printf("Big Endian\n");
973      for(index = 0; index < bytes+3; index += 4)
974      {
975         *(unsigned int*)&s->mem[index] = htonl(*(unsigned int*)&s->mem[index]);
976      }
977      in = fopen("big.exe", "wb");
978      fwrite(s->mem, bytes, 1, in);
979      fclose(in);
980      return(0);
981   }
982   if(argc == 3 && argv[2][1] == 'D')
983   { /*dump image*/
984      for(index = 0; index < bytes; index += 4) {
985         s->pc = index;
986         cycle(s, 10);
987      }
988      free(s->mem);
989      return(0);
990   }
991   s->pc = 0x0;
992   index = mem_read(s, 4, 0);
993   if((index & 0xffffff00) == 0x3c1c1000)
994      s->pc = 0x10000000;
995   do_debug(s);
996   free(s->mem);
997   return(0);
998}
999
1000

Archive Download this file

Branches:
master



interactive