############################
#
# MIPS32
# Basic and FP (COP1) instructions
# 
# (See bottom of file for MIPS64 instructions included with MIPS32)
#
############################

@if defined(ISA_VARIANT)
@define AMODE   "ISA_MODE=0"	# ISA_MODE must restrict MIPS instruction decoding and require ISA_MODE=0
@else
@define AMODE "epsilon"			# Mips16 instructions not supported - Mips32 only
@endif

# 0000 00ss ssst tttt dddd d000 0010 0000
:add RD32, RS32src, RT32src           is $(AMODE) & prime=0 & sa=0 & fct=0x20 & RD32 & RS32src & RT32src & RD {
    RD32 = RS32src + RT32src;
@ifdef MIPS64
    RD = sext(RD32);
@endif
}

# 0010 01ss ssst tttt iiii iiii iiii iiii
:addiu RT32, RS32src, simmed        is $(AMODE) & prime=9 & RT32 & RS32src & simmed & RT {
    RT32 = RS32src + simmed;
@ifdef MIPS64
    RT = sext(RT32);
@endif
}

# 0000 00ss ssst tttt dddd d000 0010 0001
:addu RD32, RS32src, RT32src          is $(AMODE) & prime=0 & fct=0x21 & RS32src & RT32src & RD32 & sa=0 & RD {
    RD32 = RS32src + RT32src;
@ifdef MIPS64
    RD = sext(RD32);
@endif
}

# 0000 00ss ssst tttt dddd d000 0010 0100
:and RD, RSsrc, RTsrc           is $(AMODE) & prime=0 & fct=0x24 & RSsrc & RTsrc & RD & sa=0 {
    RD = RSsrc & RTsrc; 
}

# 0011 00ss ssst tttt iiii iiii iiii iiii
:andi RT, RSsrc, immed          is $(AMODE) & prime=0xC & RSsrc & RT & immed {
    RT = RSsrc & immed; 
}

# 0001 0000 0000 0000 iiii iiii iiii iiii 
:b Rel16                        is $(AMODE) & prime=4 & rs=0 & rt=0 & Rel16 {
    delayslot(1); 
    goto Rel16; 
}

# 0001 00ss ssst tttt iiii iiii iiii iiii 
:beq RSsrc, RTsrc, Rel16        is $(AMODE) & prime=4 & RSsrc & RTsrc & Rel16 {
    delayflag:1 = ( RSsrc == RTsrc ); 
    delayslot( 1 ); 
    if delayflag goto Rel16; 
}

# 0000 01ss sss0 0001 iiii iiii iiii iiii 
:bgez RSsrc, Rel16              is $(AMODE) & prime=1 & cond=1 & RSsrc & Rel16 {
    delayflag:1 = ( RSsrc s>= 0 ); 
    delayslot( 1 ); 
    if delayflag goto Rel16; 
}
# 0001 11ss sss0 0000 iiii iiii iiii iiii 
:bgtz RSsrc, Rel16              is $(AMODE) & prime=7 & cond=0 & RSsrc & Rel16 {
    delayflag:1 = ( RSsrc s> 0 ); 
    delayslot( 1 ); 
    if delayflag goto Rel16; 
} 
# 0001 10ss sss0 0000 iiii iiii iiii iiii 
:blez RSsrc, Rel16              is $(AMODE) & prime=6 & cond=0 & RSsrc & Rel16 {
    delayflag:1 = ( RSsrc s<= 0 ); 
    delayslot( 1 ); 
    if delayflag goto Rel16; 
}

# 0000 01ss sss0 0000 iiii iiii iiii iiii 
:bltz RSsrc, Rel16              is $(AMODE) & prime=1 & cond=0 & RSsrc & Rel16 {
    delayflag:1 = ( RSsrc s< 0 ); 
    delayslot( 1 ); 
    if delayflag goto Rel16; 
}
# 0001 01ss ssst tttt iiii iiii iiii iiii 
:bne RSsrc, RTsrc, Rel16        is $(AMODE) & prime=5 & RSsrc & RTsrc & Rel16 {
    delayflag:1 = ( RSsrc != RTsrc ); 
    delayslot( 1 ); 
    if delayflag goto Rel16; 
}

# 0000 00cc cccc cccc cccc cccc cc00 1101
:break breakcode                is $(AMODE) & prime=0 & fct=0xD & breakcode {
    tmp:4=breakcode; 
    trap(tmp); 
}

# 1011 11bb bbbo oooo iiii iiii iiii iiii
:cache op, OFF_BASER6           is $(AMODE) & ((prime=0x2F & REL6=0) | (prime=0x1F & REL6=1 & fct=0x25 & bit6=0)) & OFF_BASER6 & op {
    cacheOp(op:1, OFF_BASER6); 
}

:cachee op, OFF_BASER6           is $(AMODE) & prime=0x1F & fct=0x1B & bit6=0 & OFF_BASER6 & op {
    cacheOp(op:1, OFF_BASER6); 
}

:cfc0 RT, RD0                is $(AMODE) & prime=0x10 & copop=2 & RT & RD0 & bigfunct=0 {
    RT = sext( RD0:$(SIZETO4) );
}

# 0100 1000 010t tttt ssss s000 0000 0000
:cfc2 RT, immed                 is $(AMODE) & prime=0x12 & copop=2 & RT & immed {
    tmp:4 = getCopControlWord( 2:1, immed:4 );
    RT = sext(tmp);
}

# Special case of ADDU
# 0000 0000 0000 0000 dddd d000 0010 0001
:clear RD                       is $(AMODE) & prime=0 & fct=0x21 & rs=0 & rt=0 & RD & sa=0    {
    RD = 0; 
}

define pcodeop special2;

# 0111 00ss ssst tttt dddd daaa aaxx xyyy
# valid values of x and y:
# x: 0 y: 3,6,7
# x: 1 y: 0-7
# x: 2 y: 0-7
# x: 3 y: 0-7
# x: 4 y: 2,3,6,7
# x: 5 y: 0-7
# x: 6 y: 0-7
# x: 7 y: 0-6
:SPECIAL2 RD, RSsrc, RTsrc, sa, fct      is $(AMODE) & prime=0x1C & sa & RD & RSsrc & RTsrc & fct {
    tmp:1 = fct;
    tmp2:1 = sa;
    RD = special2(RSsrc, RTsrc, tmp2, tmp);
}

# 0100 101c cccc cccc cccc cccc cccc cccc
:cop2 cofun                     is $(AMODE) & prime=0x12 & bit25=1 & cofun {
    arg:4 = cofun;
    copFunction(2:1, arg);
}

:ctc0 RTsrc, RD0                is $(AMODE) & prime=0x10 & copop=6 & RTsrc & RD0 & bigfunct=0 {
    RD0 = RTsrc;
}
# 0100 1000 110t tttt iiii iiii iiii iiii
:ctc2 RTsrc, immed              is $(AMODE) & prime=0x12 & copop=6 & RTsrc & immed {
    setCopControlWord( 2:1, immed:4, RTsrc );
}

# 0100 0010 0000 0000 0000 0000 0001 1111 
:deret                          is $(AMODE) & prime=0x10 & bit25=1 & copfill=0x0 & fct=0x1F {
    return[DEPC];
}

# 0100 0001 011t tttt 0110 0000 0000 0000
:di                             is $(AMODE) & prime=0x10 & mfmc0=0x0B & rd=0x0C & fct2=0x0 & bit5=0x0 & zero3=0x0 & rt=0x0 {
    zero = Status;
    Status = Status & -2;   # clearing last bit (ffff..fffe == -2 signed)
}
:di RT                          is $(AMODE) & prime=0x10 & mfmc0=0x0B & rd=0x0C & fct2=0x0 & bit5=0x0 & zero3=0x0 & RT {
    RT = Status;
    Status = Status & -2;   # clearing last bit (ffff..fffe == -2 signed)
}

# 0000 0000 0000 0000 0000 0000 1100 0000
:ehb                            is $(AMODE) & prime=0x0 & rs=0x0 & rt=0x0 & rd=0x0 & fct2=0x3 & fct=0x0 {
} 

# 0100 0001 011t tttt 0110 0000 0010 0000
:ei                             is $(AMODE) & prime=0x10 & mfmc0=0x0B & rd=0x0C & fct2=0x0 & bit5=0x01 & zero3=0x0 & rt=0x0 {
    zero = Status;
    Status = Status | 1;
}
:ei RT                          is $(AMODE) & prime=0x10 & mfmc0=0x0B & rd=0x0C & fct2=0x0 & bit5=0x01 & zero3=0x0 & RT {
    RT = Status;
    Status = Status | 1;
}

# 0100 0010 0000 0000 0000 0000 0001 1000
:eret                           is $(AMODE) & prime=0x10 & fct=0x18 & bit25=1 & copfill=0  {
    return[EPC];
}

:eretnc							is $(AMODE) & prime=0x10 & fct=0x18 & bit25=1 & copfill=1  {
    return[EPC];
}

# 0111 11ss ssst tttt mmmm mLLL LL00 0000 
:ext RT, RSsrc, lsb, ExtSize    is $(AMODE) & prime=0x1F & fct=0x0 & RT & RSsrc & lsb & msbd & ExtSize {
    # Extract Bit Field
    # RT = extractField(RSsrc, msbd:1, lsb:1);
    # Note that msbd = size - 1
@if REGSIZE == "4"
    rs_tmp:4 = RSsrc << (32 - (msbd + lsb + 1));
    rs_tmp = rs_tmp >> (32 - (msbd + 1));
    RT = zext(rs_tmp);
@else
    rs_tmp:8 = RSsrc << (64 - (msbd + lsb + 1));
    rs_tmp = rs_tmp >> (64 - (msbd + 1));
    RT = zext(rs_tmp);
@endif
}

# 0111 11ss ssst tttt mmmm mLLL LL00 0100
:ins RT, RSsrc, lsb, InsSize    is $(AMODE) & prime=0x1F & fct=0x04 & RT & RTsrc & RSsrc & lsb & msbd & InsSize {
    tmpa:$(REGSIZE) = -1;
    tmpa = tmpa >> ($(REGSIZE) - InsSize);
    tmpb:$(REGSIZE) = RSsrc & tmpa;
    tmpa = tmpa << lsb;
    tmpa = ~tmpa;
    tmpb = tmpb << lsb;
    RT = (RT & tmpa) | tmpb;
}

