#include "emu.h"
#include "tms32082.h"

#define OP_LINK() ((m_ir >> 27) & 0x1f)
#define OP_RD() ((m_ir >> 27) & 0x1f)
#define OP_RS() ((m_ir >> 22) & 0x1f)
#define OP_BASE() ((m_ir >> 22) & 0x1f)
#define OP_SIMM15() ((m_ir & 0x4000) ? (0xffffe000 | (m_ir & 0x7fff)) : (m_ir & 0x7fff))
#define OP_UIMM15() (m_ir & 0x7fff)
#define OP_BITNUM() ((m_ir >> 27) & 0x1f)
#define OP_ROTATE() (m_ir & 0x1f)
#define OP_ENDMASK() ((m_ir >> 5) & 0x1f)
#define OP_SRC1() (m_ir & 0x1f)
#define OP_PD() ((m_ir >> 9) & 0x3)
#define OP_P1() ((m_ir >> 5) & 0x3)
#define OP_P2() ((m_ir >> 7) & 0x3)
#define OP_ACC() ((m_ir >> 15) & 0x2) | ((m_ir >> 11) & 1)

#define ROTATE_L(x, r) ((x << r) | (x >> (32-r)))
#define ROTATE_R(x, r) ((x >> r) | (x << (32-r)))

#define CMP_OVERFLOW32(r, s, d)     ((((d) ^ (s)) & ((d) ^ (r)) & 0x80000000) ? 1 : 0)
#define CMP_OVERFLOW16(r, s, d)     ((((d) ^ (s)) & ((d) ^ (r)) & 0x8000) ? 1 : 0)
#define CMP_OVERFLOW8(r, s, d)      ((((d) ^ (s)) & ((d) ^ (r)) & 0x80) ? 1 : 0)
#define CARRY32(x)                  (((x) & (((uint64_t)1) << 32)) ? 1 : 0)
#define CARRY16(x)                  (((x) & 0x10000) ? 1 : 0)
#define CARRY8(x)                   (((x) & 0x100) ? 1 : 0)
#define SIGN32(x)                   (((x) & 0x80000000) ? 1 : 0)
#define SIGN16(x)                   (((x) & 0x8000) ? 1 : 0)
#define SIGN8(x)                    (((x) & 0x80) ? 1 : 0)

#define SIGN_EXTEND(x, r)           ((x) | (((x) & (0x80000000 >> r)) ? ((int32_t)(0x80000000) >> r) : 0))

bool tms32082_mp_device::test_condition(int condition, uint32_t value)
{
	switch (condition)
	{
		case 0x00:  return false;                   
		case 0x01:  return (int8_t)(value) > 0;       
		case 0x02:  return (int8_t)(value) == 0;      
		case 0x03:  return (int8_t)(value) >= 0;      
		case 0x04:  return (int8_t)(value) < 0;       
		case 0x05:  return (int8_t)(value) != 0;      
		case 0x06:  return (int8_t)(value) <= 0;      
		case 0x07:  return true;                    
		case 0x08:  return false;                   
		case 0x09:  return (int16_t)(value) > 0;      
		case 0x0a:  return (int16_t)(value) == 0;     
		case 0x0b:  return (int16_t)(value) >= 0;     
		case 0x0c:  return (int16_t)(value) < 0;      
		case 0x0d:  return (int16_t)(value) != 0;     
		case 0x0e:  return (int16_t)(value) <= 0;     
		case 0x0f:  return true;                    
		case 0x10:  return false;                   
		case 0x11:  return (int32_t)(value) > 0;      
		case 0x12:  return (int32_t)(value) == 0;     
		case 0x13:  return (int32_t)(value) >= 0;     
		case 0x14:  return (int32_t)(value) < 0;      
		case 0x15:  return (int32_t)(value) != 0;     
		case 0x16:  return (int32_t)(value) <= 0;     
		case 0x17:  return true;                    
		default:    return false;                   
	}
}

uint32_t tms32082_mp_device::calculate_cmp(uint32_t src1, uint32_t src2)
{
	uint16_t src1_16 = (uint16_t)(src1);
	uint8_t src1_8 = (uint8_t)(src1);
	uint16_t src2_16 = (uint16_t)(src2);
	uint8_t src2_8 = (uint8_t)(src2);

	uint64_t res32 = (uint64_t)src1 - (uint64_t)src2;
	int z32 = (res32 == 0) ? 1 : 0;
	int n32 = SIGN32(res32);
	int v32 = CMP_OVERFLOW32(res32, src2, src1);
	int c32 = CARRY32(res32);

	uint32_t res16 = (uint32_t)src1_16 - (uint32_t)src2_16;
	int z16 = (res16 == 0) ? 1 : 0;
	int n16 = SIGN16(res16);
	int v16 = CMP_OVERFLOW16(res16, src2_16, src1_16);
	int c16 = CARRY16(res16);

	uint16_t res8 = (uint16_t)src1_8 - (uint16_t)src2_8;
	int z8 = (res8 == 0) ? 1 : 0;
	int n8 = SIGN8(res8);
	int v8 = CMP_OVERFLOW8(res8, src2_8, src1_8);
	int c8 = CARRY8(res8);

	uint32_t flags = 0;

	flags |= ((~c32) & 1) << 29;                                
	flags |= ((c32) & 1) << 28;                                 
	flags |= ((c32|z32) & 1) << 27;                             
	flags |= ((~c32&~z32) & 1) << 26;                           
	flags |= (((n32&v32)|(~n32&~v32)) & 1) << 25;               
	flags |= (((n32&~v32)|(~n32&v32)) & 1) << 24;               
	flags |= (((n32&~v32)|(~n32&v32)|(z32)) & 1) << 23;         
	flags |= (((n32&v32&~z32)|(~n32&~v32&~z32)) & 1) << 22;     
	flags |= ((~z32) & 1) << 21;                                
	flags |= ((z32) & 1) << 20;                                 

	flags |= ((~c16) & 1) << 19;                                
	flags |= ((c16) & 1) << 18;                                 
	flags |= ((c16|z16) & 1) << 17;                             
	flags |= ((~c16&~z16) & 1) << 16;                           
	flags |= (((n16&v16)|(~n16&~v16)) & 1) << 15;               
	flags |= (((n16&~v16)|(~n16&v16)) & 1) << 14;               
	flags |= (((n16&~v16)|(~n16&v16)|(z16)) & 1) << 13;         
	flags |= (((n16&v16&~z16)|(~n16&~v16&~z16)) & 1) << 12;     
	flags |= ((~z16) & 1) << 11;                                
	flags |= ((z16) & 1) << 10;                                 

	flags |= ((~c8) & 1) << 9;                                  
	flags |= ((c8) & 1) << 8;                                   
	flags |= ((c8|z8) & 1) << 7;                                
	flags |= ((~c8&~z8) & 1) << 6;                              
	flags |= (((n8&v8)|(~n8&~v8)) & 1) << 5;                    
	flags |= (((n8&~v8)|(~n8&v8)) & 1) << 4;                    
	flags |= (((n8&~v8)|(~n8&v8)|(z8)) & 1) << 3;               
	flags |= (((n8&v8&~z8)|(~n8&~v8&~z8)) & 1) << 2;            
	flags |= ((~z8) & 1) << 1;                                  
	flags |= ((z8) & 1) << 0;                                   

	return flags;
}

void tms32082_mp_device::vector_loadstore()
{
	int rd = OP_RD();
	int vector_ls_bits = (((m_ir >> 9) & 0x3) << 1) | ((m_ir >> 6) & 1);

	switch (vector_ls_bits)
	{
		case 0x01:          
		{
			m_program->write_dword(m_outp, m_reg[rd]);
			m_outp += 4;
			break;
		}
		case 0x03:          
		{
			uint64_t data = m_fpair[rd >> 1];
			m_program->write_qword(m_outp, data);
			m_outp += 8;
			break;
		}
		case 0x04:          
		{
			m_reg[rd] = m_program->read_dword(m_in0p);
			m_in0p += 4;
			break;
		}
		case 0x05:          
		{
			m_reg[rd] = m_program->read_dword(m_in1p);
			m_in1p += 4;
			break;
		}
		case 0x06:          
		{
			m_fpair[rd >> 1] = m_program->read_qword(m_in0p);
			m_in0p += 8;
			break;
		}
		case 0x07:          
		{
			m_fpair[rd >> 1] = m_program->read_qword(m_in1p);
			m_in1p += 8;
			break;
		}

		default:
			fatalerror("vector_loadstore(): ls bits = %02X\n", vector_ls_bits);
	}
}

