
############################
#
# MIPS Floating Point (COP1 - coprocessor 1) instructions
#       includes arithmetic, compares, branch on FP condition flag, conversions
# Also Coprocessor 0 instructions
#
# Note a MIPS word is 32-bits, and a long is a 64-bit integer
#
# mipsP6float.sinc contains floating point instructions that are in pre-Release 6 but not in Release 6
#
# mipsR6float.sinc contains floating point instructions that are in Release 6 and later
#
############################

define pcodeop mipsFloatPS;

# 0100 01ff fff0 0000 ssss sddd dd00 0101
:abs.S fd, fs               is $(AMODE) & prime=17 & fct=5 & fmt1 & format=0x10 & fs & fd {
	fd[0,32] = abs( fs:4 );
}
:abs.D fd, fs               is $(AMODE) & prime=17 & fct=5 & fmt1 & format=0x11 & fs & fd & fsD & fdD {
    fdD = abs(fsD);
}
:abs.PS fd, fs               is $(AMODE) & REL6=0 & prime=17 & fct=5 & fmt1 & fs & fd & format=0x16 & fdD & fsD {
    fdD = mipsFloatPS(fsD);
}

# 0100 01ff ffft tttt ssss sddd dd00 0000
:add.S fd, fs, ft           is $(AMODE) & prime=17 & fct=0 & fmt1 & format=0x10 & ft & fs & fd {
    fd_tmp:4 = fs:4 f+ ft:4;
    fd[0,32] = fs:4 f+ ft:4;
}
:add.D fd, fs, ft           is $(AMODE) & prime=17 & fct=0 & fmt1 & format=0x11 & ft & fs & fd & ftD & fsD & fdD {
    fdD = fsD f+ ftD;
}
:add.PS fd, fs, ft           is $(AMODE) & REL6=0 & prime=17 & fct=0 & fmt1 & ft & fs & fd & format=0x16 & ftD & fsD & fdD {
    fdD = mipsFloatPS(fsD, ftD);
}

# 0100 01ff fff0 0000 ssss sddd dd00 1010
:ceil.l.S fd, fs            is $(AMODE) & prime=0x11 & ft=0x0 & fct=0x0A & fmt2 & fd & fs & format=0x10 & fdD {
    # Note this instruction is in release 2 and later
    fd_tmp:4 = ceil(fs:4); # Note that ceil returns a float the same size as its argument
    fdD = trunc(fd_tmp); # Note that trunc converts a float to an integer
}

:ceil.l.D fd, fs            is $(AMODE) & prime=0x11 & ft=0x0 & fct=0x0A & fmt2 & fd & fs & format=0x11 & fsD & fdD {
    # Note this instruction is in release 2 and later
    fsD_tmp:8 = ceil(fsD); # Note that ceil returns a float the same size as its argument
    fdD = trunc(fsD_tmp); # Convert to 64-bit integer
}
# 0100 01ff fff0 0000 ssss sddd dd00 1110
:ceil.w.S fd, fs            is $(AMODE) & prime=0x11 & ft=0x0 & fct=0x0E & fmt2 & fd & fs & format=0x10 {
    fs_ceil_tmp:4 = ceil(fs:4); # Note that ceil returns a float the same size as its argument
    fd[0,32] = trunc( ceil(fs:4) );
}
:ceil.w.D fd, fs            is $(AMODE) & prime=0x11 & ft=0x0 & fct=0x0E & fmt2 & fd & fs & format=0x11 & fsD {
    fs_tmp:8 = ceil(fsD); # Note that ceil returns a float the same size as its argument
    fd[0,32] = trunc( fs_tmp ); # Need to set only 32 bits of fd
}

# 0100 0100 010t tttt ssss s000 0000 0000
:cfc1 RT, fs_unk                    is $(AMODE) & prime=17 & copop=2 & RT & fs_unk & bigfunct=0 {    
    tmp:4 = getCopControlWord( 1:1, fs_unk:4 );
    RT = sext(tmp);
}
:cfc1 RT, fs_fcr                is $(AMODE) & prime=17 & copop=2 & RT & fs_fcr & (fs=0 | fs=25 | fs=26 | fs=28 | fs=31) & bigfunct=0 { 
    RT = sext(fs_fcr);
}
# Since we don't track the state of the FCSR bits, no sense in introducing complex code
#:cfc1 RT, fs_fcr               is $(AMODE) & prime=17 & copop=2 & RT & fs_fcr & fs=25 & bigfunct=0 {  
#    tmp1:4 = (fcsr & 0x00800000) >> 23;  
#    tmp2:4 = (fcsr & 0xfe000000) >> 24;
#    RT = sext(tmp2 + tmp1);
#}
#:cfc1 RT, fs_fcr                    is $(AMODE) & prime=17 & copop=2 & RT & fs_fcr & fs=26 & bigfunct=0 {
#    tmp1:4 = fcsr & 0x0003f07c;   
#    RT = sext(tmp1);
#}
#:cfc1 RT, fs_fcr                    is $(AMODE) & prime=17 & copop=2 & RT & fs_fcr & fs=28 & bigfunct=0 {
#    tmp1:4 = fcsr & 0x00000f83;
#    tmp2:4 = (fcsr & 0x01000000) >> 24;  
#    RT = sext(tmp1 + tmp2);
#}
#:cfc1 RT, fs_fcr                    is $(AMODE) & prime=17 & copop=2 & RT & fs_fcr & fs=31 & bigfunct=0 {
#    RT = sext(fcsr);
#}

# 0100 0100 110t tttt ssss s000 0000 0000
:ctc1 RTsrc, fs_unk             is $(AMODE) & prime=17 & copop=6 & RTsrc & fs_unk & bigfunct=0 {    
    setCopControlWord( 1:1, fs_unk:4, RTsrc );
}
:ctc1 RTsrc, fs_fcr             is $(AMODE) & prime=17 & copop=6 & RTsrc & fs_fcr & (fs=0 | fs=25 | fs=26 | fs=28 | fs=31) & bigfunct=0 {    
    fs_fcr = RTsrc:$(SIZETO4);
}

# 0100 01ff fff0 0000 ssss sddd dd10 0001
:cvt.d.S fd, fs             is $(AMODE) & prime=0x11 & ft=0x0 & fct=0x21 & fmt3 & fd & fs & format=0x10 & fdD {
    # Convert from single float to double float
    fdD = float2float(fs:4);
}
:cvt.d.W fd, fs             is $(AMODE) & prime=0x11 & ft=0x0 & fct=0x21 & fmt3 & fd & fs & format=0x14 & fdD {
    # Convert from 32-bit int word source to double float
    fs_tmp:4 = fs:4;
    fdD = int2float(fs_tmp);
}
:cvt.d.L fd, fs             is $(AMODE) & prime=0x11 & ft=0x0 & fct=0x21 & fmt3 & fd & fs & format=0x15 & fdD & fsD {
    # Note this instruction is in release 2 and later
    # Convert from 64-bit long source to double float
    fdD = int2float(fsD);
}
# 0100 01ff fff0 0000 ssss sddd dd10 0101
:cvt.l.S fd, fs             is $(AMODE) & prime=0x11 & ft=0x0 & fct=0x25 & fmt2 & fd & fs & format=0x10 & fdD {
    # Note this instruction is in release 2 and later
    # Convert from single float source to 64-bit long integer, using the fcsr RM rounding mode bits
    rm_tmp:1 = fcsr[0,2]; # Get RM rounding mode bits
    fs_tmp:4 = fs:4; # Get the lower 32-bits as a floating point single
    fs_cvt_tmp:4 = 0;
    if (rm_tmp == 0) goto <do_round>;
      fs_cvt_tmp = floor(fs_tmp); # RM is 1, no rounding, and floor returns a float
      goto <done>;
    <do_round>
      fs_cvt_tmp = round(fs_tmp); # round returns a float
    <done>
    fdD = trunc(fs_cvt_tmp); # trunc returns an integer
}
:cvt.l.D fd, fs             is $(AMODE) & prime=0x11 & ft=0x0 & fct=0x25 & fmt2 & fd & fs & format=0x11 & fsD & fdD {
    # Note this instruction is in release 2 and later
    # Convert from double float to 64-bit long integer, using fcsr RM rounding mode bits
    rm_tmp:1 = fcsr[0,2]; # Get RM rounding mode bits
    if (rm_tmp == 0) goto <do_round>;
      fd_tmp:8 = floor(fsD); # RM is 1, no rounding
      goto <done>;
    <do_round>
      fd_tmp = round(fsD);
    <done>
    fdD = trunc(fd_tmp);
}
# 0100 0110 000t tttt ssss sddd dd10 0110
:cvt.PS.S fd, fs, ft            is $(AMODE) & REL6=0 & prime=0x11 & format=0x10 & fct=0x26 & fd & fs & ft & ftD & fsD & fdD {
    fdD = mipsFloatPS(fsD, ftD);
}