# 0000 10aa aaaa aaaa aaaa aaaa aaaa aaaa
:j Abs26                        is $(AMODE) & prime=2 & Abs26 {
    delayslot( 1 ); 
    goto Abs26; 
}
# 0000 11aa aaaa aaaa aaaa aaaa aaaa aaaa
:jal Abs26                      is $(AMODE) & prime=3 & Abs26 {
    ra = inst_next; 
    delayslot( 1 ); 
    call Abs26; 
}
@ifdef ISA_VARIANT
# 0000 00ss sss0 0000 dddd dhhh hh00 1001
:jalr RD, RSsrc                 is $(AMODE) & prime=0 & fct=9 & RSsrc & rt=0 & RD {
	build RD;
	build RSsrc;
	JXWritePC(RSsrc); 
    RD = inst_next;
    delayslot( 1 );
    call [pc];
}
:jalr RSsrc                     is $(AMODE) & prime=0 & fct=9 & RSsrc & rt=0 & rd=0x1F  {
	build RSsrc;
	JXWritePC(RSsrc); 
    ra = inst_next; 
    delayslot( 1 ); 
    call [pc];
}
@else
# 0000 00ss sss0 0000 dddd dhhh hh00 1001
:jalr RD, RSsrc                 is $(AMODE) & prime=0 & fct=9 & RSsrc & rt=0 & RD {
    RD = inst_next;
    delayslot( 1 );
	tmp:$(ADDRSIZE) = 0;
	ValCast(tmp,RSsrc);
    call [tmp];     
}
:jalr RSsrc                     is $(AMODE) & prime=0 & fct=9 & RSsrc & rt=0 & rd=0x1F {
    ra = inst_next; 
    delayslot( 1 ); 
	tmp:$(ADDRSIZE) = 0;
	ValCast(tmp,RSsrc);
    call [tmp];     
}
@endif
@ifdef ISA_VARIANT
# 0000 00ss sss0 0000 dddd d1hh hh00 1001
:jalr.hb RD, RSsrc              is $(AMODE) & prime=0 & fct=9 & RSsrc & rt=0 & RD & bit10=1 {
	build RD;
	build RSsrc;
	JXWritePC(RSsrc); 
    RD = inst_next; 
    delayslot( 1 ); 
    call [pc];
}
:jalr.hb RSsrc                  is $(AMODE) & prime=0 & fct=9 & RSsrc & rt=0 & rd=0x1F & bit10=1 {
 	build RSsrc;
	JXWritePC(RSsrc); 
    ra = inst_next; 
    delayslot( 1 ); 
    call [pc];
}
@else
# 0000 00ss sss0 0000 dddd d1hh hh00 1001
:jalr.hb RD, RSsrc              is $(AMODE) & prime=0 & fct=9 & RSsrc & rt=0 & RD & bit10=1 {
    RD = inst_next; 
    delayslot( 1 ); 
	tmp:$(ADDRSIZE) = 0;
	ValCast(tmp,RSsrc);
    call [tmp];     
}
:jalr.hb RSsrc                  is $(AMODE) & prime=0 & fct=9 & RSsrc & rt=0 & rd=0x1F & bit10=1 {
    ra = inst_next; 
    delayslot( 1 ); 
	tmp:$(ADDRSIZE) = 0;
	ValCast(tmp,RSsrc);
    call [tmp];     
}
@endif

@ifdef ISA_VARIANT
# 0000 00ss sss0 0000 0000 0hhh hh00 1000
:jr RSsrc                       is $(AMODE) & prime=0 & ((REL6=0 & fct=8) | (REL6=1 & fct=0x09)) & RSsrc & rt=0 & rd=0  {
 	build RSsrc;
	JXWritePC(RSsrc); 
    delayslot(1); 
    goto [pc]; 
}
@else
# 0000 00ss sss0 0000 0000 0hhh hh00 1000
:jr RSsrc                       is $(AMODE) & prime=0 & ((REL6=0 & fct=8) | (REL6=1 & fct=0x09)) & RSsrc & rt=0 & rd=0 {
    delayslot(1); 
 	tmp:$(ADDRSIZE) = 0;
	ValCast(tmp,RSsrc);
    goto [tmp]; 
}
@endif
@ifdef ISA_VARIANT
# 0000 00ss sss0 0000 0000 01hh hh00 1000
:jr.hb RSsrc                    is $(AMODE) & prime=0 & ((REL6=0 & fct=8) | (REL6=1 & fct=0x09)) & RSsrc & rt=0 & rd=0 & bit10=1 {
  	build RSsrc;
	JXWritePC(RSsrc); 
    delayslot(1); 
    goto [pc]; 
}
@else
# 0000 00ss sss0 0000 0000 01hh hh00 1000
:jr.hb RSsrc                    is $(AMODE) & prime=0 & ((REL6=0 & fct=8) | (REL6=1 & fct=0x09)) & RSsrc & rt=0 & rd=0 & bit10=1 {
    delayslot(1); 
 	tmp:$(ADDRSIZE) = 0;
	ValCast(tmp,RSsrc);
    goto [tmp]; 
}
@endif

# Special case of JR
# 0000 0011 1110 0000 0000 0hhh hh00 1000
@ifdef ISA_VARIANT
:jr ra                           is $(AMODE) & prime=0 & ((REL6=0 & fct=8) | (REL6=1 & fct=0x09)) & rs=0x1F & ra & rt=0 & rd=0 & sa=0    {
	JXWritePC(ra); 
    delayslot(1); 
    return[pc]; 
}
@else
:jr ra                           is $(AMODE) & prime=0 & ((REL6=0 & fct=8) | (REL6=1 & fct=0x09)) & rs=0x1F & ra & rt=0 & rd=0 & sa=0    {
    delayslot(1); 
    return[ra]; 
}
@endif




# 1000 00bb bbbt tttt iiii iiii iiii iiii
:lb RT, OFF_BASE                is $(AMODE) & prime=0x20 & OFF_BASE & RT {
    RT = sext(*[ram]:1 OFF_BASE);  
}

:lbe RT, OFF_BASER6           	is $(AMODE) & prime=0x1F & fct=0x2C & bit6=0 & OFF_BASER6 & RT {
    RT = sext(*[ram]:1 OFF_BASER6);  
}

# 1001 00bb bbbt tttt iiii iiii iiii iiii
:lbu RT, OFF_BASE               is $(AMODE) & prime=0x24 & OFF_BASE & RT {
    RT = zext( *[ram]:1 OFF_BASE );
}

:lbue RT, OFF_BASER6           	is $(AMODE) & prime=0x1F & fct=0x28 & bit6=0 & OFF_BASER6 & RT {
    RT = zext( *[ram]:1 OFF_BASER6 );
}

# 1000 01bb bbbt tttt iiii iiii iiii iiii
:lh RT, OFF_BASE                is $(AMODE) & prime=0x21 & OFF_BASE & RT {
    RT = sext( *[ram]:2 OFF_BASE );
}

:lhe RT, OFF_BASER6           	is $(AMODE) & prime=0x1F & fct=0x2D & bit6=0 & OFF_BASER6 & RT {
    RT = sext( *[ram]:2 OFF_BASER6 );
}

# 1001 01bb bbbt tttt iiii iiii iiii iiii
:lhu RT, OFF_BASE               is $(AMODE) & prime=0x25 & OFF_BASE & RT {
    RT =  zext( *[ram]:2 OFF_BASE ); 
}

:lhue RT, OFF_BASER6           	is $(AMODE) & prime=0x1F & fct=0x29 & bit6=0 & OFF_BASER6 & RT {
    RT =  zext( *[ram]:2 OFF_BASER6 ); 
}

:lle RT, OFF_BASER6           	is $(AMODE) & prime=0x1F & fct=0x2E & bit6=0 & OFF_BASER6 & RT {
    RT = sext(*[ram]:4 OFF_BASER6);
}

# 1000 11bb bbbt tttt iiii iiii iiii iiii
:lw RT, OFF_BASE                is $(AMODE) & prime=0x23 & OFF_BASE & RT {
    RT = sext( *[ram]:4 OFF_BASE );
}

:lwe RT, OFF_BASER6           	is $(AMODE) & prime=0x1F & fct=0x2F & bit6=0 & OFF_BASER6 & RT {
    RT = sext( *[ram]:4 OFF_BASER6 );
}

:lbx RD, INDEX_BASE		is $(AMODE) & prime=0x1F & RD & fct=10 & fct2=22 & INDEX_BASE {
    RD = sext(*[ram]:1 INDEX_BASE);
}

:lbux RD, INDEX_BASE		is $(AMODE) & prime=0x1F & RD & fct=10 & fct2=6 & INDEX_BASE {
    RD = zext(*[ram]:1 INDEX_BASE);
}

@ifdef MIPS64
:ldx RD, INDEX_BASE		is $(AMODE) & prime=0x1F & RD & fct=10 & fct2=8 & INDEX_BASE {
    RD = *[ram]:8 INDEX_BASE;
}
@endif

:lhx RD, INDEX_BASE		is $(AMODE) & prime=0x1F & RD & fct=10 & fct2=4 & INDEX_BASE {
    RD = sext(*[ram]:2 INDEX_BASE);
}

:lhux RD, INDEX_BASE		is $(AMODE) & prime=0x1F & RD & fct=10 & fct2=20 & INDEX_BASE {
    RD = zext(*[ram]:2 INDEX_BASE);
}

:lwx RD, INDEX_BASE		is $(AMODE) & prime=0x1F & RD & fct=10 & fct2=0 & INDEX_BASE {
@ifdef MIPS64
    RD = sext(*[ram]:4 INDEX_BASE);
@else
    RD = *[ram]:4 INDEX_BASE;
@endif
}

@ifdef MIPS64
:lwux RD, INDEX_BASE		is $(AMODE) & prime=0x1F & RD & fct=10 & fct2=16 & INDEX_BASE {
    RD = zext(*[ram]:4 INDEX_BASE);
}
@endif

# 0100 0000 000t tttt dddd d000 0000 0sss
:mfc0 RT, RD0                   is $(AMODE) & prime=0x10 & copop=0 & RT & RD0 & zero6=0 {
    RT = sext( RD0:$(SIZETO4) );
}

# 0100 1000 000t tttt iiii iiii iiii iiii
:mfc2 RT, immed                 is $(AMODE) & prime=0x12 & copop=0 & RT & immed {
    tmp:$(REGSIZE) = getCopReg(2:1, immed:4);
    RT = sext( tmp );
}

# 0100 1000 011t tttt iiii iiii iiii iiii
:mfhc2 RT, immed                is $(AMODE) & prime=0x12 & copop=3 & RT & fs & immed {
    tmp:$(REGSIZE) = getCopReg(2:1, immed:4);
    RT = sext(tmp >> 32);
}

# Special case of ADDIU
# 0010 0100 000t tttt iiii iiii iiii iiii
:li RT, simmed                is $(AMODE) & prime=9 & rs=0 & RT & simmed            {
    RT = simmed;
}
# Special case of ADDU
# 0000 0000 000t tttt dddd d000 0010 0001
:move RD, RTsrc                 is $(AMODE) & prime=0 & fct=0x21 & rs=0 & RD & RTsrc & sa=0    {
    RD = RTsrc;
}
# Special case of ADDU
# 0000 00ss sss0 0000 dddd d000 0010 0001
:move RD, RSsrc                 is $(AMODE) & prime=0 & fct=0x21 & RSsrc & rt=0 & RD & sa=0    {
    RD = RSsrc; 
}

# 0100 0000 100t tttt dddd d000 0000 0sss
:mtc0 RTsrc, RD0, sel               is $(AMODE) & prime=0x10 & copop=4 & RTsrc & RD0 & zero6=0 & sel {
	setCopReg(0:1, RD0, RTsrc, sel:1); 
}
# 0100 1000 100t tttt iiii iiii iiii iiii
:mtc2 RTsrc, immed              is $(AMODE) & prime=0x12 & copop=4 & RTsrc & immed {
    setCopReg(2:1, immed:4, RTsrc);
}

