/*
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