# 0100 01ff fff0 0000 ssss sddd dd10 0000
:cvt.s.D fd, fs             is $(AMODE) & prime=0x11 & ft=0x0 & fct=0x20 & fmt4 & fd & fs & format=0x11 & fsD {
    fd[0,32] = float2float(fsD);
}
:cvt.s.W fd, fs             is $(AMODE) & prime=0x11 & ft=0x0 & fct=0x20 & fmt4 & fd & fs & format=0x14 {
    fd[0,32] = int2float(fs:4);
}
:cvt.s.L fd, fs             is $(AMODE) & prime=0x11 & ft=0x0 & fct=0x20 & fmt4 & fd & fs & format=0x15 & fsD {
    # Note this instruction is in release 2 and later
    fd[0,32] = int2float(fsD);
}
# 0100 0110 1100 0000 ssss sddd dd10 1000
:cvt.s.pl fd, fs                is $(AMODE) & REL6=0 & prime=0x11 & format=0x16 & ft=0x0 & fct=0x28 & fd & fs & fdD & fsD {
    fdD = mipsFloatPS(fsD);
}
# 0100 0110 1100 0000 ssss sddd dd10 0000
:cvt.s.pu fd, fs                is $(AMODE) & REL6=0 & prime=0x11 & format=0x16 & ft=0x0 & fct=0x20 & fd & fs & fdD & fsD {
    fdD = mipsFloatPS(fsD);
}

# 0100 01ff fff0 0000 ssss sddd dd10 0100
:cvt.w.S fd, fs             is $(AMODE) & prime=0x11 & ft=0x0 & fct=0x24 & fmt2 & fd & fs & format=0x10 {
    # Convert from single float source to 32-bit integer word, using the fcsr RM rounding mode bits
    rm_tmp:1 = fcsr[0,2]; # Get RM rounding mode bits
    fs_tmp:4 = fs:4;
    fs_cvt_tmp:4 = 0;
    if (rm_tmp == 0) goto <do_round>;
      fs_cvt_tmp = floor(fs_tmp); # RM is 1, no rounding, and floor returns a float
      goto <done>;
    <do_round>
      fs_cvt_tmp = round(fs_tmp); # round returns a float
    <done>
    fd[0,32] = trunc(fs_cvt_tmp);	# trunc returns an integer
}
:cvt.w.D fd, fs             is $(AMODE) & prime=0x11 & ft=0x0 & fct=0x24 & fmt2 & fd & fs & format=0x11 & fsD {
    # Convert from double float source to 32-bit integer word, using the fcsr RM rounding mode bits
    rm_tmp:1 = fcsr[0,2]; # Get RM rounding mode bits
    if (rm_tmp == 0) goto <do_round>;
      fs_tmp:8 = floor(fsD); # RM is 1, no rounding
      goto <done>;
    <do_round>
      fs_tmp = round(fsD);
    <done>
    fd[0,32] = trunc(fs_tmp);
}

# 0100 01ff ffft tttt ssss sddd dd00 0011
:div.S fd, fs, ft           is $(AMODE) & prime=17 & fct=3 & fmt2 & ft & fs & fd & format=0x10 {
    fd[0,32] = fs:4 f/ ft:4;
}
:div.D fd, fs, ft           is $(AMODE) & prime=17 & fct=3 & fmt2 & ft & fs & fd & format=0x11 & fdD & fsD & ftD {
    fdD = fsD f/ ftD;
}

# 0100 01ff fff0 0000 ssss sddd dd00 1011
:floor.l.S fd, fs           is $(AMODE) & prime=0x11 & ft=0x0 & fct=0x0B & fmt2 & fd & fs & format=0x10 & fdD {
    # Note this instruction is in release 2 and later
    # Convert floor of single float to a 64-bit long integer
    fd_tmp:4 = floor(fs:4); # returns a float
    fdD = trunc(fd_tmp);  # converts float to int
}
:floor.l.D fd, fs           is $(AMODE) & prime=0x11 & ft=0x0 & fct=0x0B & fmt2 & fd & fs & format=0x11 & fdD & fsD {
    # Note this instruction is in release 2 and later
    fsD_tmp:8 = floor(fsD);
    fdD = trunc(fsD_tmp);
}
# 0100 01ff fff0 0000 ssss sddd dd00 1111
:floor.w.S fd, fs           is $(AMODE) & prime=0x11 & ft=0x0 & fct=0x0F & fmt2 & fd & fs & format=0x10 {
    # Floor of single float copied to a 32-bit integer word
    fd_tmp:4 = floor(fs:4); # returns a float
    fd = trunc(fd_tmp);  # converts float to int
}
:floor.w.D fd, fs           is $(AMODE) & prime=0x11 & ft=0x0 & fct=0x0F & fmt2 & fd & fs & format=0x11 & fsD {
    # Floor of double float to a 32-bit integer word
    fd[0,32] = trunc(floor(fsD));
}

# 1101 01bb bbbt tttt iiii iiii iiii iiii
:ldc1 ft, OFF_BASE              is $(AMODE) & prime=53 & OFF_BASE & ft & ftD {
    ftD = *[ram]:8 OFF_BASE;
}

# 1111 01bb bbbt tttt iiii iiii iiii iiii
:sdc1 ft, OFF_BASE              is $(AMODE) & prime=61 & OFF_BASE & ft & ftD {
    *[ram]:8 OFF_BASE = ftD;
}

# 1100 01bb bbbt tttt iiii iiii iiii iiii
:lwc1 ft, OFF_BASE              is $(AMODE) & prime=49 & OFF_BASE & ft {        
    ft[0,32] = *[ram]:4 OFF_BASE;
}

# 0100 0100 000t tttt ssss s000 0000 0000
:mfc1 RT, fs                    is $(AMODE) & prime=17 & copop=0 & RT & fs & bigfunct=0 {
    # Move just a word, 32-bits
    RT = sext( fs:$(SIZETO4) );
}

# 0100 0100 011t tttt ssss s000 0000 0000
:mfhc1 RT, fs                   is $(AMODE) & prime=17 & copop=3 & bigfunct=0 & RT & fs & fsD {
    RT = sext(fsD[32,32]);
}

# 0100 01ff fff0 0000 ssss sddd dd00 0110
:mov.S fd, fs               is $(AMODE) & prime=17 & fct=6 & fmt1 & fs & fd & format=0x10 {
    fd[0,32] = fs:4;
}
:mov.D fd, fs               is $(AMODE) & prime=17 & fct=6 & fmt1 & fs & fd & format=0x11 & fdD & fsD {
    fdD = fsD;
}
:mov.PS fd, fs               is $(AMODE) & REL6=0 & prime=17 & fct=6 & fmt1 & fs & fd & format=0x16 & fsD & fdD {
    fdD = mipsFloatPS(fsD);
}

# 0100 0100 100t tttt dddd d000 0000 0000
:mtc1 RTsrc, fs                 is $(AMODE) & prime=17 & copop=4 & RTsrc & fs & bigfunct=0 {
    # Move 32-bits of RTsrc to Low Half of FPR fs
	fs[0,32] = RTsrc:$(SIZETO4);
}

# 0100 0100 111t tttt ssss s000 0000 0000
:mthc1 RTsrc, fs                is $(AMODE) & prime=17 & copop=0x07 & bigfunct=0x0 & RTsrc & fs & fsD {
    # Move 32-bits of RTsrc to High Half of FPR
    fsD[32,32] = RTsrc:4;
}

# 0100 01ff ffft tttt ssss sddd dd00 0010
:mul.S fd, fs, ft           is $(AMODE) & prime=17 & fct=2 & fmt1 & ft & fs & fd & format=0x10 {
    fd[0,32] = fs:4 f* ft:4; # need to only get the single float 32-bit (fs might be 64-bits)
}
:mul.D fd, fs, ft           is $(AMODE) & prime=17 & fct=2 & fmt1 & ft & fs & fd & format=0x11 & fdD & fsD & ftD {
    fdD = fsD f* ftD;
}
:mul.PS fd, fs, ft           is $(AMODE) & REL6=0 & prime=17 & fct=2 & fmt1 & ft & fs & fd & format=0x16 & ftD & fsD & fdD {
    fdD = mipsFloatPS(fsD, ftD);
}

# 0100 01ff fff0 0000 ssss sddd dd00 0111
:neg.S fd, fs               is $(AMODE) & prime=17 & fct=7 & fmt1 & fs & fd & format=0x10 {
    fd[0,32] = f- fs:4;
}
:neg.D fd, fs               is $(AMODE) & prime=17 & fct=7 & fmt1 & fs & fd & format=0x11 & fdD & fsD {
    fdD = f- fsD;
}
:neg.PS fd, fs               is $(AMODE) & REL6=0 & prime=17 & fct=7 & fmt1 & fs & fd & format=0x16 & fsD & fdD {
    fdD = mipsFloatPS(fsD);
}

# 0100 01ff fff0 0000 ssss sddd dd01 0101
:recip.S fd, fs             is $(AMODE) & prime=17 & ft=0 & fct=21 & fmt2 & fd & fs  & format=0x10 {
    fd[0,32] = 1:4 f/ fs:4;
}
:recip.D fd, fs             is $(AMODE) & prime=17 & ft=0 & fct=21 & fmt2 & fd & fs  & format=0x11 & fdD & fsD {
    fdD = 1:8 f/ fsD;
}