:mthc0 RTsrc, RD0, sel          is $(AMODE) & prime=0x10 & copop=6 & RTsrc & RD0 & zero6=0 & sel {
	setCopReg(0:1, RD0, RTsrc, sel:1); 
}

# 0100 1000 111t tttt iiii iiii iiii iiii
:mthc2 RTsrc, immed             is $(AMODE) & prime=0x12 & copop=0x07 & RTsrc & immed {
    arg:4 = immed;
    tmp:4 = RTsrc:$(SIZETO4);
    low:4 = getCopReg(2:1, arg);
    val:8 = (zext(tmp) << 32) + zext(low);
    setCopReg(2:1, arg, val);
}

:nal             				is $(AMODE) & REL6=0 & prime=1 & cond=0x10 & zero21=0 {
	delayslot(1);
	ra = inst_next;
} 

# 0000 0000 0000 0000 0000 0000 0000 0000 
:nop                            is $(AMODE) & prime=0 & rs=0 & rt=0 & rd=0 & sa=0 & fct=0  {
}

# 0000 00ss ssst tttt dddd d000 0010 0111
:nor RD, RSsrc, RTsrc           is $(AMODE) & prime=0 & fct=0x27 & RSsrc & RTsrc & RD & sa=0 {
    RD = ~(RSsrc | RTsrc); 
}
# 0000 00ss ssst tttt dddd d000 0010 0101
:or RD, RSsrc, RTsrc            is $(AMODE) & prime=0 & fct=0x25 & RSsrc & RTsrc & RD & sa=0 {
    RD = RSsrc | RTsrc; 
}
# 0011 01ss ssst tttt iiii iiii iiii iiii
:ori RT, RSsrc, immed           is $(AMODE) & prime=0xD & RSsrc & RT & immed  {
    RT = RSsrc | immed; 
}

:pause							is $(AMODE) & prime=0 & szero=0 & fct=0 & fct2=0x05 {
	wait();
}

:pref hint, OFF_BASE            is $(AMODE) & prime=0x33 & hint & OFF_BASE {
    prefetch(OFF_BASE, hint:1); 
}

:prefe hint, OFF_BASER6         is $(AMODE) & prime=0x1F & fct=0x23 & bit6=0 & OFF_BASER6 & hint {
    prefetch(OFF_BASER6, hint:1); 
}        

# 0111 1100 000t tttt dddd d000 0011 1011
:rdhwr RT, RDsrc                is $(AMODE) & prime=0x1F & rs=0 & fct2=0 & fct=0x3B & RT & RDsrc {
    RT = getHWRegister(RDsrc);
}

# 0100 0001 010t tttt dddd d000 0000 0000 
:rdpgpr RD, RT                  is $(AMODE) & prime=0x10 & rs=10 & bigfunct=0 & RD & RT {
    RD = getShadow(RT);
}

# 0000 0000 001t tttt dddd daaa aa00 0010
:rotr RD32, RT32src, sa             is $(AMODE) & prime=0 & zero1=0 & bit21=1 & fct=2 & RD32 & RT32src & sa & RD {
    tmp1:4 = RT32src >> sa;
    tmp2:4 = RT32src << (32 - sa);
    RD32 = tmp1 + tmp2;
@ifdef MIPS64
    RD = sext(RD32);
@endif
}
# 0000 00ss ssst tttt dddd d000 0100 0110
:rotrv RD32, RT32src, RS32src         is $(AMODE) & prime=0 & zero2=0 & bit6=1 & fct=6 & RD32 & RT32src & RS32src & RD {
    shift:4 = RS32src & 0x1f;
    tmp1:4 = RT32src >> shift;
    tmp2:4 = RT32src << (32 - shift);
    RD32 = tmp1 + tmp2;
@ifdef MIPS64
    RD = sext(RD32);
@endif
}

# 1010 00bb bbbt tttt iiii iiii iiii iiii
:sb RTsrc, OFF_BASE             is $(AMODE) & prime=0x28 & OFF_BASE & RTsrc {
    *[ram]:1 OFF_BASE = RTsrc:1;
}

:sbe RTsrc, OFF_BASER6          is $(AMODE) & prime=0x1F & fct=0x1C & bit6=0 & OFF_BASER6 & RTsrc {
    *[ram]:1 OFF_BASER6 = RTsrc:1;
}

:sce RTsrc, OFF_BASER6          is $(AMODE) & prime=0x1F & fct=0x1E & bit6=0 & OFF_BASER6 & RTsrc {
    *[ram]:4 OFF_BASER6 = RTsrc:$(SIZETO4);
    RTsrc = 1;
}

# 0111 00cc cccc cccc cccc cccc cc11 1111
:sdbbp breakcode                is $(AMODE) & prime=0x1C & fct=0x3F & breakcode {
    signalDebugBreakpointException();
}

@ifndef COPR_C
# 1111 10bb bbbt tttt iiii iiii iiii iiii        
:sdc2 RTsrc, OFF_BASE           is $(AMODE) & prime=0x3E & OFF_BASE & RTsrc {
    *[ram]:8 OFF_BASE = getCopReg(2:1, RTsrc);
}
@endif

# 0111 1100 000t tttt dddd d100 0010 0000
:seb RD, RTsrc                  is $(AMODE) & prime=0x1F & rs=0 & fct2=0x10 & fct=0x20 & RD & RTsrc {
    RD = sext( RTsrc:1 );
}
# 0111 1100 000t tttt dddd d110 0010 0000
:seh RD, RTsrc                  is $(AMODE) & prime=0x1F & rs=0 & fct2=0x18 & fct=0x20 & RD & RTsrc {
    RD = sext( RTsrc:2 );  
}
# 1010 01bb bbbt tttt iiii iiii iiii iiii
:sh RTsrc, OFF_BASE             is $(AMODE) & prime=0x29 & OFF_BASE & RTsrc {
    *[ram]:2 OFF_BASE = RTsrc:2;  
}

:she RTsrc, OFF_BASER6          is $(AMODE) & prime=0x1F & fct=0x1D & bit6=0 & OFF_BASER6 & RTsrc {
    *[ram]:2 OFF_BASER6 = RTsrc:2;  
}

# 0000 0000 000t tttt dddd daaa aa00 0000
:sll RD32, RT32src, sa              is $(AMODE) & prime=0 & fct=0 & rs=0 & RD32 & RT32src & sa & RD {
    RD32 = RT32src << sa;
@ifdef MIPS64
    RD = sext(RD32);
@endif
}
# 0000 00ss ssst tttt dddd d000 0000 0100
:sllv RD32, RT32src, RS32src          is $(AMODE) & prime=0 & fct=4 & RS32src & RT32src & RD32 & sa=0 & RD {
    shift:4 = RS32src & 0x1f;
    RD32 = RT32src << shift;
@ifdef MIPS64
    RD = sext(RD32);
@endif
}
# 0000 00ss ssst tttt dddd d000 0010 1010
:slt RD, RSsrc, RTsrc           is $(AMODE) & prime=0 & fct=0x2A & RSsrc & RTsrc & RD & sa=0 {
    RD = zext( RSsrc s< RTsrc ); 
}
# 0010 10ss ssst tttt iiii iiii iiii iiii
:slti RT, RSsrc, simmed         is $(AMODE) & prime=10 & RSsrc & RT & simmed {
    RT = zext( RSsrc s< simmed ); 
}
# 0010 11ss ssst tttt iiii iiii iiii iiii
:sltiu RT, RSsrc, simmed        is $(AMODE) & prime=0xB & RSsrc & RT & simmed {
    RT = zext( RSsrc < simmed ); 
}
# 0000 00ss ssst tttt dddd d000 0010 1011
:sltu RD, RSsrc, RTsrc          is $(AMODE) & prime=0 & fct=0x2B & RSsrc & RTsrc & RD & sa=0 {
    RD = zext( RSsrc < RTsrc ); 
}

# 0000 0000 000t tttt dddd daaa aa00 0011
:sra RD32, RT32src, sa              is $(AMODE) & prime=0 & fct=3 & rs=0 & RT32src & RD32 & sa & RD {
    RD32 = RT32src s>> sa;
@ifdef MIPS64
    RD = sext(RD32);
@endif
}
# 0000 00ss ssst tttt dddd d000 0000 0111
:srav RD32, RT32src, RS32src          is $(AMODE) & prime=0 & fct=7 & RS32src & RT32src & RD32 & sa=0 & RD {
    shift:4 = RS32src & 0x1f;
    RD32 = RT32src s>> shift;
@ifdef MIPS64
    RD = sext(RD32);
@endif
}
# 0000 0000 000t tttt dddd daaa aa00 0010
:srl RD32, RT32src, sa              is $(AMODE) & prime=0 & fct=2 & rs=0 & RT32src & RD32 & sa & RD {
    RD32 = RT32src >> sa; 
@ifdef MIPS64
    RD = sext(RD32);
@endif
}
# 0000 00ss ssst tttt dddd d000 0000 0110
:srlv RD32, RT32src, RS32src          is $(AMODE) & prime=0 & fct=6 & RS32src & RT32src & RD32 & sa=0 & RD {
    shift:4 = RS32src & 0x1f;
    RD32 = RT32src >> shift; 
@ifdef MIPS64
    RD = sext(RD32);
@endif
}

# 0000 0000 0000 0000 0000 0000 0100 0000
:ssnop                          is $(AMODE) & prime=0 & rs=0 & rt=0 & rd=0 & sa=1 & fct=0 {
}

# 0000 00ss ssst tttt dddd d000 0010 0010                           
:sub RD32, RS32src, RT32src           is $(AMODE) & prime=0 & fct=0x22 & RS32src & RT32src & RD32 & sa=0 & RD {
    RD32 = RS32src - RT32src; 
@ifdef MIPS64
    RD = sext(RD32);
@endif
}
# 0000 00ss ssst tttt dddd d000 0010 0011
:subu RD32, RS32src, RT32src          is $(AMODE) & prime=0 & fct=0x23 & RS32src & RT32src & RD32 & sa=0 & RD {
    RD32 = RS32src - RT32src;
@ifdef MIPS64
    RD = sext(RD32);
@endif
}

# 1010 11bb bbbt tttt iiii iiii iiii iiii
:sw RTsrc, OFF_BASE             is $(AMODE) & prime=0x2B & OFF_BASE & RTsrc {
    *[ram]:4 OFF_BASE = RTsrc:$(SIZETO4);    
}

@ifndef COPR_C
# 1110 10bb bbbt tttt iiii iiii iiii iiii
:swc2 hint, OFF_BASE              is $(AMODE) & prime=0x3A & OFF_BASE & hint {
	tmp:4 = getCopReg(2:1, hint:4);
    *[ram]:4 OFF_BASE = tmp; 
}
@endif

:swe RTsrc, OFF_BASER6          is $(AMODE) & prime=0x1F & fct=0x1F & bit6=0 & OFF_BASER6 & RTsrc {
    *[ram]:4 OFF_BASER6 = RTsrc:$(SIZETO4);    
}

define pcodeop SYNC;

# 0000 0000 0000 0000 0000 0yyy yy00 1111
:sync scalar                    is $(AMODE) & prime=0 & fct=0xF & szero=0 & stype [ scalar = stype + 0; ] {
    SYNC(scalar:1);
}