void tms32082_mp_device::execute_short_imm()
{
	switch ((m_ir >> 15) & 0x7f)
	{
		case 0x02:          
		{
			uint32_t data = OP_UIMM15();

			processor_command(data);
			break;
		}

		case 0x04:          
		{
			int rd = OP_RD();
			uint32_t imm = OP_UIMM15();

			uint32_t r = read_creg(imm);

			if (rd)
				m_reg[rd] = r;
			break;
		}

		case 0x05:          
		{
			int rd = OP_RD();
			int rs = OP_RS();
			uint32_t imm = OP_UIMM15();

			uint32_t r = read_creg(imm);
			if (rd)
				m_reg[rd] = r;

			write_creg(imm, m_reg[rs]);
			break;
		}

		case 0x06:          
		{
			int cr = OP_UIMM15();

			if (cr == 0x0001)
			{

			}
			else
			{
				uint32_t data = read_creg(cr);

				m_fetchpc = data & ~3;
				m_ie = (m_ie & ~1) | (data & 1);        

			}
			break;
		}

		case 0x08:          
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = OP_ROTATE();
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = SHIFT_MASK[end ? end : 32];
			if (inv) endmask = ~endmask;

			uint32_t compmask = endmask;          

			uint32_t res;
			if (r)      
			{
				res = ROTATE_R(source, rot) & compmask;
			}
			else        
			{
				res = ROTATE_L(source, rot) & compmask;
			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x0a:          
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = OP_ROTATE();
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = SHIFT_MASK[end ? end : 32];
			if (inv) endmask = ~endmask;

			uint32_t compmask = endmask;          

			uint32_t res;
			if (r)      
			{
				res = ROTATE_R(source, rot) & compmask;
				res = SIGN_EXTEND(res, rot);
			}
			else        
			{
				res = ROTATE_L(source, rot) & compmask;

			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x0b:          
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = OP_ROTATE();
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = SHIFT_MASK[end ? end : 32];
			if (inv) endmask = ~endmask;

			int shift = r ? 32-rot : rot;
			uint32_t shiftmask = SHIFT_MASK[shift ? shift : 32];
			uint32_t compmask = endmask & shiftmask;

			uint32_t res;
			if (r)      
			{
				res = ROTATE_R(source, rot) & compmask;
			}
			else        
			{
				res = ROTATE_L(source, rot) & compmask;
			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x0c:          
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = OP_ROTATE();
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = SHIFT_MASK[end ? end : 32];
			if (inv) endmask = ~endmask;

			uint32_t shiftmask = SHIFT_MASK[r ? 32-rot : rot];
			uint32_t compmask = endmask & shiftmask;

			uint32_t res;
			if (r)      
			{
				res = (ROTATE_R(source, rot) & compmask) | (m_reg[rd] & ~compmask);
			}
			else        
			{
				res = (ROTATE_L(source, rot) & compmask) | (m_reg[rd] & ~compmask);
			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x0d:          
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = OP_ROTATE();
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = SHIFT_MASK[end ? end : 32];
			if (inv) endmask = ~endmask;

			int shift = r ? 32-rot : rot;
			uint32_t shiftmask = SHIFT_MASK[shift ? shift : 32];
			uint32_t compmask = endmask & shiftmask;

			uint32_t res;
			if (r)      
			{
				res = ROTATE_R(source, rot) & compmask;
				res = SIGN_EXTEND(res, rot);
			}
			else        
			{
				res = ROTATE_L(source, rot) & compmask;

			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x0e:          
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = OP_ROTATE();
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = SHIFT_MASK[end ? end : 32];
			if (inv) endmask = ~endmask;

			uint32_t shiftmask = SHIFT_MASK[r ? 32-rot : rot];
			uint32_t compmask = endmask & ~shiftmask;

			uint32_t res;
			if (r)      
			{
				res = ROTATE_R(source, rot) & compmask;
			}
			else        
			{
				res = ROTATE_L(source, rot) & compmask;
			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x0f:          
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = OP_ROTATE();
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = SHIFT_MASK[end ? end : 32];
			if (inv) endmask = ~endmask;

			uint32_t shiftmask = SHIFT_MASK[r ? 32-rot : rot];
			uint32_t compmask = endmask & ~shiftmask;

			uint32_t res;
			if (r)      
			{
				res = (ROTATE_R(source, rot) & compmask) | (m_reg[rd] & ~compmask);
			}
			else        
			{
				res = (ROTATE_L(source, rot) & compmask) | (m_reg[rd] & ~compmask);
			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x11:          
		{
			int rd = OP_RD();
			int rs = OP_RS();
			uint32_t imm = OP_UIMM15();

			if (rd)
				m_reg[rd] = m_reg[rs] & imm;
			break;
		}

		case 0x12:          
		{
			int rd = OP_RD();
			int rs = OP_RS();
			uint32_t imm = OP_UIMM15();

			if (rd)
				m_reg[rd] = ~m_reg[rs] & imm;
			break;
		}

		case 0x14:          
		{
			int rd = OP_RD();
			int rs = OP_RS();
			uint32_t imm = OP_UIMM15();

			if (rd)
				m_reg[rd] = m_reg[rs] & ~imm;
			break;
		}

		case 0x17:          
		{
			int rd = OP_RD();
			int rs = OP_RS();
			uint32_t imm = OP_UIMM15();

			if (rd)
				m_reg[rd] = m_reg[rs] | imm;
			break;
		}

		case 0x1d:          
		{
			int rd = OP_RD();
			int rs = OP_RS();
			uint32_t imm = OP_UIMM15();

			if (rd)
				m_reg[rd] = m_reg[rs] | ~imm;
			break;
		}

		case 0x24:
		case 0x20:          
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;
			uint32_t data = (uint8_t)m_program->read_byte(address);
			if (data & 0x80) data |= 0xffffff00;
			if (rd)
				m_reg[rd] = data;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x25:
		case 0x21:          
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;
			uint32_t data = (uint16_t)m_program->read_word(address);
			if (data & 0x8000) data |= 0xffff0000;
			if (rd)
				m_reg[rd] = data;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x26:
		case 0x22:          
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;
			uint32_t data = m_program->read_dword(address);
			if (rd)
				m_reg[rd] = data;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x27:
		case 0x23:          
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;
			uint32_t data1 = m_program->read_dword(address);
			uint32_t data2 = m_program->read_dword(address+4);
			if (rd)
			{
				m_reg[(rd & ~1)+1] = data1;
				m_reg[(rd & ~1)] = data2;
			}

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x28:
		case 0x2c:          
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;
			uint32_t data = (uint8_t)(m_program->read_byte(address));
			if (rd)
				m_reg[rd] = data;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x2d:
		case 0x29:          
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;
			uint32_t data = (uint16_t)(m_program->read_word(address));
			if (rd)
				m_reg[rd] = data;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x34:
		case 0x30:          
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;

			m_program->write_byte(address, (uint8_t)(m_reg[rd]));

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x35:
		case 0x31:          
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;

			m_program->write_word(address, (uint16_t)(m_reg[rd]));

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x36:
		case 0x32:          
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;

			m_program->write_dword(address, m_reg[rd]);

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x37:
		case 0x33:          
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;

			m_program->write_dword(address+0, m_reg[(rd & ~1) + 1]);
			m_program->write_dword(address+4, m_reg[rd & ~1]);

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x45:          
		{
			int link = OP_LINK();
			int base = OP_BASE();
			int32_t offset = OP_SIMM15();

			if (link)
				m_reg[link] = m_fetchpc;

			m_fetchpc = m_reg[base] + offset;
			break;
		}

		case 0x48:          
		{
			int bitnum = OP_BITNUM() ^ 0x1f;
			int32_t offset = OP_SIMM15();
			int rs = OP_RS();

			if ((m_reg[rs] & (1 << bitnum)) == 0)
			{
				uint32_t address = m_pc + (offset * 4);

				m_pc = m_fetchpc;
				delay_slot();

				m_fetchpc = address;
			}
			break;
		}

		case 0x49:          
		{
			int bitnum = OP_BITNUM() ^ 0x1f;
			int32_t offset = OP_SIMM15();
			int rs = OP_RS();

			if ((m_reg[rs] & (1 << bitnum)) == 0)
			{
				m_fetchpc = m_pc + (offset * 4);
			}
			break;
		}

		case 0x4a:          
		{
			int bitnum = OP_BITNUM() ^ 0x1f;
			int32_t offset = OP_SIMM15();
			int rs = OP_RS();

			if ((m_reg[rs] & (1 << bitnum)) != 0)
			{
				uint32_t address = m_pc + (offset * 4);

				m_pc = m_fetchpc;
				delay_slot();

				m_fetchpc = address;
			}
			break;
		}

		case 0x4b:          
		{
			int bitnum = OP_BITNUM() ^ 0x1f;
			int32_t offset = OP_SIMM15();
			int rs = OP_RS();

			if ((m_reg[rs] & (1 << bitnum)) != 0)
			{
				m_fetchpc = m_pc + (offset * 4);
			}
			break;
		}

		case 0x4c:          
		{
			int32_t offset = OP_SIMM15();
			int code = OP_RD();
			int rs = OP_RS();

			if (test_condition(code, m_reg[rs]))
			{
				uint32_t address = m_pc + (offset * 4);

				m_pc = m_fetchpc;
				delay_slot();

				m_fetchpc = address;
			}
			break;
		}

		case 0x4d:          
		{
			int32_t offset = OP_SIMM15();
			int code = OP_RD();
			int rs = OP_RS();

			if (test_condition(code, m_reg[rs]))
			{
				m_fetchpc = m_pc + (offset * 4);
			}
			break;
		}

		case 0x50:          
		{
			uint32_t src1 = OP_SIMM15();
			uint32_t src2 = m_reg[OP_RS()];
			int rd = OP_RD();

			if (rd)
				m_reg[rd] = calculate_cmp(src1, src2);
			break;
		}

		case 0x58:          
		{
			int32_t imm = OP_SIMM15();
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = m_reg[rs] + imm;

			break;
		}

		case 0x59:          
		{
			int32_t imm = OP_SIMM15();
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = m_reg[rs] + imm;
			break;
		}

		case 0x5a:          
		{
			int32_t imm = OP_SIMM15();
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = imm - m_reg[rs];

			break;
		}

		case 0x5b:          
		{
			int32_t imm = OP_SIMM15();
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = imm - m_reg[rs];
			break;
		}

		default:
			fatalerror("execute_short_imm(): %08X: opcode %08X (%02X)", m_pc, m_ir, (m_ir >> 15) & 0x7f);
	}
}

void tms32082_mp_device::execute_reg_long_imm()
{
	uint32_t imm32 = 0;

	int has_imm = (m_ir & (1 << 12));

	if (has_imm)
		imm32 = fetch();

	switch ((m_ir >> 12) & 0xff)
	{
		case 0x04:          
		{
			uint32_t data = has_imm ? imm32 : m_reg[OP_SRC1()];

			processor_command(data);
			break;
		}

		case 0x16:          
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = m_reg[OP_ROTATE()];
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = end ? SHIFT_MASK[end ? end : 32] : m_reg[OP_ROTATE()+1];
			if (inv) endmask = ~endmask;

			int shift = r ? 32-rot : rot;
			uint32_t shiftmask = SHIFT_MASK[shift ? shift : 32];
			uint32_t compmask = endmask & shiftmask;

			uint32_t res;
			if (r)      
			{
				res = ROTATE_R(source, rot) & compmask;
			}
			else        
			{
				res = ROTATE_L(source, rot) & compmask;
			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x1a:          
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = m_reg[OP_ROTATE()];
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = end ? SHIFT_MASK[end ? end : 32] : m_reg[OP_ROTATE()+1];
			if (inv) endmask = ~endmask;

			int shift = r ? 32-rot : rot;
			uint32_t shiftmask = SHIFT_MASK[shift ? shift : 32];
			uint32_t compmask = endmask & shiftmask;

			uint32_t res;
			if (r)      
			{
				res = ROTATE_R(source, rot) & compmask;
				res = SIGN_EXTEND(res, rot);
			}
			else        
			{
				res = ROTATE_L(source, rot) & compmask;
			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x1c:          
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = m_reg[OP_ROTATE()];
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = end ? SHIFT_MASK[end ? end : 32] : m_reg[OP_ROTATE()+1];
			if (inv) endmask = ~endmask;

			int shift = r ? 32-rot : rot;
			uint32_t shiftmask = SHIFT_MASK[shift ? shift : 32];
			uint32_t compmask = endmask & ~shiftmask;

			uint32_t res;
			if (r)      
			{
				res = ROTATE_R(source, rot) & compmask;
			}
			else        
			{
				res = ROTATE_L(source, rot) & compmask;
			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x22:
		case 0x23:          
		{
			int rd = OP_RD();
			int rs = OP_RS();
			uint32_t src1 = has_imm ? imm32 : m_reg[OP_SRC1()];

			if (rd)
				m_reg[rd] = src1 & m_reg[rs];
			break;
		}

		case 0x24:
		case 0x25:          
		{
			int rd = OP_RD();
			int rs = OP_RS();
			uint32_t src1 = has_imm ? imm32 : m_reg[OP_SRC1()];

			if (rd)
				m_reg[rd] = src1 & ~(m_reg[rs]);
			break;
		}

		case 0x2c:
		case 0x2d:          
		{
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = m_reg[rs] ^ (has_imm ? imm32 : m_reg[OP_SRC1()]);
			break;
		}

		case 0x2e:
		case 0x2f:          
		{
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = m_reg[rs] | (has_imm ? imm32 : m_reg[OP_SRC1()]);
			break;
		}

		case 0x3a:
		case 0x3b:          
		{
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = m_reg[rs] | ~(has_imm ? imm32 : m_reg[OP_SRC1()]);
			break;
		}

		case 0x40:
		case 0x41:
		case 0x48:
		case 0x49:          
		{
			int m = m_ir & (1 << 15);

			int base = OP_BASE();
			int rd = OP_RD();

			uint32_t address = m_reg[base] + (has_imm ? imm32 : m_reg[OP_SRC1()]);
			uint32_t r = m_program->read_byte(address);
			if (r & 0x80) r |= 0xffffff00;

			if (rd)
				m_reg[rd] = r;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x42:
		case 0x4a:
		case 0x43:
		case 0x4b:          
		{
			int shift = (m_ir & (1 << 11)) ? 1 : 0;
			int m = m_ir & (1 << 15);

			int base = OP_BASE();
			int rd = OP_RD();

			uint32_t address = m_reg[base] + ((has_imm ? imm32 : m_reg[OP_SRC1()]) << shift);
			uint32_t r = m_program->read_word(address);
			if (r & 0x8000) r |= 0xffff0000;

			if (rd)
				m_reg[rd] = r;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x4c:
		case 0x44:
		case 0x4d:
		case 0x45:          
		{
			int shift = (m_ir & (1 << 11)) ? 2 : 0;
			int m = m_ir & (1 << 15);
			int base = OP_BASE();
			int rd = OP_RD();

			uint32_t address = m_reg[base] + ((has_imm ? imm32 : m_reg[OP_SRC1()]) << shift);
			uint32_t r = m_program->read_dword(address);

			if (rd)
				m_reg[rd] = r;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x4e:
		case 0x4f:
		case 0x46:
		case 0x47:          
		{
			int shift = (m_ir & (1 << 11)) ? 3 : 0;
			int m = m_ir & (1 << 15);
			int base = OP_BASE();
			int rd = OP_RD();

			uint32_t address = m_reg[base] + ((has_imm ? imm32 : m_reg[OP_SRC1()]) << shift);
			uint64_t r = m_program->read_qword(address);

			if (rd)
				m_fpair[rd >> 1] = r;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x58:
		case 0x59:
		case 0x50:
		case 0x51:          
		{
			int m = m_ir & (1 << 15);
			int base = OP_BASE();
			int rd = OP_RD();

			uint32_t address = m_reg[base] + (has_imm ? imm32 : m_reg[OP_SRC1()]);
			uint32_t r = (uint8_t)(m_program->read_byte(address));

			if (rd)
				m_reg[rd] = r;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x5a:
		case 0x5b:
		case 0x52:
		case 0x53:          
		{
			int shift = (m_ir & (1 << 11)) ? 1 : 0;
			int m = m_ir & (1 << 15);
			int base = OP_BASE();
			int rd = OP_RD();

			uint32_t address = m_reg[base] + ((has_imm ? imm32 : m_reg[OP_SRC1()]) << shift);
			uint32_t r = (uint16_t)(m_program->read_word(address));

			if (rd)
				m_reg[rd] = r;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x60:
		case 0x61:
		case 0x68:
		case 0x69:          
		{
			int m = m_ir & (1 << 15);

			int base = OP_BASE();

			uint32_t address = m_reg[base] + (has_imm ? imm32 : m_reg[OP_SRC1()]);
			m_program->write_byte(address, (uint8_t)(m_reg[OP_RD()]));

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x62:
		case 0x63:
		case 0x6a:
		case 0x6b:          
		{
			int shift = (m_ir & (1 << 11)) ? 1 : 0;
			int m = m_ir & (1 << 15);

			int base = OP_BASE();

			uint32_t address = m_reg[base] + ((has_imm ? imm32 : m_reg[OP_SRC1()]) << shift);
			m_program->write_word(address, (uint16_t)(m_reg[OP_RD()]));

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x6c:
		case 0x6d:
		case 0x64:
		case 0x65:          
		{
			int shift = (m_ir & (1 << 11)) ? 2 : 0;
			int m = m_ir & (1 << 15);

			int base = OP_BASE();

			uint32_t address = m_reg[base] + ((has_imm ? imm32 : m_reg[OP_SRC1()]) << shift);
			m_program->write_dword(address, m_reg[OP_RD()]);

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x88:
		case 0x89:          
		{
			int link = OP_LINK();
			int base = OP_BASE();

			if (link)
				m_reg[link] = m_fetchpc + 4;

			uint32_t address = m_reg[base] + (has_imm ? imm32 : m_reg[OP_SRC1()]);

			m_pc = m_fetchpc;
			delay_slot();

			m_fetchpc = address;
			break;
		}

		case 0x8a:
		case 0x8b:          
		{
			int link = OP_LINK();
			int base = OP_BASE();

			if (link)
				m_reg[link] = m_fetchpc;

			m_fetchpc = m_reg[base] + (has_imm ? imm32 : m_reg[OP_SRC1()]);
			break;
		}

		case 0xa0:
		case 0xa1:          
		{
			int rd = OP_RD();
			uint32_t src1 = has_imm ? imm32 : m_reg[OP_SRC1()];
			uint32_t src2 = m_reg[OP_RS()];

			if (rd)
				m_reg[rd] = calculate_cmp(src1, src2);
			break;
		}

		case 0xb2:
		case 0xb3:          
		{
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = m_reg[rs] + (has_imm ? imm32 : m_reg[OP_SRC1()]);
			break;
		}

		case 0xb4:
		case 0xb5:          
		{
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = (has_imm ? imm32 : m_reg[OP_SRC1()]) - m_reg[rs];

			break;
		}

		case 0xb6:
		case 0xb7:          
		{
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = (has_imm ? imm32 : m_reg[OP_SRC1()]) - m_reg[rs];
			break;
		}

		case 0xc4:
		case 0xd4:
		case 0xc5:
		case 0xd5:          
		{
			int p1 = m_ir & (1 << 5);
			int pd = m_ir & (1 << 7);
			int ls_bit1 = m_ir & (1 << 10);
			int ls_bit2 = m_ir & (1 << 6);
			int rd = OP_RS();
			int src1 OP_SRC1();

			double source = has_imm ? (double)u2f(imm32) : (p1 ? u2d(m_fpair[src1 >> 1]) : (double)u2f(m_reg[src1]));

			if (rd)
			{
				if (pd)
				{
					double res = source * u2d(m_fpair[rd >> 1]);
					m_fpair[rd >> 1] = d2u(res);
				}
				else
				{
					float res = (float)(source) * u2f(m_reg[rd]);
					m_reg[rd] = f2u(res);
				}
			}

			if (!(ls_bit1 == 0 && ls_bit2 == 0))
			{
				vector_loadstore();
			}
			break;
		}

		case 0xc8:
		case 0xd8:
		case 0xc9:
		case 0xd9:          
		{
			int acc = OP_ACC();
			int p1 = m_ir & (1 << 5);
			int pd = (m_ir >> 7) & 3;
			int ls_bit1 = m_ir & (1 << 10);
			int ls_bit2 = m_ir & (1 << 6);
			int rd = OP_RS();
			int rs1 = OP_SRC1();

			double source = has_imm ? (double)u2f(imm32) : (p1 ? u2d(m_fpair[rs1 >> 1]) : (double)u2f(m_reg[rs1]));

			if (rd)
			{

				switch (pd)
				{
					case 0:
						m_reg[rd] = f2u((float)source);
						break;
					case 1:
						m_fpair[rd >> 1] = d2u(source);
						break;
					case 2:
						m_reg[rd] = (int32_t)(source);
						break;
					case 3:
						m_reg[rd] = (uint32_t)(source);
						break;
				}
			}
			else
			{

				if (pd != 1)
					fatalerror("vrnd pd = %d at %08X\n", pd, m_pc);

				m_facc[acc] = source;
			}

			if (!(ls_bit1 == 0 && ls_bit2 == 0))
			{
				vector_loadstore();
			}
			break;
		}

		case 0xcc:
		case 0xdc:
		case 0xcd:
		case 0xdd:          
		{
			int acc = OP_ACC();
			int z = m_ir & (1 << 8);
			int pd = m_ir & (1 << 9);
			int ls_bit1 = m_ir & (1 << 10);
			int ls_bit2 = m_ir & (1 << 6);
			int rd = OP_RD();

			float src1 = u2f(m_reg[OP_SRC1()]);
			float src2 = u2f(m_reg[OP_RS()]);

			float res = (src1 * src2) + (z ? 0.0f : m_facc[acc]);

			if (!(ls_bit1 == 0 && ls_bit2 == 0))
			{
				vector_loadstore();

				m_facc[acc] = (double)res;
			}
			else
			{
				if (rd)
				{
					if (pd)
						m_fpair[rd >> 1] = d2u(res);
					else
						m_reg[rd] = f2u((float)res);
				}
				else
				{

					m_facc[acc] = (double)res;
				}
			}
			break;
		}

		case 0xce:
		case 0xde:
		case 0xcf:
		case 0xdf:          
		{
			int acc = OP_ACC();
			int z = m_ir & (1 << 8);
			int pd = m_ir & (1 << 9);
			int ls_bit1 = m_ir & (1 << 10);
			int ls_bit2 = m_ir & (1 << 6);
			int rd = OP_RD();

			float src1 = u2f(m_reg[OP_SRC1()]);
			float src2 = u2f(m_reg[OP_RS()]);

			float res = (z ? 0.0f : m_facc[acc]) - (src1 * src2);

			if (!(ls_bit1 == 0 && ls_bit2 == 0))
			{
				vector_loadstore();

				m_facc[acc] = (double)res;
			}
			else
			{
				if (rd)
				{
					if (pd)
						m_fpair[rd >> 1] = d2u(res);
					else
						m_reg[rd] = f2u((float)res);
				}
				else
				{

					m_facc[acc] = (double)res;
				}
			}
			break;
		}

		case 0xe0:
		case 0xe1:          
		{
			int rd = OP_RD();
			int rs = OP_RS();
			int src1 = OP_SRC1();
			int precision = (m_ir >> 5) & 0x3f;

			if (rd)     
			{
				switch (precision)
				{
					case 0x00:          
					{
						float s1 = u2f(has_imm ? imm32 : m_reg[src1]);
						float s2 = u2f(m_reg[rs]);
						m_reg[rd] = f2u(s1 + s2);
						break;
					}
					case 0x10:          
					{
						float s1 = u2f(has_imm ? imm32 : m_reg[src1]);
						float s2 = u2f(m_reg[rs]);
						uint64_t res = d2u((double)(s1 + s2));
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x14:          
					{
						float s1 = u2f(has_imm ? imm32 : m_reg[src1]);
						double s2 = u2d(m_fpair[rs >> 1]);
						uint64_t res = d2u((double) s1 + s2);
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x11:          
					{
						double s1 = u2d(m_fpair[src1 >> 1]);
						float s2 = u2f(m_reg[rs]);
						uint64_t res = d2u(s1 + (double) s2);
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x15:          
					{
						double s1 = u2d(m_fpair[src1 >> 1]);
						double s2 = u2d(m_fpair[rs >> 1]);
						uint64_t res = d2u((double)(s1 + s2));
						m_fpair[rd >> 1] = res;
						break;
					}
					default:
						fatalerror("fadd: invalid precision combination %02X\n", precision);
				}
			}
			break;
		}

		case 0xe2:
		case 0xe3:          
		{
			int rd = OP_RD();
			int rs = OP_RS();
			int src1 = OP_SRC1();
			int precision = (m_ir >> 5) & 0x3f;

			if (rd)     
			{
				switch (precision)
				{
					case 0x00:          
					{
						float s1 = u2f(has_imm ? imm32 : m_reg[src1]);
						float s2 = u2f(m_reg[rs]);
						m_reg[rd] = f2u(s1 - s2);
						break;
					}
					case 0x10:          
					{
						float s1 = u2f(has_imm ? imm32 : m_reg[src1]);
						float s2 = u2f(m_reg[rs]);
						uint64_t res = d2u((double)(s1 - s2));
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x14:          
					{
						float s1 = u2f(has_imm ? imm32 : m_reg[src1]);
						double s2 = u2d(m_fpair[rs >> 1]);
						uint64_t res = d2u((double) s1 - s2);
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x11:          
					{
						double s1 = u2d(m_fpair[src1 >> 1]);
						float s2 = u2f(m_reg[rs]);
						uint64_t res = d2u(s1 - (double) s2);
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x15:          
					{
						double s1 = u2d(m_fpair[src1 >> 1]);
						double s2 = u2d(m_fpair[rs >> 1]);
						uint64_t res = d2u((double)(s1 - s2));
						m_fpair[rd >> 1] = res;
						break;
					}
					default:
						fatalerror("fsub: invalid precision combination %02X\n", precision);
				}
			}
			break;
		}

		case 0xe4:
		case 0xe5:          
		{
			int rd = OP_RD();
			int rs = OP_RS();
			int src1 = OP_SRC1();
			int precision = (m_ir >> 5) & 0x3f;

			if (rd)     
			{
				switch (precision)
				{
					case 0x00:          
					{
						float s1 = u2f(has_imm ? imm32 : m_reg[src1]);
						float s2 = u2f(m_reg[rs]);
						m_reg[rd] = f2u(s1 * s2);
						break;
					}
					case 0x10:          
					{
						float s1 = u2f(has_imm ? imm32 : m_reg[src1]);
						float s2 = u2f(m_reg[rs]);
						uint64_t res = d2u((double)(s1 * s2));
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x14:          
					{
						float s1 = u2f(has_imm ? imm32 : m_reg[src1]);
						double s2 = u2d(m_fpair[rs >> 1]);
						uint64_t res = d2u((double)s1 * s2);
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x11:          
					{
						double s1 = u2d(m_fpair[src1 >> 1]);
						float s2 = u2f(m_reg[rs]);
						uint64_t res = d2u(s1 * (double) s2);
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x15:          
					{
						double s1 = u2d(m_fpair[src1 >> 1]);
						double s2 = u2d(m_fpair[rs >> 1]);
						uint64_t res = d2u(s1 * s2);
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x2a:          
					{
						m_reg[rd] = (int32_t)(m_reg[rs]) * (int32_t)(has_imm ? imm32 : m_reg[OP_SRC1()]);
						break;
					}
					case 0x3f:          
					{
						m_reg[rd] = (uint32_t)(m_reg[rs]) * (uint32_t)(has_imm ? imm32 : m_reg[OP_SRC1()]);
						break;
					}
					default:
						fatalerror("fmpy: invalid precision combination %02X\n", precision);
				}
			}
			break;
		}

		case 0xe6:
		case 0xe7:          
		{
			int rd = OP_RD();
			int p1 = m_ir & (1 << 5);
			int p2 = m_ir & (1 << 7);
			int pd = m_ir & (1 << 9);
			int rs1 = OP_SRC1();
			int rs2 = OP_RS();

			if (rd)
			{
				double src1 = has_imm ? (double)u2f(imm32) : (p1 ? u2d(m_fpair[rs1 >> 1]) : (double)u2f(m_reg[rs1]));
				double src2 = p2 ? u2d(m_fpair[rs2 >> 1]) : (double)u2f(m_reg[rs2]);

				double res;
				if (src2 != 0.0)
					res = src1 / src2;
				else
					res = 0.0f;

				if (pd)
					m_fpair[rd >> 1] = d2u(res);
				else
					m_reg[rd] = f2u((float)res);
			}
			break;
		}

		case 0xe8:
		case 0xe9:          
		{

			int p1 = (m_ir >> 5) & 3;
			int pd = (m_ir >> 9) & 3;
			int src1 = OP_SRC1();
			int rd = OP_RD();

			double s = 0.0;

			switch (p1)
			{
				case 0:
					s = has_imm ? (double)(u2f(imm32)) : (double)u2f(m_reg[src1]);
					break;
				case 1:
					s = u2d(m_fpair[src1 >> 1]);
					break;
				case 2:
					s = has_imm ? (double)((int32_t)(imm32)) : (double)(int32_t)(m_reg[src1]);
					break;
				case 3:
					s = has_imm ? (double)((uint32_t)(imm32)) : (double)(uint32_t)(m_reg[src1]);
					break;
			}

			if (rd)
			{
				switch (pd)
				{
					case 0:
						m_reg[rd] = f2u((float)(s));
						break;
					case 1:
						m_fpair[rd >> 1] = d2u(s);
						break;
					case 2:
						m_reg[rd] = (int32_t)(s);
						break;
					case 3:
						m_reg[rd] = (uint32_t)(s);
						break;
				}
			}
			break;
		}

		case 0xea:
		case 0xeb:          
		{
			int rd = OP_RD();
			int p1 = m_ir & (1 << 5);
			int p2 = m_ir & (1 << 7);
			int rs1 = OP_SRC1();
			int rs2 = OP_RS();

			double src1 = has_imm ? (double)(u2f(imm32)) : (p1 ? u2d(m_fpair[rs1 >> 1]) : (double)u2f(m_reg[rs1]));
			double src2 = p2 ? u2d(m_fpair[rs2 >> 1]) : (double)u2f(m_reg[rs2]);

			if (rd)
			{
				uint32_t flags = 0;
				flags |= (src1 == src2) ? (1 << 20) : 0;
				flags |= (src1 != src2) ? (1 << 21) : 0;
				flags |= (src1 >  src2) ? (1 << 22) : 0;
				flags |= (src1 <= src2) ? (1 << 23) : 0;
				flags |= (src1 <  src2) ? (1 << 24) : 0;
				flags |= (src1 >= src2) ? (1 << 25) : 0;
				flags |= (src1 < 0 || src1 > src2) ? (1 << 26) : 0;
				flags |= (src1 > 0 && src1 < src2) ? (1 << 27) : 0;
				flags |= (src1 >= 0 && src1 <= src2) ? (1 << 28) : 0;
				flags |= (src1 <= 0 || src1 >= src2) ? (1 << 29) : 0;

				m_reg[rd] = flags;
			}
			break;
		}

		case 0xee:
		case 0xef:          
		{
			int rd = OP_RD();
			int src1 = OP_SRC1();
			int p1 = m_ir & (1 << 5);
			int pd = m_ir & (1 << 9);
			double source = has_imm ? (double)u2f(imm32) : (p1 ? u2d(m_fpair[src1 >> 1]) : (double)u2f(m_reg[src1]));

			if (rd)
			{
				double res;
				if (source >= 0.0f)
					res = sqrt(source);
				else
					res = 0.0;

				if (pd)
					m_fpair[rd >> 1] = d2u(res);
				else
					m_reg[rd] = f2u((float)res);
			}
			break;
		}

		case 0xf2:          
		{
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			int bit = 32;

			for (int i=0; i < 32; i++)
			{
				if (source & (1 << (31-i)))
				{
					bit = i;
					break;
				}
			}

			if (rd)
				m_reg[rd] = bit;
			break;
		}

		default:
			fatalerror("execute_reg_long_imm(): %08X: opcode %08X (%02X)", m_pc, m_ir, (m_ir >> 12) & 0xff);
	}
}

void tms32082_mp_device::execute()
{
	switch ((m_ir >> 20) & 3)
	{
		case 0:
		case 1:
		case 2:
			execute_short_imm();
			break;

		case 3:
			execute_reg_long_imm();
			break;
	}
}
// license:BSD-3-Clause
// copyright-holders:Ville Linde
// TMS320C82 Master Processor core execution

#include "emu.h"
#include "tms32082.h"


#define OP_LINK() ((m_ir >> 27) & 0x1f)
#define OP_RD() ((m_ir >> 27) & 0x1f)
#define OP_RS() ((m_ir >> 22) & 0x1f)
#define OP_BASE() ((m_ir >> 22) & 0x1f)
#define OP_SIMM15() ((m_ir & 0x4000) ? (0xffffe000 | (m_ir & 0x7fff)) : (m_ir & 0x7fff))
#define OP_UIMM15() (m_ir & 0x7fff)
#define OP_BITNUM() ((m_ir >> 27) & 0x1f)
#define OP_ROTATE() (m_ir & 0x1f)
#define OP_ENDMASK() ((m_ir >> 5) & 0x1f)
#define OP_SRC1() (m_ir & 0x1f)
#define OP_PD() ((m_ir >> 9) & 0x3)
#define OP_P1() ((m_ir >> 5) & 0x3)
#define OP_P2() ((m_ir >> 7) & 0x3)
#define OP_ACC() ((m_ir >> 15) & 0x2) | ((m_ir >> 11) & 1)

#define ROTATE_L(x, r) ((x << r) | (x >> (32-r)))
#define ROTATE_R(x, r) ((x >> r) | (x << (32-r)))

#define CMP_OVERFLOW32(r, s, d)     ((((d) ^ (s)) & ((d) ^ (r)) & 0x80000000) ? 1 : 0)
#define CMP_OVERFLOW16(r, s, d)     ((((d) ^ (s)) & ((d) ^ (r)) & 0x8000) ? 1 : 0)
#define CMP_OVERFLOW8(r, s, d)      ((((d) ^ (s)) & ((d) ^ (r)) & 0x80) ? 1 : 0)
#define CARRY32(x)                  (((x) & (((uint64_t)1) << 32)) ? 1 : 0)
#define CARRY16(x)                  (((x) & 0x10000) ? 1 : 0)
#define CARRY8(x)                   (((x) & 0x100) ? 1 : 0)
#define SIGN32(x)                   (((x) & 0x80000000) ? 1 : 0)
#define SIGN16(x)                   (((x) & 0x8000) ? 1 : 0)
#define SIGN8(x)                    (((x) & 0x80) ? 1 : 0)

#define SIGN_EXTEND(x, r)           ((x) | (((x) & (0x80000000 >> r)) ? ((int32_t)(0x80000000) >> r) : 0))



bool tms32082_mp_device::test_condition(int condition, uint32_t value)
{
	switch (condition)
	{
		case 0x00:  return false;                   // never, byte
		case 0x01:  return (int8_t)(value) > 0;       // greater than zero, byte
		case 0x02:  return (int8_t)(value) == 0;      // equals zero, byte
		case 0x03:  return (int8_t)(value) >= 0;      // greater than or equal to zero, byte
		case 0x04:  return (int8_t)(value) < 0;       // less than zero, byte
		case 0x05:  return (int8_t)(value) != 0;      // not equal to zero, byte
		case 0x06:  return (int8_t)(value) <= 0;      // less than or equal to zero, byte
		case 0x07:  return true;                    // always, byte
		case 0x08:  return false;                   // never, word
		case 0x09:  return (int16_t)(value) > 0;      // greater than zero, word
		case 0x0a:  return (int16_t)(value) == 0;     // equals zero, word
		case 0x0b:  return (int16_t)(value) >= 0;     // greater than or equal to zero, word
		case 0x0c:  return (int16_t)(value) < 0;      // less than zero, word
		case 0x0d:  return (int16_t)(value) != 0;     // not equal to zero, word
		case 0x0e:  return (int16_t)(value) <= 0;     // less than or equal to zero, word
		case 0x0f:  return true;                    // always, word
		case 0x10:  return false;                   // never, dword
		case 0x11:  return (int32_t)(value) > 0;      // greater than zero, dword
		case 0x12:  return (int32_t)(value) == 0;     // equals zero, dword
		case 0x13:  return (int32_t)(value) >= 0;     // greater than or equal to zero, dword
		case 0x14:  return (int32_t)(value) < 0;      // less than zero, dword
		case 0x15:  return (int32_t)(value) != 0;     // not equal to zero, dword
		case 0x16:  return (int32_t)(value) <= 0;     // less than or equal to zero, dword
		case 0x17:  return true;                    // always, dword
		default:    return false;                   // reserved
	}
}

uint32_t tms32082_mp_device::calculate_cmp(uint32_t src1, uint32_t src2)
{
	uint16_t src1_16 = (uint16_t)(src1);
	uint8_t src1_8 = (uint8_t)(src1);
	uint16_t src2_16 = (uint16_t)(src2);
	uint8_t src2_8 = (uint8_t)(src2);

	uint64_t res32 = (uint64_t)src1 - (uint64_t)src2;
	int z32 = (res32 == 0) ? 1 : 0;
	int n32 = SIGN32(res32);
	int v32 = CMP_OVERFLOW32(res32, src2, src1);
	int c32 = CARRY32(res32);

	uint32_t res16 = (uint32_t)src1_16 - (uint32_t)src2_16;
	int z16 = (res16 == 0) ? 1 : 0;
	int n16 = SIGN16(res16);
	int v16 = CMP_OVERFLOW16(res16, src2_16, src1_16);
	int c16 = CARRY16(res16);

	uint16_t res8 = (uint16_t)src1_8 - (uint16_t)src2_8;
	int z8 = (res8 == 0) ? 1 : 0;
	int n8 = SIGN8(res8);
	int v8 = CMP_OVERFLOW8(res8, src2_8, src1_8);
	int c8 = CARRY8(res8);

	uint32_t flags = 0;
	// 32-bits (bits 20-29)
	flags |= ((~c32) & 1) << 29;                                // higher than or same (C)
	flags |= ((c32) & 1) << 28;                                 // lower than (~C)
	flags |= ((c32|z32) & 1) << 27;                             // lower than or same (~C|Z)
	flags |= ((~c32&~z32) & 1) << 26;                           // higher than (C&~Z)
	flags |= (((n32&v32)|(~n32&~v32)) & 1) << 25;               // greater than or equal (N&V)|(~N&~V)
	flags |= (((n32&~v32)|(~n32&v32)) & 1) << 24;               // less than (N&~V)|(~N&V)
	flags |= (((n32&~v32)|(~n32&v32)|(z32)) & 1) << 23;         // less than or equal (N&~V)|(~N&V)|Z
	flags |= (((n32&v32&~z32)|(~n32&~v32&~z32)) & 1) << 22;     // greater than (N&V&~Z)|(~N&~V&~Z)
	flags |= ((~z32) & 1) << 21;                                // not equal (~Z)
	flags |= ((z32) & 1) << 20;                                 // equal (Z)
	// 16-bits (bits 10-19)
	flags |= ((~c16) & 1) << 19;                                // higher than or same (C)
	flags |= ((c16) & 1) << 18;                                 // lower than (~C)
	flags |= ((c16|z16) & 1) << 17;                             // lower than or same (~C|Z)
	flags |= ((~c16&~z16) & 1) << 16;                           // higher than (C&~Z)
	flags |= (((n16&v16)|(~n16&~v16)) & 1) << 15;               // greater than or equal (N&V)|(~N&~V)
	flags |= (((n16&~v16)|(~n16&v16)) & 1) << 14;               // less than (N&~V)|(~N&V)
	flags |= (((n16&~v16)|(~n16&v16)|(z16)) & 1) << 13;         // less than or equal (N&~V)|(~N&V)|Z
	flags |= (((n16&v16&~z16)|(~n16&~v16&~z16)) & 1) << 12;     // greater than (N&V&~Z)|(~N&~V&~Z)
	flags |= ((~z16) & 1) << 11;                                // not equal (~Z)
	flags |= ((z16) & 1) << 10;                                 // equal (Z)
	// 8-bits (bits 0-9)
	flags |= ((~c8) & 1) << 9;                                  // higher than or same (C)
	flags |= ((c8) & 1) << 8;                                   // lower than (~C)
	flags |= ((c8|z8) & 1) << 7;                                // lower than or same (~C|Z)
	flags |= ((~c8&~z8) & 1) << 6;                              // higher than (C&~Z)
	flags |= (((n8&v8)|(~n8&~v8)) & 1) << 5;                    // greater than or equal (N&V)|(~N&~V)
	flags |= (((n8&~v8)|(~n8&v8)) & 1) << 4;                    // less than (N&~V)|(~N&V)
	flags |= (((n8&~v8)|(~n8&v8)|(z8)) & 1) << 3;               // less than or equal (N&~V)|(~N&V)|Z
	flags |= (((n8&v8&~z8)|(~n8&~v8&~z8)) & 1) << 2;            // greater than (N&V&~Z)|(~N&~V&~Z)
	flags |= ((~z8) & 1) << 1;                                  // not equal (~Z)
	flags |= ((z8) & 1) << 0;                                   // equal (Z)

	return flags;
}

void tms32082_mp_device::vector_loadstore()
{
	int rd = OP_RD();
	int vector_ls_bits = (((m_ir >> 9) & 0x3) << 1) | ((m_ir >> 6) & 1);

	switch (vector_ls_bits)
	{
		case 0x01:          // vst.s
		{
			m_program->write_dword(m_outp, m_reg[rd]);
			m_outp += 4;
			break;
		}
		case 0x03:          // vst.d
		{
			uint64_t data = m_fpair[rd >> 1];
			m_program->write_qword(m_outp, data);
			m_outp += 8;
			break;
		}
		case 0x04:          // vld0.s
		{
			m_reg[rd] = m_program->read_dword(m_in0p);
			m_in0p += 4;
			break;
		}
		case 0x05:          // vld1.s
		{
			m_reg[rd] = m_program->read_dword(m_in1p);
			m_in1p += 4;
			break;
		}
		case 0x06:          // vld0.d
		{
			m_fpair[rd >> 1] = m_program->read_qword(m_in0p);
			m_in0p += 8;
			break;
		}
		case 0x07:          // vld1.d
		{
			m_fpair[rd >> 1] = m_program->read_qword(m_in1p);
			m_in1p += 8;
			break;
		}

		default:
			fatalerror("vector_loadstore(): ls bits = %02X\n", vector_ls_bits);
	}
}

void tms32082_mp_device::execute_short_imm()
{
	switch ((m_ir >> 15) & 0x7f)
	{
		case 0x02:          // cmnd
		{
			uint32_t data = OP_UIMM15();

			processor_command(data);
			break;
		}

		case 0x04:          // rdcr
		{
			int rd = OP_RD();
			uint32_t imm = OP_UIMM15();

			uint32_t r = read_creg(imm);

			if (rd)
				m_reg[rd] = r;
			break;
		}

		case 0x05:          // swcr
		{
			int rd = OP_RD();
			int rs = OP_RS();
			uint32_t imm = OP_UIMM15();

			uint32_t r = read_creg(imm);
			if (rd)
				m_reg[rd] = r;

			write_creg(imm, m_reg[rs]);
			break;
		}

		case 0x06:          // brcr
		{
			int cr = OP_UIMM15();

			if (cr == 0x0001)
			{
				// ignore jump to EIP because of how we emulate the pipeline
			}
			else
			{
				uint32_t data = read_creg(cr);

				m_fetchpc = data & ~3;
				m_ie = (m_ie & ~1) | (data & 1);        // global interrupt mask from creg
				// TODO: user/supervisor latch from creg
			}
			break;
		}

		case 0x08:          // shift.dz
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = OP_ROTATE();
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = SHIFT_MASK[end ? end : 32];
			if (inv) endmask = ~endmask;

			uint32_t compmask = endmask;          // shiftmask == 0xffffffff

			uint32_t res;
			if (r)      // right
			{
				res = ROTATE_R(source, rot) & compmask;
			}
			else        // left
			{
				res = ROTATE_L(source, rot) & compmask;
			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x0a:          // shift.ds
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = OP_ROTATE();
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = SHIFT_MASK[end ? end : 32];
			if (inv) endmask = ~endmask;

			uint32_t compmask = endmask;          // shiftmask == 0xffffffff

			uint32_t res;
			if (r)      // right
			{
				res = ROTATE_R(source, rot) & compmask;
				res = SIGN_EXTEND(res, rot);
			}
			else        // left
			{
				res = ROTATE_L(source, rot) & compmask;
				// sign extend makes no sense to left..
			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x0b:          // shift.ez
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = OP_ROTATE();
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = SHIFT_MASK[end ? end : 32];
			if (inv) endmask = ~endmask;

			int shift = r ? 32-rot : rot;
			uint32_t shiftmask = SHIFT_MASK[shift ? shift : 32];
			uint32_t compmask = endmask & shiftmask;

			uint32_t res;
			if (r)      // right
			{
				res = ROTATE_R(source, rot) & compmask;
			}
			else        // left
			{
				res = ROTATE_L(source, rot) & compmask;
			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x0c:          // shift.em
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = OP_ROTATE();
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = SHIFT_MASK[end ? end : 32];
			if (inv) endmask = ~endmask;

			uint32_t shiftmask = SHIFT_MASK[r ? 32-rot : rot];
			uint32_t compmask = endmask & shiftmask;

			uint32_t res;
			if (r)      // right
			{
				res = (ROTATE_R(source, rot) & compmask) | (m_reg[rd] & ~compmask);
			}
			else        // left
			{
				res = (ROTATE_L(source, rot) & compmask) | (m_reg[rd] & ~compmask);
			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x0d:          // shift.es
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = OP_ROTATE();
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = SHIFT_MASK[end ? end : 32];
			if (inv) endmask = ~endmask;

			int shift = r ? 32-rot : rot;
			uint32_t shiftmask = SHIFT_MASK[shift ? shift : 32];
			uint32_t compmask = endmask & shiftmask;

			uint32_t res;
			if (r)      // right
			{
				res = ROTATE_R(source, rot) & compmask;
				res = SIGN_EXTEND(res, rot);
			}
			else        // left
			{
				res = ROTATE_L(source, rot) & compmask;
				// sign extend makes no sense to left..
			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x0e:          // shift.iz
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = OP_ROTATE();
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = SHIFT_MASK[end ? end : 32];
			if (inv) endmask = ~endmask;

			uint32_t shiftmask = SHIFT_MASK[r ? 32-rot : rot];
			uint32_t compmask = endmask & ~shiftmask;

			uint32_t res;
			if (r)      // right
			{
				res = ROTATE_R(source, rot) & compmask;
			}
			else        // left
			{
				res = ROTATE_L(source, rot) & compmask;
			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x0f:          // shift.im
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = OP_ROTATE();
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = SHIFT_MASK[end ? end : 32];
			if (inv) endmask = ~endmask;

			uint32_t shiftmask = SHIFT_MASK[r ? 32-rot : rot];
			uint32_t compmask = endmask & ~shiftmask;

			uint32_t res;
			if (r)      // right
			{
				res = (ROTATE_R(source, rot) & compmask) | (m_reg[rd] & ~compmask);
			}
			else        // left
			{
				res = (ROTATE_L(source, rot) & compmask) | (m_reg[rd] & ~compmask);
			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x11:          // and
		{
			int rd = OP_RD();
			int rs = OP_RS();
			uint32_t imm = OP_UIMM15();

			if (rd)
				m_reg[rd] = m_reg[rs] & imm;
			break;
		}

		case 0x12:          // and.tf
		{
			int rd = OP_RD();
			int rs = OP_RS();
			uint32_t imm = OP_UIMM15();

			if (rd)
				m_reg[rd] = ~m_reg[rs] & imm;
			break;
		}

		case 0x14:          // and.ft
		{
			int rd = OP_RD();
			int rs = OP_RS();
			uint32_t imm = OP_UIMM15();

			if (rd)
				m_reg[rd] = m_reg[rs] & ~imm;
			break;
		}

		case 0x17:          // or
		{
			int rd = OP_RD();
			int rs = OP_RS();
			uint32_t imm = OP_UIMM15();

			if (rd)
				m_reg[rd] = m_reg[rs] | imm;
			break;
		}

		case 0x1d:          // or.ft
		{
			int rd = OP_RD();
			int rs = OP_RS();
			uint32_t imm = OP_UIMM15();

			if (rd)
				m_reg[rd] = m_reg[rs] | ~imm;
			break;
		}

		case 0x24:
		case 0x20:          // ld.b
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;
			uint32_t data = (uint8_t)m_program->read_byte(address);
			if (data & 0x80) data |= 0xffffff00;
			if (rd)
				m_reg[rd] = data;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x25:
		case 0x21:          // ld.h
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;
			uint32_t data = (uint16_t)m_program->read_word(address);
			if (data & 0x8000) data |= 0xffff0000;
			if (rd)
				m_reg[rd] = data;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x26:
		case 0x22:          // ld
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;
			uint32_t data = m_program->read_dword(address);
			if (rd)
				m_reg[rd] = data;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x27:
		case 0x23:          // ld.d
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;
			uint32_t data1 = m_program->read_dword(address);
			uint32_t data2 = m_program->read_dword(address+4);
			if (rd)
			{
				m_reg[(rd & ~1)+1] = data1;
				m_reg[(rd & ~1)] = data2;
			}

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x28:
		case 0x2c:          // ld.ub
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;
			uint32_t data = (uint8_t)(m_program->read_byte(address));
			if (rd)
				m_reg[rd] = data;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x2d:
		case 0x29:          // ld.uh
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;
			uint32_t data = (uint16_t)(m_program->read_word(address));
			if (rd)
				m_reg[rd] = data;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x34:
		case 0x30:          // st.b
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;

			m_program->write_byte(address, (uint8_t)(m_reg[rd]));

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x35:
		case 0x31:          // st.h
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;

			m_program->write_word(address, (uint16_t)(m_reg[rd]));

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x36:
		case 0x32:          // st
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;

			m_program->write_dword(address, m_reg[rd]);

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x37:
		case 0x33:          // st.d
		{
			int rd = OP_RD();
			int base = OP_BASE();
			int m = m_ir & (1 << 17);
			int32_t offset = OP_SIMM15();

			uint32_t address = m_reg[base] + offset;

			m_program->write_dword(address+0, m_reg[(rd & ~1) + 1]);
			m_program->write_dword(address+4, m_reg[rd & ~1]);

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x45:          // jsr.a
		{
			int link = OP_LINK();
			int base = OP_BASE();
			int32_t offset = OP_SIMM15();

			if (link)
				m_reg[link] = m_fetchpc;

			m_fetchpc = m_reg[base] + offset;
			break;
		}

		case 0x48:          // bbz
		{
			int bitnum = OP_BITNUM() ^ 0x1f;
			int32_t offset = OP_SIMM15();
			int rs = OP_RS();

			if ((m_reg[rs] & (1 << bitnum)) == 0)
			{
				uint32_t address = m_pc + (offset * 4);

				m_pc = m_fetchpc;
				delay_slot();

				m_fetchpc = address;
			}
			break;
		}

		case 0x49:          // bbz.a
		{
			int bitnum = OP_BITNUM() ^ 0x1f;
			int32_t offset = OP_SIMM15();
			int rs = OP_RS();

			if ((m_reg[rs] & (1 << bitnum)) == 0)
			{
				m_fetchpc = m_pc + (offset * 4);
			}
			break;
		}

		case 0x4a:          // bbo
		{
			int bitnum = OP_BITNUM() ^ 0x1f;
			int32_t offset = OP_SIMM15();
			int rs = OP_RS();

			if ((m_reg[rs] & (1 << bitnum)) != 0)
			{
				uint32_t address = m_pc + (offset * 4);

				m_pc = m_fetchpc;
				delay_slot();

				m_fetchpc = address;
			}
			break;
		}

		case 0x4b:          // bbo.a
		{
			int bitnum = OP_BITNUM() ^ 0x1f;
			int32_t offset = OP_SIMM15();
			int rs = OP_RS();

			if ((m_reg[rs] & (1 << bitnum)) != 0)
			{
				m_fetchpc = m_pc + (offset * 4);
			}
			break;
		}

		case 0x4c:          // bcnd
		{
			int32_t offset = OP_SIMM15();
			int code = OP_RD();
			int rs = OP_RS();

			if (test_condition(code, m_reg[rs]))
			{
				uint32_t address = m_pc + (offset * 4);

				m_pc = m_fetchpc;
				delay_slot();

				m_fetchpc = address;
			}
			break;
		}

		case 0x4d:          // bcnd.a
		{
			int32_t offset = OP_SIMM15();
			int code = OP_RD();
			int rs = OP_RS();

			if (test_condition(code, m_reg[rs]))
			{
				m_fetchpc = m_pc + (offset * 4);
			}
			break;
		}

		case 0x50:          // cmp
		{
			uint32_t src1 = OP_SIMM15();
			uint32_t src2 = m_reg[OP_RS()];
			int rd = OP_RD();

			if (rd)
				m_reg[rd] = calculate_cmp(src1, src2);
			break;
		}

		case 0x58:          // add
		{
			int32_t imm = OP_SIMM15();
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = m_reg[rs] + imm;

			// TODO: integer overflow exception
			break;
		}

		case 0x59:          // addu
		{
			int32_t imm = OP_SIMM15();
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = m_reg[rs] + imm;
			break;
		}

		case 0x5a:          // sub
		{
			int32_t imm = OP_SIMM15();
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = imm - m_reg[rs];

			// TODO: integer overflow exception
			break;
		}

		case 0x5b:          // subu
		{
			int32_t imm = OP_SIMM15();
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = imm - m_reg[rs];
			break;
		}

		default:
			fatalerror("execute_short_imm(): %08X: opcode %08X (%02X)", m_pc, m_ir, (m_ir >> 15) & 0x7f);
	}
}

void tms32082_mp_device::execute_reg_long_imm()
{
	uint32_t imm32 = 0;

	int has_imm = (m_ir & (1 << 12));

	if (has_imm)
		imm32 = fetch();

	switch ((m_ir >> 12) & 0xff)
	{
		case 0x04:          // cmnd
		{
			uint32_t data = has_imm ? imm32 : m_reg[OP_SRC1()];

			processor_command(data);
			break;
		}

		case 0x16:          // shift.ez
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = m_reg[OP_ROTATE()];
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = end ? SHIFT_MASK[end ? end : 32] : m_reg[OP_ROTATE()+1];
			if (inv) endmask = ~endmask;

			int shift = r ? 32-rot : rot;
			uint32_t shiftmask = SHIFT_MASK[shift ? shift : 32];
			uint32_t compmask = endmask & shiftmask;

			uint32_t res;
			if (r)      // right
			{
				res = ROTATE_R(source, rot) & compmask;
			}
			else        // left
			{
				res = ROTATE_L(source, rot) & compmask;
			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x1a:          // shift.es
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = m_reg[OP_ROTATE()];
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = end ? SHIFT_MASK[end ? end : 32] : m_reg[OP_ROTATE()+1];
			if (inv) endmask = ~endmask;

			int shift = r ? 32-rot : rot;
			uint32_t shiftmask = SHIFT_MASK[shift ? shift : 32];
			uint32_t compmask = endmask & shiftmask;

			uint32_t res;
			if (r)      // right
			{
				res = ROTATE_R(source, rot) & compmask;
				res = SIGN_EXTEND(res, rot);
			}
			else        // left
			{
				res = ROTATE_L(source, rot) & compmask;
			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x1c:          // shift.iz
		{
			int r = (m_ir & (1 << 10));
			int inv = (m_ir & (1 << 11));
			int rot = m_reg[OP_ROTATE()];
			int end = OP_ENDMASK();
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			uint32_t endmask = end ? SHIFT_MASK[end ? end : 32] : m_reg[OP_ROTATE()+1];
			if (inv) endmask = ~endmask;

			int shift = r ? 32-rot : rot;
			uint32_t shiftmask = SHIFT_MASK[shift ? shift : 32];
			uint32_t compmask = endmask & ~shiftmask;

			uint32_t res;
			if (r)      // right
			{
				res = ROTATE_R(source, rot) & compmask;
			}
			else        // left
			{
				res = ROTATE_L(source, rot) & compmask;
			}

			if (rd)
				m_reg[rd] = res;
			break;
		}

		case 0x22:
		case 0x23:          // and
		{
			int rd = OP_RD();
			int rs = OP_RS();
			uint32_t src1 = has_imm ? imm32 : m_reg[OP_SRC1()];

			if (rd)
				m_reg[rd] = src1 & m_reg[rs];
			break;
		}

		case 0x24:
		case 0x25:          // and.tf
		{
			int rd = OP_RD();
			int rs = OP_RS();
			uint32_t src1 = has_imm ? imm32 : m_reg[OP_SRC1()];

			if (rd)
				m_reg[rd] = src1 & ~(m_reg[rs]);
			break;
		}

		case 0x2c:
		case 0x2d:          // xor
		{
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = m_reg[rs] ^ (has_imm ? imm32 : m_reg[OP_SRC1()]);
			break;
		}

		case 0x2e:
		case 0x2f:          // or
		{
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = m_reg[rs] | (has_imm ? imm32 : m_reg[OP_SRC1()]);
			break;
		}

		case 0x3a:
		case 0x3b:          // or.ft
		{
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = m_reg[rs] | ~(has_imm ? imm32 : m_reg[OP_SRC1()]);
			break;
		}

		case 0x40:
		case 0x41:
		case 0x48:
		case 0x49:          // ld.b
		{
			int m = m_ir & (1 << 15);

			int base = OP_BASE();
			int rd = OP_RD();

			uint32_t address = m_reg[base] + (has_imm ? imm32 : m_reg[OP_SRC1()]);
			uint32_t r = m_program->read_byte(address);
			if (r & 0x80) r |= 0xffffff00;

			if (rd)
				m_reg[rd] = r;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x42:
		case 0x4a:
		case 0x43:
		case 0x4b:          // ld.h
		{
			int shift = (m_ir & (1 << 11)) ? 1 : 0;
			int m = m_ir & (1 << 15);

			int base = OP_BASE();
			int rd = OP_RD();

			uint32_t address = m_reg[base] + ((has_imm ? imm32 : m_reg[OP_SRC1()]) << shift);
			uint32_t r = m_program->read_word(address);
			if (r & 0x8000) r |= 0xffff0000;

			if (rd)
				m_reg[rd] = r;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x4c:
		case 0x44:
		case 0x4d:
		case 0x45:          // ld
		{
			int shift = (m_ir & (1 << 11)) ? 2 : 0;
			int m = m_ir & (1 << 15);
			int base = OP_BASE();
			int rd = OP_RD();

			uint32_t address = m_reg[base] + ((has_imm ? imm32 : m_reg[OP_SRC1()]) << shift);
			uint32_t r = m_program->read_dword(address);

			if (rd)
				m_reg[rd] = r;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x4e:
		case 0x4f:
		case 0x46:
		case 0x47:          // ld.d
		{
			int shift = (m_ir & (1 << 11)) ? 3 : 0;
			int m = m_ir & (1 << 15);
			int base = OP_BASE();
			int rd = OP_RD();

			uint32_t address = m_reg[base] + ((has_imm ? imm32 : m_reg[OP_SRC1()]) << shift);
			uint64_t r = m_program->read_qword(address);

			if (rd)
				m_fpair[rd >> 1] = r;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x58:
		case 0x59:
		case 0x50:
		case 0x51:          // ld.ub
		{
			int m = m_ir & (1 << 15);
			int base = OP_BASE();
			int rd = OP_RD();

			uint32_t address = m_reg[base] + (has_imm ? imm32 : m_reg[OP_SRC1()]);
			uint32_t r = (uint8_t)(m_program->read_byte(address));

			if (rd)
				m_reg[rd] = r;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x5a:
		case 0x5b:
		case 0x52:
		case 0x53:          // ld.uh
		{
			int shift = (m_ir & (1 << 11)) ? 1 : 0;
			int m = m_ir & (1 << 15);
			int base = OP_BASE();
			int rd = OP_RD();

			uint32_t address = m_reg[base] + ((has_imm ? imm32 : m_reg[OP_SRC1()]) << shift);
			uint32_t r = (uint16_t)(m_program->read_word(address));

			if (rd)
				m_reg[rd] = r;

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x60:
		case 0x61:
		case 0x68:
		case 0x69:          // st.b
		{
			int m = m_ir & (1 << 15);

			int base = OP_BASE();

			uint32_t address = m_reg[base] + (has_imm ? imm32 : m_reg[OP_SRC1()]);
			m_program->write_byte(address, (uint8_t)(m_reg[OP_RD()]));

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x62:
		case 0x63:
		case 0x6a:
		case 0x6b:          // st.h
		{
			int shift = (m_ir & (1 << 11)) ? 1 : 0;
			int m = m_ir & (1 << 15);

			int base = OP_BASE();

			uint32_t address = m_reg[base] + ((has_imm ? imm32 : m_reg[OP_SRC1()]) << shift);
			m_program->write_word(address, (uint16_t)(m_reg[OP_RD()]));

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x6c:
		case 0x6d:
		case 0x64:
		case 0x65:          // st
		{
			int shift = (m_ir & (1 << 11)) ? 2 : 0;
			int m = m_ir & (1 << 15);

			int base = OP_BASE();

			uint32_t address = m_reg[base] + ((has_imm ? imm32 : m_reg[OP_SRC1()]) << shift);
			m_program->write_dword(address, m_reg[OP_RD()]);

			if (m && base)
				m_reg[base] = address;
			break;
		}

		case 0x88:
		case 0x89:          // jsr
		{
			int link = OP_LINK();
			int base = OP_BASE();

			if (link)
				m_reg[link] = m_fetchpc + 4;

			uint32_t address = m_reg[base] + (has_imm ? imm32 : m_reg[OP_SRC1()]);

			m_pc = m_fetchpc;
			delay_slot();

			m_fetchpc = address;
			break;
		}

		case 0x8a:
		case 0x8b:          // jsr.a
		{
			int link = OP_LINK();
			int base = OP_BASE();

			if (link)
				m_reg[link] = m_fetchpc;

			m_fetchpc = m_reg[base] + (has_imm ? imm32 : m_reg[OP_SRC1()]);
			break;
		}

		case 0xa0:
		case 0xa1:          // cmp
		{
			int rd = OP_RD();
			uint32_t src1 = has_imm ? imm32 : m_reg[OP_SRC1()];
			uint32_t src2 = m_reg[OP_RS()];

			if (rd)
				m_reg[rd] = calculate_cmp(src1, src2);
			break;
		}

		case 0xb2:
		case 0xb3:          // addu
		{
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = m_reg[rs] + (has_imm ? imm32 : m_reg[OP_SRC1()]);
			break;
		}

		case 0xb4:
		case 0xb5:          // sub
		{
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = (has_imm ? imm32 : m_reg[OP_SRC1()]) - m_reg[rs];

			// TODO: overflow interrupt
			break;
		}

		case 0xb6:
		case 0xb7:          // subu
		{
			int rd = OP_RD();
			int rs = OP_RS();

			if (rd)
				m_reg[rd] = (has_imm ? imm32 : m_reg[OP_SRC1()]) - m_reg[rs];
			break;
		}

		case 0xc4:
		case 0xd4:
		case 0xc5:
		case 0xd5:          // vmpy
		{
			int p1 = m_ir & (1 << 5);
			int pd = m_ir & (1 << 7);
			int ls_bit1 = m_ir & (1 << 10);
			int ls_bit2 = m_ir & (1 << 6);
			int rd = OP_RS();
			int src1 OP_SRC1();

			double source = has_imm ? (double)u2f(imm32) : (p1 ? u2d(m_fpair[src1 >> 1]) : (double)u2f(m_reg[src1]));

			if (rd)
			{
				if (pd)
				{
					double res = source * u2d(m_fpair[rd >> 1]);
					m_fpair[rd >> 1] = d2u(res);
				}
				else
				{
					float res = (float)(source) * u2f(m_reg[rd]);
					m_reg[rd] = f2u(res);
				}
			}

			// parallel load/store op
			if (!(ls_bit1 == 0 && ls_bit2 == 0))
			{
				vector_loadstore();
			}
			break;
		}

		case 0xc8:
		case 0xd8:
		case 0xc9:
		case 0xd9:          // vrnd
		{
			int acc = OP_ACC();
			int p1 = m_ir & (1 << 5);
			int pd = (m_ir >> 7) & 3;
			int ls_bit1 = m_ir & (1 << 10);
			int ls_bit2 = m_ir & (1 << 6);
			int rd = OP_RS();
			int rs1 = OP_SRC1();

			double source = has_imm ? (double)u2f(imm32) : (p1 ? u2d(m_fpair[rs1 >> 1]) : (double)u2f(m_reg[rs1]));

			if (rd)
			{
				// destination register
				switch (pd)
				{
					case 0:
						m_reg[rd] = f2u((float)source);
						break;
					case 1:
						m_fpair[rd >> 1] = d2u(source);
						break;
					case 2:
						m_reg[rd] = (int32_t)(source);
						break;
					case 3:
						m_reg[rd] = (uint32_t)(source);
						break;
				}
			}
			else
			{
				// destination accumulator
				if (pd != 1)
					fatalerror("vrnd pd = %d at %08X\n", pd, m_pc);

				m_facc[acc] = source;
			}

			// parallel load/store op
			if (!(ls_bit1 == 0 && ls_bit2 == 0))
			{
				vector_loadstore();
			}
			break;
		}

		case 0xcc:
		case 0xdc:
		case 0xcd:
		case 0xdd:          // vmac
		{
			int acc = OP_ACC();
			int z = m_ir & (1 << 8);
			int pd = m_ir & (1 << 9);
			int ls_bit1 = m_ir & (1 << 10);
			int ls_bit2 = m_ir & (1 << 6);
			int rd = OP_RD();

			float src1 = u2f(m_reg[OP_SRC1()]);
			float src2 = u2f(m_reg[OP_RS()]);

			float res = (src1 * src2) + (z ? 0.0f : m_facc[acc]);

			// parallel load/store op
			if (!(ls_bit1 == 0 && ls_bit2 == 0))
			{
				vector_loadstore();

				// if the opcode has load/store, dest is always accumulator
				m_facc[acc] = (double)res;
			}
			else
			{
				if (rd)
				{
					if (pd)
						m_fpair[rd >> 1] = d2u(res);
					else
						m_reg[rd] = f2u((float)res);
				}
				else
				{
					// write to accumulator
					m_facc[acc] = (double)res;
				}
			}
			break;
		}

		case 0xce:
		case 0xde:
		case 0xcf:
		case 0xdf:          // vmsc
		{
			int acc = OP_ACC();
			int z = m_ir & (1 << 8);
			int pd = m_ir & (1 << 9);
			int ls_bit1 = m_ir & (1 << 10);
			int ls_bit2 = m_ir & (1 << 6);
			int rd = OP_RD();

			float src1 = u2f(m_reg[OP_SRC1()]);
			float src2 = u2f(m_reg[OP_RS()]);

			float res = (z ? 0.0f : m_facc[acc]) - (src1 * src2);

			// parallel load/store op
			if (!(ls_bit1 == 0 && ls_bit2 == 0))
			{
				vector_loadstore();

				// if the opcode has load/store, dest is always accumulator
				m_facc[acc] = (double)res;
			}
			else
			{
				if (rd)
				{
					if (pd)
						m_fpair[rd >> 1] = d2u(res);
					else
						m_reg[rd] = f2u((float)res);
				}
				else
				{
					// write to accumulator
					m_facc[acc] = (double)res;
				}
			}
			break;
		}

		case 0xe0:
		case 0xe1:          // fadd
		{
			int rd = OP_RD();
			int rs = OP_RS();
			int src1 = OP_SRC1();
			int precision = (m_ir >> 5) & 0x3f;

			if (rd)     // only calculate if destination register is valid
			{
				switch (precision)
				{
					case 0x00:          // SP - SP -> SP
					{
						float s1 = u2f(has_imm ? imm32 : m_reg[src1]);
						float s2 = u2f(m_reg[rs]);
						m_reg[rd] = f2u(s1 + s2);
						break;
					}
					case 0x10:          // SP - SP -> DP
					{
						float s1 = u2f(has_imm ? imm32 : m_reg[src1]);
						float s2 = u2f(m_reg[rs]);
						uint64_t res = d2u((double)(s1 + s2));
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x14:          // SP - DP -> DP
					{
						float s1 = u2f(has_imm ? imm32 : m_reg[src1]);
						double s2 = u2d(m_fpair[rs >> 1]);
						uint64_t res = d2u((double) s1 + s2);
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x11:          // DP - SP -> DP
					{
						double s1 = u2d(m_fpair[src1 >> 1]);
						float s2 = u2f(m_reg[rs]);
						uint64_t res = d2u(s1 + (double) s2);
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x15:          // DP - DP -> DP
					{
						double s1 = u2d(m_fpair[src1 >> 1]);
						double s2 = u2d(m_fpair[rs >> 1]);
						uint64_t res = d2u((double)(s1 + s2));
						m_fpair[rd >> 1] = res;
						break;
					}
					default:
						fatalerror("fadd: invalid precision combination %02X\n", precision);
				}
			}
			break;
		}

		case 0xe2:
		case 0xe3:          // fsub
		{
			int rd = OP_RD();
			int rs = OP_RS();
			int src1 = OP_SRC1();
			int precision = (m_ir >> 5) & 0x3f;

			if (rd)     // only calculate if destination register is valid
			{
				switch (precision)
				{
					case 0x00:          // SP - SP -> SP
					{
						float s1 = u2f(has_imm ? imm32 : m_reg[src1]);
						float s2 = u2f(m_reg[rs]);
						m_reg[rd] = f2u(s1 - s2);
						break;
					}
					case 0x10:          // SP - SP -> DP
					{
						float s1 = u2f(has_imm ? imm32 : m_reg[src1]);
						float s2 = u2f(m_reg[rs]);
						uint64_t res = d2u((double)(s1 - s2));
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x14:          // SP - DP -> DP
					{
						float s1 = u2f(has_imm ? imm32 : m_reg[src1]);
						double s2 = u2d(m_fpair[rs >> 1]);
						uint64_t res = d2u((double) s1 - s2);
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x11:          // DP - SP -> DP
					{
						double s1 = u2d(m_fpair[src1 >> 1]);
						float s2 = u2f(m_reg[rs]);
						uint64_t res = d2u(s1 - (double) s2);
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x15:          // DP - DP -> DP
					{
						double s1 = u2d(m_fpair[src1 >> 1]);
						double s2 = u2d(m_fpair[rs >> 1]);
						uint64_t res = d2u((double)(s1 - s2));
						m_fpair[rd >> 1] = res;
						break;
					}
					default:
						fatalerror("fsub: invalid precision combination %02X\n", precision);
				}
			}
			break;
		}

		case 0xe4:
		case 0xe5:          // fmpy
		{
			int rd = OP_RD();
			int rs = OP_RS();
			int src1 = OP_SRC1();
			int precision = (m_ir >> 5) & 0x3f;

			if (rd)     // only calculate if destination register is valid
			{
				switch (precision)
				{
					case 0x00:          // SP x SP -> SP
					{
						float s1 = u2f(has_imm ? imm32 : m_reg[src1]);
						float s2 = u2f(m_reg[rs]);
						m_reg[rd] = f2u(s1 * s2);
						break;
					}
					case 0x10:          // SP x SP -> DP
					{
						float s1 = u2f(has_imm ? imm32 : m_reg[src1]);
						float s2 = u2f(m_reg[rs]);
						uint64_t res = d2u((double)(s1 * s2));
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x14:          // SP x DP -> DP
					{
						float s1 = u2f(has_imm ? imm32 : m_reg[src1]);
						double s2 = u2d(m_fpair[rs >> 1]);
						uint64_t res = d2u((double)s1 * s2);
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x11:          // DP x SP -> DP
					{
						double s1 = u2d(m_fpair[src1 >> 1]);
						float s2 = u2f(m_reg[rs]);
						uint64_t res = d2u(s1 * (double) s2);
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x15:          // DP x DP -> DP
					{
						double s1 = u2d(m_fpair[src1 >> 1]);
						double s2 = u2d(m_fpair[rs >> 1]);
						uint64_t res = d2u(s1 * s2);
						m_fpair[rd >> 1] = res;
						break;
					}
					case 0x2a:          // I x I -> I
					{
						m_reg[rd] = (int32_t)(m_reg[rs]) * (int32_t)(has_imm ? imm32 : m_reg[OP_SRC1()]);
						break;
					}
					case 0x3f:          // U x U -> U
					{
						m_reg[rd] = (uint32_t)(m_reg[rs]) * (uint32_t)(has_imm ? imm32 : m_reg[OP_SRC1()]);
						break;
					}
					default:
						fatalerror("fmpy: invalid precision combination %02X\n", precision);
				}
			}
			break;
		}

		case 0xe6:
		case 0xe7:          // fdiv
		{
			int rd = OP_RD();
			int p1 = m_ir & (1 << 5);
			int p2 = m_ir & (1 << 7);
			int pd = m_ir & (1 << 9);
			int rs1 = OP_SRC1();
			int rs2 = OP_RS();

			if (rd)
			{
				double src1 = has_imm ? (double)u2f(imm32) : (p1 ? u2d(m_fpair[rs1 >> 1]) : (double)u2f(m_reg[rs1]));
				double src2 = p2 ? u2d(m_fpair[rs2 >> 1]) : (double)u2f(m_reg[rs2]);

				double res;
				if (src2 != 0.0)
					res = src1 / src2;
				else
					res = 0.0f;

				if (pd)
					m_fpair[rd >> 1] = d2u(res);
				else
					m_reg[rd] = f2u((float)res);
			}
			break;
		}

		case 0xe8:
		case 0xe9:          // frnd
		{
			//int mode = (m_ir >> 7) & 3;
			int p1 = (m_ir >> 5) & 3;
			int pd = (m_ir >> 9) & 3;
			int src1 = OP_SRC1();
			int rd = OP_RD();

			double s = 0.0;

			switch (p1)
			{
				case 0:
					s = has_imm ? (double)(u2f(imm32)) : (double)u2f(m_reg[src1]);
					break;
				case 1:
					s = u2d(m_fpair[src1 >> 1]);
					break;
				case 2:
					s = has_imm ? (double)((int32_t)(imm32)) : (double)(int32_t)(m_reg[src1]);
					break;
				case 3:
					s = has_imm ? (double)((uint32_t)(imm32)) : (double)(uint32_t)(m_reg[src1]);
					break;
			}

			// TODO: round

			if (rd)
			{
				switch (pd)
				{
					case 0:
						m_reg[rd] = f2u((float)(s));
						break;
					case 1:
						m_fpair[rd >> 1] = d2u(s);
						break;
					case 2:
						m_reg[rd] = (int32_t)(s);
						break;
					case 3:
						m_reg[rd] = (uint32_t)(s);
						break;
				}
			}
			break;
		}

		case 0xea:
		case 0xeb:          // fcmp
		{
			int rd = OP_RD();
			int p1 = m_ir & (1 << 5);
			int p2 = m_ir & (1 << 7);
			int rs1 = OP_SRC1();
			int rs2 = OP_RS();

			double src1 = has_imm ? (double)(u2f(imm32)) : (p1 ? u2d(m_fpair[rs1 >> 1]) : (double)u2f(m_reg[rs1]));
			double src2 = p2 ? u2d(m_fpair[rs2 >> 1]) : (double)u2f(m_reg[rs2]);

			if (rd)
			{
				uint32_t flags = 0;
				flags |= (src1 == src2) ? (1 << 20) : 0;
				flags |= (src1 != src2) ? (1 << 21) : 0;
				flags |= (src1 >  src2) ? (1 << 22) : 0;
				flags |= (src1 <= src2) ? (1 << 23) : 0;
				flags |= (src1 <  src2) ? (1 << 24) : 0;
				flags |= (src1 >= src2) ? (1 << 25) : 0;
				flags |= (src1 < 0 || src1 > src2) ? (1 << 26) : 0;
				flags |= (src1 > 0 && src1 < src2) ? (1 << 27) : 0;
				flags |= (src1 >= 0 && src1 <= src2) ? (1 << 28) : 0;
				flags |= (src1 <= 0 || src1 >= src2) ? (1 << 29) : 0;
				// TODO: src1 or src2 unordered
				// TODO: src1 and src2 ordered

				m_reg[rd] = flags;
			}
			break;
		}

		case 0xee:
		case 0xef:          // fsqrt
		{
			int rd = OP_RD();
			int src1 = OP_SRC1();
			int p1 = m_ir & (1 << 5);
			int pd = m_ir & (1 << 9);
			double source = has_imm ? (double)u2f(imm32) : (p1 ? u2d(m_fpair[src1 >> 1]) : (double)u2f(m_reg[src1]));

			if (rd)
			{
				double res;
				if (source >= 0.0f)
					res = sqrt(source);
				else
					res = 0.0;

				if (pd)
					m_fpair[rd >> 1] = d2u(res);
				else
					m_reg[rd] = f2u((float)res);
			}
			break;
		}

		case 0xf2:          // rmo
		{
			uint32_t source = m_reg[OP_RS()];
			int rd = OP_RD();

			int bit = 32;

			for (int i=0; i < 32; i++)
			{
				if (source & (1 << (31-i)))
				{
					bit = i;
					break;
				}
			}

			if (rd)
				m_reg[rd] = bit;
			break;
		}

		default:
			fatalerror("execute_reg_long_imm(): %08X: opcode %08X (%02X)", m_pc, m_ir, (m_ir >> 12) & 0xff);
	}
}


void tms32082_mp_device::execute()
{
	switch ((m_ir >> 20) & 3)
	{
		case 0:
		case 1:
		case 2:
			execute_short_imm();
			break;

		case 3:
			execute_reg_long_imm();
			break;
	}
}