# 0100 01ff fff0 0000 ssss sddd dd00 1000
:round.l.S fd, fs           is $(AMODE) & prime=17 & ft=0 & fct=8 & fmt2 & fd & fs & format=0x10 & fdD {
    # Note this instruction is in release 2 and later
    fd_tmp:4 = round(fs:4);  # round returns a float of the same size are the arg
    fdD = trunc(fd_tmp);     # trunc converts to any size integer
}
:round.l.D fd, fs           is $(AMODE) & prime=17 & ft=0 & fct=8 & fmt2 & fd & fs &format=0x11 & fsD & fdD {
    # Note this instruction is in release 2 and later
    fsD_tmp:8 = round(fsD);
    fdD = trunc(fsD_tmp);
}
# 0100 01ff fff0 0000 ssss sddd dd00 1100
:round.w.S fd, fs           is $(AMODE) & prime=17 & ft=0 & fct=12 & fmt2 & fd & fs & format=0x10 {
    fd_tmp:4 = round(fs:4);
    fd = trunc(fd_tmp);
}
:round.w.D fd, fs           is $(AMODE) & prime=17 & ft=0 & fct=12 & fmt2 & fd & fs & format=0x11 & fsD {
    fdD_tmp:8 = round(fsD); # round returns a float, not an int
    fd[0,32] = trunc(fdD_tmp); # We need only a 32-bit integer
}

# 0100 01ff fff0 0000 ssss sddd dd01 0110
:rsqrt.S fd, fs             is $(AMODE) & prime=17 & ft=0 & fct=22 & fmt2 & fd & fs & format=0x10 {
    fd[0,32] = 1:4 f/ sqrt(fs:4);
}
:rsqrt.D fd, fs             is $(AMODE) & prime=17 & ft=0 & fct=22 & fmt2 & fd & fs & format=0x11 & fdD & fsD {
    fdD = 1:8 f/ sqrt(fsD);
}

# 0100 01ff fff0 0000 ssss sddd dd00 0100
:sqrt.S fd, fs              is $(AMODE) & prime=17 & ft=0 & fct=4 & fmt2 & fd & fs & format=0x10 {
    fd[0,32] = sqrt(fs:4);
}
:sqrt.D fd, fs              is $(AMODE) & prime=17 & ft=0 & fct=4 & fmt2 & fd & fs & format=0x11 & fsD & fdD {
    fdD = sqrt(fsD);
}

# 0100 01ff ffft tttt ssss sddd dd00 0001
:sub.S fmt1 fd, fs, ft           is $(AMODE) & prime=17 & fct=1 & fmt1 & ft & fs & fd & format=0x10 {
    fd[0,32] = fs:4 f- ft:4;
}
:sub.D fmt1 fd, fs, ft           is $(AMODE) & prime=17 & fct=1 & fmt1 & ft & fs & fd & format=0x11 & fdD & fsD & ftD {
    fdD = fsD f- ftD;
}
:sub.PS fmt1 fd, fs, ft           is $(AMODE) & REL6=0 & prime=17 & fct=1 & fmt1 & ft & fs & fd & format=0x16 & ftD & fsD & fdD {
    fdD = mipsFloatPS(fsD, ftD);
}

# 1110 01bb bbbt tttt iiii iiii iiii iiii
:swc1 ft, OFF_BASE              is $(AMODE) & prime=57 & OFF_BASE & ft { 
    *[ram]:4 OFF_BASE = ft:$(SIZETO4); 
}

# 0100 01ff fff0 0000 ssss sddd dd00 1001
:trunc.l.S fd, fs           is $(AMODE) & prime=17 & cop1code=0 & fmt2 & fs & fd & fct=9 & format=0x10 & fdD {
    # Note this instruction is in release 2 and later
    fd = trunc(fs:4);
}
:trunc.l.D fd, fs           is $(AMODE) & prime=17 & cop1code=0 & fmt2 & fs & fd & fct=9 & format=0x11 & fdD & fsD {
    # Note this instruction is in release 2 and later
    fdD = trunc(fsD);
}
# 0100 01ff fff0 0000 ssss sddd dd00 1101
:trunc.w.S fd, fs           is $(AMODE) & prime=17 & cop1code=0 & fmt2 & fs & fd & fct=13 & format=0x10 {
    fd[0,32] = trunc(fs:4);
}
:trunc.w.D fd, fs           is $(AMODE) & prime=17 & cop1code=0 & fmt2 & fs & fd & fct=13 & format=0x11 & fsD {
    fd[0,32] = trunc(fsD);
}

############################
#
# COP1X (Extended FP)
#
############################

# 0100 11ss ssst tttt ssss sddd dd01 1110
:alnv.PS fd, fs, ft, rs         is $(AMODE) & REL6=0 & prime=0x13 & fct=0x1E & rs & ft & fs & fd & ftD & fsD & fdD {
    fdD = mipsFloatPS(fsD, ftD);
}

# 0100 11bb bbbi iiii 0000 0ddd dd00 0001
:ldxc1 fd, INDEX_BASE           is $(AMODE) & REL6=0 & prime=0x13 & zero4=0 & fct=0x01 & INDEX_BASE & fd & fdD {   
    fdD = *[ram]:8 INDEX_BASE;
}

# 0100 11bb bbbi iiii 0000 0ddd dd00 0101
:luxc1 fd, INDEX_BASE           is $(AMODE) & REL6=0 & prime=0x13 & zero4=0 & fct=0x05 & INDEX_BASE & fd & fdD {
    ptr:$(ADDRSIZE) = INDEX_BASE & -16:$(ADDRSIZE);          
    fdD = *[ram]:8 ptr;
}

# 0100 11bb bbbi iiii 0000 0ddd dd00 0000
:lwxc1 fd, INDEX_BASE           is $(AMODE) & REL6=0 & prime=0x13 & zero4=0 & fct=0x0  & INDEX_BASE & fd {
    fd[0,32] = *[ram]:4 INDEX_BASE;
}

# 0100 11rr rrrt tttt ssss sddd dd10 0fff
:madd.S fd, fr, fs, ft      is $(AMODE) & REL6=0 & prime=0x13 & op4=0x04 & fmt5 & fd & fr & fs & ft & format1X=0x0 {
    fd[0,32] = (fs:4 f* ft:4) f+ fr:4; # must do floating arithmetic in 32 bit
}
:madd.D fd, fr, fs, ft      is $(AMODE) & REL6=0 & prime=0x13 & op4=0x04 & fmt5 & fd & fr & fs & ft &
				format1X=0x1 & fdD & fsD & frD & ftD {
    fdD = (fsD f* ftD) f+ frD;
}
:madd.PS fd, fr, fs, ft      is $(AMODE) & REL6=0 & prime=0x13 & op4=0x04 & fmt5 & fd & fr & fs & ft & format1X=0x6 & ftD & fsD & fdD {
    fdD = mipsFloatPS(fsD, ftD);
}

# 0100 11rr rrrt tttt ssss sddd dd10 1fff
:msub.S fd, fr, fs, ft      is $(AMODE) & REL6=0 & prime=0x13 & op4=0x05 & fmt5 & fd & fr & fs & ft & format1X=0x0 {
    fd[0,32] = (fs:4 f* ft:4) f- fr:4; # must do floating arithmetic in 32 bit
}
:msub.D fd, fr, fs, ft      is $(AMODE) & REL6=0 & prime=0x13 & op4=0x05 & fmt5 & fd & fr & fs & ft &
				format1X=0x1 & fdD & fsD & ftD & frD {
    fdD = (fsD f* ftD) f- frD;
}
:msub.PS fd, fr, fs, ft      is $(AMODE) & REL6=0 & prime=0x13 & op4=0x05 & fmt5 & fd & fr & fs & ft & format1X=0x6 & ftD & fsD & fdD {
    fdD = mipsFloatPS(fsD, ftD);
}

# 0100 11rr rrrt tttt ssss sddd dd11 0fff
:nmadd.S fd, fr, fs, ft     is $(AMODE) & REL6=0 & prime=0x13 & op4=0x06 & fmt5 & fd & fr & fs & ft & format1X=0x0 {
    fd[0,32] = f- (fs:4 f* ft:4) f+ fr:4; # must do floating arithmetic in 32 bit
}
:nmadd.D fd, fr, fs, ft     is $(AMODE) & REL6=0 & prime=0x13 & op4=0x06 & fmt5 & fd & fr & fs & ft &
				format1X=0x1 & fdD & fsD & ftD & frD {
    fdD = f- ((fsD f* ftD) f+ frD);
}
:nmadd.PS fd, fr, fs, ft     is $(AMODE) & REL6=0 & prime=0x13 & op4=0x06 & fmt5 & fd & fr & fs & ft & format1X=0x6 & ftD & fsD & fdD {
    fdD = mipsFloatPS(fsD, ftD);
}