# 0000 01bb bbb1 1111 iiii iiii iiii iiii
:synci OFF_BASE                 is $(AMODE) & prime=1 & OFF_BASE & synci=0x1F  {
}

# 0000 00cc cccc cccc cccc cccc cc00 1100
:syscall                        is $(AMODE) & prime=0 & fct=0xC & breakcode {
    tmp:4=breakcode; 
    syscall(tmp); 
}

# 0000 00ss ssst tttt cccc cccc cc11 0100
:teq RSsrc, RTsrc               is $(AMODE) & prime=0 & fct=0x34 & RSsrc & RTsrc & code {
    if (RSsrc != RTsrc) goto <done>; 
    tmp:2=code; 
    trap(tmp);
    <done>
}
# 0000 00ss ssst tttt cccc cccc cc11 0000
:tge RSsrc, RTsrc               is $(AMODE) & prime=0 & fct=0x30 & RSsrc & RTsrc & code {
    if (RSsrc < RTsrc) goto <done>; 
    tmp:2=code; 
    trap(tmp);
    <done>
}
# 0000 00ss ssst tttt cccc cccc cc11 0001
:tgeu RSsrc, RTsrc              is $(AMODE) & prime=0 & fct=0x31 & RSsrc & RTsrc & code {
    if (RSsrc < RTsrc) goto <done>; 
    tmp:2=code; 
    trap(tmp);
    <done>
}

:tlbinv		is $(AMODE) & prime=0x10 & bit25=1 & copfill=0x00 & fct=0x03 {
    TLB_invalidate(Index, EntryHi);
}

:tlbinvf	is $(AMODE) & prime=0x10 & bit25=1 & copfill=0x00 & fct=0x04 {
    TLB_invalidate_flush(Index);
}

:tlbp		is $(AMODE) & prime=0x10  & bit25=1 & copfill=0x00 & fct=0x08 {
    Index = TLB_probe_for_matching_entry(EntryHi);
}

:tlbr           is $(AMODE) & prime=0x10  & bit25=1 & copfill=0x00 & fct=0x01 {
    EntryHi = TLB_read_indexed_entryHi(Index);
    EntryLo0 = TLB_read_indexed_entryLo0(Index);
    EntryLo1 = TLB_read_indexed_entryLo1(Index);
    PageMask = TLB_read_indexed_entryLo1(Index);
}

:tlbwi		is $(AMODE) & prime=0x10  & bit25=1 & copfill=0x00 & fct=0x02 {
    TLB_write_indexed_entry(Index, EntryHi, EntryLo0, EntryLo1, PageMask);
}

:tlbwr          is $(AMODE) & prime=0x10  & bit25=1 & copfill=0x00 & fct=0x06 {
    TLB_write_random_entry(Random, EntryHi, EntryLo0, EntryLo1, PageMask);
}

# 0000 00ss ssst tttt cccc cccc cc11 0010
:tlt RSsrc, RTsrc               is $(AMODE) & prime=0 & fct=0x32 & RSsrc & RTsrc & code {
    if (RSsrc s>= RTsrc) goto <done>; 
    tmp:2=code; 
    trap(tmp);
    <done>
}
# 0000 00ss ssst tttt cccc cccc cc11 0011
:tltu RSsrc, RTsrc              is $(AMODE) & prime=0 & fct=0x33 & RSsrc & RTsrc & code {
    if (RSsrc >= RTsrc) goto <done>; 
    tmp:2=code; 
    trap(tmp);
    <done>
}
# 0000 00ss ssst tttt cccc cccc cc11 0110
:tne RSsrc, RTsrc               is $(AMODE) & prime=0 & fct=0x36 & RSsrc & RTsrc & code {
    if (RSsrc == RTsrc) goto <done>; 
    tmp:2=code; 
    trap(tmp);
    <done>
}

# 0100 001c cccc cccc cccc cccc cc10 0000
:wait                           is $(AMODE) & prime=0x10 & fct=0x20 & copfill & bit25=1  {
    tmp:4 = copfill; 
    wait(tmp); 
}

# 0100 0001 110t tttt dddd d000 0000 0000
:wrpgpr  RD, RTsrc              is $(AMODE) & prime=0x10 & format=0xE & RTsrc & RD & bigfunct=0  {
    setShadow(RD, RTsrc);
}

# 0111 1100 000t tttt dddd d000 1010 0000
:wsbh RD, RTsrc                 is $(AMODE) & prime=0x1F & format=0 & RTsrc & RD & wsbh=2 & bshfl=0x20 {
    tmp1:$(REGSIZE) = RTsrc & 0xff; 
    tmp2:$(REGSIZE) = (RTsrc >> 8) & 0xff;
    tmp3:$(REGSIZE) = (RTsrc >> 16) & 0xff; 
    tmp4:$(REGSIZE) = (RTsrc >> 24) & 0xff;
    RD = (tmp3 << 24) | (tmp4 << 16) | (tmp1 << 8) | (tmp2); 
}

# 0000 00ss ssst tttt dddd d000 0010 0110
:xor RD, RSsrc, RTsrc           is $(AMODE) & prime=0 & fct=0x26 & RSsrc & RTsrc & RD & sa=0 {
    RD = RSsrc ^ RTsrc; 
}
# 0011 10ss ssst tttt iiii iiii iiii iiii 
:xori RT, RSsrc, immed          is $(AMODE) & prime=0xE & RSsrc & RT & immed {
    RT = RSsrc ^ immed; 
}

############################
#
# MIPS64 Instructions to be included with all MIPS32 processors
#
############################

##  Allow MIPS 64 instructions below for compilers
##     using a 64-bit chip, but really keeping things to 32-bits

# Special case of daddu
# 0000 00ss ssst tttt dddd d000 0010 1101
:clear RD         is $(AMODE) & prime=0 & fct=0x2D & rs=0 & rt=0 & RD & sa=0 {
    RD = 0; 
}

# 0000 00ss ssst tttt dddd d000 0010 1100
:dadd RD, RSsrc, RTsrc          is $(AMODE) & prime=0 & fct=0x2C & RSsrc & RTsrc & RD & sa=0 {
    RD = RSsrc + RTsrc; 
}
# 0110 01ss ssst tttt iiii iiii iiii iiii
:daddiu RT, RSsrc, simmed       is $(AMODE) & prime=0x19 & RSsrc & RT & simmed {
    RT = RSsrc + simmed; 
}
# 0000 00ss ssst tttt dddd d000 0010 1101
:daddu RD, RSsrc, RTsrc         is $(AMODE) & prime=0 & fct=0x2D & RSsrc & RTsrc & RD & sa=0 {
    RD = RSsrc + RTsrc; 
}

####
#
# Pre-6 semantics
#
####
# 0010 00ss ssst tttt iiii iiii iiii iiii
:addi RT32, RS32src, simmed         is $(AMODE) & REL6=0 & prime=8 & RT32 & RS32src & simmed & RT {
    RT32 = RS32src + simmed;
@ifdef MIPS64
    RT = sext(RT32);
@endif
}

# 0000 01ss sss1 0001 iiii iiii iiii iiii
:bal Rel16            is $(AMODE) & REL6=0 & prime=1 & cond=0x11 & rs=0 & Rel16 {
    ra = inst_next; 
    delayslot( 1 ); 
    call Rel16; 
}

# Special case PIC
:bal Rel16            is $(AMODE) & REL6=0 & prime=1 & cond=0x11 & rs=0 & off16=1 & Rel16 {
    ra = inst_next; 
    delayslot( 1 ); 
    goto Rel16; 
}

# 0100 1001 000c cc00 iiii iiii iiii iiii
:bc2f Rel16                     is $(AMODE) & REL6=0 & prime=0x12 & copop=8 & cc=0 & nd=0 & tf=0 & Rel16 {
    tmp:1 = getCopCondition(2:1, 0:1); 
    delayslot(1); 
    if (tmp != 0) goto inst_next; 
    goto Rel16; 
}
:bc2f cc,Rel16                  is $(AMODE) & REL6=0 & prime=0x12 & copop=8 & cc & nd=0 & tf=0 & Rel16 {
    tmp:1 = getCopCondition(2:1, cc:1); 
    delayslot(1); 
    if (tmp != 0) goto inst_next; 
    goto Rel16; 
}
# 0100 1001 000c cc10 iiii iiii iiii iiii
:bc2fl Rel16                    is $(AMODE) & REL6=0 & prime=0x12 & copop=8 & cc=0 & nd=1 & tf=0 & Rel16 {
    tmp:1 = getCopCondition(2:1, 0:1); 
    if (tmp != 0) goto inst_next; 
    delayslot(1); 
    goto Rel16; 
}
:bc2fl cc,Rel16                 is $(AMODE) & REL6=0 & prime=0x12 & copop=8 & cc & nd=1 & tf=0 & Rel16 {
    tmp:1 = getCopCondition(2:1, cc:1); 
    if (tmp != 0) goto inst_next; 
    delayslot(1); 
    goto Rel16; 
}
# 0100 1001 000c cc01 iiii iiii iiii iiii
:bc2t Rel16                     is $(AMODE) & REL6=0 & prime=0x12 & copop=8 & cc=0 & nd=0 & tf=1 & Rel16 {
    tmp:1 = getCopCondition(2:1, 0:1); 
    delayslot(1); 
    if (tmp == 0) goto inst_next; 
    goto Rel16; 
}
:bc2t cc,Rel16                  is $(AMODE) & REL6=0 & prime=0x12 & copop=8 & cc & nd=0 & tf=1 & Rel16 {
    tmp:1 = getCopCondition(2:1, cc:1); 
    delayslot(1); 
    if (tmp == 0) goto inst_next; 
    goto Rel16; 
}
# 0100 1001 000c cc11 iiii iiii iiii iiii
:bc2tl Rel16                    is $(AMODE) & REL6=0 & prime=0x12 & copop=8 & cc=0 & nd=1 & tf=1 & Rel16 {
    tmp:1 = getCopCondition(2:1, 0:1); 
    if (tmp == 0) goto inst_next; 
    delayslot(1); 
    goto Rel16; 
}
:bc2tl cc,Rel16                 is $(AMODE) & REL6=0 & prime=0x12 & copop=8 & cc & nd=1 & tf=1 & Rel16 {
    tmp:1 = getCopCondition(2:1, cc:1); 
    if (tmp == 0) goto inst_next; 
    delayslot(1); 
    goto Rel16; 
}

# 0101 00ss ssst tttt iiii iiii iiii iiii
:beql RSsrc, RTsrc, Rel16       is $(AMODE) & REL6=0 & prime=0x14 & RSsrc & RTsrc & Rel16 {
    if (!(RSsrc==RTsrc)) goto inst_next; 
    delayslot(1); 
    goto Rel16; 
}

:bgezal RSsrc, Rel16            is $(AMODE) & REL6=0 & prime=1 & cond=0x11 & RSsrc & Rel16 {
    ra = inst_next; 
    delayflag:1 = ( RSsrc s>= 0 ); 
    delayslot( 1 ); 
    if (!delayflag) goto inst_next; 
    call Rel16; 
}

