/* Copyright (c) 1992-1993 The Regents of the University of California. All rights reserved. See copyright.h for copyright notice and limitation of liability and disclaimer of warranty provisions. */ #include "copyright.h" #include <stdio.h> #include "instr.h" #include "encode.h" #include "int.h" #define FAST 0 #define true 1 #define false 0 extern char mem[]; extern int TRACE, Regtrace; /* Machine registers */ int Reg[32]; /* GPR's */ int HI, LO; /* mul/div machine registers */ /* statistics gathering places */ int numjmpls; int arch1cycles; /* Condition-code calculations */ #define b31(z) (((z) >>31 )&0x1) /* extract bit 31 */ /* code looks funny but is fast thanx to MIPS! */ #define cc_add(rr, op1, op2) \ N = (rr < 0); \ Z = (rr == 0); \ C = ((unsigned) rr < (unsigned) op2); \ V = ((op1^op2) >= 0 && (op1^rr) < 0); #define cc_sub(rr, op1, op2) \ N = (rr < 0); \ Z = (rr == 0); \ V = b31((op1 & ~op2 & ~rr) | (~op1 & op2 & rr)); \ C = ((unsigned) op1 < (unsigned) op2); /* C = b31((~op1 & op2) | (rr & (~op1 | op2))); /* */ #define cc_logic(rr) \ N = (rr < 0); \ Z = (rr == 0); \ V = 0; \ C = 0; #define cc_mulscc(rr, op1, op2) \ N = (rr < 0); \ Z = (rr == 0); \ V = b31((op1 & op2 & ~rr) | (~op1 & ~op2 & rr)); \ C = b31((op1 & op2) | (~rr & (op1 | op2))); runprogram(startpc, argc, argv) int startpc, argc; char *argv[]; { int aci, ai, j; register int instr, pc, xpc, npc; register int i; /* temporary for local stuff */ register int icount; extern char *strcpy(); icount = 0; pc = startpc; npc = pc + 4; i = MEMSIZE - 1024 + memoffset; /* Initial SP value */ Reg[29] = i; /* Initialize SP */ /* setup argc and argv stuff (icky!) */ store(i, argc); aci = i + 4; ai = aci + 32; for ( j=0; j<argc; ++j ) { strcpy((mem-memoffset)+ai, argv[j]); store(aci, ai); aci += 4; ai += strlen(argv[j]) + 1; } for ( ; ; ) { ++icount; xpc = pc; pc = npc; npc = pc + 4; instr = ifetch(xpc); Reg[0] = 0; /* Force r0 = 0 */ if ( instr != 0 ) /* eliminate no-ops */ { switch ( (instr>>26) & 0x0000003f) { case I_SPECIAL: { switch ( instr & 0x0000003f ) { case I_SLL: Reg[rd(instr)] = Reg[rt(instr)] << shamt(instr); break; case I_SRL: Reg[rd(instr)] = (unsigned) Reg[rt(instr)] >> shamt(instr); break; case I_SRA: Reg[rd(instr)] = Reg[rt(instr)] >> shamt(instr); break; case I_SLLV: Reg[rd(instr)] = Reg[rt(instr)] << Reg[rs(instr)]; break; case I_SRLV: Reg[rd(instr)] = (unsigned) Reg[rt(instr)] >> Reg[rs(instr)]; break; case I_SRAV: Reg[rd(instr)] = Reg[rt(instr)] >> Reg[rs(instr)]; break; case I_JR: npc = Reg[rs(instr)]; break; case I_JALR: npc = Reg[rs(instr)]; Reg[rd(instr)] = xpc + 8; break; case I_SYSCALL: system_trap(); break; case I_BREAK: system_break(); break; case I_MFHI: Reg[rd(instr)] = HI; break; case I_MTHI: HI = Reg[rs(instr)]; break; case I_MFLO: Reg[rd(instr)] = LO; break; case I_MTLO: LO = Reg[rs(instr)]; break; case I_MULT: { int t1, t2; int t1l, t1h, t2l, t2h; int neg; t1 = Reg[rs(instr)]; t2 = Reg[rt(instr)]; neg = 0; if ( t1 < 0 ) { t1 = -t1 ; neg = !neg; } if ( t2 < 0 ) { t2 = -t2 ; neg = !neg; } LO = t1 * t2; t1l = t1 & 0xffff; t1h = (t1 >> 16) & 0xffff; t2l = t2 & 0xffff; t2h = (t2 >> 16) & 0xffff; HI = t1h*t2h+((t1h*t2l)>>16)+((t2h*t1l)>>16); if ( neg ) { LO = ~LO; HI = ~HI; LO = LO + 1; if ( LO == 0 ) HI = HI + 1; } } break; case I_MULTU: { int t1, t2; int t1l, t1h, t2l, t2h; t1 = Reg[rs(instr)]; t2 = Reg[rt(instr)]; t1l = t1 & 0xffff; t1h = (t1 >> 16) & 0xffff; t2l = t2 & 0xffff; t2h = (t2 >> 16) & 0xffff; LO = t1*t2; HI = t1h*t2h+((t1h*t2l)>>16)+((t2h*t1l)>>16); }break; case I_DIV: LO = Reg[rs(instr)] / Reg[rt(instr)]; HI = Reg[rs(instr)] % Reg[rt(instr)]; break; case I_DIVU: LO = (unsigned)Reg[rs(instr)] / (unsigned)Reg[rt(instr)]; HI = (unsigned)Reg[rs(instr)] % (unsigned)Reg[rt(instr)]; break; case I_ADD: case I_ADDU: Reg[rd(instr)] = Reg[rs(instr)] + Reg[rt(instr)]; break; case I_SUB: case I_SUBU: Reg[rd(instr)] = Reg[rs(instr)] - Reg[rt(instr)]; break; case I_AND: Reg[rd(instr)] = Reg[rs(instr)] & Reg[rt(instr)]; break; case I_OR: Reg[rd(instr)] = Reg[rs(instr)] | Reg[rt(instr)]; break; case I_XOR: Reg[rd(instr)] = Reg[rs(instr)] ^ Reg[rt(instr)]; break; case I_NOR: Reg[rd(instr)] = ~(Reg[rs(instr)] | Reg[rt(instr)]); break; case I_SLT: Reg[rd(instr)] = (Reg[rs(instr)] < Reg[rt(instr)]); break; case I_SLTU: Reg[rd(instr)] = ((unsigned) Reg[rs(instr)] < (unsigned) Reg[rt(instr)]); break; default: u(); break; } } break; case I_BCOND: { switch ( rt(instr) ) /* this field encodes the op */ { case I_BLTZ: if ( Reg[rs(instr)] < 0 ) npc = xpc + 4 + (immed(instr)<<2); break; case I_BGEZ: if ( Reg[rs(instr)] >= 0 ) npc = xpc + 4 + (immed(instr)<<2); break; case I_BLTZAL: Reg[31] = xpc + 8; if ( Reg[rs(instr)] < 0 ) npc = xpc + 4 + (immed(instr)<<2); break; case I_BGEZAL: Reg[31] = xpc + 8; if ( Reg[rs(instr)] >= 0 ) npc = xpc + 4 + (immed(instr)<<2); break; default: u(); break; } } break; case I_J: npc = (xpc & 0xf0000000) | ((instr & 0x03ffffff) << 2); break; case I_JAL: Reg[31] = xpc + 8; npc = (xpc & 0xf0000000) | ((instr & 0x03ffffff) << 2); break; case I_BEQ: if ( Reg[rs(instr)] == Reg[rt(instr)] ) npc = xpc + 4 + (immed(instr) << 2); break; case I_BNE: if ( Reg[rs(instr)] != Reg[rt(instr)] ) npc = xpc + 4 + (immed(instr) << 2); break; case I_BLEZ: if ( Reg[rs(instr)] <= 0 ) npc = xpc + 4 + (immed(instr) << 2); break; case I_BGTZ: if ( Reg[rs(instr)] > 0 ) npc = xpc + 4 + (immed(instr) << 2); break; case I_ADDI: Reg[rt(instr)] = Reg[rs(instr)] + immed(instr); break; case I_ADDIU: Reg[rt(instr)] = Reg[rs(instr)] + immed(instr); break; case I_SLTI: Reg[rt(instr)] = (Reg[rs(instr)] < immed(instr)); break; case I_SLTIU: Reg[rt(instr)] = ((unsigned) Reg[rs(instr)] < (unsigned) immed(instr)); break; case I_ANDI: Reg[rt(instr)] = Reg[rs(instr)] & immed(instr); break; case I_ORI: Reg[rt(instr)] = Reg[rs(instr)] | immed(instr); break; case I_XORI: Reg[rt(instr)] = Reg[rs(instr)] ^ immed(instr); break; case I_LUI: Reg[rt(instr)] = instr << 16; break; case I_LB: Reg[rt(instr)] = cfetch(Reg[rs(instr)] + immed(instr)); break; case I_LH: Reg[rt(instr)] = sfetch(Reg[rs(instr)] + immed(instr)); break; case I_LWL: i = Reg[rs(instr)] + immed(instr); Reg[rt(instr)] &= (-1 >> 8*((-i) & 0x03)); Reg[rt(instr)] |= ((fetch(i & 0xfffffffc)) << 8*(i & 0x03)); break; case I_LW: Reg[rt(instr)] = fetch(Reg[rs(instr)] + immed(instr)); break; case I_LBU: Reg[rt(instr)] = ucfetch(Reg[rs(instr)] + immed(instr)); break; case I_LHU: Reg[rt(instr)] = usfetch(Reg[rs(instr)] + immed(instr)); break; case I_LWR: i = Reg[rs(instr)] + immed(instr); Reg[rt(instr)] &= (-1 << 8*(i & 0x03)); if ( (i & 0x03)== 0 ) Reg[rt(instr)] = 0; Reg[rt(instr)] |= ((fetch(i & 0xfffffffc)) >> 8*((-i) & 0x03)); break; case I_SB: cstore(Reg[rs(instr)] + immed(instr), Reg[rt(instr)]); break; case I_SH: sstore(Reg[rs(instr)] + immed(instr), Reg[rt(instr)]); break; case I_SWL: fprintf(stderr, "sorry, no SWL yet.\n"); u(); break; case I_SW: store(Reg[rs(instr)] + immed(instr), Reg[rt(instr)]); break; case I_SWR: fprintf(stderr, "sorry, no SWR yet.\n"); u(); break; case I_LWC0: case I_LWC1: case I_LWC2: case I_LWC3: case I_SWC0: case I_SWC1: case I_SWC2: case I_SWC3: case I_COP0: case I_COP1: case I_COP2: case I_COP3: fprintf(stderr, "Sorry, no coprocessors.\n"); exit(2); break; default: u(); break; } } #ifdef DEBUG /* printf(" %d(%x) = %d(%x) op %d(%x)\n", Reg[rd], Reg[rd], op1, op1, op2, op2); /* */ #endif #if !FAST if ( TRACE ) { dump_ascii(instr, xpc); printf("\n"); /* */ if ( Regtrace ) dump_reg(); } #endif } } u() /* unimplemented */ { printf("Unimplemented Instruction\n"); exit(2); } ny() { printf("This opcode not implemeted yet.\n"); exit(2); } /* debug aids */ RS(i) int i; { return rs(i); } RT(i) int i; { return rt(i); } RD(i) int i; { return rd(i); } IM(i) int i; { return immed(i); } dump_reg() { int j; printf(" 0:"); for ( j=0; j<8; ++j ) printf(" %08x", Reg[j]); printf("\n"); printf(" 8:"); for ( ; j<16; ++j ) printf(" %08x", Reg[j]); printf("\n"); printf("16:"); for ( ; j<24; ++j ) printf(" %08x", Reg[j]); printf("\n"); printf("24:"); for ( ; j<32; ++j ) printf(" %08x", Reg[j]); printf("\n"); } /* 0 -> 0 1 -> 1 2 -> 1 3 -> 2 4 -> 2 5 -> 2 6 -> 2 7 -> 3 8 -> 3 9 -> 3 ... Treats all ints as unsigned numbers. */ ilog2(i) int i; { int j, l; if ( i == 0 ) return 0; j = 0; l = 1; if ( (j=(i&0xffff0000)) != 0 ) { i = j; l += 16; } if ( (j=(i&0xff00ff00)) != 0 ) { i = j; l += 8; } if ( (j=(i&0xf0f0f0f0)) != 0 ) { i = j; l += 4; } if ( (j=(i&0xcccccccc)) != 0 ) { i = j; l += 2; } if ( (j=(i&0xaaaaaaaa)) != 0 ) { i = j; l += 1; } return l; } #define NH 32 #define NNN 33 static int hists[NH][NNN]; int hoflo[NH], htotal[NH]; void henters(n, hist) int n, hist; { if ( 0 <= n && n < NNN ) ++hists[hist][n]; else ++hoflo[hist]; ++htotal[hist]; } hprint() { int h, i; double I; for ( h=0; h<=NH; ++h ) if ( htotal[h] > 0 ) { printf("\nhisto %d:\n", h); I = 0.0; for ( i=0; i<NNN; ++i ) { I += hists[h][i]; printf("%d\t%d\t%5.2f%%\t%5.2f%%\n", i, hists[h][i], (double) 100*hists[h][i] / htotal[h], (double) 100*I/htotal[h]); } printf("oflo %d:\t%d/%d\t%5.2f%%\n", h, hoflo[h], htotal[h], (double) 100*hoflo[h] / htotal[h]); } } int numadds=1, numsubs=1, numsuccesses, numcarries; int addtable[33][33]; int subtable[33][33]; char fmt[] = "%6d"; char fmt2[] = "------"; patable(tab) int tab[33][33]; { int i, j; printf(" |"); for ( j=0; j<33; ++j ) printf(fmt, j); putchar('\n'); printf(" |"); for ( j=0; j<33; ++j ) printf(fmt2); putchar('\n'); for ( i=0; i<33; ++i ) { printf("%2d|", i); for ( j=0; j<33; ++j ) printf(fmt, tab[i][j]); putchar('\n'); } } printstatistics() { /* printhist(); /* printf("numjmpls = %d / %d = %5.2f%%\n", numjmpls, arch1cycles, 100.0*numjmpls/arch1cycles); printf("numadds = %d, numsubs = %d, numcycles = %d, frac = %5.2f%%\n", numadds, numsubs, arch1cycles, (double) 100 * (numadds+numsubs) / arch1cycles); printf("numsuccesses = %d (%5.2f%%) numcarries = %d\n", numsuccesses, 100.0*numsuccesses/(numadds+numsubs), numcarries); /* hprint(); printf("\nADD table:\n");patable(addtable); printf("\nSUB table:\n");patable(subtable); */ } #define NNNN (64) static int hist[NNNN]; henter(n) int n; { if ( 0 <= n && n < NNNN ) ++hist[n]; } printhist() { int i; for ( i=0; i<NNNN; ++i ) printf("%d %d\n", i, hist[i]); }