# 0100 11rr rrrt tttt ssss sddd dd11 1fff
:nmsub.S fd, fr, fs, ft     is $(AMODE) & REL6=0 & prime=0x13 & op4=0x07 & fmt5 & fd & fr & fs & ft & format1X=0x0 {
    fd[0,32] = f- (fs:4 f* ft:4) f- fr:4; # must do floating arithmetic in 32 bit
}
:nmsub.D fd, fr, fs, ft     is $(AMODE) & REL6=0 & prime=0x13 & op4=0x07 & fmt5 & fd & fr & fs & ft &
				format1X=0x1 & fdD & fsD & ftD & frD {
    fdD = f- ((fsD f* ftD) f- frD);
}
:nmsub.PS fd, fr, fs, ft     is $(AMODE) & REL6=0 & prime=0x13 & op4=0x07 & fmt5 & fd & fr & fs & ft & format1X=0x6 & ftD & fsD & fdD {
    fdD = mipsFloatPS(fsD, ftD);
}

# 0100 11bb bbbi iiii hhhh h000 0000 1111
:prefx hint, INDEX_BASE         is $(AMODE) & REL6=0 & prime=0x13 & zero5=0x0 & fct=0x0F & hint & INDEX_BASE {
    prefetch(INDEX_BASE, hint:1); 
}
# 0100 11bb bbbi iiii ssss s000 0000 1001
:sdxc1 fs, INDEX_BASE           is $(AMODE) & REL6=0 & prime=0x13 & zero5=0x0 & fct=0x09 & fs & fsD & INDEX_BASE {
    *[ram]:8 INDEX_BASE = fsD;
}
# 0100 11bb bbbi iiii ssss s000 0000 1101
:suxc1 fs, INDEX_BASE           is $(AMODE) & REL6=0 & prime=19 & fct=13 & INDEX_BASE & fs & fsD {
    INDEX_BASE = INDEX_BASE & 0xfffffffffffffff0;          
    *[ram]:8 INDEX_BASE = fsD;    
}
# 0100 11bb bbbi iiii ssss s000 0000 1000
:swxc1 fs, INDEX_BASE           is $(AMODE) & REL6=0 & prime=19 & INDEX_BASE & fs & fd=0 & fct=8  {
    *[ram]:4 INDEX_BASE = fs:$(SIZETO4);    
}
####
#
# Pre-6 semantics
#
####
# 0100 0101 000c cc00 iiii iiii iiii iiii
:bc1f Rel16                     is $(AMODE) & REL6=0 & prime=17 & copop=8 & cc=0 & nd=0 & tf=0 & Rel16 {
    tmp:1 = fcsr[23,1]; # The floating point condition bit
    delayslot(1);
    if (tmp != 0) goto inst_next;
    goto Rel16;
}
:bc1f cc,Rel16                  is $(AMODE) & REL6=0 & prime=17 & copop=8 & cc & nd=0 & tf=0 & Rel16 {
    # tmp:1 = getFpCondition(cc:1);  # Note that other cc conditions are not implemented
    tmp:1 = fcsr[23,1]; # The floating point condition bit
    delayslot(1);
    if (tmp != 0) goto inst_next;
    goto Rel16;
}
# 0100 0101 000c cc10 iiii iiii iiii iiii
:bc1fl Rel16                    is $(AMODE) & REL6=0 & prime=17 & copop=8 & cc=0 & nd=1 & tf=0 & Rel16 {
    tmp:1 = fcsr[23,1];
    if (tmp != 0) goto inst_next;
    delayslot(1);
    goto Rel16;
}
:bc1fl cc,Rel16                 is $(AMODE) & REL6=0 & prime=17 & copop=8 & cc & nd=1 & tf=0 & Rel16 {
    # tmp:1 = getFpCondition(cc:1);
    tmp:1 = fcsr[23,1]; # The floating point condition bit
    if (tmp != 0) goto inst_next;
    delayslot(1);
    goto Rel16;
}

# 0100 0101 000c cc01 iiii iiii iiii iiii
:bc1t Rel16                     is $(AMODE) & REL6=0 & prime=17 & copop=8 & cc=0 & nd=0 & tf=1 & Rel16 {
    tmp:1 = fcsr[23,1];
    delayslot(1);
    if (tmp == 0) goto inst_next;
    goto Rel16;
}
:bc1t cc,Rel16                  is $(AMODE) & REL6=0 & prime=17 & copop=8 & cc & nd=0 & tf=1 & Rel16 {
    # tmp:1 = getFpCondition(cc:1);
    tmp:1 = fcsr[23,1]; # The floating point condition bit
    delayslot(1);
    if (tmp == 0) goto inst_next;
    goto Rel16;
}
# 0100 0101 000c cc11 iiii iiii iiii iiii
:bc1tl Rel16                    is $(AMODE) & REL6=0 & prime=17 & copop=8 & cc=0 & nd=1 & tf=1 & Rel16 {
    tmp:1 = fcsr[23,1];
    if (tmp == 0) goto inst_next;
    delayslot(1);
    goto Rel16;
}
:bc1tl cc,Rel16                 is $(AMODE) & REL6=0 & prime=17 & copop=8 & cc & nd=1 & tf=1 & Rel16 {
    # tmp:1 = getFpCondition(cc:1);
    tmp:1 = fcsr[23,1]; # The floating point condition bit
    if (tmp == 0) goto inst_next;
    delayslot(1);
    goto Rel16;
}

# The pre-release 6 floating point compare instructions, c.condn.S or .D, set the fcsr bit 23

macro trapIfNaN(x1, x2) { }
macro trapIfSNaN(x1, x2) { }

:c.f.S fs, ft               is $(AMODE) & REL6=0 & prime=17 & fct=48 & fmt1 & format=0x10 & fs & ft {
    trapIfSNaN(fs:4, ft:4); # Trap if either operand is a Signaling NaN
    fcsr[23,1] = 0; # Always false
}
:c.f.D fs, ft               is $(AMODE) & REL6=0 & prime=17 & fct=48 & fmt1 & format=0x11 & fs & ft & fsD & ftD {
    trapIfSNaN(fsD, ftD);
    fcsr[23,1] = 0;
}
:c.f.PS fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=48 & fmt1 & fs & ft & format=0x16 & ftD & fsD & fdD {
    fcsr[23,1] = mipsFloatPS(fsD, ftD);
}

:c.un.S fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=49 & fmt1 & format=0x10 & fs & ft {
    trapIfSNaN(fs:4, ft:4);
    fcsr[23,1] = nan(fs:4) || nan(ft:4); # True if operands are NaN
}
:c.un.D fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=49 & fmt1 & fs & ft & format=0x11 & fsD & ftD {
    trapIfSNaN(fsD, ftD);
    fcsr[23,1] = nan(fsD) || nan(ftD);
}
:c.un.PS fs, ft             is $(AMODE) & REL6=0 & prime=17 & fct=49 & fmt1 & fs & ft & format=0x16 & ftD & fsD {
    fcsr[23,1] = mipsFloatPS(fsD, ftD);
}

:c.eq.S fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=50 & fmt1 & format=0x10 & fs & ft {
    trapIfSNaN(fs:4, ft:4);
    fcsr[23,1] = (fs:4 f== ft:4);
}
:c.eq.D fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=50 & fmt1 & fs & ft & format=0x11 & fsD & ftD {
    trapIfSNaN(fsD, ftD);
    fcsr[23,1] = (fsD f== ftD);
}
:c.eq.PS fs, ft             is $(AMODE) & REL6=0 & prime=17 & fct=50 & fmt1 & fs & ft & format=0x16 & ftD & fsD {
    fcsr[23,1] = mipsFloatPS(fsD, ftD);
}

:c.ueq.S fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=51 & fmt1 & format=0x10 & fs & ft {
    trapIfSNaN(fs:4, ft:4);
    fcsr[23,1] = (fs:4 f== ft:4);
}
:c.ueq.D fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=51 & fmt1 & fs & ft & format=0x11 & fsD & ftD {
    trapIfSNaN(fsD, ftD);
    fcsr[23,1] = (fsD f== ftD);
}
:c.ueq.PS fs, ft             is $(AMODE) & REL6=0 & prime=17 & fct=51 & fmt1 & fs & ft & format=0x16 & ftD & fsD {
    fcsr[23,1] = mipsFloatPS(fsD, ftD);
}

:c.olt.S fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=52 & fmt1 & format=0x10 & fs & ft {
    trapIfSNaN(fs:4, ft:4);
    fcsr[23,1] = (fs:4 f< ft:4);
}
:c.olt.D fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=52 & fmt1 & fs & ft & format=0x11 & fsD & ftD {
    trapIfSNaN(fsD, ftD);
    fcsr[23,1] = (fsD f< ftD);
}
:c.olt.PS fs, ft             is $(AMODE) & REL6=0 & prime=17 & fct=52 & fmt1 & fs & ft & format=0x16 & ftD & fsD {
    fcsr[23,1] = mipsFloatPS(fsD, ftD);
}

:c.ult.S fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=53 & fmt1 & format=0x10 & fs & ft {
    trapIfSNaN(fs:4, ft:4);
    fcsr[23,1] = (fs:4 f< ft:4) || nan(fs:4) || nan(ft:4); # Less than or NaN
}
:c.ult.D fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=53 & fmt1 & fs & ft & format=0x11 & fsD & ftD {
    trapIfSNaN(fsD, ftD);
    fcsr[23,1] = (fsD f< ftD) || nan(fsD) || nan(ftD);
}
:c.ult.PS fs, ft             is $(AMODE) & REL6=0 & prime=17 & fct=53 & fmt1 & fs & ft & format=0x16  & ftD & fsD {
    fcsr[23,1] = mipsFloatPS(fsD, ftD);
}