# 0000 01ss sss1 0011 iiii iiii iiii iiii
:bgezall RSsrc, Rel16           is $(AMODE) & REL6=0 & prime=1 & cond=0x13 & RSsrc & Rel16 {
    ra = inst_next; 
    if (!(RSsrc s>= 0)) goto inst_next; 
    delayslot( 1 ); 
    call Rel16; 
}
# 0000 01ss sss0 0011 iiii iiii iiii iiii 
:bgezl RSsrc, Rel16             is $(AMODE) & REL6=0 & prime=1 & cond=3 & RSsrc & Rel16 {
    if (!(RSsrc s>= 0)) goto inst_next; 
    delayslot(1); 
    goto Rel16; 
}
# 0101 11ss sss0 0000 iiii iiii iiii iiii 
:bgtzl RSsrc, Rel16             is $(AMODE) & REL6=0 & prime=0x17 & cond=0 & RSsrc & Rel16 {
    if (!(RSsrc s> 0)) goto inst_next; 
    delayslot(1); 
    goto Rel16; 
}
# 0101 10ss sss0 0000 iiii iiii iiii iiii 
:blezl RSsrc, Rel16             is $(AMODE) & REL6=0 & prime=0x16 & cond=0 & RSsrc & Rel16 {
    if (!(RSsrc s<= 0)) goto inst_next; 
    delayslot(1); 
    goto Rel16; 
}
# 0000 01ss sss1 0000 iiii iiii iiii iiii
:bltzal RSsrc, Rel16            is $(AMODE) & REL6=0 & prime=1 & cond=0x10 & RSsrc & Rel16 {
    ra = inst_next; 
    delayflag:1 = ( RSsrc s< 0 ); 
    delayslot( 1 ); 
    if (!delayflag) goto inst_next; 
    call Rel16; 
}
# 0000 01ss sss1 0010 iiii iiii iiii iiii
:bltzall RSsrc, Rel16           is $(AMODE) & REL6=0 & prime=1 & cond=0x12 & RSsrc & Rel16 {
    ra = inst_next; 
    if (!(RSsrc s< 0)) goto inst_next; 
    delayslot(1); 
    call Rel16; 
}
# 0000 01ss sss0 0010 iiii iiii iiii iiii 
:bltzl RSsrc, Rel16             is $(AMODE) & REL6=0 & prime=1 & cond=2 & RSsrc & Rel16 {
    if (!(RSsrc s< 0)) goto inst_next; 
    delayslot(1);
    goto Rel16; 
}
# 0101 01ss ssst tttt iiii iiii iiii iiii 
:bnel RSsrc, RTsrc, Rel16       is $(AMODE) & REL6=0 & prime=0x15 & RSsrc & RTsrc & Rel16 {
    if (!(RSsrc!=RTsrc)) goto inst_next; 
    delayslot(1); 
    goto Rel16; 
}

# 0111 00ss ssst tttt dddd d000 0010 0001
:clo RD, RSsrc                  is $(AMODE) & REL6=0 & prime=0x1C & sa=0x0 & fct=0x21 & RD & RSsrc {
    # Count leading ones in a word
    RD = countLeadingOnes( RSsrc );
}

# 0111 00ss ssst tttt dddd d000 0010 0000
:clz RD, RSsrc                  is $(AMODE) & REL6=0 & prime=0x1C & sa=0x0 & fct=0x20 & RD & RSsrc {
    # Count leading zeros in a word
    RD = countLeadingZeros( RSsrc );
}

# 0000 00ss ssst tttt 0000 0000 0001 1010
:div RS32src, RT32src               is $(AMODE) & REL6=0 & prime=0 & fct=0x1A & RS32src & RT32src & rd=0 & sa=0 {
    lo = sext(RS32src s/ RT32src); 
    hi = sext(RS32src s% RT32src); 
}
# 0000 00ss ssst tttt 0000 0000 0001 1011
:divu RS32src, RT32src              is $(AMODE) & REL6=0 & prime=0 & fct=0x1B & RS32src & RT32src & rd=0 & sa=0 {
    lo = sext(RS32src / RT32src); 
    hi = sext(RS32src % RT32src);   
}
@ifdef ISA_VARIANT
# 0111 01aa aaaa aaaa aaaa aaaa aaaa aaaa
:jalx Abs26                      is $(AMODE) & REL6=0 & prime=0x1D & Abs26 [ ISA_MODE = 1; globalset(Abs26, ISA_MODE);] {
    ra = inst_next; 
    delayslot( 1 );
    ISAModeSwitch = 1;
    call Abs26; 
}
@endif

@ifndef COPR_C
# 1101 10bb bbbt tttt iiii iiii iiii iiii
:ldc2 rt, OFF_BASE              is $(AMODE) & REL6=0 & prime=0x36 & OFF_BASE & rt {
    setCopReg(2:1, rt, *[ram]:8 OFF_BASE);
}
@endif

# 1100 00bb bbbt tttt iiii iiii iiii iiii
:ll RT, OFF_BASE                is $(AMODE) & REL6=0 & prime=0x30 & OFF_BASE & RT {
    RT = sext(*[ram]:4 OFF_BASE);
}

# 0011 1100 000t tttt iiii iiii iiii iiii
:lui RT, immed                  is $(AMODE) & REL6=0 & prime=0xF & rs=0 & RT & immed {
    tmp:4 = immed << 16;
    RT = sext(tmp); 
}

@ifndef COPR_C
# 1100 10bb bbbt tttt iiii iiii iiii iiii
:lwc2 rt, OFF_BASE              is $(AMODE) & REL6=0 & prime=0x32 & OFF_BASE & rt {
    setCopReg( 2:1, rt, *[ram]:4 OFF_BASE );    
}
@endif

@if ENDIAN == "big"
# 1000 10bb bbbt tttt iiii iiii iiii iiii
:lwl RT, OFF_BASE               is $(AMODE) & REL6=0 & prime=0x22 & OFF_BASE & RT & RTsrc {
    shft:$(ADDRSIZE) = OFF_BASE & 0x3; 
    addr:$(ADDRSIZE) = OFF_BASE - shft; 
    valOrig:4 = RTsrc:$(SIZETO4) & (0xffffffff >> ((4-shft) * 8));
    valLoad:4 = *(addr) << (shft * 8);     
    RT = sext( valLoad | valOrig );            
}

# 1001 10bb bbbt tttt iiii iiii iiii iiii
:lwr RT, OFF_BASE               is $(AMODE) & REL6=0 & prime=0x26 & OFF_BASE & RT & RTsrc {
    shft:$(ADDRSIZE) = OFF_BASE & 0x3; 
    addr:$(ADDRSIZE) = OFF_BASE - shft; 
    valOrig:4 = RTsrc:$(SIZETO4) & (0xffffffff << ((shft+1) * 8));
    valLoad:4 = *(addr) >> ((3-shft) * 8);
    RT = sext( valOrig | valLoad );
}
:lwle RTsrc, OFF_BASER6         is $(AMODE) & REL6=0 & prime=0x1F & fct=0x19 & bit6=0 & OFF_BASER6 & RTsrc & RT {
    shft:$(ADDRSIZE) = OFF_BASER6 & 0x3; 
    addr:$(ADDRSIZE) = OFF_BASER6 - shft; 
    valOrig:4 = RTsrc:$(SIZETO4) & (0xffffffff >> ((4-shft) * 8));
    valLoad:4 = *(addr) << (shft * 8);     
    RT = sext( valLoad | valOrig );            
}

:lwre RTsrc, OFF_BASER6         is $(AMODE) & REL6=0 & prime=0x1F & fct=0x1A & bit6=0 & OFF_BASER6 & RTsrc & RT {
    shft:$(ADDRSIZE) = OFF_BASER6 & 0x3; 
    addr:$(ADDRSIZE) = OFF_BASER6 - shft; 
    valOrig:4 = RTsrc:$(SIZETO4) & (0xffffffff << ((shft+1) * 8));
    valLoad:4 = *(addr) >> ((3-shft) * 8);
    RT = sext( valOrig | valLoad );
}
@else
:lwl RT, OFF_BASE               is $(AMODE) & REL6=0 & prime=0x22 & OFF_BASE & RT & RTsrc {
    shft:$(ADDRSIZE) = OFF_BASE & 0x3; 
    addr:$(ADDRSIZE) = OFF_BASE - shft; 
    valOrig:4 = RTsrc:$(SIZETO4) & (0xffffffff >> ((shft+1)* 8));
    valLoad:4 = *(addr) << ((3-shft) * 8);     
    RT = sext( valLoad | valOrig );            
}

# 1001 10bb bbbt tttt iiii iiii iiii iiii
:lwr RT, OFF_BASE               is $(AMODE) & REL6=0 & prime=0x26 & OFF_BASE & RT & RTsrc {
    shft:$(ADDRSIZE) = OFF_BASE & 0x3; 
    addr:$(ADDRSIZE) = OFF_BASE - shft; 
    valOrig:4 = RTsrc:$(SIZETO4) & (0xffffffff << ((4-shft)* 8));
    valLoad:4 = *(addr) >> (shft * 8);
    RT = sext( valOrig | valLoad );
}
:lwle RTsrc, OFF_BASER6         is $(AMODE) & REL6=0 & prime=0x1F & fct=0x19 & bit6=0 & OFF_BASER6 & RTsrc & RT {
    shft:$(ADDRSIZE) = OFF_BASER6 & 0x3; 
    addr:$(ADDRSIZE) = OFF_BASER6 - shft; 
    valOrig:4 = RTsrc:$(SIZETO4) & (0xffffffff >> ((shft+1)* 8));
    valLoad:4 = *(addr) << ((3-shft) * 8);     
    RT = sext( valLoad | valOrig );            
}

:lwre RTsrc, OFF_BASER6         is $(AMODE) & REL6=0 & prime=0x1F & fct=0x1A & bit6=0 & OFF_BASER6 & RTsrc & RT {
    shft:$(ADDRSIZE) = OFF_BASER6 & 0x3; 
    addr:$(ADDRSIZE) = OFF_BASER6 - shft; 
    valOrig:4 = RTsrc:$(SIZETO4) & (0xffffffff << ((4-shft)* 8));
    valLoad:4 = *(addr) >> (shft * 8);
    RT = sext( valOrig | valLoad );
}
@endif

# lwl and lwr almost always come in pairs. 
# When the analyzer does finds a matching lwl/lwr pair, the pcode is simplified so that 
# lwl does all the loading while lwr is a no-op
@if ENDIAN == "big"
:lwl RT, OFF_BASE               is $(AMODE) & REL6=0 & prime=0x22 & OFF_BASE & RT & PAIR_INSTRUCTION_FLAG=1 [ PAIR_INSTRUCTION_FLAG = 1; globalset(inst_next, PAIR_INSTRUCTION_FLAG);] {
    RT = sext( *[ram]:4 OFF_BASE );    
}
:lwr RT, OFF_BASE               is $(AMODE) & REL6=0 & prime=0x26 & OFF_BASE & RT & PAIR_INSTRUCTION_FLAG=1 [ PAIR_INSTRUCTION_FLAG = 0; ] {
}
@else
:lwl RT, OFF_BASE               is $(AMODE) & REL6=0 & prime=0x22 & OFF_BASE & RT & PAIR_INSTRUCTION_FLAG=1 [ PAIR_INSTRUCTION_FLAG = 1; globalset(inst_next, PAIR_INSTRUCTION_FLAG);] {
}
:lwr RT, OFF_BASE               is $(AMODE) & REL6=0 & prime=0x26 & OFF_BASE & RT & PAIR_INSTRUCTION_FLAG=1 [ PAIR_INSTRUCTION_FLAG = 0; ] {
    RT = sext( *[ram]:4 OFF_BASE );    
}
@endif

