]> rtime.felk.cvut.cz Git - fpga/plasma.git/blob - tools/mlite.c
Local copy of Plasma MIPS project.
[fpga/plasma.git] / 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
35 void Sleep(unsigned int value)
36
37    usleep(value * 1000);
38 }
39
40 int 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
62 int 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>
78 extern 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
99 typedef struct
100 {
101    unsigned int virtualAddress;
102    unsigned int physicalAddress;
103 } MmuEntry;
104
105 typedef 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
123 static 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
134 static 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
145 static char *regimm_string[]={
146    "BLTZ","BGEZ","BLTZL","BGEZL","?","?","?","?",
147    "TGEI","TGEIU","TLTI","TLTIU","TEQI","?","TNEI","?",
148    "BLTZAL","BEQZAL","BLTZALL","BGEZALL","?","?","?","?",
149    "?","?","?","?","?","?","?","?"
150 };
151
152 static unsigned int HWMemory[8];
153
154
155 static 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
212 static 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 */
275 unsigned 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
309 static int cacheData[CACHE_SET_ASSOC][CACHE_SIZE/sizeof(int)];
310 static int cacheAddr[CACHE_SET_ASSOC][CACHE_SIZE/CACHE_LINE_SIZE];
311 static int cacheSetNext;
312 static int cacheMiss, cacheWriteBack, cacheCount;
313
314 static 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 */
326 static 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
398 static 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
425 static 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
466 static 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
474 static unsigned int cacheData[1024];
475 static unsigned int cacheAddr[1024]; //9-bit addresses
476 static int cacheTry, cacheMiss, cacheInit;
477
478 static 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
523 static 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
549 void 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
576 void 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    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
604 void 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
813 void 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
837 void 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
927 int 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