:c.ole.S fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=54 & fmt1 & format=0x10 & fs & ft {
    trapIfSNaN(fs:4, ft:4);
    fcsr[23,1] = (fs:4 f<= ft:4);
}
:c.ole.D fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=54 & fmt1 & fs & ft & format=0x11 & fsD & ftD {
    trapIfSNaN(fsD, ftD);
    fcsr[23,1] = (fsD f<= ftD);
}
:c.ole.PS fs, ft             is $(AMODE) & REL6=0 & prime=17 & fct=54 & fmt1 & fs & ft & format=0x16 & ftD & fsD {
    fcsr[23,1] = mipsFloatPS(fsD, ftD);
}

:c.ule.S fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=55 & fmt1 & format=0x10 & fs & ft {
    trapIfSNaN(fs:4, ft:4);
    fcsr[23,1] = (fs:4 f<= ft:4) || nan(fs:4) || nan(ft:4); # Less than or equal or NaN
}
:c.ule.D fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=55 & fmt1 & fs & ft & format=0x11 & fsD & ftD {
    trapIfSNaN(fsD, ftD);
    fcsr[23,1] = (fsD f<= ftD) || nan(fsD) || nan(ftD);
}
:c.ule.PS fs, ft             is $(AMODE) & REL6=0 & prime=17 & fct=55 & fmt1 & fs & ft & format=0x16 & ftD & fsD {
    fcsr[23,1] = mipsFloatPS(fsD, ftD);
}

# The pre-release 6 floating point compare instructions that trap if either operand is NaN (either QNaN or SNaN)

:c.sf.S fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=56 & fmt1 & fs & ft & format=0x10 {
    trapIfNaN(fs:4, ft:4);
    fcsr[23,1] = 0; # Always false
}
:c.sf.D fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=56 & fmt1 & fs & ft & format=0x11 & fsD & ftD {
    trapIfNaN(fsD, ftD);
    fcsr[23,1] = 0;
}
:c.sf.PS fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=56 & fmt1 & fs & ft & format=0x16 & ftD & fsD {
    fcsr[23,1] = mipsFloatPS(fsD, ftD);
}

:c.ngle.S fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=57 & fmt1 & format=0x10 & fs & ft {
    trapIfNaN(fs:4, ft:4);
    fcsr[23,1] = nan(fs:4) || nan(ft:4);
}
:c.ngle.D fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=57 & fmt1 & fs & ft & format=0x11 & fsD & ftD {
    trapIfNaN(fsD, ftD);
    fcsr[23,1] = nan(fsD) || nan(ftD);
}
:c.ngle.PS fs, ft             is $(AMODE) & REL6=0 & prime=17 & fct=57 & fmt1 & fs & ft & format=0x16 & ftD & fsD {
    fcsr[23,1] = mipsFloatPS(fsD, ftD);
}

:c.seq.S fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=58 & fmt1 & format=0x10 & fs & ft {
    trapIfNaN(fs:4, ft:4);
    fcsr[23,1] = (fs:4 f== ft:4);
}
:c.seq.D fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=58 & fmt1 & fs & ft & format=0x11 & fsD & ftD {
    trapIfNaN(fsD, ftD);
    fcsr[23,1] = (fsD f== ftD);
}
:c.seq.PS fs, ft             is $(AMODE) & REL6=0 & prime=17 & fct=58 & fmt1 & fs & ft & format=0x16 & ftD & fsD {
    fcsr[23,1] = mipsFloatPS(fsD, ftD);
}

:c.ngl.S fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=59 & fmt1 & format=0x10 & fs & ft {
    trapIfNaN(fs:4, ft:4);
    fcsr[23,1] = (fs:4 f== ft:4) || nan(fs:4) || nan(ft:4);
}
:c.ngl.D fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=59 & fmt1 & fs & ft & format=0x11 & fsD & ftD {
    trapIfNaN(fsD, ftD);
    fcsr[23,1] = (fsD f== ftD) || nan(fsD) || nan(ftD);
}
:c.ngl.PS fs, ft             is $(AMODE) & REL6=0 & prime=17 & fct=59 & fmt1 & fs & ft & format=0x16 & ftD & fsD {
    fcsr[23,1] = mipsFloatPS(fsD, ftD);
}

:c.lt.S fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=60 & fmt1 & format=0x10 & fs & ft {
    trapIfNaN(fs:4, ft:4);
    fcsr[23,1] = (fs:4 f< ft:4);
}
:c.lt.D fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=60 & fmt1 & fs & ft & format=0x11 & fsD & ftD {
    trapIfNaN(fsD, ftD);
    fcsr[23,1] = (fsD f< ftD);
}
:c.lt.PS fs, ft             is $(AMODE) & REL6=0 & prime=17 & fct=60 & fmt1 & fs & ft & format=0x16 & ftD & fsD {
    fcsr[23,1] = mipsFloatPS(fsD, ftD);
}

:c.nge.S fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=61 & fmt1 & format=0x10 & fs & ft {
    trapIfNaN(fs:4, ft:4);
    fcsr[23,1] = (fs:4 f< ft:4) || nan(fs:4) || nan(ft:4);
}
:c.nge.D fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=61 & fmt1 & fs & ft & format=0x11 & fsD & ftD {
    trapIfNaN(fsD, ftD);
    fcsr[23,1] = (fsD f< ftD) || nan(fsD) || nan(ftD);
}
:c.nge.PS fs, ft             is $(AMODE) & REL6=0 & prime=17 & fct=61 & fmt1 & fs & ft & format=0x16 & ftD & fsD {
    fcsr[23,1] = mipsFloatPS(fsD, ftD);
}

:c.le.S fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=62 & fmt1 & format=0x10 & fs & ft {
    trapIfNaN(fs:4, ft:4);
    fcsr[23,1] = (fs:4 f<= ft:4);
}
:c.le.D fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=62 & fmt1 & fs & ft & format=0x11 & fsD & ftD {
    trapIfNaN(fsD, ftD);
    fcsr[23,1] = (fsD f<= ftD);
}
:c.le.PS fs, ft             is $(AMODE) & REL6=0 & prime=17 & fct=62 & fmt1 & fs & ft & format=0x16 & ftD & fsD {
    fcsr[23,1] = mipsFloatPS(fsD, ftD);
}

:c.ngt.S fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=63 & fmt1 & format=0x10 & fs & ft {
    trapIfNaN(fs:4, ft:4);
    fcsr[23,1] = (fs:4 f<= ft:4) || nan(fs:4) || nan(ft:4); # Less than or equal or NaN
}
:c.ngt.D fs, ft              is $(AMODE) & REL6=0 & prime=17 & fct=63 & fmt1 & fs & ft & format=0x11 & fsD & ftD {
    trapIfNaN(fsD, ftD);
    fcsr[23,1] = (fsD f<= ftD) || nan(fsD) || nan(ftD);
}
:c.ngt.PS fs, ft             is $(AMODE) & REL6=0 & prime=17 & fct=63 & fmt1 & fs & ft & format=0x16 & ftD & fsD {
    fcsr[23,1] = mipsFloatPS(fsD, ftD);
}

# 0000 00ss sssc cc00 dddd d000 0000 0001
:movf RD, RSsrc, cc             is $(AMODE) & REL6=0 & prime=0 & nd=0 & tf=0 & zero5=0 & fct=1 & RD & RSsrc & cc  {
    # Move if FP condition flag is false
    tmp:1 = fcsr[23,1];
    if (tmp != 0) goto <done>;
    RD = RSsrc;
    <done>
}

# 0100 01ff fffc cc00 ssss sddd dd01 0001
:movf.S fd, fs, cc          is $(AMODE) & REL6=0 & prime=17 & nd=0 & tf=0 & fct=17 & fmt1 & fd & fs & cc & format=0x10 {
    # Move if FP condition flag is false
    tmp:1 = fcsr[23,1];
    if (tmp != 0) goto <done>;
    fd[0,32] = fs:4;
    <done>
}
:movf.D fd, fs, cc          is $(AMODE) & REL6=0 & prime=17 & nd=0 & tf=0 & fct=17 & fmt1 & fd & fs & cc & format=0x11 & fdD & fsD {
    # Move if FP condition flag is false
    tmp:1 = fcsr[23,1];
    if (tmp != 0) goto <done>;
    fdD = fsD;
    <done>
}
:movf.PS fd, fs, cc          is $(AMODE) & REL6=0 & prime=17 & nd=0 & tf=0 & fct=17 & fmt1 & fd & fs & cc & format=0x16 & fsD & fdD {
    fdD = mipsFloatPS(fcsr[23,1], fsD);
}