# 0111 00ss ssst tttt 000a a000 0000 0000
:madd RS32src, RT32src              is $(AMODE) & REL6=0 & prime=0x1C & zero1315=0x0 & fct2=0x0 & fct=0x0 & RS32src & RT32src & achi & aclo {
    tmp1:8 = sext(RS32src);
    tmp2:8 = sext(RT32src);
    prod:8 = tmp1 * tmp2;
    aclo = aclo & 0xffffffff;       # Make sure any upper bits of lo don't contribute to sum
    sum:8 = (zext(achi) << 32) + zext(aclo) + prod;
    aclo = sext(sum:4);
    sum = sum >> 32;
    achi = sext(sum:4);
}

# 0111 00ss ssst tttt 000a a000 0000 0001
:maddu RS32src, RT32src             is $(AMODE) & REL6=0 & prime=0x1C & zero1315=0x0 & fct2=0x0 & fct=0x01 & RS32src & RT32src & achi & aclo {
    tmp1:8 = zext(RS32src);
    tmp2:8 = zext(RT32src);
    prod:8 = tmp1 * tmp2;
    aclo = aclo & 0xffffffff;       # Make sure any upper bits of lo don't contribute to sum
    sum:8 = (zext(achi) << 32) + zext(aclo) + prod;
    aclo = sext(sum:4);
    sum = sum >> 32;
    achi = sext(sum:4);
}

# 0000 0000 0aa0 0000 dddd d000 0001 0000
:mfhi RD                        is $(AMODE) & REL6=0 & prime=0 & fct=0x10 & RD & zero5=0 & zero1620=0 & zero2325=0 & acfhi {
    RD = acfhi;
}

# 0000 0000 0aa0 0000 dddd d000 0001 0010
:mflo RD                        is $(AMODE) & REL6=0 & prime=0 & fct=0x12 & RD & zero5=0 & zero1620=0 & zero2325=0 & acflo {
    RD = acflo;
}

# 0000 00ss ssst tttt dddd d000 0000 1011
:movn RD, RSsrc, RTsrc          is $(AMODE) & REL6=0 & prime=0 & zero5=0 & fct=0xB & RD & RSsrc & RTsrc  {
    if (RTsrc == 0) goto <done>; 
      RD = RSsrc;
    <done>
}

# 0000 00ss ssst tttt dddd d000 0000 1010
:movz RD, RSsrc, RTsrc          is $(AMODE) & REL6=0 & prime=0 & zero5=0 & fct=10 & RD & RSsrc & RTsrc {
     if (RTsrc != 0) goto <done>; # We can't use goto inst_next because it fails if we are in a delay slot
       RD = RSsrc;
     <done>
}


# 0111 00ss ssst tttt 000a a000 0000 0100
:msub RS32src, RT32src              is $(AMODE) & REL6=0 & prime=0x1C & fct2=0 & fct=0x04 & RS32src & RT32src & zero1315=0 & aclo & achi {
    tmp1:8 = sext(RS32src);
    tmp2:8 = sext(RT32src);
    prod:8 = tmp1 * tmp2;
    aclo = aclo & 0xffffffff;       # Make sure any upper bits of lo don't contribute to sum
    sum:8 = (zext(achi) << 32) + zext(aclo) - prod;
    aclo = sext(sum:4);
    sum = sum >> 32;
    achi = sext(sum:4);
}

# 0111 00ss ssst tttt 000a a000 0000 0101
:msubu RS32src, RT32src             is $(AMODE) & REL6=0 & prime=0x1C & fct2=0 & fct=0x05 & RS32src & RT32src & zero1315=0 & aclo & achi {
    tmp1:8 = zext(RS32src);
    tmp2:8 = zext(RT32src);
    prod:8 = tmp1 * tmp2;
    aclo = aclo & 0xffffffff;       # Make sure any upper bits of lo don't contribute to sum
    sum:8 = (zext(achi) << 32) + zext(aclo) - prod;
    aclo = sext(sum:4);
    sum = sum >> 32;
    achi = sext(sum:4);
}

# 0000 00ss sss0 0000 000a a000 0001 0001
:mthi RSsrc                     is $(AMODE) & REL6=0 & prime=0 & fct=0x11 & RSsrc & zero5=0 & zero1320=0 & achi {
    achi = RSsrc;
}

# 0000 00ss sss0 0000 000a a000 0001 0011
:mtlo RSsrc                     is $(AMODE) & REL6=0 & prime=0 & fct=0x13 & RSsrc & zero5=0 & zero1320=0 & aclo {
    aclo = RSsrc;
}

# 0111 00ss ssst tttt dddd d000 0000 0010
:mul RD, RS32src, RT32src           is $(AMODE) & REL6=0 & prime=0x1C & sa=0x0 & fct=0x02 & RD & RS32src & RT32src {
    tmp1:8 = sext( RS32src );
    tmp2:8 = sext( RT32src );
    prod:8 = tmp1 * tmp2;
    RD = sext( prod:4 );
}

# 0000 00ss ssst tttt 000a a000 0001 1000
:mult RS32src, RT32src              is $(AMODE) & REL6=0 & prime=0 & fct=0x18 & RS32src & RT32src & zero5=0 & zero1315=0 & aclo & achi {
    tmp1:8 = sext( RS32src );
    tmp2:8 = sext( RT32src );
    prod:8 = tmp1 * tmp2;
    aclo = sext(prod:4);
    prod = prod >> 32;
    achi = sext(prod:4);
}

# 0000 00ss ssst tttt 000a a000 0001 1001
:multu RS32src, RT32src             is $(AMODE) & REL6=0 & prime=0 & fct=0x19 & RS32src & RT32src & zero5=0 & zero1315=0 & aclo & achi {
    tmp1:8 = zext( RS32src );
    tmp2:8 = zext( RT32src );
    prod:8 = tmp1 * tmp2;
    aclo = sext(prod:4);
    prod = prod >> 32;
    achi = sext(prod:4);
}

# 0100 0110 110t tttt ssss sddd dd10 1100
:pll.ps fd, fs, ft              is $(AMODE) & REL6=0 & prime=0x11 & format=0x16 & fct=0x2C & ft & fs & fd
    unimpl

# 0100 0110 110t tttt ssss sddd dd10 1101
:plu.ps fd, fs, ft              is $(AMODE) & REL6=0 & prime=0x11 & format=0x16 & fct=0x2D & ft & fs & fd
    unimpl 

#:prefx

# 0100 0110 110t tttt ssss sddd dd10 1110
:pul.ps fd, fs, ft              is $(AMODE) & REL6=0 & prime=0x11 & format=0x16 & fct=0x2E & fd & fs & ft
    unimpl
# 0100 0110 110t tttt ssss sddd dd10 1111
:puu.ps fd, fs, ft              is $(AMODE) & REL6=0 & prime=0x11 & format=0x16 & fct=0x2F & fd & fs & ft
    unimpl

# 1110 00bb bbbt tttt iiii iiii iiii iiii
:sc RTsrc, OFF_BASE             is $(AMODE) & REL6=0 & prime=0x38 & OFF_BASE & RT & RTsrc {
    *[ram]:4 OFF_BASE = RTsrc:$(SIZETO4);
    RT = 1;
}

@if ENDIAN == "big"
# 1010 10bb bbbt tttt iiii iiii iiii iiii
:swl RTsrc, OFF_BASE            is $(AMODE) & REL6=0 & prime=0x2A & OFF_BASE & RTsrc {
    tmpRT:4 = RTsrc:$(SIZETO4);  
    shft:$(ADDRSIZE) = OFF_BASE & 0x3; 
    addr:$(ADDRSIZE) = OFF_BASE - shft; 
    valOrig:4 = *(addr) & (0xffffffff << ((4-shft) * 8));
    valStore:4 = tmpRT >> (shft * 8);
    *(addr) = valOrig | valStore; 
}
# 1011 10bb bbbt tttt iiii iiii iiii iiii
:swr RTsrc, OFF_BASE            is $(AMODE) & REL6=0 & prime=0x2E & OFF_BASE & RTsrc {
    tmpRT:4 = RTsrc:$(SIZETO4);
    shft:$(ADDRSIZE) = OFF_BASE & 0x3;      
    addr:$(ADDRSIZE) = OFF_BASE - shft; 
    valOrig:4 = *(addr) & (0xffffffff >> ((shft+1) * 8));
    valStore:4 = tmpRT << ((3-shft)*8);
    *(addr) = valOrig | valStore;
}
:swle RTsrc, OFF_BASER6         is $(AMODE) & REL6=0 & prime=0x1F & fct=0x21 & bit6=0 & OFF_BASER6 & RTsrc & RT {
    tmpRT:4 = RTsrc:$(SIZETO4);  
    shft:$(ADDRSIZE) = OFF_BASER6 & 0x3; 
    addr:$(ADDRSIZE) = OFF_BASER6 - shft; 
    valOrig:4 = *(addr) & (0xffffffff << ((4-shft) * 8));
    valStore:4 = tmpRT >> (shft * 8);
    *(addr) = valOrig | valStore; 
}
:swre RTsrc, OFF_BASER6         is $(AMODE) & REL6=0 & prime=0x1F & fct=0x22 & bit6=0 & OFF_BASER6 & RTsrc & RT {
    tmpRT:4 = RTsrc:$(SIZETO4);
    shft:$(ADDRSIZE) = OFF_BASER6 & 0x3;      
    addr:$(ADDRSIZE) = OFF_BASER6 - shft; 
    valOrig:4 = *(addr) & (0xffffffff >> ((shft+1) * 8));
    valStore:4 = tmpRT << ((3-shft)*8);
    *(addr) = valOrig | valStore;
}

@else
# 1010 10bb bbbt tttt iiii iiii iiii iiii
:swl RTsrc, OFF_BASE            is $(AMODE) & REL6=0 & prime=0x2A & OFF_BASE & RTsrc {
    tmpRT:4 = RTsrc:$(SIZETO4);  
    shft:$(ADDRSIZE) = OFF_BASE & 0x3; 
    addr:$(ADDRSIZE) = OFF_BASE - shft; 
    valOrig:4 = *(addr) & (0xffffffff << ((shft+1) * 8));
    valStore:4 = tmpRT >> ((3-shft) * 8);
    *(addr) = valOrig | valStore; 
}
# 1011 10bb bbbt tttt iiii iiii iiii iiii
:swr RTsrc, OFF_BASE            is $(AMODE) & REL6=0 & prime=0x2E & OFF_BASE & RTsrc {
    tmpRT:4 = RTsrc:$(SIZETO4);
    shft:$(ADDRSIZE) = OFF_BASE & 0x3;      
    addr:$(ADDRSIZE) = OFF_BASE - shft; 
    valOrig:4 = *(addr) & (0xffffffff >> ((4-shft) * 8));
    valStore:4 = tmpRT << (shft*8);
    *(addr) = valOrig | valStore;
}
:swle RTsrc, OFF_BASER6         is $(AMODE) & REL6=0 & prime=0x1F & fct=0x21 & bit6=0 & OFF_BASER6 & RTsrc & RT {
    tmpRT:4 = RTsrc:$(SIZETO4);  
    shft:$(ADDRSIZE) = OFF_BASER6 & 0x3; 
    addr:$(ADDRSIZE) = OFF_BASER6 - shft; 
    valOrig:4 = *(addr) & (0xffffffff << ((shft+1) * 8));
    valStore:4 = tmpRT >> ((3-shft) * 8);
    *(addr) = valOrig | valStore; 
}
:swre RTsrc, OFF_BASER6         is $(AMODE) & REL6=0 & prime=0x1F & fct=0x22 & bit6=0 & OFF_BASER6 & RTsrc & RT {
    tmpRT:4 = RTsrc:$(SIZETO4);
    shft:$(ADDRSIZE) = OFF_BASER6 & 0x3;      
    addr:$(ADDRSIZE) = OFF_BASER6 - shft; 
    valOrig:4 = *(addr) & (0xffffffff >> ((4-shft) * 8));
    valStore:4 = tmpRT << (shft*8);
    *(addr) = valOrig | valStore;
}

@endif

# When the analyzer finds a matching swl/swr pair, the pcode is simplified so that 
# swl does all the storing while swr is a no-op
@if ENDIAN == "big"
:swl RTsrc, OFF_BASE            is $(AMODE) & REL6=0 & prime=0x2A & OFF_BASE & RTsrc & PAIR_INSTRUCTION_FLAG=1 [ PAIR_INSTRUCTION_FLAG = 1; globalset(inst_next, PAIR_INSTRUCTION_FLAG);] {
    *[ram]:4 OFF_BASE = RTsrc:$(SIZETO4);
}
:swr RTsrc, OFF_BASE            is $(AMODE) & REL6=0 & prime=0x2E & OFF_BASE & RTsrc & PAIR_INSTRUCTION_FLAG=1 [ PAIR_INSTRUCTION_FLAG = 0; ]{
}
@else
:swl RTsrc, OFF_BASE            is $(AMODE) & REL6=0 & prime=0x2A & OFF_BASE & RTsrc & PAIR_INSTRUCTION_FLAG=1 [ PAIR_INSTRUCTION_FLAG = 1; globalset(inst_next, PAIR_INSTRUCTION_FLAG);] {
}
:swr RTsrc, OFF_BASE            is $(AMODE) & REL6=0 & prime=0x2E & OFF_BASE & RTsrc & PAIR_INSTRUCTION_FLAG=1 [ PAIR_INSTRUCTION_FLAG = 0; ]{
    *[ram]:4 OFF_BASE = RTsrc:$(SIZETO4);
}
@endif

# 0000 01ss sss0 1100 iiii iiii iiii iiii
:teqi RSsrc, simmed             is $(AMODE) & REL6=0 & prime=1 & cond=0xC & RSsrc & simmed {
    if (RSsrc != simmed) goto <done>; 
    trap();
    <done>
}
# 0000 01ss sss0 1000 iiii iiii iiii iiii
:tgei RSsrc, simmed             is $(AMODE) & REL6=0 & prime=1 & cond=8 & RSsrc & simmed {
    if (RSsrc s< simmed) goto <done>; 
    trap();
    <done>
}
# 0000 01ss sss0 1001 iiii iiii iiii iiii
:tgeiu RSsrc, simmed            is $(AMODE) & REL6=0 & prime=1 & cond=9 & RSsrc & simmed {
    if (RSsrc < simmed) goto <done>; 
    trap();
    <done> 
}
# 0000 01ss sss0 1010 iiii iiii iiii iiii
:tlti RSsrc, simmed             is $(AMODE) & REL6=0 & prime=1 & cond=10 & RSsrc & simmed {
    if (RSsrc s>= simmed) goto <done>; 
    trap();
    <done>
}
# 0000 01ss sss0 1011 iiii iiii iiii iiii
:tltiu RSsrc, simmed            is $(AMODE) & REL6=0 & prime=1 & cond=0xB & RSsrc & simmed {
    if (RSsrc >= simmed) goto <done>; 
    trap();
    <done>
}
# 0000 01ss sss0 1110 iiii iiii iiii iiii
:tnei RSsrc, simmed             is $(AMODE) & REL6=0 & prime=1 & cond=0xE & RSsrc & simmed {
    if (RSsrc == simmed) goto <done>; 
    trap();
    <done> 
}

############################
#
# MIPS64 Instructions to be included with all MIPS32 processors
#
############################

##  Allow MIPS 64 instructions below for compilers
##     using a 64-bit chip, but really keeping things to 32-bits
# 0110 00ss ssst tttt iiii iiii iiii iiii
:daddi RT, RSsrc, simmed        is $(AMODE) & REL6=0 & prime=0x18 & RSsrc & RT & simmed {
    RT = RSsrc + simmed; 
}

####
#
# Release 6 semantics
#
####

:addiupc RSsrc, S19L2				is $(AMODE) & REL6=1 & prime=0x3B & bitz19=0 & RSsrc & S19L2 {
	RSsrc = inst_start + sext(S19L2);
}

:align RD, RS32src, RT32src, bp2 	is $(AMODE) & REL6=1 & prime=0x1F & spec3=0x2 & fct=0x20 & bp2 & RS32src & RT32src & RD {
	tmp:4 = RT32src << (8 * bp2);
	tmp = tmp | (RS32src >> (32 - (8 * bp2)));
	RD = sext(tmp);
}

:aluipc RSsrc, S16L16				is $(AMODE) & REL6=1 & prime=0x3B & op=0x1F & RSsrc & S16L16 {
	RSsrc = inst_start + sext(S16L16);
	RSsrc = RSsrc & ~0xFFFF;
}

:aui RTsrc, RSsrc, S16L16			is $(AMODE) & REL6=1 & prime=0x0F & RSsrc & RTsrc & S16L16 {
	RTsrc = RSsrc + sext(S16L16);
}

:auipc RSsrc, S16L16				is $(AMODE) & REL6=1 & prime=0x3B & op=0x1E & RSsrc & S16L16 {
	RSsrc = inst_start + sext(S16L16);
}

# 0000 0100 0001 0001 iiii iiii iiii iiii
:bal Rel16               			is $(AMODE) & REL6=1 & prime=0x01 & cond=0x11 & rs=0 & Rel16 {
    ra = inst_next; 
    delayslot(1); 
    call Rel16; 
}

:bal Rel16               			is $(AMODE) & REL6=1 & prime=0x01 & cond=0x11 & rs=0 & off16=1 & Rel16 {
    ra = inst_next; 
    delayslot(1); 
    goto Rel16; 
}

:balc Rel26							is $(AMODE) & REL6=1 & prime=0x3A & Rel26 {
    ra = inst_next; 
    call Rel26; 
} 

:bc Rel26							is $(AMODE) & REL6=1 & prime=0x32 & Rel26 {
	goto Rel26;
}

:bc2eqz op, Rel16					is $(AMODE) & REL6=1 & prime=0x12 & copop=0x09 & op & Rel16 {
    tmp:1 = getCopCondition(2:1, op:1); 
    if (tmp == 0) goto inst_next; 
    goto Rel16; 
}

:bc2nez op, Rel16					is $(AMODE) & REL6=1 & prime=0x12 & copop=0x0D & op & Rel16 {
    tmp:1 = getCopCondition(2:1, op:1); 
    if (tmp != 0) goto inst_next; 
    goto Rel16; 
}

:bad1								is $(AMODE) & REL6=1 & prime=0x06 & rs=0 & rt=0 unimpl
:blezalc RTsrc, Rel16				is $(AMODE) & REL6=1 & prime=0x06 & rs=0 & RTsrc & Rel16 {
	if (RTsrc s> 0) goto inst_next;
    ra = inst_next; 
	call Rel16;
}

:bgezalc RTsrc, Rel16				is $(AMODE) & REL6=1 & prime=0x06 & rs=rt & rt!=0 & RTsrc & Rel16 {
	if (RTsrc s< 0) goto inst_next;
    ra = inst_next; 
	call Rel16;
}	

:bgeuc RSsrc, RTsrc, Rel16			is $(AMODE) & REL6=1 & prime=0x06 & rt!=0 & rs!=rt & RSsrc & RTsrc & Rel16 {
	if (RSsrc >= RTsrc) goto Rel16;
}

:bad2								is $(AMODE) & REL6=1 & prime=0x07 & rs=0 & rt=0 unimpl
:bgtzalc RTsrc, Rel16				is $(AMODE) & REL6=1 & prime=0x07 & rs=0 & RTsrc & Rel16 {
	if (RTsrc s<= 0) goto inst_next;
    ra = inst_next; 
	call Rel16;
}

:bltzalc RTsrc, Rel16				is $(AMODE) & REL6=1 & prime=0x07 & rs=rt & rt!=0 & RTsrc & Rel16 {
	if (RTsrc s>= 0) goto inst_next;
    ra = inst_next; 
	call Rel16;
}	

:bltuc RSsrc, RTsrc, Rel16			is $(AMODE) & REL6=1 & prime=0x07 & rt!=0 & rs!=rt & RSsrc & RTsrc & Rel16 {
	if (RSsrc < RTsrc) goto Rel16;
}


:beqzalc RTsrc, Rel16				is $(AMODE) & REL6=1 & prime=0x08 & rs=0 & rt!=0 & RTsrc & Rel16 {
	if (RTsrc s> 0) goto inst_next;
    ra = inst_next; 
	call Rel16;
}

:beqc RSsrc, RTsrc, Rel16			is $(AMODE) & REL6=1 & prime=0x08 & rs!=0 & rs<rt & RSsrc & RTsrc & Rel16 {
	if (RSsrc == RTsrc) goto Rel16;
}

:bovc RSsrc, RTsrc, Rel16			is $(AMODE) & REL6=1 & prime=0x08 & RSsrc & RTsrc & rs32 & rt32 & Rel16 {
	tmpS:8 = sext(rs32);
	tmpT:8 = sext(rt32);
	tmpS = tmpS + tmpT;
	tmpF:1 = (tmpS s> 0x7FFFFFFF) || (tmpS s< -2147483648);
@if REGSIZE == "8"
	tmpF = tmpF || (RTsrc s> 0x7FFFFFFF) || (RTsrc s< -2147483648) || (RSsrc s> 0x7FFFFFFF) || (RSsrc s< -2147483648);
@endif
	if (tmpF == 1) goto Rel16;
}

:bnezalc RTsrc, Rel16				is $(AMODE) & REL6=1 & prime=0x18 & rs=0 & rt!=0 & RTsrc & Rel16 {
	if (RTsrc == 0) goto inst_next;
    ra = inst_next; 
	call Rel16;
}

:bnec RSsrc, RTsrc, Rel16			is $(AMODE) & REL6=1 & prime=0x18 & rs!=0 & rs<rt & RSsrc & RTsrc & Rel16 {
	if (RSsrc != RTsrc) goto Rel16;
}