# 0100 01ff ffft tttt ssss sddd dd01 0011
:movn.S fd, fs, RTsrc       is $(AMODE) & REL6=0 & prime=17 & fct=19 & fmt1 & fd & fs & RTsrc & format=0x10 {
    if (RTsrc == 0) goto <done>;
    fd[0,32] = fs:4;
    <done>
}
:movn.D fd, fs, RTsrc       is $(AMODE) & REL6=0 & prime=17 & fct=19 & fmt1 & fd & fs & RTsrc & format=0x11 & fdD & fsD {
    if (RTsrc == 0) goto <done>;
    fdD = fsD;
    <done>
}
:movn.PS fd, fs, RTsrc       is $(AMODE) & REL6=0 & prime=17 & fct=19 & fmt1 & fd & fs & RTsrc & format=0x16 & fsD & fdD {
    fdD = mipsFloatPS(fcsr[23,1], fsD);
}

# 0000 00ss sssc cc01 dddd d000 0000 0001
:movt RD, RSsrc, cc             is $(AMODE) & REL6=0 & prime=0 & nd=0 & tf=1 & zero5=0 & fct=1 & RD & RSsrc & cc  {
    # Move if FP condition flag is true
    tmp:1 = fcsr[23,1];
    if (tmp != 1) goto <done>;
    RD = RSsrc;
    <done>
}

# 0100 01ff fffc cc01 ssss sddd dd01 0001
:movt.S fd, fs, cc          is $(AMODE) & REL6=0 & prime=17 & nd=0 & tf=1 & fct=17 & fmt1 & fd & fs & cc & format=0x10 {
    # Move if FP condition flag is true
    tmp:1 = fcsr[23,1];
    if (tmp != 1) goto <done>;
    fd[0,32] = fs:4;
    <done>
}
:movt.D fd, fs, cc          is $(AMODE) & REL6=0 & prime=17 & nd=0 & tf=1 & fct=17 & fmt1 & fd & fs & cc & format=0x11 & fdD & fsD {
    # Move if FP condition flag is true
    tmp:1 = fcsr[23,1];
    if (tmp != 1) goto <done>;
    fdD = fsD;
    <done>
}
:movt.PS fd, fs, cc          is $(AMODE) & REL6=0 & prime=17 & nd=0 & tf=1 & fct=17 & fmt1 & fd & fs & cc & format=0x16 & fsD & ftD & fdD {
    fdD = mipsFloatPS(fsD, ftD);
}

# 0100 01ff ffft tttt ssss sddd dd01 0010
:movz.S fd, fs, RTsrc       is $(AMODE) & REL6=0 & prime=17 & fct=18 & fmt1 & fd & fs & RTsrc & format=0x10 {
    if (RTsrc != 0) goto <done>;
    fd[0,32] = fs:4;
    <done>
}
:movz.D fd, fs, RTsrc       is $(AMODE) & REL6=0 & prime=17 & fct=18 & fmt1 & fd & fs & RTsrc & format=0x11 & fdD & fsD {
    if (RTsrc != 0) goto <done>;
    fdD = fsD;
    <done>
}
:movz.PS fd, fs, RTsrc       is $(AMODE) & REL6=0 & prime=17 & fct=18 & fmt1 & fd & fs & RTsrc & format=0x16 & fsD & fdD {
    fdD = mipsFloatPS(RTsrc, fsD);
}

####
#
# Release 6 semantics
#
####
:bc1eqz ft,Rel16	is $(AMODE) & REL6=1 & prime=0x11 & format=0x09 & Rel16 & ft {
    # Branch if FPR ft LSB equals 0 (false) (This insn replaces bc1f)
    tmp:1 = ft[0,8] & 0x01; # Only need to check the LSB
    delayslot(1);
    if (tmp == 0x00) goto Rel16;
}

:bc1nez ft,Rel16        is $(AMODE) & REL6=1 & prime=0x11 & format=0x0d & Rel16 & ft & ftD {
    # Branch if FPR ft LSB equals 1 (true) (This insn replaces bc1t)
    tmp:1 = ft[0,8] & 0x01; # Only need to check the LSB
    delayslot(1);
    if (tmp == 0x01) goto Rel16;
}

:class.S fd,fs	is $(AMODE) & REL6=1 & prime=0x11 & format=0x10 & op=0x00 & fct=0x1b & fd & fs {
    # Set fd to the 10-bit mask that is the IEEE floating point class of the value in fs
    # Bit 0: signaling SNaN
    # Bit 1: quiet QNaN
    # Bit 2: negative infinity

    # Bit 3: negative normalized number
    # Bit 4: negative subnormal, ie denormalized
    # Bit 5: negative zero
    # Bit 6: positive infinity
    # Bit 7: positive normal
    # Bit 8: positive subnormal
    # Bit 9: positive zero
    # Bits 31-10 are set to 0

    tmp_fs:4 = fs:4; # Get just the 4 byte single floating point value
    tmp_exponent:4 = zext(tmp_fs[23,8]);
    tmp_fraction:4 = zext(tmp_fs[0,23]);
    tmp_sign:4 = zext(tmp_fs[31,1]);
    tmp_b1:4 = zext(tmp_fs[22,1]); # High order bit of fraction, used for NaN

    tmp_SNaN:4 = zext((tmp_exponent == 0x0ff) && (tmp_fraction != 0x0) && (tmp_b1 == 0x0)); 
    tmp_QNaN:4 = zext((tmp_exponent == 0x0ff) && (tmp_fraction != 0x0) && (tmp_b1 == 0x01));
    tmp_Neg_Infinity:4 = zext((tmp_sign == 0x01) && (tmp_exponent == 0x0ff)  && (tmp_fraction == 0x0));
    tmp_Neg_Normal:4 = zext((tmp_sign == 0x01) && (tmp_exponent != 0x0) && (tmp_exponent != 0x0ff));
    tmp_Neg_Subnormal:4 = zext((tmp_sign == 0x01) && (tmp_exponent == 0x0) && (tmp_fraction != 0x0));
    tmp_Neg_Zero:4 = zext((tmp_sign == 0x01) && (tmp_exponent == 0x0) && (tmp_fraction == 0x0));
    tmp_Pos_Infinity:4 = zext((tmp_sign == 0x0) && (tmp_exponent == 0x0ff)  && (tmp_fraction == 0x0));
    tmp_Pos_Normal:4 = zext((tmp_sign == 0x0) && (tmp_exponent != 0x0) && (tmp_exponent != 0x0ff));
    tmp_Pos_Subnormal:4 = zext((tmp_sign == 0x0) && (tmp_exponent == 0x0) && (tmp_fraction != 0x0));
    tmp_Pos_Zero:4 = zext((tmp_sign == 0x0) && (tmp_exponent == 0x0) && (tmp_fraction == 0x0));

    tmp_fd:4 = 0;
    tmp_fd = tmp_SNaN | (tmp_QNaN << 1) | (tmp_Neg_Infinity << 2) | (tmp_Neg_Normal << 3) |
		(tmp_Neg_Subnormal << 4) | (tmp_Neg_Zero << 5) | (tmp_Pos_Infinity << 6) |
		(tmp_Pos_Normal << 7) | (tmp_Pos_Subnormal << 8) | (tmp_Pos_Zero << 9);

    fd = zext(tmp_fd);
}

:class.D fd,fs  is $(AMODE) & REL6=1 & prime=0x11 & format=0x11 & op=0x00 & fct=0x1b & fd & fs & fdD & fsD {
    # Set fd to the 10-bit mask that is the IEEE floating point class of the value in fs
    # Bit 0: signaling SNaN
    # Bit 1: quiet QNaN
    # Bit 2: negative infinity
    # Bit 3: negative normalized number
    # Bit 4: negative subnormal, ie denormalized
    # Bit 5: negative zero
    # Bit 6: positive infinity
    # Bit 7: positive normal
    # Bit 8: positive subnormal
    # Bit 9: positive zero
    # Bits 31-10 are set to 0

    tmp_fs:8 = fsD;
    tmp_sign:4 = zext(tmp_fs[63,1]);
    tmp_exponent:4 = zext(tmp_fs[52,11]);
    tmp_fraction:8 = zext(tmp_fs[0,51]);
    tmp_b1:4 = zext(tmp_fs[51,1]); # High order bit of fraction, used for NaN

    tmp_SNaN:4 = zext((tmp_exponent == 0x07ff) && (tmp_fraction != 0x0) && (tmp_b1 == 0x0));
    tmp_QNaN:4 = zext((tmp_exponent == 0x07ff) && (tmp_fraction != 0x0) && (tmp_b1 == 0x01));
    tmp_Neg_Infinity:4 = zext((tmp_sign == 0x01) && (tmp_exponent == 0x07ff)  && (tmp_fraction == 0x0));
    tmp_Neg_Normal:4 = zext((tmp_sign == 0x01) && (tmp_exponent != 0x0) && (tmp_exponent != 0x07ff));
    tmp_Neg_Subnormal:4 = zext((tmp_sign == 0x01) && (tmp_exponent == 0x0) && (tmp_fraction != 0x0));
    tmp_Neg_Zero:4 = zext((tmp_sign == 0x01) && (tmp_exponent == 0x0) && (tmp_fraction == 0x0));
    tmp_Pos_Infinity:4 = zext((tmp_sign == 0x0) && (tmp_exponent == 0x07ff)  && (tmp_fraction == 0x0));
    tmp_Pos_Normal:4 = zext((tmp_sign == 0x0) && (tmp_exponent != 0x0) && (tmp_exponent != 0x07ff));
    tmp_Pos_Subnormal:4 = zext((tmp_sign == 0x0) && (tmp_exponent == 0x0) && (tmp_fraction != 0x0));
    tmp_Pos_Zero:4 = zext((tmp_sign == 0x0) && (tmp_exponent == 0x0) && (tmp_fraction == 0x0));

    tmp_fd:4 = 0;
    tmp_fd = tmp_SNaN | (tmp_QNaN << 1) | (tmp_Neg_Infinity << 2) | (tmp_Neg_Normal << 3) |
                (tmp_Neg_Subnormal << 4) | (tmp_Neg_Zero << 5) | (tmp_Pos_Infinity << 6) |
                (tmp_Pos_Normal << 7) | (tmp_Pos_Subnormal << 8) | (tmp_Pos_Zero << 9);

    fdD = zext(tmp_fd);
}

:sel.S fd,fs,ft                is $(AMODE) & REL6=1 & prime=0x11 & format=0x10 & fct=0x10 & fd & fs & ft {
    # Floating point select, if LSB of fd == 1 then fd = ft, else fd = fs
    # Note that the data in the FPRs might be 32-bit ints, ie there's no interpretation of the values
    tmp:1 = (fd[0,1] == 0x01);
    fd = (zext(tmp) * ft) | (zext(tmp == 0x0) * fs);
}
:sel.D fd,fs,ft         is $(AMODE) & REL6=1 & prime=0x11 & format=0x11 & fct=0x10 & fd & fs & ft & fdD & fsD & ftD {
    # Floating point select, if LSB of fd == 1 then fd = ft, else fd = fs
    # Note that the data in the FPRs might be 64-bit ints, ie there's no interpretation of the values
    tmp:1 = (fdD[0,1] == 0x01);
    fdD = (zext(tmp) * ftD) | (zext(tmp == 0x0) * fsD);
}

#
# The R6 floating point compare cmp instruction is described on page 146 of the
# MIPS64 Architecture Volume II ISA manual
#
# Note that when the condition is true the target FPR is set to all ones, and to 0 if false.
# If the target is 32-bit and you have 64-bit FPRs, then setting the top word is optional
#
# Note that when the format is Single and you have 64-bit FPRS,
# then you need to first pull out the 32-bit float word and then pass that to the correct p-code
#
# TBD: Note that when fct bits 5 and 4 (left most 2 bits) are 01 then the condition is negated
#

:cmp.af.S fd, fs, ft	is $(AMODE) & REL6=1 & prime=0x11 & fct=0x00 & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    trapIfSNaN(fs:4, ft:4); # Trap if either operand is a Signaling NaN
    fd = 0x0; # Always false
}
:cmp.af.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x00 & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & ft & fsD & ftD {
    trapIfSNaN(fsD, ftD);
    fdD = 0x0;
}

:cmp.un.S fd, fs, ft	is $(AMODE) & REL6=1 & prime=0x11 & fct=0x01 & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    trapIfSNaN(fs:4, ft:4);
    fd[0,32] = sext((nan(fs:4) || nan(ft:4)) * 0xff); # True if operands are NaN
}
:cmp.un.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x01 & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD { 
    trapIfSNaN(fsD, ftD);
    fdD = sext((nan(fsD) || nan(ftD)) * 0xff);
}

:cmp.or.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x11 & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    trapIfSNaN(fs:4, ft:4);
    fd[0,32] = sext( (!(nan(fs:4) || nan(ft:4))) * 0xff); # The negated predicate of "c.un"
}
:cmp.or.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x11 & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfSNaN(fsD, ftD);
    fdD = sext( (!(nan(fsD) || nan(ftD))) * 0xff);
}

:cmp.eq.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x02 & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    trapIfSNaN(fs:4, ft:4);
    fd[0,32] = sext((fs:4 f== ft:4) * 0xff);
}
:cmp.eq.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x02 & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfSNaN(fsD, ftD);
    fdD = sext((fsD f== ftD) * 0xff);
}

:cmp.une.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x12 & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    # The negated predicate of cmp.eq
    trapIfSNaN(fs:4, ft:4);
    fd[0,32] = sext((fs:4 f!= ft:4) * 0xff);
}
:cmp.une.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x12 & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfSNaN(fsD, ftD);
    fdD = sext((fsD f!= ftD) * 0xff);
}

:cmp.ueq.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x03 & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    # NaN or equal
    trapIfSNaN(fs:4, ft:4);
    fd[0,32] = sext( ( nan(fs:4) || nan(ft:4) || (fs:4 f== ft:4) ) * 0xff);
}
:cmp.ueq.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x03 & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfSNaN(fsD, ftD);
    fdD = sext( ( nan(fsD) || nan(ftD) || (fsD f== ftD) ) * 0xff);
}

:cmp.ne.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x13 & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    # The negated predicate of cmp.ueq
    trapIfSNaN(fs:4, ft:4);
    fd[0,32] = sext( (!( ( nan(fs:4) || nan(ft:4) || (fs:4 f== ft:4) ))) * 0xff);
}
:cmp.ne.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x13 & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfSNaN(fsD, ftD);
    fdD = sext( (!( ( nan(fsD) || nan(ftD) || (fsD f== ftD) ))) * 0xff);
}

:cmp.lt.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x04 & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    trapIfSNaN(fs:4, ft:4);
    fd[0,32] = sext((fs:4 f< ft:4) * 0xff);
}
:cmp.lt.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x04 & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfSNaN(fsD, ftD);
    fdD = sext((fsD f< ftD) * 0xff);
}

:cmp.ult.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x05 & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    # NaN or less than
    trapIfSNaN(fs:4, ft:4);
    fd[0,32] = sext( ( nan(fs:4) || nan(ft:4) || (fs:4 f< ft:4) ) * 0xff);
}
:cmp.ult.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x05 & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfSNaN(fsD, ftD);
    fdD = sext( ( nan(fsD) || nan(ftD) || (fsD f< ftD) ) * 0xff);
}

:cmp.le.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x06 & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    # Less than or equal
    trapIfSNaN(fs:4, ft:4);
    fd[0,32] = sext((fs:4 f<= ft:4) * 0xff);
}
:cmp.le.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x06 & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfSNaN(fsD, ftD);
    fdD = sext((fsD f<= ftD) * 0xff);
}

:cmp.ule.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x07 & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    # NaN or less than or equal
    trapIfSNaN(fs:4, ft:4);
    fd[0,32] = sext( ( nan(fs:4) || nan(ft:4) || (fs:4 f<= ft:4) ) * 0xff);
}
:cmp.ule.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x07 & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfSNaN(fsD, ftD);
    fdD = sext( ( nan(fsD) || nan(ftD) || (fsD f<= ftD) ) * 0xff);
}

# The cmp instructions that signal (ie trap) if either of the operands are NaN

:cmp.saf.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x08 & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    trapIfNaN(fs:4, ft:4);
    fd = 0x0; # Always false
}
:cmp.saf.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x08 & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfNaN(fsD, ftD);
    fdD = 0x0;
}

:cmp.sun.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x09 & bit5=0 & fmt6 & format=0x14 & fd & fdD & fs & fsD & ft & ftD {
    trapIfNaN(fs:4, ft:4);
    fd[0,32] = sext((nan(fs:4) || nan(ft:4)) * 0xff);
}
:cmp.sun.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x09 & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfNaN(fsD, ftD);
    fdD = sext((nan(fsD) || nan(ftD)) * 0xff);
}

:cmp.sor.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x19 & bit5=0 & fmt6 & format=0x14 & fd & fdD & fs & fsD & ft & ftD {
    trapIfNaN(fs:4, ft:4);
    fd[0,32] = sext( (!(nan(fs:4) || nan(ft:4))) * 0xff); # negate of cmp.sun
}
:cmp.sor.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x19 & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfNaN(fsD, ftD);
    fdD = sext( (!(nan(fsD) || nan(ftD))) * 0xff);
}

:cmp.seq.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x0a & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    trapIfNaN(fs:4, ft:4);
    fd[0,32] = sext((fs:4 f== ft:4) * 0xff);
}
:cmp.seq.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x0a & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfNaN(fsD, ftD);
    fdD = sext((fsD f== ftD) * 0xff);
}

:cmp.sune.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x1a & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    trapIfNaN(fs:4, ft:4);
    fd[0,32] = sext((fs:4 f!= ft:4) * 0xff);
}
:cmp.sune.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x1a & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfNaN(fsD, ftD);
    fdD = sext((fsD f!= ftD) * 0xff);
}

:cmp.sueq.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x0b & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    # NaN or equal
    trapIfNaN(fs:4, ft:4);
    fd[0,32] = sext( ( nan(fs:4) || nan(ft:4) || (fs:4 f== ft:4) ) * 0xff);
}
:cmp.sueq.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x0b & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfNaN(fsD, ftD);
    fdD = sext( ( nan(fsD) || nan(ftD) || (fsD f== ftD) ) * 0xff);
}

:cmp.sne.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x1b & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    trapIfNaN(fs:4, ft:4); # negate of cmp.sueq
    fd[0,32] = sext( (! ( nan(fs:4) || nan(ft:4) || (fs:4 f== ft:4) )) * 0xff);
}
:cmp.sne.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x1b & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfNaN(fsD, ftD);
    fdD = sext( (! ( nan(fsD) || nan(ftD) || (fsD f== ftD) )) * 0xff);
}