:bnvc RSsrc, RTsrc, Rel16			is $(AMODE) & REL6=1 & prime=0x18 & RSsrc & RTsrc & rs32 & rt32 & Rel16 {
	tmpS:8 = sext(rs32);
	tmpT:8 = sext(rt32);
	tmpS = tmpS + tmpT;
	tmpF:1 = (tmpS s> 0x7FFFFFFF) || (tmpS s< -2147483648);
@if REGSIZE == "8"
	tmpF = tmpF || (RTsrc s> 0x7FFFFFFF) || (RTsrc s< -2147483648) || (RSsrc s> 0x7FFFFFFF) || (RSsrc s< -2147483648);
@endif
	if (tmpF == 0) goto Rel16;
}

:bad3								is $(AMODE) & REL6=1 & prime=0x16 & rs=0 & rt=0 unimpl
:blezc RTsrc, Rel16					is $(AMODE) & REL6=1 & prime=0x16 & rs=0 & rt!=0 & RTsrc & Rel16 {
	if (RTsrc s<= 0) goto Rel16;
}
:bgezc RTsrc, Rel16					is $(AMODE) & REL6=1 & prime=0x16 & rs=rt & rt!=0 & RTsrc & Rel16 {
	if (RTsrc s>= 0) goto Rel16;
}
:bgec RSsrc, RTsrc, Rel16			is $(AMODE) & REL6=1 & prime=0x16 & RSsrc & RTsrc & Rel16 {
	if (RSsrc s>= RTsrc) goto Rel16;
}


:bad4								is $(AMODE) & REL6=1 & prime=0x17 & rs=0 & rt=0 unimpl
:bgtzc RTsrc, Rel16					is $(AMODE) & REL6=1 & prime=0x17 & rs=0 & rt!=0 & RTsrc & Rel16 {
	if (RTsrc s> 0) goto Rel16;
}

:bltzc RTsrc, Rel16					is $(AMODE) & REL6=1 & prime=0x17 & rs=rt & rt!=0 & RTsrc & Rel16 {
	if (RTsrc s< 0) goto Rel16;
}

:bltc RSsrc, RTsrc, Rel16			is $(AMODE) & REL6=1 & prime=0x17 & RSsrc & RTsrc & Rel16 {
	if (RSsrc s< RTsrc) goto Rel16;
}

# The jic instruction takes care of the 'bad' case here
:beqzc RSsrc, Rel21					is $(AMODE) & REL6=1 & prime=0x36 & RSsrc & Rel21 {
	if (RSsrc == 0) goto Rel21;
}

# The jialc instruction takes care of the 'bad' case here
:bnezc RSsrc, Rel21					is $(AMODE) & REL6=1 & prime=0x3E & RSsrc & Rel21 {
	if (RSsrc != 0) goto Rel21;
}

:bitswap RD, RT32src				is $(AMODE) & REL6=1 & prime=0x1F & zero21=0 & fct2=0 & bshfl=0x20 & RT32src & RD {
	tmp:4 = bitSwap(RT32src);
	RD = sext(tmp);
}

:clo RD, RSsrc                  	is $(AMODE) & REL6=1 & prime=0x00 & op=0 & sa=0x1 & fct=0x11 & RD & RSsrc {
    RD = countLeadingOnes( RSsrc );
}

:clz RD, RSsrc                  	is $(AMODE) & REL6=1 & prime=0x00 & op=0 & sa=0x1 & fct=0x10 & RD & RSsrc {
    RD = countLeadingZeros( RSsrc );
}

:div RD, RS32src, RT32src           is $(AMODE) & REL6=1 & prime=0x00 & fct=0x1A & fct2=0x02 & RD & RS32src & RT32src {
	tmp:4 = RS32src s/ RT32src;
	RD = sext(tmp);
}

:mod RD, RS32src, RT32src           is $(AMODE) & REL6=1 & prime=0x00 & fct=0x1A & fct2=0x03 & RD & RS32src & RT32src {
	tmp:4 = RS32src s% RT32src;
	RD = sext(tmp);
}

:divu RD, RS32src, RT32src          is $(AMODE) & REL6=1 & prime=0x00 & fct=0x1B & fct2=0x02 & RD & RS32src & RT32src {
	tmp:4 = RS32src / RT32src;
	RD = sext(tmp);
}

:modu RD, RS32src, RT32src          is $(AMODE) & REL6=1 & prime=0x00 & fct=0x1B & fct2=0x03 & RD & RS32src & RT32src {
	tmp:4 = RS32src % RT32src;
	RD = sext(tmp);
}

:dvp RT                   			is $(AMODE) & REL6=1 & prime=0x10 & mfmc0=0x0B & fct=0x24 & RT & RD0 & zero5=0 & zero4=0 {
	disableProcessor(RT);
}

:evp RT                   			is $(AMODE) & REL6=1 & prime=0x10 & mfmc0=0x0B & fct=0x04 & RT & RD0 & zero5=0 & zero4=0 {
	enableProcessor(RT);
}

# NOTE: Unlike almost every other branch/jump that has an immediate, the immediate is *IS NOT* shifted. This allows
# this instruction to serve same function as jalx in pre-6.
:jialc RTsrc, simmed				is $(AMODE) & REL6=1 & prime=0x3E & jsub=0x00 & RTsrc & simmed {
	build RTsrc;
	tmp:$(REGSIZE) = sext(simmed:2) + RTsrc;	
	JXWritePC(tmp); 
    ra = inst_next; 
    call [pc];
}

:jic RTsrc, simmed					is $(AMODE) & REL6=1 & prime=0x36 & jsub=0x00 & RTsrc & simmed {
	build RTsrc;
	tmp:$(REGSIZE) = sext(simmed:2) + RTsrc;	
	JXWritePC(tmp); 
    call [pc];
}

@ifndef COPR_C
:ldc2 RTsrc, simmed11(baser6)       is $(AMODE) & REL6=1 & prime=0x12 & copop=0x0E & simmed11 & baser6 & RTsrc {
	tmp:$(REGSIZE) = simmed11;
	tmp = tmp + baser6;
	tmpa:$(ADDRSIZE) = 0;
	ValCast(tmpa,tmp);
    setCopReg(2:1, RTsrc, *[ram]:8 tmpa);
}
@endif

:ll RT, OFF_BASER6                	is $(AMODE) & REL6=1 & prime=0x1F & fct=0x36 & bit6=0 & OFF_BASER6 & RT {
    RT = sext(*[ram]:4 OFF_BASER6);
}

:llx RT, OFF_BASER6                	is $(AMODE) & REL6=1 & prime=0x1F & fct=0x36 & bit6=1 & OFF_BASER6 & RT {
    RT = sext(*[ram]:4 OFF_BASER6);
}

:llxe RT, OFF_BASER6                is $(AMODE) & REL6=1 & prime=0x1F & fct=0x27 & bit6=1 & OFF_BASER6 & RT {
    RT = sext(*[ram]:4 OFF_BASER6);
}

:lsa RD, RS32src, RT32src, SAV		is $(AMODE) & REL6=1 & prime=0x00 & fct=0x05 & spec3=0 & SAV & RD & RS32src & RT32src {
	tmp:4 = (RS32src << SAV) + RT32src;
	RD = sext(tmp);
}

@ifndef COPR_C
:lwc2 RTsrc, simmed11(baser6)       is $(AMODE) & REL6=1 & prime=0x12 & copop=0x0A & simmed11 & baser6 & RTsrc {
	tmp:$(REGSIZE) = simmed11;
	tmp = tmp + baser6;
	tmpa:$(ADDRSIZE) = 0;
	ValCast(tmpa,tmp);
    setCopReg( 2:1, RTsrc, *[ram]:4 tmpa);    
}
@endif

:lwpc RS, S19L2						is $(AMODE) & REL6=1 & prime=0x3B & pcrel=0x1 & RS & S19L2 {
	tmp:$(REGSIZE) = inst_start + sext(S19L2);
	tmpa:$(ADDRSIZE) = 0;
	ValCast(tmpa,tmp);
	RS = sext(*[ram]:4 tmpa);
}

:mul RD, RS32src, RT32src           is $(AMODE) & REL6=1 & prime=0x00 & fct=0x18 & fct2=0x02 & RD & RS32src & RT32src {
	tmpS:8 = sext(RS32src);
	tmpT:8 = sext(RT32src);
	tmpS = tmpS * tmpT;
	tmp:4 = tmpS[0,32];
	RD = sext(tmp);
}

:muh RD, RS32src, RT32src           is $(AMODE) & REL6=1 & prime=0x00 & fct=0x18 & fct2=0x03 & RD & RS32src & RT32src {
	tmpS:8 = sext(RS32src);
	tmpT:8 = sext(RT32src);
	tmpS = tmpS * tmpT;
	tmp:4 = tmpS[32,32];
	RD = sext(tmp);
}

:mulu RD, RS32src, RT32src           is $(AMODE) & REL6=1 & prime=0x00 & fct=0x19 & fct2=0x02 & RD & RS32src & RT32src {
	tmpS:8 = zext(RS32src);
	tmpT:8 = zext(RT32src);
	tmpS = tmpS * tmpT;
	tmp:4 = tmpS[0,32];
	RD = sext(tmp);
}

:muhu RD, RS32src, RT32src           is $(AMODE) & REL6=1 & prime=0x00 & fct=0x19 & fct2=0x03 & RD & RS32src & RT32src {
	tmpS:8 = zext(RS32src);
	tmpT:8 = zext(RT32src);
	tmpS = tmpS * tmpT;
	tmp:4 = tmpS[32,32];
	RD = sext(tmp);
}

:scx RTsrc, OFF_BASER6          is $(AMODE) & REL6=1 & prime=0x1F & fct=0x26 & bit6=1 & OFF_BASER6 & RTsrc {
    *[ram]:4 OFF_BASER6 = RTsrc:$(SIZETO4);
}

:scxe RTsrc, OFF_BASER6          is $(AMODE) & REL6=1 & prime=0x1F & fct=0x1E & bit6=1 & OFF_BASER6 & RTsrc {
    *[ram]:4 OFF_BASER6 = RTsrc:$(SIZETO4);
    RTsrc = 1;
}

:seleqz RD, RSsrc, RTsrc           	is $(AMODE) & REL6=1 & prime=0x00 & fct=0x35 & fct2=0x00 & RD & RSsrc & RTsrc {
	# We use tmp to cover case where rs and rd are the same reg
	tmps:$(REGSIZE) = RSsrc;
	tmpt:$(REGSIZE) = RTsrc;
	RD = 0;
	if (tmpt != 0) goto <done>;
	RD = tmps;
	<done>
}

:selnez RD, RSsrc, RTsrc           is $(AMODE) & REL6=1 & prime=0x00 & fct=0x37 & fct2=0x00 & RD & RSsrc & RTsrc {
	# We use tmp to cover case where rs and rd are the same reg
	tmps:$(REGSIZE) = RSsrc;
	tmpt:$(REGSIZE) = RTsrc;
	RD = 0;
	if (tmpt == 0) goto <done>;
	RD = tmps;
	<done>
}

:sigrie immed							is $(AMODE) & REL6=1 & prime=0x01 & zero21=0 & cond=0x17 & immed {
	signalReservedInstruction(immed:2);
}


@include "mipsfloat.sinc"