:cmp.slt.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x0c & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    trapIfNaN(fs:4, ft:4);
    fd[0,32] = sext( (fs:4 f< ft:4) * 0xff);
}
:cmp.slt.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x0c & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfNaN(fsD, ftD);
    fdD = sext( (fsD f< ftD) * 0xff);
}

:cmp.sult.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x0d & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    trapIfNaN(fs:4, ft:4);
    fd[0,32] = sext( ( nan(fs:4) || nan(ft:4) || (fs:4 f< ft:4) ) * 0xff);
}
:cmp.sult.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x0d & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfNaN(fsD, ftD);
    fdD = sext( ( nan(fsD) || nan(ftD) || (fsD f< ftD) ) * 0xff);
}

:cmp.sle.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x0e & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    trapIfNaN(fs:4, ft:4);
    fd[0,32] = sext( (fs:4 f<= ft:4) * 0xff);
}
:cmp.sle.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x0e & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfNaN(fsD, ftD);
    fdD = sext( (fsD f<= ftD) * 0xff);
}

:cmp.sule.S fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x0f & bit5=0 & fmt6 & format=0x14 & fd & fs & ft {
    trapIfNaN(fs:4, ft:4);
    fd[0,32] = sext( ( nan(fs:4) || nan(ft:4) || (fs:4 f<= ft:4) ) * 0xff);
}
:cmp.sule.D fd, fs, ft    is $(AMODE) & REL6=1 & prime=0x11 & fct=0x0f & bit5=0 & fmt6 & format=0x15 & fd & fdD & fs & fsD & ft & ftD {
    trapIfNaN(fsD, ftD);
    fdD = sext( ( nan(fsD) || nan(ftD) || (fsD f<= ftD) ) * 0xff);
}

:rint.S fd, fs		is $(AMODE) & REL6=1 & prime=0x11 & format=0x10 & cop1code=0x0 & fs & fd & fct=0x1a {
    # floating point round to integral floating point
    rm_tmp:1 = fcsr[0,2]; # Get RM rounding mode bits
    fs_tmp:4 = fs:4;
    if (rm_tmp == 0) goto <do_round>;
      fd[0,32] = floor(fs_tmp); # RM is 1, no rounding, and floor returns a float
      goto <done>;
    <do_round>
      fd[0,32] = round(fs_tmp); # round returns a float
    <done>
}

:rint.D fd, fs          is $(AMODE) & REL6=1 & prime=0x11 & format=0x11 & cop1code=0x0 & fs & fd & fsD & fdD & fct=0x1a {
    # floating point round to integral floating point
    rm_tmp:1 = fcsr[0,2]; # Get RM rounding mode bits
    if (rm_tmp == 0) goto <do_round>;
      fdD = floor(fsD); # RM is 1, no rounding, and floor returns a float
      goto <done>;
    <do_round>
      fdD = round(fsD); # round returns a float
    <done>
}

:min.S fd, fs, ft	is $(AMODE) & REL6=1 & prime=0x11 & format=0x10 & cop1code=0x0 & fs & fd & ft & fct=0x1c {
    # set floating point fd to the min of fs and ft, TBD special case for NaN
    tmp_cond:1 = fs:4 f< ft:4;
    fd[0,32] = (fs:4 * zext(tmp_cond == 1)) | (ft:4 * zext(tmp_cond == 0) );
}
:min.D fd, fs, ft       is $(AMODE) & REL6=1 & prime=0x11 & format=0x11 & cop1code=0x0 & fs & fd & ft & fct=0x1c 
				& fsD & fdD & ftD {
    tmp_cond:1 = fsD f< ftD;
    fdD = zext( (fsD * zext(tmp_cond == 1)) | (ftD * zext(tmp_cond == 0) ) );
}

:max.S fd, fs, ft       is $(AMODE) & REL6=1 & prime=0x11 & format=0x10 & cop1code=0x0 & fs & fd & ft & fct=0x1d {
    # set floating point fd to the max of fs and ft, TBD special case for NaN
    tmp_cond:1 = fs:4 f> ft:4;
    fd[0,32] = (fs:4 * zext(tmp_cond == 1)) | (ft:4 * zext(tmp_cond == 0) );
}
:max.D fd, fs, ft       is $(AMODE) & REL6=1 & prime=0x11 & format=0x11 & cop1code=0x0 & fs & fd & ft & fct=0x1d
                                & fsD & fdD & ftD {
    tmp_cond:1 = fsD f> ftD;
    fdD = zext( (fsD * zext(tmp_cond == 1)) | (ftD * zext(tmp_cond == 0) ) );
}

:mina.S fd, fs, ft       is $(AMODE) & REL6=1 & prime=0x11 & format=0x10 & cop1code=0x0 & fs & fd & ft & fct=0x1e {
    # set floating point fd to the min of absolute values of fs and ft, TBD special case for NaN
    tmp_cond:1 = abs(fs:4) f< abs(ft:4);
    fd[0,32] = (fs:4 * zext(tmp_cond == 1)) | (ft:4 * zext(tmp_cond == 0) );
}
:mina.D fd, fs, ft       is $(AMODE) & REL6=1 & prime=0x11 & format=0x11 & cop1code=0x0 & fs & fd & ft & fct=0x1e 
                                & fsD & fdD & ftD {
    tmp_cond:1 = abs(fsD) f< abs(ftD);
    fdD = zext( (fsD * zext(tmp_cond == 1)) | (ftD * zext(tmp_cond == 0) ) );
}

:maxa.S fd, fs, ft       is $(AMODE) & REL6=1 & prime=0x11 & format=0x10 & cop1code=0x0 & fs & fd & ft & fct=0x1f {
    # set floating point fd to the max of absolute values of fs and ft, TBD special case for NaN
    tmp_cond:1 = abs(fs:4) f> abs(ft:4);
    fd[0,32] = (fs:4 * zext(tmp_cond == 1)) | (ft:4 * zext(tmp_cond == 0) );
}
:maxa.D fd, fs, ft       is $(AMODE) & REL6=1 & prime=0x11 & format=0x11 & cop1code=0x0 & fs & fd & ft & fct=0x1f
                                & fsD & fdD & ftD {
    tmp_cond:1 = abs(fsD) f> abs(ftD);
    fdD = zext( (fsD * zext(tmp_cond == 1)) | (ftD * zext(tmp_cond == 0) ) );
}

:maddf.S fd, fs, ft       is $(AMODE) & REL6=1 & prime=0x11 & format=0x10 & cop1code=0x0 & fs & fd & ft & fct=0x18 {
    # set floating point fd = fd + fs * ft, using 32-bit floating values
    fd[0,32] = fd:4 f+ (fs:4 f* ft:4);
}
:maddf.D fd, fs, ft       is $(AMODE) & REL6=1 & prime=0x11 & format=0x11 & cop1code=0x0 & fs & fd & ft & fct=0x18
                                & fsD & fdD & ftD {
    fdD = fdD f+ (fsD f* ftD);
}

:msubf.S fd, fs, ft       is $(AMODE) & REL6=1 & prime=0x11 & format=0x10 & cop1code=0x0 & fs & fd & ft & fct=0x19 {
    # set floating point fd = fd - fs * ft, using 32-bit floating values
    fd[0,32] = fd:4 f- (fs:4 f* ft:4);
}
:msubf.D fd, fs, ft       is $(AMODE) & REL6=1 & prime=0x11 & format=0x11 & cop1code=0x0 & fs & fd & ft & fct=0x19 
                                & fsD & fdD & ftD {
    fdD = fdD f- (fsD f* ftD);
}

:seleqz.S fd, fs, ft       is $(AMODE) & REL6=1 & prime=0x11 & format=0x10 & cop1code=0x0 & fs & fd & ft & fct=0x14 {
    # Set floating point register fd to fs if ft[0] == 0, else if == 1 then set fd to 0, TBD special case for NaN
    # Note that the description of these select instructions in the MIPS manual does not properly use the C conditional operator
    fd = zext(fs * zext(ft[0,1] == 0));
}
:seleqz.D fd, fs, ft       is $(AMODE) & REL6=1 & prime=0x11 & format=0x11 & cop1code=0x0 & fs & fd & ft & fct=0x14
                                & fsD & fdD & ftD {
    fdD = zext(fsD * zext(ftD[0,1] == 0));
}

:selnez.S fd, fs, ft       is $(AMODE) & REL6=1 & prime=0x11 & format=0x10 & cop1code=0x0 & fs & fd & ft & fct=0x17 {
    # set floating point register fd to fs if ft[0] == 1, else if == 0 then set fd to 0, TBD special case for NaN
    fd = zext(fs * zext(ft[0,1] == 1));
}
:selnez.D fd, fs, ft       is $(AMODE) & REL6=1 & prime=0x11 & format=0x11 & cop1code=0x0 & fs & fd & ft & fct=0x17
                                & fsD & fdD & ftD {
    fdD = zext(fsD * zext(ftD[0,1] == 1));
}
