// license:BSD-3-Clause
// copyright-holders:Ville Linde

/******************************************************************************

    SHARC UML recompiler core

******************************************************************************/

#include "emu.h"
#include "debugger.h"
#include "sharc.h"
#include "sharcfe.h"
#include "cpu/drcfe.h"
#include "cpu/drcuml.h"
#include "cpu/drcumlsh.h"

using namespace uml;

#define USE_SWAPDQ  0


// map variables
#define MAPVAR_PC                       M0
#define MAPVAR_CYCLES                   M1

// exit codes
#define EXECUTE_OUT_OF_CYCLES           0
#define EXECUTE_MISSING_CODE            1
#define EXECUTE_UNMAPPED_CODE           2
#define EXECUTE_RESET_CACHE             3


#define REG(reg)                        m_regmap[reg]
#define DM_I(reg)                       mem(&m_core->dag1.i[reg])
#define DM_M(reg)                       mem(&m_core->dag1.m[reg])
#define DM_L(reg)                       mem(&m_core->dag1.l[reg])
#define DM_B(reg)                       mem(&m_core->dag1.b[reg])
#define PM_I(reg)                       mem(&m_core->dag2.i[reg])
#define PM_M(reg)                       mem(&m_core->dag2.m[reg])
#define PM_L(reg)                       mem(&m_core->dag2.l[reg])
#define PM_B(reg)                       mem(&m_core->dag2.b[reg])
#define ASTAT_AZ                        mem(&m_core->astat_drc.az)
#define ASTAT_AV                        mem(&m_core->astat_drc.av)
#define ASTAT_AN                        mem(&m_core->astat_drc.an)
#define ASTAT_AC                        mem(&m_core->astat_drc.ac)
#define ASTAT_AS                        mem(&m_core->astat_drc.as)
#define ASTAT_AI                        mem(&m_core->astat_drc.ai)
#define ASTAT_AF                        mem(&m_core->astat_drc.af)
#define ASTAT_MN                        mem(&m_core->astat_drc.mn)
#define ASTAT_MV                        mem(&m_core->astat_drc.mv)
#define ASTAT_MU                        mem(&m_core->astat_drc.mu)
#define ASTAT_MI                        mem(&m_core->astat_drc.mi)
#define ASTAT_SV                        mem(&m_core->astat_drc.sv)
#define ASTAT_SZ                        mem(&m_core->astat_drc.sz)
#define ASTAT_SS                        mem(&m_core->astat_drc.ss)
#define ASTAT_BTF                       mem(&m_core->astat_drc.btf)
#define FLAG0                           mem(&m_core->flag[0])
#define FLAG1                           mem(&m_core->flag[1])
#define FLAG2                           mem(&m_core->flag[2])
#define FLAG3                           mem(&m_core->flag[3])
#define CURLCNTR                        mem(&m_core->curlcntr)
#define LCNTR                           mem(&m_core->lcntr)
#define PCSTK                           mem(&m_core->pcstk)
#define PCSTKP                          mem(&m_core->pcstkp)
#define STKY                            mem(&m_core->stky)
#define LSTKP                           mem(&m_core->lstkp)
#define USTAT1                          mem(&m_core->ustat1)
#define USTAT2                          mem(&m_core->ustat2)
#define IRPTL                           mem(&m_core->irptl)
#define MODE1                           mem(&m_core->mode1)
#define MODE2                           mem(&m_core->mode2)
#define IMASK                           mem(&m_core->imask)
#define IMASKP                          mem(&m_core->imaskp)
#define MRF                             mem(&m_core->mrf)
#define MRB                             mem(&m_core->mrb)

#define AZ_CALC_REQUIRED                ((desc->regreq[0] & 0x00010000) || desc->flags & OPFLAG_IN_DELAY_SLOT)
#define AV_CALC_REQUIRED                ((desc->regreq[0] & 0x00020000) || desc->flags & OPFLAG_IN_DELAY_SLOT)
#define AN_CALC_REQUIRED                ((desc->regreq[0] & 0x00040000) || desc->flags & OPFLAG_IN_DELAY_SLOT)
#define AC_CALC_REQUIRED                ((desc->regreq[0] & 0x00080000) || desc->flags & OPFLAG_IN_DELAY_SLOT)
#define AS_CALC_REQUIRED                ((desc->regreq[0] & 0x00100000) || desc->flags & OPFLAG_IN_DELAY_SLOT)
#define AI_CALC_REQUIRED                ((desc->regreq[0] & 0x00200000) || desc->flags & OPFLAG_IN_DELAY_SLOT)
#define MN_CALC_REQUIRED                ((desc->regreq[0] & 0x00400000) || desc->flags & OPFLAG_IN_DELAY_SLOT)
#define MV_CALC_REQUIRED                ((desc->regreq[0] & 0x00800000) || desc->flags & OPFLAG_IN_DELAY_SLOT)
#define MU_CALC_REQUIRED                ((desc->regreq[0] & 0x01000000) || desc->flags & OPFLAG_IN_DELAY_SLOT)
#define MI_CALC_REQUIRED                ((desc->regreq[0] & 0x02000000) || desc->flags & OPFLAG_IN_DELAY_SLOT)
#define SV_CALC_REQUIRED                ((desc->regreq[0] & 0x04000000) || desc->flags & OPFLAG_IN_DELAY_SLOT)
#define SZ_CALC_REQUIRED                ((desc->regreq[0] & 0x08000000) || desc->flags & OPFLAG_IN_DELAY_SLOT)
#define SS_CALC_REQUIRED                ((desc->regreq[0] & 0x10000000) || desc->flags & OPFLAG_IN_DELAY_SLOT)
#define BTF_CALC_REQUIRED               ((desc->regreq[0] & 0x20000000) || desc->flags & OPFLAG_IN_DELAY_SLOT)
#define AF_CALC_REQUIRED                ((desc->regreq[0] & 0x40000000) || desc->flags & OPFLAG_IN_DELAY_SLOT)


#define IRAM_BLOCK0_START               0x20000
#define IRAM_BLOCK0_END                 0x27fff
#define IRAM_BLOCK1_START               0x28000
#define IRAM_BLOCK1_END                 0x3ffff
#define IRAM_SHORT_BLOCK0_START         0x40000
#define IRAM_SHORT_BLOCK0_END           0x4ffff
#define IRAM_SHORT_BLOCK1_START         0x50000
#define IRAM_SHORT_BLOCK1_END           0x7ffff
#define IOP_REGISTER_START              0x00000
#define IOP_REGISTER_END                0x000ff
#define IRAM_END                        0x7ffff


inline void adsp21062_device::alloc_handle(drcuml_state *drcuml, code_handle **handleptr, const char *name)
{
	if (*handleptr == nullptr)
		*handleptr = drcuml->handle_alloc(name);
}




static void cfunc_unimplemented(void *param)
{
	adsp21062_device *sharc = (adsp21062_device *)param;
	sharc->sharc_cfunc_unimplemented();
}

static void cfunc_pcstack_overflow(void *param)
{
	adsp21062_device *sharc = (adsp21062_device *)param;
	sharc->sharc_cfunc_pcstack_overflow();
}

static void cfunc_pcstack_underflow(void *param)
{
	adsp21062_device *sharc = (adsp21062_device *)param;
	sharc->sharc_cfunc_pcstack_underflow();
}

static void cfunc_loopstack_overflow(void *param)
{
	adsp21062_device *sharc = (adsp21062_device *)param;
	sharc->sharc_cfunc_loopstack_overflow();
}

static void cfunc_loopstack_underflow(void *param)
{
	adsp21062_device *sharc = (adsp21062_device *)param;
	sharc->sharc_cfunc_loopstack_underflow();
}

static void cfunc_statusstack_overflow(void *param)
{
	adsp21062_device *sharc = (adsp21062_device *)param;
	sharc->sharc_cfunc_statusstack_overflow();
}

static void cfunc_statusstack_underflow(void *param)
{
	adsp21062_device *sharc = (adsp21062_device *)param;
	sharc->sharc_cfunc_statusstack_underflow();
}

static void cfunc_unimplemented_compute(void *param)
{
	adsp21062_device *sharc = (adsp21062_device *)param;
	sharc->sharc_cfunc_unimplemented_compute();
}

static void cfunc_unimplemented_shiftimm(void *param)
{
	adsp21062_device *sharc = (adsp21062_device *)param;
	sharc->sharc_cfunc_unimplemented_shiftimm();
}

void adsp21062_device::sharc_cfunc_unimplemented()
{
	uint64_t op = m_core->arg64;
	fatalerror("PC=%08X: Unimplemented op %04X%08X\n", m_core->pc, (uint32_t)(op >> 32), (uint32_t)(op));
}

void adsp21062_device::sharc_cfunc_unimplemented_compute()
{
	uint64_t op = m_core->arg64;
	fatalerror("PC=%08X: Unimplemented compute %04X%08X\n", m_core->pc, (uint32_t)(op >> 32), (uint32_t)(op));
}

void adsp21062_device::sharc_cfunc_unimplemented_shiftimm()
{
	uint64_t op = m_core->arg64;
	fatalerror("PC=%08X: Unimplemented shiftimm %04X%08X\n", m_core->pc, (uint32_t)(op >> 32), (uint32_t)(op));
}

void adsp21062_device::sharc_cfunc_pcstack_overflow()
{
	fatalerror("SHARC: PCStack overflow");
}

void adsp21062_device::sharc_cfunc_pcstack_underflow()
{
	fatalerror("SHARC: PCStack underflow");
}

void adsp21062_device::sharc_cfunc_loopstack_overflow()
{
	fatalerror("SHARC: Loop Stack overflow");
}

void adsp21062_device::sharc_cfunc_loopstack_underflow()
{
	fatalerror("SHARC: Loop Stack underflow");
}

void adsp21062_device::sharc_cfunc_statusstack_overflow()
{
	fatalerror("SHARC: Status Stack overflow");
}

void adsp21062_device::sharc_cfunc_statusstack_underflow()
{
	fatalerror("SHARC: Status Stack underflow");
}


bool adsp21062_device::if_condition_always_true(int condition)
{
	if (condition == 0x1f || condition == 0x1e)
		return true;
	else
		return false;
}

uint32_t adsp21062_device::do_condition_astat_bits(int condition)
{
	uint32_t r = 0;
	switch (condition)
	{
		case 0x00: r = AZ; break;               // EQ
		case 0x01: r = AZ | AN; break;          // LT
		case 0x02: r = AZ | AN; break;          // LE
		case 0x03: r = AC; break;               // AC
		case 0x04: r = AV; break;               // AV
		case 0x05: r = MV; break;               // MV
		case 0x06: r = MN; break;               // MS
		case 0x07: r = SV; break;               // SV
		case 0x08: r = SZ; break;               // SZ
		case 0x0d: r = BTF; break;              // TF
		case 0x10: r = AZ; break;               // NOT EQUAL
		case 0x11: r = AZ | AN; break;          // GE
		case 0x12: r = AZ | AN; break;          // GT
		case 0x13: r = AC; break;               // NOT AC
		case 0x14: r = AV; break;               // NOT AV
		case 0x15: r = MV; break;               // NOT MV
		case 0x16: r = MN; break;               // NOT MS
		case 0x17: r = SV; break;               // NOT SV
		case 0x18: r = SZ; break;               // NOT SZ
		case 0x1d: r = BTF; break;              // NOT TF
	}

	return r;
}


/*-------------------------------------------------
load_fast_iregs - load any fast integer
registers
-------------------------------------------------*/

inline void adsp21062_device::load_fast_iregs(drcuml_block *block)
{
	int regnum;

	for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++)
	{
		if (m_regmap[regnum].is_int_register())
		{
			UML_MOV(block, ireg(m_regmap[regnum].ireg() - REG_I0), mem(&m_core->r[regnum]));
		}
	}
}


/*-------------------------------------------------
save_fast_iregs - save any fast integer
registers
-------------------------------------------------*/

void adsp21062_device::save_fast_iregs(drcuml_block *block)
{
	int regnum;

	for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++)
	{
		if (m_regmap[regnum].is_int_register())
		{
			UML_MOV(block, mem(&m_core->r[regnum]), ireg(m_regmap[regnum].ireg() - REG_I0));
		}
	}
}

void adsp21062_device::static_generate_memory_accessor(MEM_ACCESSOR_TYPE type, const char *name, code_handle *&handleptr)
{
	// I0 = read/write data
	// I1 = address

	drcuml_block *block = m_drcuml->begin_block(1024);

	// add a global entry for this
	alloc_handle(m_drcuml.get(), &handleptr, name);
	UML_HANDLE(block, *handleptr);                                                          // handle  *handleptr

	switch (type)
	{
		case MEM_ACCESSOR_PM_READ48:
			UML_DREAD(block, I0, I1, SIZE_QWORD, SPACE_PROGRAM);
			break;

		case MEM_ACCESSOR_PM_WRITE48:
			UML_DWRITE(block, I1, I0, SIZE_QWORD, SPACE_PROGRAM);
			UML_MOV(block, mem(&m_core->force_recompile), 1);
			break;

		case MEM_ACCESSOR_PM_READ32:
			UML_READ(block, I0, I1, SIZE_DWORD, SPACE_PROGRAM);
			break;

		case MEM_ACCESSOR_PM_WRITE32:
			UML_WRITE(block, I1, I0, SIZE_DWORD, SPACE_PROGRAM);
			UML_MOV(block, mem(&m_core->force_recompile), 1);
			break;

		case MEM_ACCESSOR_DM_READ32:
			UML_READ(block, I0, I1, SIZE_DWORD, SPACE_DATA);
			break;

		case MEM_ACCESSOR_DM_WRITE32:
			UML_WRITE(block, I1, I0, SIZE_DWORD, SPACE_DATA);
			break;
	}

	UML_RET(block);

	block->end();
}

void adsp21062_device::static_generate_push_pc()
{
	// Push contents of I0 to PC stack
	// Trashes I1

	code_label label = 1;
	drcuml_block *block = m_drcuml->begin_block(32);

	// add a global entry for this
	alloc_handle(m_drcuml.get(), &m_push_pc, "push_pc");
	UML_HANDLE(block, *m_push_pc);                                          // handle  *m_push_pc

	UML_MOV(block, I1, PCSTKP);                                             // mov     i1,PCSTKP
	UML_ADD(block, I1, I1, 1);                                              // add     i1,i1,1
	UML_CMP(block, I1, 32);                                                 // cmp     i1,32
	UML_JMPc(block, COND_L,label);                                          // jl      label1
	UML_CALLC(block, cfunc_pcstack_overflow, this);                         // callc   cfunc_pcstack_overflow

	UML_LABEL(block, label++);                                              // label1:
	UML_CMP(block, I1, 0);                                                  // cmp     i1,0
	UML_JMPc(block, COND_E, label);                                         // je      label2
	UML_AND(block, STKY, STKY, ~0x400000);                                  // and     STKY,~0x400000
	UML_JMP(block, label + 1);                                              // jmp     label3
	UML_LABEL(block, label++);                                              // label2:
	UML_OR(block, STKY, STKY, 0x400000);                                    // or      STKY,0x400000

	UML_LABEL(block, label++);                                              // label3:
	UML_MOV(block, PCSTK, I0);                                              // mov     PCSTK,pc
	UML_STORE(block, &m_core->pcstack, I1, I0, SIZE_DWORD, SCALE_x4);       // store   [m_core->pcstack],i1,i0,dword,scale_x4
	UML_MOV(block, PCSTKP, I1);                                             // mov     PCSTKP,i1

	UML_RET(block);

	block->end();
}

void adsp21062_device::static_generate_pop_pc()
{
	// Pop PC stack into I0
	// Trashes I1

	code_label label = 1;
	drcuml_block *block = m_drcuml->begin_block(32);

	// add a global entry for this
	alloc_handle(m_drcuml.get(), &m_pop_pc, "pop_pc");
	UML_HANDLE(block, *m_pop_pc);                                           // handle  *m_pop_pc

	UML_MOV(block, I1, PCSTKP);                                             // mov     i0,PCSTKP
	UML_LOAD(block, I0, &m_core->pcstack, I1, SIZE_DWORD, SCALE_x4);        // load    i1,[m_core->pcstack],i0,dword,scale_x4
	UML_CMP(block, I1, 0);                                                  // cmp     i1,0
	UML_JMPc(block, COND_NE, label);                                        // jne     label1
	UML_CALLC(block, cfunc_pcstack_underflow, this);                        // callc   cfunc_pcstack_underflow

	UML_LABEL(block, label++);                                              // label1:
	UML_SUB(block, I1, I1, 1);                                              // sub     i1,i1,1
	UML_CMP(block, I1, 0);                                                  // cmp     i1,0
	UML_JMPc(block, COND_E, label);                                         // je      label2
	UML_AND(block, STKY, STKY, ~0x400000);                                  // and     STKY,~0x400000
	UML_JMP(block, label + 1);                                              // jmp     label3
	UML_LABEL(block, label++);                                              // label2:
	UML_OR(block, STKY, STKY, 0x400000);                                    // or      STKY,0x400000

	UML_LABEL(block, label++);                                              // label3:
	UML_MOV(block, PCSTKP, I1);                                             // mov     PCSTKP,i1
	UML_MOV(block, PCSTK, I0);                                              // mov     PCSTK,i0

	UML_RET(block);

	block->end();
}

void adsp21062_device::static_generate_push_loop()
{
	// I0 = counter
	// I1 = type/condition/addr
	// Trashes I2

	code_label label = 1;
	drcuml_block *block = m_drcuml->begin_block(32);

	// add a global entry for this
	alloc_handle(m_drcuml.get(), &m_push_loop, "push_loop");
	UML_HANDLE(block, *m_push_loop);                                        // handle  *m_push_loop

	UML_MOV(block, I2, LSTKP);                                              // mov     i2,LSTKP
	UML_ADD(block, I2, I2, 1);                                              // add     i2,1
	UML_CMP(block, I2, 6);                                                  // cmp     i2,6
	UML_JMPc(block, COND_L, label);                                         // jl      label1
	UML_CALLC(block, cfunc_loopstack_overflow, this);                       // callc   cfunc_loopstack_overflow

	UML_LABEL(block, label++);                                              // label1:
	UML_CMP(block, I2, 0);                                                  // cmp     i2,0
	UML_JMPc(block, COND_E, label);                                         // je      label2
	UML_AND(block, STKY, STKY, ~0x4000000);                                 // and     STKY,~0x4000000
	UML_JMP(block, label + 1);                                              // jmp     label3
	UML_LABEL(block, label++);                                              // label2:
	UML_OR(block, STKY, STKY, 0x4000000);                                   // or      STKY,0x4000000

	UML_LABEL(block, label++);                                              // label3:

	UML_STORE(block, m_core->lcstack, I2, I0, SIZE_DWORD, SCALE_x4);        // store   m_core->lcstack,i2,i0,dword,scale_x4
	UML_STORE(block, m_core->lastack, I2, I1, SIZE_DWORD, SCALE_x4);        // store   m_core->lastack,i2,i1,dword,scale_x4
	UML_MOV(block, CURLCNTR, I0);                                           // mov     CURLCNTR,i0
	UML_MOV(block, LSTKP, I2);                                              // mov     LSTKP,i2

	UML_RET(block);

	block->end();
}

void adsp21062_device::static_generate_pop_loop()
{
	// Trashes I0,I2

	code_label label = 1;
	drcuml_block *block = m_drcuml->begin_block(32);

	// add a global entry for this
	alloc_handle(m_drcuml.get(), &m_pop_loop, "pop_loop");
	UML_HANDLE(block, *m_pop_loop);                                         // handle  *m_pop_loop

	UML_MOV(block, I2, LSTKP);                                              // mov     i2,LSTKP
	UML_CMP(block, I2, 0);                                                  // cmp     i2,0
	UML_JMPc(block, COND_NE, label);                                        // jne     label1
	UML_CALLC(block, cfunc_loopstack_underflow, this);                      // callc   cfunc_loopstack_underflow

	UML_LABEL(block, label++);                                              // label1:
	UML_SUB(block, I2, I2, 1);                                              // sub     i2,i2,1
	UML_CMP(block, I2, 0);                                                  // cmp     i2,0
	UML_JMPc(block, COND_E, label);                                         // je      label2
	UML_AND(block, STKY, STKY, ~0x4000000);                                 // and     STKY,~0x4000000
	UML_JMP(block, label + 1);                                              // jmp     label3
	UML_LABEL(block, label++);                                              // label2:
	UML_OR(block, STKY, STKY, 0x4000000);                                   // or      STKY,0x4000000

	UML_LABEL(block, label++);                                              // label3:
	UML_LOAD(block, I0, m_core->lcstack, I2, SIZE_DWORD, SCALE_x4);         // load    i0,m_core->lcstack,i2,dword,scale_x4
	UML_MOV(block, CURLCNTR, I0);                                           // mov     CURLCNTR,i0
	UML_MOV(block, LSTKP, I2);                                              // mov     LSTKP,i2

	UML_RET(block);

	block->end();
}

void adsp21062_device::static_generate_push_status()
{
	// Trashes I2

	code_label label = 1;
	drcuml_block *block = m_drcuml->begin_block(32);

	// add a global entry for this
	alloc_handle(m_drcuml.get(), &m_push_status, "push_status");
	UML_HANDLE(block, *m_push_status);                                      // handle  *m_push_status

	UML_MOV(block, I2, mem(&m_core->status_stkp));                          // mov     i2,[status_stkp]
	UML_ADD(block, I2, I2, 1);                                              // add     i2,1
	UML_CMP(block, I2, 5);                                                  // cmp     i2,5
	UML_JMPc(block, COND_L, label);                                         // jl      label1
	UML_CALLC(block, cfunc_statusstack_overflow, this);                     // callc   cfunc_statusstack_overflow

	UML_LABEL(block, label++);                                              // label1:
	UML_CMP(block, I2, 0);                                                  // cmp     i2,0
	UML_JMPc(block, COND_E, label);                                         // je      label2
	UML_AND(block, STKY, STKY, ~0x1000000);                                 // and     STKY,~0x1000000
	UML_JMP(block, label + 1);                                              // jmp     label3
	UML_LABEL(block, label++);                                              // label2:
	UML_OR(block, STKY, STKY, 0x1000000);                                   // or      STKY,0x1000000

	UML_LABEL(block, label++);                                              // label3:
	UML_MOV(block, mem(&m_core->status_stkp), I2);                          // mov     [status_stkp],i2

	//TODO: load MODE1
	//TODO: load ASTAT

	UML_RET(block);

	block->end();
}

void adsp21062_device::static_generate_pop_status()
{
	// Trashes I2

	code_label label = 1;
	drcuml_block *block = m_drcuml->begin_block(32);

	// add a global entry for this
	alloc_handle(m_drcuml.get(), &m_pop_status, "pop_status");
	UML_HANDLE(block, *m_pop_status);                                       // handle  *m_pop_status

	//TODO: store MODE1
	//TODO: store ASTAT

	UML_MOV(block, I2, mem(&m_core->status_stkp));                          // mov     i2,[status_stkp]
	UML_CMP(block, I2, 0);                                                  // cmp     i2,0
	UML_JMPc(block, COND_NE, label);                                        // jl      label1
	UML_CALLC(block, cfunc_statusstack_underflow, this);                    // callc   cfunc_statusstack_underflow

	UML_LABEL(block, label++);                                              // label1:
	UML_SUB(block, I2, I2, 1);                                              // sub     i2,1
	UML_CMP(block, I2, 0);                                                  // cmp     i2,0
	UML_JMPc(block, COND_E, label);                                         // je      label2
	UML_AND(block, STKY, STKY, ~0x1000000);                                 // and     STKY,~0x1000000
	UML_JMP(block, label + 1);                                              // jmp     label3
	UML_LABEL(block, label++);                                              // label2:
	UML_OR(block, STKY, STKY, 0x1000000);                                   // or      STKY,0x1000000

	UML_LABEL(block, label++);                                              // label3:
	UML_MOV(block, mem(&m_core->status_stkp), I2);                          // mov     [status_stkp],i2

	UML_RET(block);

	block->end();
}


void adsp21062_device::static_generate_exception(uint8_t exception, const char *name)
{
	code_handle *&exception_handle = m_exception[exception];

	code_label label = 1;

	code_label label_nopush = label++;

	/* begin generating */
	drcuml_block *block = m_drcuml->begin_block(1024);

	/* add a global entry for this */
	alloc_handle(m_drcuml.get(), &exception_handle, name);
	UML_HANDLE(block, *exception_handle);                                   // handle  name

	UML_AND(block, I3, mem(&m_core->irq_pending), IMASK);                   // and     i3,[irq_pending],IMASK
	UML_TZCNT(block, I3, I3);                                               // tzcnt   i3,i3

	UML_MOV(block, I2, 1);                                                  // mov     i2,1
	UML_SHL(block, I2, I2, I3);                                             // shl     i2,i2,i3
	UML_OR(block, IRPTL, IRPTL, I2);                                        // or      IRPTL,i2
	UML_XOR(block, mem(&m_core->irq_pending), mem(&m_core->irq_pending), I2); // xor     [irq_pending],i2
	UML_MOV(block, mem(&m_core->active_irq_num), I3);                       // mov     [active_irq_num],i3
	UML_MOV(block, mem(&m_core->interrupt_active), 1);                      // mov     [interrupt_active],1

	UML_CALLH(block, *m_push_pc);                                           // callh   m_push_pc

	UML_CMP(block, I3, 6);                                                  // cmp     i3,6
	UML_JMPc(block, COND_L, label_nopush);                                  // jl      label_nopush
	UML_CMP(block, I3, 8);                                                  // cmp     i3,8
	UML_JMPc(block, COND_G, label_nopush);                                  // jg      label_nopush
	UML_CALLH(block, *m_push_status);                                       // callh   m_push_status

	UML_LABEL(block, label_nopush);                                         // label_nopush:
	UML_SHL(block, I0, I3, 2);                                              // shl     i0,i3,2
	UML_ADD(block, I0, I0, 0x20000);                                        // add     i0,0x20000
	UML_HASHJMP(block, 0, I0, *m_nocode);                                   // hashjmp i0,m_nocode

	block->end();
}


void adsp21062_device::static_generate_mode1_ops()
{
	drcuml_block *block;

	// TODO: these could be further optimized with 64-bit or 128-bit swaps
	// e.g SWAP128 instruction (swap 128 bits between 2 memory locations)

	block = m_drcuml->begin_block(128);
	alloc_handle(m_drcuml.get(), &m_swap_dag1_0_3, "swap_dag1_0_3");
	UML_HANDLE(block, *m_swap_dag1_0_3);                                    // handle  name
#if !USE_SWAPDQ
	for (int i = 0; i < 4; i++)
	{
		UML_MOV(block, I0, mem(&m_core->dag1.i[i]));
		UML_MOV(block, I1, mem(&m_core->dag1_alt.i[i]));
		UML_MOV(block, mem(&m_core->dag1.i[i]), I1);
		UML_MOV(block, mem(&m_core->dag1_alt.i[i]), I0);
		UML_MOV(block, I0, mem(&m_core->dag1.m[i]));
		UML_MOV(block, I1, mem(&m_core->dag1_alt.m[i]));
		UML_MOV(block, mem(&m_core->dag1.m[i]), I1);
		UML_MOV(block, mem(&m_core->dag1_alt.m[i]), I0);
		UML_MOV(block, I0, mem(&m_core->dag1.l[i]));
		UML_MOV(block, I1, mem(&m_core->dag1_alt.l[i]));
		UML_MOV(block, mem(&m_core->dag1.l[i]), I1);
		UML_MOV(block, mem(&m_core->dag1_alt.l[i]), I0);
		UML_MOV(block, I0, mem(&m_core->dag1.b[i]));
		UML_MOV(block, I1, mem(&m_core->dag1_alt.b[i]));
		UML_MOV(block, mem(&m_core->dag1.b[i]), I1);
		UML_MOV(block, mem(&m_core->dag1_alt.b[i]), I0);
	}
#else
	UML_SWAPDQ(block, mem(&m_core->dag1.i[0]), mem(&m_core->dag1_alt.i[0]));
	UML_SWAPDQ(block, mem(&m_core->dag1.m[0]), mem(&m_core->dag1_alt.m[0]));
	UML_SWAPDQ(block, mem(&m_core->dag1.l[0]), mem(&m_core->dag1_alt.l[0]));
	UML_SWAPDQ(block, mem(&m_core->dag1.b[0]), mem(&m_core->dag1_alt.b[0]));
#endif
	UML_RET(block);
	block->end();

	block = m_drcuml->begin_block(128);
	alloc_handle(m_drcuml.get(), &m_swap_dag1_4_7, "swap_dag1_4_7");
	UML_HANDLE(block, *m_swap_dag1_4_7);                                    // handle  name
#if !USE_SWAPDQ
	for (int i = 4; i < 8; i++)
	{
		UML_MOV(block, I0, mem(&m_core->dag1.i[i]));
		UML_MOV(block, I1, mem(&m_core->dag1_alt.i[i]));
		UML_MOV(block, mem(&m_core->dag1.i[i]), I1);
		UML_MOV(block, mem(&m_core->dag1_alt.i[i]), I0);
		UML_MOV(block, I0, mem(&m_core->dag1.m[i]));
		UML_MOV(block, I1, mem(&m_core->dag1_alt.m[i]));
		UML_MOV(block, mem(&m_core->dag1.m[i]), I1);
		UML_MOV(block, mem(&m_core->dag1_alt.m[i]), I0);
		UML_MOV(block, I0, mem(&m_core->dag1.l[i]));
		UML_MOV(block, I1, mem(&m_core->dag1_alt.l[i]));
		UML_MOV(block, mem(&m_core->dag1.l[i]), I1);
		UML_MOV(block, mem(&m_core->dag1_alt.l[i]), I0);
		UML_MOV(block, I0, mem(&m_core->dag1.b[i]));
		UML_MOV(block, I1, mem(&m_core->dag1_alt.b[i]));
		UML_MOV(block, mem(&m_core->dag1.b[i]), I1);
		UML_MOV(block, mem(&m_core->dag1_alt.b[i]), I0);
	}
#else
	UML_SWAPDQ(block, mem(&m_core->dag1.i[4]), mem(&m_core->dag1_alt.i[4]));
	UML_SWAPDQ(block, mem(&m_core->dag1.m[4]), mem(&m_core->dag1_alt.m[4]));
	UML_SWAPDQ(block, mem(&m_core->dag1.l[4]), mem(&m_core->dag1_alt.l[4]));
	UML_SWAPDQ(block, mem(&m_core->dag1.b[4]), mem(&m_core->dag1_alt.b[4]));
#endif
	UML_RET(block);
	block->end();

	block = m_drcuml->begin_block(128);
	alloc_handle(m_drcuml.get(), &m_swap_dag2_0_3, "swap_dag2_0_3");
	UML_HANDLE(block, *m_swap_dag2_0_3);                                    // handle  name
#if !USE_SWAPDQ
	for (int i = 0; i < 4; i++)
	{
		UML_MOV(block, I0, mem(&m_core->dag2.i[i]));
		UML_MOV(block, I1, mem(&m_core->dag2_alt.i[i]));
		UML_MOV(block, mem(&m_core->dag2.i[i]), I1);
		UML_MOV(block, mem(&m_core->dag2_alt.i[i]), I0);
		UML_MOV(block, I0, mem(&m_core->dag2.m[i]));
		UML_MOV(block, I1, mem(&m_core->dag2_alt.m[i]));
		UML_MOV(block, mem(&m_core->dag2.m[i]), I1);
		UML_MOV(block, mem(&m_core->dag2_alt.m[i]), I0);
		UML_MOV(block, I0, mem(&m_core->dag2.l[i]));
		UML_MOV(block, I1, mem(&m_core->dag2_alt.l[i]));
		UML_MOV(block, mem(&m_core->dag2.l[i]), I1);
		UML_MOV(block, mem(&m_core->dag2_alt.l[i]), I0);
		UML_MOV(block, I0, mem(&m_core->dag2.b[i]));
		UML_MOV(block, I1, mem(&m_core->dag2_alt.b[i]));
		UML_MOV(block, mem(&m_core->dag2.b[i]), I1);
		UML_MOV(block, mem(&m_core->dag2_alt.b[i]), I0);
	}
#else
	UML_SWAPDQ(block, mem(&m_core->dag2.i[0]), mem(&m_core->dag2_alt.i[0]));
	UML_SWAPDQ(block, mem(&m_core->dag2.m[0]), mem(&m_core->dag2_alt.m[0]));
	UML_SWAPDQ(block, mem(&m_core->dag2.l[0]), mem(&m_core->dag2_alt.l[0]));
	UML_SWAPDQ(block, mem(&m_core->dag2.b[0]), mem(&m_core->dag2_alt.b[0]));
#endif
	UML_RET(block);
	block->end();

	block = m_drcuml->begin_block(128);
	alloc_handle(m_drcuml.get(), &m_swap_dag2_4_7, "swap_dag2_4_7");
	UML_HANDLE(block, *m_swap_dag2_4_7);                                    // handle  name
#if !USE_SWAPDQ
	for (int i = 4; i < 8; i++)
	{
		UML_MOV(block, I0, mem(&m_core->dag2.i[i]));
		UML_MOV(block, I1, mem(&m_core->dag2_alt.i[i]));
		UML_MOV(block, mem(&m_core->dag2.i[i]), I1);
		UML_MOV(block, mem(&m_core->dag2_alt.i[i]), I0);
		UML_MOV(block, I0, mem(&m_core->dag2.m[i]));
		UML_MOV(block, I1, mem(&m_core->dag2_alt.m[i]));
		UML_MOV(block, mem(&m_core->dag2.m[i]), I1);
		UML_MOV(block, mem(&m_core->dag2_alt.m[i]), I0);
		UML_MOV(block, I0, mem(&m_core->dag2.l[i]));
		UML_MOV(block, I1, mem(&m_core->dag2_alt.l[i]));
		UML_MOV(block, mem(&m_core->dag2.l[i]), I1);
		UML_MOV(block, mem(&m_core->dag2_alt.l[i]), I0);
		UML_MOV(block, I0, mem(&m_core->dag2.b[i]));
		UML_MOV(block, I1, mem(&m_core->dag2_alt.b[i]));
		UML_MOV(block, mem(&m_core->dag2.b[i]), I1);
		UML_MOV(block, mem(&m_core->dag2_alt.b[i]), I0);
	}
#else
	UML_SWAPDQ(block, mem(&m_core->dag2.i[4]), mem(&m_core->dag2_alt.i[4]));
	UML_SWAPDQ(block, mem(&m_core->dag2.m[4]), mem(&m_core->dag2_alt.m[4]));
	UML_SWAPDQ(block, mem(&m_core->dag2.l[4]), mem(&m_core->dag2_alt.l[4]));
	UML_SWAPDQ(block, mem(&m_core->dag2.b[4]), mem(&m_core->dag2_alt.b[4]));
#endif
	UML_RET(block);
	block->end();

	block = m_drcuml->begin_block(64);
	alloc_handle(m_drcuml.get(), &m_swap_r0_7, "swap_r0_7");
	UML_HANDLE(block, *m_swap_r0_7);                                        // handle  name
#if !USE_SWAPDQ
	for (int i = 0; i < 8; i++)
	{
		UML_MOV(block, I0, mem(&m_core->r[i]));
		UML_MOV(block, I1, mem(&m_core->reg_alt[i]));
		UML_MOV(block, mem(&m_core->r[i]), I1);
		UML_MOV(block, mem(&m_core->reg_alt[i]), I0);
	}
#else
	UML_SWAPDQ(block, mem(&m_core->r[0]), mem(&m_core->reg_alt[0]));
	UML_SWAPDQ(block, mem(&m_core->r[4]), mem(&m_core->reg_alt[4]));
#endif
	UML_RET(block);
	block->end();

	block = m_drcuml->begin_block(64);
	alloc_handle(m_drcuml.get(), &m_swap_r8_15, "swap_r8_15");
	UML_HANDLE(block, *m_swap_r8_15);                                       // handle  name
#if !USE_SWAPDQ
	for (int i = 8; i < 16; i++)
	{
		UML_MOV(block, I0, mem(&m_core->r[i]));
		UML_MOV(block, I1, mem(&m_core->reg_alt[i]));
		UML_MOV(block, mem(&m_core->r[i]), I1);
		UML_MOV(block, mem(&m_core->reg_alt[i]), I0);
	}
#else
	UML_SWAPDQ(block, mem(&m_core->r[8]), mem(&m_core->reg_alt[8]));
	UML_SWAPDQ(block, mem(&m_core->r[12]), mem(&m_core->reg_alt[12]));
#endif
	UML_RET(block);
	block->end();
}




void adsp21062_device::execute_run_drc()
{
	drcuml_state *drcuml = m_drcuml.get();
	int execute_result;

//  if (m_cache_dirty)
//      printf("SHARC cache reset\n");

	/* reset the cache if dirty */
	if (m_core->cache_dirty)
		flush_cache();

	m_core->cache_dirty = 0;
	m_core->force_recompile = 0;

	/* execute */
	do
	{
		execute_result = drcuml->execute(*m_entry);

		/* if we need to recompile, do it */
		if (execute_result == EXECUTE_MISSING_CODE)
		{
			compile_block(m_core->pc);
		}
		else if (execute_result == EXECUTE_UNMAPPED_CODE)
		{
			fatalerror("Attempted to execute unmapped code at PC=%08X\n", m_core->pc);
		}
		else if (execute_result == EXECUTE_RESET_CACHE)
		{
			flush_cache();
		}
	} while (execute_result != EXECUTE_OUT_OF_CYCLES);
}


void adsp21062_device::compile_block(offs_t pc)
{
	compiler_state compiler = { 0 };

	const opcode_desc *seqhead, *seqlast;
	const opcode_desc *desclist;
	bool override = false;

	drcuml_block *block;

	desclist = m_drcfe->describe_code(pc);

	bool succeeded = false;
	while (!succeeded)
	{
		try
		{
			block = m_drcuml->begin_block(4096);

			for (seqhead = desclist; seqhead != nullptr; seqhead = seqlast->next())
			{
				const opcode_desc *curdesc;
				uint32_t nextpc;

				/* determine the last instruction in this sequence */
				for (seqlast = seqhead; seqlast != nullptr; seqlast = seqlast->next())
					if (seqlast->flags & OPFLAG_END_SEQUENCE)
						break;
				assert(seqlast != nullptr);

				/* if we don't have a hash for this mode/pc, or if we are overriding all, add one */
				if (override || m_drcuml->hash_exists(0, seqhead->pc))
					UML_HASH(block, 0, seqhead->pc);                                        // hash    mode,pc

																							/* if we already have a hash, and this is the first sequence, assume that we */
																							/* are recompiling due to being out of sync and allow future overrides */
				else if (seqhead == desclist)
				{
					override = true;
					UML_HASH(block, 0, seqhead->pc);                                        // hash    mode,pc
				}

				/* otherwise, redispatch to that fixed PC and skip the rest of the processing */
				else
				{
					UML_LABEL(block, seqhead->pc | 0x80000000);                             // label   seqhead->pc
					UML_HASHJMP(block, 0, seqhead->pc, *m_nocode);                          // hashjmp <0>,seqhead->pc,nocode
					continue;
				}

				/* label this instruction, if it may be jumped to locally */
				if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET)
					UML_LABEL(block, seqhead->pc | 0x80000000);                             // label   seqhead->pc

				/* iterate over instructions in the sequence and compile them */
				for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next())
					generate_sequence_instruction(block, &compiler, curdesc, false);

				/* if we need to return to the start, do it */
				if (seqlast->flags & OPFLAG_RETURN_TO_START)
					nextpc = pc;
				/* otherwise we just go to the next instruction */
				else
					nextpc = seqlast->pc + (seqlast->skipslots + 1);


				// force recompilation at end of block, if needed
				UML_CMP(block, mem(&m_core->force_recompile), 0);
				UML_JMPc(block, COND_Z, compiler.labelnum);
				UML_MOV(block, mem(&m_core->cache_dirty), 1);
				UML_MOV(block, mem(&m_core->icount), 0);
				UML_LABEL(block, compiler.labelnum++);


				/* count off cycles and go there */
				generate_update_cycles(block, &compiler, nextpc, true);                     // <subtract cycles>

				if (seqlast->next() == nullptr || seqlast->next()->pc != nextpc)
					UML_HASHJMP(block, 0, nextpc, *m_nocode);                               // hashjmp <mode>,nextpc,nocode
			}

			block->end();
			succeeded = true;
		}
		catch (drcuml_block::abort_compilation &)
		{
			flush_cache();
		}
	}
}


void adsp21062_device::flush_cache()
{
	/* empty the transient cache contents */
	m_drcuml->reset();

	try
	{
		// generate the entry point and out-of-cycles handlers
		static_generate_entry_point();
		static_generate_nocode_handler();
		static_generate_out_of_cycles();

		// generate utility functions
		static_generate_push_pc();
		static_generate_pop_pc();
		static_generate_push_loop();
		static_generate_pop_loop();
		static_generate_push_status();
		static_generate_pop_status();
		static_generate_mode1_ops();

		// generate exception handlers
		static_generate_exception(EXCEPTION_INTERRUPT, "exception_interrupt");

		// generate memory accessors
		static_generate_memory_accessor(MEM_ACCESSOR_PM_READ48, "pm_read48", m_pm_read48);
		static_generate_memory_accessor(MEM_ACCESSOR_PM_WRITE48, "pm_write48", m_pm_write48);
		static_generate_memory_accessor(MEM_ACCESSOR_PM_READ32, "pm_read32", m_pm_read32);
		static_generate_memory_accessor(MEM_ACCESSOR_PM_WRITE32, "pm_write32", m_pm_write32);
		static_generate_memory_accessor(MEM_ACCESSOR_DM_READ32, "dm_read32", m_dm_read32);
		static_generate_memory_accessor(MEM_ACCESSOR_DM_WRITE32, "dm_write32", m_dm_write32);
	}
	catch (drcuml_block::abort_compilation &)
	{
		fatalerror("Error generating SHARC static handlers\n");
	}
}


void adsp21062_device::static_generate_entry_point()
{
	code_label skip = 1;
	drcuml_block *block;

	/* begin generating */
	block = m_drcuml->begin_block(20);

	/* forward references */
	alloc_handle(m_drcuml.get(), &m_nocode, "nocode");
	alloc_handle(m_drcuml.get(), &m_exception[EXCEPTION_INTERRUPT], "exception_interrupt");

	alloc_handle(m_drcuml.get(), &m_entry, "entry");
	UML_HANDLE(block, *m_entry);                                                            // handle  entry

	load_fast_iregs(block);                                                                 // <load fastregs>

	/* check for interrupts */
	UML_CMP(block, mem(&m_core->irq_pending), 0);                                       // cmp     [irq_pending],0
	UML_JMPc(block, COND_E, skip);                                                      // je      skip
	UML_CMP(block, mem(&m_core->interrupt_active), 0);                                  // cmp     [interrupt_active],0
	UML_JMPc(block, COND_NE, skip);                                                     // jne     skip
	UML_TEST(block, mem(&m_core->irq_pending), IMASK);                                  // test    [irq_pending],IMASK
	UML_JMPc(block, COND_Z, skip);                                                      // jz      skip
	UML_TEST(block, mem(&m_core->mode1), MODE1_IRPTEN);                                 // test    MODE1,MODE1_IRPTEN
	UML_JMPc(block, COND_Z, skip);                                                      // jz      skip

	UML_MOV(block, I0, mem(&m_core->pc));                                               // mov     i0,nextpc
	UML_MOV(block, I1, 0);                                                              // mov     i1,0
	UML_CALLH(block, *m_exception[EXCEPTION_INTERRUPT]);                                // callh   m_exception[EXCEPTION_INTERRUPT]

	UML_LABEL(block, skip);

	/* generate a hash jump via the current mode and PC */
	UML_HASHJMP(block, 0, mem(&m_core->pc), *m_nocode);   // hashjmp <mode>,<pc>,nocode

	block->end();
}


void adsp21062_device::static_generate_nocode_handler()
{
	drcuml_block *block;

	/* begin generating */
	block = m_drcuml->begin_block(10);

	/* generate a hash jump via the current mode and PC */
	alloc_handle(m_drcuml.get(), &m_nocode, "nocode");
	UML_HANDLE(block, *m_nocode);                                                           // handle  nocode
	UML_GETEXP(block, I0);                                                                  // getexp  i0
	UML_MOV(block, mem(&m_core->pc), I0);                                                   // mov     [pc],i0
	save_fast_iregs(block);                                                                 // <save fastregs>
	UML_EXIT(block, EXECUTE_MISSING_CODE);                                                  // exit    EXECUTE_MISSING_CODE

	block->end();
}

void adsp21062_device::static_generate_out_of_cycles()
{
	drcuml_block *block;

	/* begin generating */
	block = m_drcuml->begin_block(10);

	/* generate a hash jump via the current mode and PC */
	alloc_handle(m_drcuml.get(), &m_out_of_cycles, "out_of_cycles");
	UML_HANDLE(block, *m_out_of_cycles);                                                    // handle  out_of_cycles
	UML_GETEXP(block, I0);                                                                  // getexp  i0
	UML_MOV(block, mem(&m_core->pc), I0);                                                   // mov     <pc>,i0
	save_fast_iregs(block);                                                                 // <save fastregs>
	UML_EXIT(block, EXECUTE_OUT_OF_CYCLES);                                                 // exit    EXECUTE_OUT_OF_CYCLES

	block->end();
}


void adsp21062_device::generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, bool last_delayslot)
{
	/* add an entry for the log */
//  if (m_drcuml->logging() && !(desc->flags & OPFLAG_VIRTUAL_NOOP))
//      log_add_disasm_comment(block, desc->pc, desc->opptr.l[0]);

	/* set the PC map variable */
	UML_MAPVAR(block, MAPVAR_PC, desc->pc);                                                 // mapvar  PC,desc->pc

																							/* accumulate total cycles */
	compiler->cycles += desc->cycles;

	/* update the icount map variable */
	UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles);                                     // mapvar  CYCLES,compiler->cycles

	/* if we are debugging, call the debugger */
	if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
	{
		UML_MOV(block, mem(&m_core->pc), desc->pc);                                         // mov     [pc],desc->pc
		save_fast_iregs(block);                                                             // <save fastregs>
		UML_DEBUG(block, desc->pc);                                                         // debug   desc->pc
	}

	/* if we hit an unmapped address, fatal error */
	if (desc->flags & OPFLAG_COMPILER_UNMAPPED)
	{
		UML_MOV(block, mem(&m_core->pc), desc->pc);                                         // mov     [pc],desc->pc
		save_fast_iregs(block);                                                             // <save fastregs>
		UML_EXIT(block, EXECUTE_UNMAPPED_CODE);                                             // exit    EXECUTE_UNMAPPED_CODE
	}

	// handle a special case where call is used as the last operation in a loop
	if (desc->userflags & OP_USERFLAG_CALL && desc->userflags & (OP_USERFLAG_COND_LOOP | OP_USERFLAG_COUNTER_LOOP))
	{
		if (desc->userflags & OP_USERFLAG_COUNTER_LOOP)
		{
			code_label end = compiler->labelnum++;
			UML_LOAD(block, I0, m_core->lastack, LSTKP, SIZE_DWORD, SCALE_x4);
			UML_CMP(block, I0, desc->pc);
			UML_JMPc(block, COND_NE, end);

			code_label label_expire = compiler->labelnum++;
			UML_MOV(block, I1, mem(&m_core->lstkp));                            // mov     i1,[m_core->lstkp]
			UML_LOAD(block, I0, m_core->lcstack, I1, SIZE_DWORD, SCALE_x4);     // load    i0,m_core->lcstack,i1,dword,scale_x4
			UML_SUB(block, I0, I0, 1);                                          // sub     i0,1
			UML_STORE(block, m_core->lcstack, I1, I0, SIZE_DWORD, SCALE_x4);    // store   m_core->lcstack,i1,i0,dword,scale_x4
			UML_SUB(block, CURLCNTR, CURLCNTR, 1);                              // sub     CURLCNTR,1
			UML_JMPc(block, COND_E, label_expire);                              // jne     label_expire

			UML_MOV(block, mem(&m_core->temp_return), desc->userdata0);
			UML_JMP(block, end);

			UML_LABEL(block, label_expire);                                     // label_expire:
			UML_CALLH(block, *m_pop_pc);                                        // callh   m_pop_pc
			UML_CALLH(block, *m_pop_loop);                                      // callh   m_pop_loop
			UML_MOV(block, mem(&m_core->temp_return), desc->pc + 1);

			UML_LABEL(block, end);
		}
		if (desc->userflags & OP_USERFLAG_COND_LOOP)
		{
			code_label end = compiler->labelnum++;
			UML_LOAD(block, I0, m_core->lastack, LSTKP, SIZE_DWORD, SCALE_x4);
			UML_CMP(block, I0, desc->pc);
			UML_JMPc(block, COND_NE, end);

			code_label label_expire = compiler->labelnum++;

			int condition = (desc->userflags & OP_USERFLAG_COND_FIELD) >> OP_USERFLAG_COND_FIELD_SHIFT;
			generate_do_condition(block, compiler, desc, condition, label_expire, m_core->astat_delay_copy);
			UML_MOV(block, mem(&m_core->temp_return), desc->userdata0);
			UML_JMP(block, end);

			UML_LABEL(block, label_expire);
			UML_CALLH(block, *m_pop_pc);
			UML_CALLH(block, *m_pop_loop);
			UML_MOV(block, mem(&m_core->temp_return), desc->pc + 1);

			UML_LABEL(block, end);
		}
	}

	/* if this is an invalid opcode, generate the exception now */
//  if (desc->flags & OPFLAG_INVALID_OPCODE)
//      UML_EXH(block, *m_exception[EXCEPTION_PROGRAM], 0x80000);                           // exh    exception_program,0x80000

	/* unless this is a virtual no-op, it's a regular instruction */
	if (!(desc->flags & OPFLAG_VIRTUAL_NOOP))
	{
		/* compile the instruction */
		if (!generate_opcode(block, compiler, desc))
		{
			UML_MOV(block, mem(&m_core->pc), desc->pc);                                     // mov     [pc],desc->pc
			UML_DMOV(block, mem(&m_core->arg64), desc->opptr.q[0]);                         // dmov    [arg64],*desc->opptr.q
			UML_CALLC(block, cfunc_unimplemented, this);                                    // callc   cfunc_unimplemented,ppc
		}
	}


	// insert delayed MODE1 operation if needed
	if (compiler->mode1_delay.counter > 0)
	{
		compiler->mode1_delay.counter--;

		// delayed operation in the last delay slot needs to be done before the branch is taken
		if (last_delayslot)
			compiler->mode1_delay.counter = 0;

		if (compiler->mode1_delay.counter <= 0)
		{
			switch (compiler->mode1_delay.mode)
			{
			case MODE1_WRITE_IMM:
				generate_write_mode1_imm(block, compiler, desc, compiler->mode1_delay.data);
				break;
			case MODE1_WRITE_REG:
				fatalerror("MODE1 delay REG");
				break;
			case MODE1_SET:
				generate_set_mode1_imm(block, compiler, desc, compiler->mode1_delay.data);
				break;
			case MODE1_CLEAR:
				generate_clear_mode1_imm(block, compiler, desc, compiler->mode1_delay.data);
				break;
			case MODE1_TOGGLE:
				fatalerror("MODE1 delay TOGGLE");
				break;
			}
		}
	}


	// insert loop check at this instruction if needed
	if (desc->userflags & OP_USERFLAG_COUNTER_LOOP)
	{
		code_label label_skip_loop = compiler->labelnum++;
		UML_LOAD(block, I0, m_core->lastack, LSTKP, SIZE_DWORD, SCALE_x4);
		UML_CMP(block, I0, desc->pc);
		UML_JMPc(block, COND_NE, label_skip_loop);

		code_label label_expire = compiler->labelnum++;
		UML_MOV(block, I1, mem(&m_core->lstkp));                            // mov     i1,[m_core->lstkp]
		UML_LOAD(block, I0, m_core->lcstack, I1, SIZE_DWORD, SCALE_x4);     // load    i0,m_core->lcstack,i1,dword,scale_x4
		UML_SUB(block, I0, I0, 1);                                          // sub     i0,1
		UML_STORE(block, m_core->lcstack, I1, I0, SIZE_DWORD, SCALE_x4);    // store   m_core->lcstack,i1,i0,dword,scale_x4
		UML_SUB(block, CURLCNTR, CURLCNTR, 1);                              // sub     CURLCNTR,1
		UML_JMPc(block, COND_E, label_expire);                              // jne     label_expire

		generate_loop_jump(block, compiler, desc);

		UML_LABEL(block, label_expire);                                     // label_expire:
		UML_CALLH(block, *m_pop_pc);                                        // callh   m_pop_pc
		UML_CALLH(block, *m_pop_loop);                                      // callh   m_pop_loop

		UML_LABEL(block, label_skip_loop);
	}
	if (desc->userflags & OP_USERFLAG_COND_LOOP)
	{
		code_label label_skip_loop = compiler->labelnum++;
		UML_LOAD(block, I0, m_core->lastack, LSTKP, SIZE_DWORD, SCALE_x4);
		UML_CMP(block, I0, desc->pc);
		UML_JMPc(block, COND_NE, label_skip_loop);

		code_label label_expire = compiler->labelnum++;

		int condition = (desc->userflags & OP_USERFLAG_COND_FIELD) >> OP_USERFLAG_COND_FIELD_SHIFT;
		generate_do_condition(block, compiler, desc, condition, label_expire, m_core->astat_delay_copy);

		generate_loop_jump(block, compiler, desc);

		UML_LABEL(block, label_expire);
		UML_CALLH(block, *m_pop_pc);
		UML_CALLH(block, *m_pop_loop);

		UML_LABEL(block, label_skip_loop);
	}

	// copy ASTAT bits over for conditional loop
	if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY)
	{
		if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY_AZ)
			UML_MOV(block, mem(&m_core->astat_delay_copy.az), mem(&m_core->astat_drc.az));
		if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY_AN)
			UML_MOV(block, mem(&m_core->astat_delay_copy.an), mem(&m_core->astat_drc.an));
		if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY_AV)
			UML_MOV(block, mem(&m_core->astat_delay_copy.av), mem(&m_core->astat_drc.av));
		if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY_AC)
			UML_MOV(block, mem(&m_core->astat_delay_copy.ac), mem(&m_core->astat_drc.ac));
		if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY_MN)
			UML_MOV(block, mem(&m_core->astat_delay_copy.mn), mem(&m_core->astat_drc.mn));
		if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY_MV)
			UML_MOV(block, mem(&m_core->astat_delay_copy.mv), mem(&m_core->astat_drc.mv));
		if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY_SV)
			UML_MOV(block, mem(&m_core->astat_delay_copy.sv), mem(&m_core->astat_drc.sv));
		if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY_SZ)
			UML_MOV(block, mem(&m_core->astat_delay_copy.sz), mem(&m_core->astat_drc.sz));
		if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY_BTF)
			UML_MOV(block, mem(&m_core->astat_delay_copy.btf), mem(&m_core->astat_drc.btf));
	}
}

void adsp21062_device::generate_update_cycles(drcuml_block *block, compiler_state *compiler, uml::parameter param, bool allow_exception)
{
	/* check full interrupts if pending */
	if (compiler->checkints)
	{
		code_label skip = compiler->labelnum++;
		compiler->checkints = false;

		UML_CMP(block, mem(&m_core->irq_pending), 0);                                       // cmp     [irq_pending],0
		UML_JMPc(block, COND_E, skip);                                                      // je      skip
		UML_CMP(block, mem(&m_core->interrupt_active), 0);                                  // cmp     [interrupt_active],0
		UML_JMPc(block, COND_NE, skip);                                                     // jne     skip
		UML_TEST(block, mem(&m_core->irq_pending), IMASK);                                  // test    [irq_pending],IMASK
		UML_JMPc(block, COND_Z, skip);                                                      // jz      skip
		UML_TEST(block, mem(&m_core->mode1), MODE1_IRPTEN);                                 // test    MODE1,MODE1_IRPTEN
		UML_JMPc(block, COND_Z, skip);                                                      // jz      skip

		UML_MOV(block, I0, param);                                                          // mov     i0,nextpc
		UML_MOV(block, I1, compiler->cycles);                                               // mov     i1,cycles
		UML_CALLH(block, *m_exception[EXCEPTION_INTERRUPT]);                                // callh   m_exception[EXCEPTION_INTERRUPT]

		UML_LABEL(block, skip);
	}

	/* account for cycles */
	if (compiler->cycles > 0)
	{
		UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), MAPVAR_CYCLES);          // sub     icount,icount,cycles
		UML_MAPVAR(block, MAPVAR_CYCLES, 0);                                                // mapvar  cycles,0
		if (allow_exception)
			UML_EXHc(block, COND_S, *m_out_of_cycles, param);                               // exh     out_of_cycles,nextpc
	}
	compiler->cycles = 0;
}

void adsp21062_device::generate_write_mode1_imm(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint32_t data)
{
	code_label skip;

	// TODO: swap effects
	if (data & 0x1)
		fatalerror("generate_write_mode1_imm: tried to enable I8 bit reversing");
	if (data & 0x2)
		fatalerror("generate_write_mode1_imm: tried to enable I0 bit reversing");
	if (data & 0x4)
		fatalerror("generate_write_mode1_imm: tried to enable MR alternate");

	// DAG1 regs 4-7
	skip = compiler->labelnum++;
	UML_TEST(block, MODE1, 0x8);
	UML_JMPc(block, (data & 0x8) ? COND_NZ : COND_Z, skip);         // don't swap if the bits are same
	UML_CALLH(block, *m_swap_dag1_4_7);
	UML_LABEL(block, skip);

	// DAG1 regs 0-3
	skip = compiler->labelnum++;
	UML_TEST(block, MODE1, 0x10);
	UML_JMPc(block, (data & 0x10) ? COND_NZ : COND_Z, skip);        // don't swap if the bits are same
	UML_CALLH(block, *m_swap_dag1_0_3);
	UML_LABEL(block, skip);

	// DAG2 regs 4-7
	skip = compiler->labelnum++;
	UML_TEST(block, MODE1, 0x20);
	UML_JMPc(block, (data & 0x20) ? COND_NZ : COND_Z, skip);        // don't swap if the bits are same
	UML_CALLH(block, *m_swap_dag2_4_7);
	UML_LABEL(block, skip);

	// DAG2 regs 0-3
	skip = compiler->labelnum++;
	UML_TEST(block, MODE1, 0x40);
	UML_JMPc(block, (data & 0x40) ? COND_NZ : COND_Z, skip);        // don't swap if the bits are same
	UML_CALLH(block, *m_swap_dag2_0_3);
	UML_LABEL(block, skip);

	// REG 8-15
	skip = compiler->labelnum++;
	UML_TEST(block, MODE1, 0x80);
	UML_JMPc(block, (data & 0x80) ? COND_NZ : COND_Z, skip);        // don't swap if the bits are same
	UML_CALLH(block, *m_swap_r8_15);
	UML_LABEL(block, skip);

	// REG 0-7
	skip = compiler->labelnum++;
	UML_TEST(block, MODE1, 0x400);
	UML_JMPc(block, (data & 0x400) ? COND_NZ : COND_Z, skip);       // don't swap if the bits are same
	UML_CALLH(block, *m_swap_r0_7);
	UML_LABEL(block, skip);

	UML_MOV(block, MODE1, data);
}

void adsp21062_device::generate_set_mode1_imm(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint32_t data)
{
	if (data & 0x1)
		fatalerror("generate_set_mode1_imm: tried to enable I8 bit reversing");
	if (data & 0x2)
		fatalerror("generate_set_mode1_imm: tried to enable I0 bit reversing");
	if (data & 0x4)
		fatalerror("generate_set_mode1_imm: tried to enable MR alternate");
	if (data & 0x8)     // DAG1 regs 4-7
	{
		code_label skip = compiler->labelnum++;
		UML_TEST(block, MODE1, 0x8);
		UML_JMPc(block, COND_NZ, skip);     // don't swap if the bit is already 1
		UML_CALLH(block, *m_swap_dag1_4_7);
		UML_LABEL(block, skip);
	}
	if (data & 0x10)    // DAG1 regs 0-3
	{
		code_label skip = compiler->labelnum++;
		UML_TEST(block, MODE1, 0x10);
		UML_JMPc(block, COND_NZ, skip);     // don't swap if the bit is already 1
		UML_CALLH(block, *m_swap_dag1_0_3);
		UML_LABEL(block, skip);
	}
	if (data & 0x20)    // DAG2 regs 4-7
	{
		code_label skip = compiler->labelnum++;
		UML_TEST(block, MODE1, 0x20);
		UML_JMPc(block, COND_NZ, skip);     // don't swap if the bit is already 1
		UML_CALLH(block, *m_swap_dag2_4_7);
		UML_LABEL(block, skip);
	}
	if (data & 0x40)    // DAG1 regs 0-3
	{
		code_label skip = compiler->labelnum++;
		UML_TEST(block, MODE1, 0x40);
		UML_JMPc(block, COND_NZ, skip);     // don't swap if the bit is already 1
		UML_CALLH(block, *m_swap_dag2_0_3);
		UML_LABEL(block, skip);
	}
	if (data & 0x80)    // REG 8-15
	{
		code_label skip = compiler->labelnum++;
		UML_TEST(block, MODE1, 0x80);
		UML_JMPc(block, COND_NZ, skip);     // don't swap if the bit is already 1
		UML_CALLH(block, *m_swap_r8_15);
		UML_LABEL(block, skip);
	}
	if (data & 0x400)   // REG 0-7
	{
		code_label skip = compiler->labelnum++;
		UML_TEST(block, MODE1, 0x400);
		UML_JMPc(block, COND_NZ, skip);     // don't swap if the bit is already 1
		UML_CALLH(block, *m_swap_r0_7);
		UML_LABEL(block, skip);
	}

	UML_OR(block, MODE1, MODE1, data);
}

void adsp21062_device::generate_clear_mode1_imm(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint32_t data)
{
	if (data & 0x1)
		fatalerror("generate_clear_mode1_imm: tried to disable I8 bit reversing");
	if (data & 0x2)
		fatalerror("generate_clear_mode1_imm: tried to disable I0 bit reversing");
	if (data & 0x4)
		fatalerror("generate_clear_mode1_imm: tried to disable MR alternate");
	if (data & 0x8)     // DAG1 regs 4-7
	{
		code_label skip = compiler->labelnum++;
		UML_TEST(block, MODE1, 0x8);
		UML_JMPc(block, COND_Z, skip);      // don't swap if the bit is already 0
		UML_CALLH(block, *m_swap_dag1_4_7);
		UML_LABEL(block, skip);
	}
	if (data & 0x10)    // DAG1 regs 0-3
	{
		code_label skip = compiler->labelnum++;
		UML_TEST(block, MODE1, 0x10);
		UML_JMPc(block, COND_Z, skip);      // don't swap if the bit is already 0
		UML_CALLH(block, *m_swap_dag1_0_3);
		UML_LABEL(block, skip);
	}
	if (data & 0x20)    // DAG2 regs 4-7
	{
		code_label skip = compiler->labelnum++;
		UML_TEST(block, MODE1, 0x20);
		UML_JMPc(block, COND_Z, skip);      // don't swap if the bit is already 0
		UML_CALLH(block, *m_swap_dag2_4_7);
		UML_LABEL(block, skip);
	}
	if (data & 0x40)    // DAG1 regs 0-3
	{
		code_label skip = compiler->labelnum++;
		UML_TEST(block, MODE1, 0x40);
		UML_JMPc(block, COND_Z, skip);      // don't swap if the bit is already 0
		UML_CALLH(block, *m_swap_dag2_0_3);
		UML_LABEL(block, skip);
	}
	if (data & 0x80)    // REG 8-15
	{
		code_label skip = compiler->labelnum++;
		UML_TEST(block, MODE1, 0x80);
		UML_JMPc(block, COND_Z, skip);      // don't swap if the bit is already 0
		UML_CALLH(block, *m_swap_r8_15);
		UML_LABEL(block, skip);
	}
	if (data & 0x400)   // REG 0-7
	{
		code_label skip = compiler->labelnum++;
		UML_TEST(block, MODE1, 0x400);
		UML_JMPc(block, COND_Z, skip);      // don't swap if the bit is already 0
		UML_CALLH(block, *m_swap_r0_7);
		UML_LABEL(block, skip);
	}

	UML_AND(block, MODE1, MODE1, ~data);
}



void adsp21062_device::generate_update_circular_buffer(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int g, int i)
{
	if (g)
	{
		// PM
		code_label end = compiler->labelnum++;
		code_label label2 = compiler->labelnum++;
		UML_CMP(block, PM_L(i), 0);
		UML_JMPc(block, COND_E, end);

		UML_ADD(block, I0, PM_B(i), PM_L(i));
		UML_CMP(block, PM_I(i), I0);
		UML_JMPc(block, COND_LE, label2);
		UML_SUB(block, PM_I(i), PM_I(i), PM_L(i));
		UML_JMP(block, end);

		UML_LABEL(block, label2);
		UML_CMP(block, PM_I(i), PM_B(i));
		UML_JMPc(block, COND_G, end);
		UML_ADD(block, PM_I(i), PM_I(i), PM_L(i));

		UML_LABEL(block, end);
	}
	else
	{
		// DM
		code_label end = compiler->labelnum++;
		code_label label2 = compiler->labelnum++;
		UML_CMP(block, DM_L(i), 0);
		UML_JMPc(block, COND_E, end);

		UML_ADD(block, I0, DM_B(i), DM_L(i));
		UML_CMP(block, DM_I(i), I0);
		UML_JMPc(block, COND_LE, label2);
		UML_SUB(block, DM_I(i), DM_I(i), DM_L(i));
		UML_JMP(block, end);

		UML_LABEL(block, label2);
		UML_CMP(block, DM_I(i), DM_B(i));
		UML_JMPc(block, COND_G, end);
		UML_ADD(block, DM_I(i), DM_I(i), DM_L(i));

		UML_LABEL(block, end);
	}
}

void adsp21062_device::generate_astat_copy(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc)
{
	UML_MOV(block, mem(&m_core->astat_drc_copy.az), ASTAT_AZ);
	UML_MOV(block, mem(&m_core->astat_drc_copy.av), ASTAT_AV);
	UML_MOV(block, mem(&m_core->astat_drc_copy.an), ASTAT_AN);
	UML_MOV(block, mem(&m_core->astat_drc_copy.av), ASTAT_AV);
	UML_MOV(block, mem(&m_core->astat_drc_copy.as), ASTAT_AS);
	UML_MOV(block, mem(&m_core->astat_drc_copy.ai), ASTAT_AI);
	UML_MOV(block, mem(&m_core->astat_drc_copy.af), ASTAT_AF);
	UML_MOV(block, mem(&m_core->astat_drc_copy.mn), ASTAT_MN);
	UML_MOV(block, mem(&m_core->astat_drc_copy.mv), ASTAT_MV);
	UML_MOV(block, mem(&m_core->astat_drc_copy.mu), ASTAT_MU);
	UML_MOV(block, mem(&m_core->astat_drc_copy.mi), ASTAT_MI);
	UML_MOV(block, mem(&m_core->astat_drc_copy.sv), ASTAT_SV);
	UML_MOV(block, mem(&m_core->astat_drc_copy.sz), ASTAT_SZ);
	UML_MOV(block, mem(&m_core->astat_drc_copy.ss), ASTAT_SS);
	UML_MOV(block, mem(&m_core->astat_drc_copy.btf), ASTAT_BTF);
	UML_MOV(block, mem(&m_core->astat_drc_copy.cacc), mem(&m_core->astat_drc.cacc));
}



void adsp21062_device::generate_call(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, bool delayslot)
{
	// I0 = target pc for dynamic branches

	compiler_state compiler_temp = *compiler;

	// save branch target
	if (desc->targetpc == BRANCH_TARGET_DYNAMIC)
	{
		UML_MOV(block, mem(&m_core->jmpdest), I0);                                     // mov     [jmpdest],i0
	}

	// compile delay slots if needed
	if (delayslot)
	{
		generate_sequence_instruction(block, &compiler_temp, desc->delay.first(), false);
		generate_sequence_instruction(block, &compiler_temp, desc->delay.last(), true);
	}

	// if this is the last instruction of a loop, we need to use the return PC from the resolved loop
	if (desc->userflags & OP_USERFLAG_CALL && desc->userflags & (OP_USERFLAG_COND_LOOP | OP_USERFLAG_COUNTER_LOOP))
	{
		UML_MOV(block, I0, mem(&m_core->temp_return));
	}
	else
	{
		if (delayslot)
			UML_MOV(block, I0, desc->pc + 3);
		else
			UML_MOV(block, I0, desc->pc + 1);
	}
	UML_CALLH(block, *m_push_pc);

	// update cycles and hash jump
	if (desc->targetpc != BRANCH_TARGET_DYNAMIC)
	{
		generate_update_cycles(block, &compiler_temp, desc->targetpc, true);
		if (desc->flags & OPFLAG_INTRABLOCK_BRANCH)
			UML_JMP(block, desc->targetpc | 0x80000000);                                // jmp      targetpc | 0x80000000
		else
			UML_HASHJMP(block, 0, desc->targetpc, *m_nocode);                           // hashjmp  0,targetpc,nocode
	}
	else
	{
		generate_update_cycles(block, &compiler_temp, mem(&m_core->jmpdest), true);
		UML_HASHJMP(block, 0, mem(&m_core->jmpdest), *m_nocode);                        // hashjmp  0,jmpdest,nocode
	}

	// update compiler label
	compiler->labelnum = compiler_temp.labelnum;

	/* reset the mapvar to the current cycles and account for skipped slots */
	compiler->cycles += desc->skipslots;
	UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles);                                 // mapvar  CYCLES,compiler->cycles
}

void adsp21062_device::generate_jump(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, bool delayslot, bool loopabort, bool clearint)
{
	// I0 = target pc for dynamic branches

	compiler_state compiler_temp = *compiler;

	// save branch target
	if (desc->targetpc == BRANCH_TARGET_DYNAMIC)
	{
		UML_MOV(block, mem(&m_core->jmpdest), I0);                                     // mov     [jmpdest],i0
	}

	// compile delay slots if needed
	if (delayslot)
	{
		generate_sequence_instruction(block, &compiler_temp, desc->delay.first(), false);
		generate_sequence_instruction(block, &compiler_temp, desc->delay.last(), true);
	}

	// clear interrupt
	if (clearint)
	{
		code_label skip_pop = compiler_temp.labelnum++;

		UML_MOV(block, mem(&m_core->interrupt_active), 0);                      // mov     [interrupt_active],0
		UML_SHL(block, I1, 1, mem(&m_core->active_irq_num));                    // shl     i1,1,[active_irq_num]
		UML_XOR(block, IRPTL, IRPTL, I1);                                       // xor     IRPTL,i1
		UML_CMP(block, mem(&m_core->status_stkp), 0);                           // cmp     [status_stkp],0
		UML_JMPc(block, COND_Z, skip_pop);                                      // jz      skip_pop
		UML_CALLH(block, *m_pop_status);                                        // callh   m_pop_status
		UML_LABEL(block, skip_pop);                                             // skip_pop:
	}

	// loop abort
	if (loopabort)
	{
		UML_CALLH(block, *m_pop_pc);
		UML_CALLH(block, *m_pop_loop);
	}

	// update cycles and hash jump
	if (desc->targetpc != BRANCH_TARGET_DYNAMIC)
	{
		generate_update_cycles(block, &compiler_temp, desc->targetpc, true);
		if (desc->flags & OPFLAG_INTRABLOCK_BRANCH)
			UML_JMP(block, desc->targetpc | 0x80000000);                                // jmp      targetpc | 0x80000000
		else
			UML_HASHJMP(block, 0, desc->targetpc, *m_nocode);                           // hashjmp  0,targetpc,nocode
	}
	else
	{
		generate_update_cycles(block, &compiler_temp, mem(&m_core->jmpdest), true);
		UML_HASHJMP(block, 0, mem(&m_core->jmpdest), *m_nocode);                        // hashjmp  0,jmpdest,nocode
	}

	// update compiler label
	compiler->labelnum = compiler_temp.labelnum;

	/* reset the mapvar to the current cycles and account for skipped slots */
	compiler->cycles += desc->skipslots;
	UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles);                                 // mapvar  CYCLES,compiler->cycles
}

void adsp21062_device::generate_loop_jump(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc)
{
	// update cycles and hash jump
	generate_update_cycles(block, compiler, desc->userdata0, true);
	/*
	if (desc->flags & OPFLAG_INTRABLOCK_BRANCH)
	    UML_JMP(block, desc->targetpc | 0x80000000);                                // jmp      targetpc | 0x80000000
	else
	    UML_HASHJMP(block, 0, desc->targetpc, *m_nocode);                           // hashjmp  0,targetpc,nocode
	    */
	UML_HASHJMP(block, 0, desc->userdata0, *m_nocode);

	/* reset the mapvar to the current cycles and account for skipped slots */
	compiler->cycles += desc->skipslots;
	UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles);                                 // mapvar  CYCLES,compiler->cycles
}

/*-------------------------------------------------
generate_write_ureg - UREG is read into I0
-------------------------------------------------*/

void adsp21062_device::generate_read_ureg(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int ureg, bool has_compute)
{
	// UREG is read into I0

	switch (ureg)
	{
		// REG 0-15
		case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
		case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
			UML_MOV(block, I0, REG(ureg & 0xf));
			break;
		// I0-7
		case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
			UML_MOV(block, I0, mem(&m_core->dag1.i[ureg & 7]));
			break;
		// I8-15
		case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
			UML_MOV(block, I0, mem(&m_core->dag2.i[ureg & 7]));
			break;
		// M0-7
		case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
			UML_MOV(block, I0, mem(&m_core->dag1.m[ureg & 7]));
			break;
		// M8-15
		case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
			UML_MOV(block, I0, mem(&m_core->dag2.m[ureg & 7]));
			break;
		// L0-7
		case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
			UML_MOV(block, I0, mem(&m_core->dag1.l[ureg & 7]));
			break;
		// L8-15
		case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
			UML_MOV(block, I0, mem(&m_core->dag2.l[ureg & 7]));
			break;
		// B0-7
		case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
			UML_MOV(block, I0, mem(&m_core->dag1.b[ureg & 7]));
			break;
		// B8-15
		case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
			UML_MOV(block, I0, mem(&m_core->dag2.b[ureg & 7]));
			break;

		case 0x64:      // PCSTK
			UML_LOAD(block, I0, &m_core->pcstack, PCSTKP, SIZE_DWORD, SCALE_x4);
			break;
		case 0x70:      // USTAT1
			UML_MOV(block, I0, mem(&m_core->ustat1));
			break;
		case 0x71:      // USTAT2
			UML_MOV(block, I0, mem(&m_core->ustat2));
			break;
		case 0x79:      // IRPTL
			UML_MOV(block, I0, mem(&m_core->irptl));
			break;
		case 0x7a:      // MODE2
			UML_MOV(block, I0, mem(&m_core->mode2));
			break;
		case 0x7b:      // MODE1
			UML_MOV(block, I0, mem(&m_core->mode1));
			break;
		case 0x7c:      // ASTAT
			// construct from bits
			if (!has_compute)
			{
				// no compute, just read normally from ASTAT
				UML_XOR(block, I0, I0, I0);
				UML_OR(block, I0, I0, ASTAT_AZ);
				UML_SHL(block, I1, ASTAT_AV, 1);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, ASTAT_AN, 2);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, ASTAT_AC, 3);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, ASTAT_AS, 4);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, ASTAT_AI, 5);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, ASTAT_MN, 6);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, ASTAT_MV, 7);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, ASTAT_MU, 8);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, ASTAT_MI, 9);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, ASTAT_AF, 10);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, ASTAT_SV, 11);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, ASTAT_SZ, 12);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, ASTAT_SS, 13);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, ASTAT_BTF, 18);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, FLAG0, 19);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, FLAG1, 20);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, FLAG2, 21);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, FLAG3, 22);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, mem(&m_core->astat_drc.cacc), 24);
				UML_OR(block, I0, I0, I1);
			}
			else
			{
				// read from ASTAT copy if this opcode also does compute
				UML_XOR(block, I0, I0, I0);
				UML_OR(block, I0, I0, mem(&m_core->astat_drc_copy.az));
				UML_SHL(block, I1, mem(&m_core->astat_drc_copy.av), 1);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, mem(&m_core->astat_drc_copy.an), 2);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, mem(&m_core->astat_drc_copy.ac), 3);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, mem(&m_core->astat_drc_copy.as), 4);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, mem(&m_core->astat_drc_copy.ai), 5);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, mem(&m_core->astat_drc_copy.mn), 6);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, mem(&m_core->astat_drc_copy.mv), 7);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, mem(&m_core->astat_drc_copy.mu), 8);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, mem(&m_core->astat_drc_copy.mi), 9);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, mem(&m_core->astat_drc_copy.af), 10);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, mem(&m_core->astat_drc_copy.sv), 11);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, mem(&m_core->astat_drc_copy.sz), 12);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, mem(&m_core->astat_drc_copy.ss), 13);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, mem(&m_core->astat_drc_copy.btf), 18);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, FLAG0, 19);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, FLAG1, 20);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, FLAG2, 21);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, FLAG3, 22);
				UML_OR(block, I0, I0, I1);
				UML_SHL(block, I1, mem(&m_core->astat_drc_copy.cacc), 24);
				UML_OR(block, I0, I0, I1);
			}
			break;
		case 0x7d:      // IMASK
			UML_MOV(block, I0, mem(&m_core->imask));
			break;
		case 0x7e:      // STKY
			UML_MOV(block, I0, mem(&m_core->stky));
			break;
		case 0xdb:      // PX
			UML_DMOV(block, I0, mem(&m_core->px));      // NOTE: this returns 64 bits
			break;
		case 0xdc:      // PX1 (bits 0-15 of PX)
			UML_MOV(block, I0, mem(&m_core->px));
			UML_AND(block, I0, I0, 0xffff);
			break;
		case 0xdd:      // PX2 (bits 16-47 of PX)
			UML_DMOV(block, I0, mem(&m_core->px));
			UML_DSHR(block, I0, I0, 16);
			UML_DAND(block, I0, I0, 0xffffffff);
			break;

		default:
			fatalerror("generate_read_ureg %02X", ureg);
			break;
	}
}


/*-------------------------------------------------
    generate_write_ureg - contents of register I0 or 32-bit immediate data are written into UREG
-------------------------------------------------*/

void adsp21062_device::generate_write_ureg(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int ureg, bool imm, uint32_t data)
{
	switch (ureg)
	{
		// REG 0-15
		case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
		case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
			UML_MOV(block, REG(ureg & 0xf), imm ? data : I0);
			break;
		// I0-7
		case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
			UML_MOV(block, DM_I(ureg & 7), imm ? data : I0);
			break;
		// I8-15
		case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
			UML_MOV(block, PM_I(ureg & 7), imm ? data : I0);
			break;
		// M0-7
		case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
			UML_MOV(block, DM_M(ureg & 7), imm ? data : I0);
			break;
		// M8-15
		case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
			UML_MOV(block, PM_M(ureg & 7), imm ? data : I0);
			break;
		// L0-7
		case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
			UML_MOV(block, DM_L(ureg & 7), imm ? data : I0);
			break;
		// L8-15
		case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
			UML_MOV(block, PM_L(ureg & 7), imm ? data : I0);
			break;
		// B0-7
		case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
			// Note: loading B also loads the same value in I
			UML_MOV(block, DM_B(ureg & 7), imm ? data : I0);
			UML_MOV(block, DM_I(ureg & 7), imm ? data : I0);
			break;
		// B8-15
		case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
			// Note: loading B also loads the same value in I
			UML_MOV(block, PM_B(ureg & 7), imm ? data : I0);
			UML_MOV(block, PM_B(ureg & 7), imm ? data : I0);
			break;

		case 0x64:      // PCSTK
			fatalerror("generate_write_ureg: PCSTK");
			break;
		case 0x65:      // PCSTKP
			UML_MOV(block, PCSTKP, imm ? data : I0);
			break;
		case 0x67:      // CURLCNTR
			UML_MOV(block, CURLCNTR, imm ? data : I0);
			break;
		case 0x68:      // LCNTR
			UML_MOV(block, LCNTR, imm ? data : I0);
			break;
		case 0x70:      // USTAT1
			UML_MOV(block, mem(&m_core->ustat1), imm ? data : I0);
			break;
		case 0x71:      // USTAT2
			UML_MOV(block, mem(&m_core->ustat2), imm ? data : I0);
			break;
		case 0x79:      // IRPTL
			UML_MOV(block, mem(&m_core->irptl), imm ? data : I0);
			break;
		case 0x7a:      // MODE2
			UML_MOV(block, mem(&m_core->mode2), imm ? data : I0);
			break;
		case 0x7b:      // MODE1
			// MODE1 needs to be written delayed
			if (imm)
			{
				compiler->mode1_delay.counter = 2;
				compiler->mode1_delay.data = data;
				compiler->mode1_delay.mode = MODE1_WRITE_IMM;
			}
			else
			{
				compiler->mode1_delay.counter = 2;
				compiler->mode1_delay.mode = MODE1_WRITE_REG;
				UML_MOV(block, mem(&m_core->mode1_delay_data), I0);
			}
			break;
		case 0x7c:      // ASTAT
			// TODO: needs bit break up
			fatalerror("generate_write_ureg: ASTAT");
			break;
		case 0x7d:      // IMASK
			UML_MOV(block, mem(&m_core->imask), imm ? data : I0);
			break;
		case 0x7e:      // STKY
			UML_MOV(block, mem(&m_core->stky), imm ? data : I0);
			break;
		case 0xdb:      // PX
			if (imm)
			{
				fatalerror("generate_write_ureg %02X with immediate!", ureg);
			}
			else
			{
				UML_DMOV(block, mem(&m_core->px), I0);
			}
			break;
		case 0xdc:      // PX1 (bits 0-15 of PX)
			if (imm)
			{
				UML_DAND(block, mem(&m_core->px), mem(&m_core->px), ~0xffff);
				UML_DOR(block, mem(&m_core->px), mem(&m_core->px), (uint64_t)(data));
			}
			else
			{
				UML_DAND(block, mem(&m_core->px), mem(&m_core->px), ~0xffff);
				UML_DXOR(block, I1, I1, I1);
				UML_DAND(block, I1, I0, 0xffff);
				UML_DOR(block, mem(&m_core->px), mem(&m_core->px), I1);
			}
			break;
		case 0xdd:      // PX2 (bits 16-47 of PX)
			if (imm)
			{
				UML_DAND(block, mem(&m_core->px), mem(&m_core->px), 0xffff);
				UML_DOR(block, mem(&m_core->px), mem(&m_core->px), (uint64_t)(data) << 16);
			}
			else
			{
				UML_DAND(block, mem(&m_core->px), mem(&m_core->px), 0xffff);
				UML_DSHL(block, I0, I0, 16);
				UML_DOR(block, mem(&m_core->px), mem(&m_core->px), I0);
			}
			break;

		default:
			fatalerror("generate_write_ureg %02X", ureg);
			break;
	}
}

bool adsp21062_device::generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc)
{
	uint64_t opcode = desc->opptr.q[0];

	switch ((opcode >> 45) & 7)
	{
		case 0:             // subops
		{
			uint32_t subop = (opcode >> 40) & 0x1f;
			switch (subop)
			{
				case 0x00:          // NOP / idle                       |000|00000|
					if (opcode & 0x008000000000U)
					{
						// IDLE
						UML_MOV(block, mem(&m_core->idle), 1);
						UML_MOV(block, mem(&m_core->icount), 0);
						return true;
					}
					else
					{
						// NOP
						return true;
					}
					break;

				case 0x01:          // compute                              |000|00001|
				{
					int cond = (opcode >> 33) & 0x1f;

					bool has_condition = !if_condition_always_true(cond);
					int skip_label = 0;

					if (has_condition)
					{
						skip_label = compiler->labelnum++;
						generate_if_condition(block, compiler, desc, cond, skip_label);
					}

					generate_compute(block, compiler, desc);

					if (has_condition)
						UML_LABEL(block, skip_label);
					return true;
				}

				case 0x02:          // immediate shift                      |000|00010|
				{
					int shiftop = (opcode >> 16) & 0x3f;
					int rn = (opcode >> 4) & 0xf;
					int rx = (opcode & 0xf);
					int cond = (opcode >> 33) & 0x1f;
					int data = ((opcode >> 8) & 0xff) | ((opcode >> 19) & 0xf00);

					bool has_condition = !if_condition_always_true(cond);
					int skip_label = 0;

					if (has_condition)
					{
						skip_label = compiler->labelnum++;
						generate_if_condition(block, compiler, desc, cond, skip_label);
					}

					generate_shift_imm(block, compiler, desc, data, shiftop, rn, rx);

					if (has_condition)
						UML_LABEL(block, skip_label);
					return true;
				}

				case 0x04:          // compute / modify                     |000|00100|
				{
					int cond = (opcode >> 33) & 0x1f;
					int g = (opcode >> 38) & 0x1;
					int m = (opcode >> 27) & 0x7;
					int i = (opcode >> 30) & 0x7;

					bool has_condition = !if_condition_always_true(cond);
					int skip_label = 0;

					if (has_condition)
					{
						skip_label = compiler->labelnum++;
						generate_if_condition(block, compiler, desc, cond, skip_label);
					}

					generate_compute(block, compiler, desc);

					if (g)
					{
						// PM
						UML_ADD(block, PM_I(i), PM_I(i), PM_M(m));
					}
					else
					{
						// DM
						UML_ADD(block, DM_I(i), DM_I(i), DM_M(m));
					}

					generate_update_circular_buffer(block, compiler, desc, g, i);

					if (has_condition)
						UML_LABEL(block, skip_label);

					return true;
				}

				case 0x06:          // direct jump|call                     |000|00110|
				{
					int b = (opcode >> 39) & 0x1;
					int j = (opcode >> 26) & 0x1;
					int la = (opcode >> 38) & 0x1;
					int ci = (opcode >> 24) & 0x1;
					int cond = (opcode >> 33) & 0x1f;

					bool has_condition = !if_condition_always_true(cond);
					int skip_label = 0;

					if (has_condition)
					{
						skip_label = compiler->labelnum++;
						generate_if_condition(block, compiler, desc, cond, skip_label);
					}
					if (b) // call
					{
						generate_call(block, compiler, desc, j != 0);
					}
					else // jump
					{
						generate_jump(block, compiler, desc, j != 0, la != 0, ci != 0);
					}
					if (has_condition)
						UML_LABEL(block, skip_label);
					return true;
				}

				case 0x07:          // direct jump|call                     |000|00111|
				{
					int b = (opcode >> 39) & 0x1;
					int j = (opcode >> 26) & 0x1;
					int la = (opcode >> 38) & 0x1;
					int ci = (opcode >> 24) & 0x1;
					int cond = (opcode >> 33) & 0x1f;

					bool has_condition = !if_condition_always_true(cond);
					int skip_label = 0;

					if (has_condition)
					{
						skip_label = compiler->labelnum++;
						generate_if_condition(block, compiler, desc, cond, skip_label);
					}
					if (b) // call
					{
						generate_call(block, compiler, desc, j != 0);
					}
					else // jump
					{
						generate_jump(block, compiler, desc, j != 0, la != 0, ci != 0);
					}
					if (has_condition)
						UML_LABEL(block, skip_label);
					return true;
				}

				case 0x08:          // indirect jump|call / compute         |000|01000|
				{
					int la = (opcode >> 38) & 0x1;
					int ci = (opcode >> 24) & 0x1;
					int b = (opcode >> 39) & 0x1;
					int j = (opcode >> 26) & 0x1;
					int e = (opcode >> 25) & 0x1;
					int pmi = (opcode >> 30) & 0x7;
					int pmm = (opcode >> 27) & 0x7;
					int cond = (opcode >> 33) & 0x1f;

					if (e)
					{
						// IF ... ELSE

						int label_else = compiler->labelnum++;
						generate_if_condition(block, compiler, desc, cond, label_else);

						UML_ADD(block, I0, PM_I(pmi), PM_M(pmm));

						if (b) // call
						{
							generate_call(block, compiler, desc, j != 0);
						}
						else // jump
						{
							generate_jump(block, compiler, desc, j != 0, la != 0, ci != 0);
						}

						UML_LABEL(block, label_else);
						generate_compute(block, compiler, desc);
					}
					else
					{
						// IF
						bool has_condition = !if_condition_always_true(cond);
						int skip_label = 0;

						if (has_condition)
						{
							skip_label = compiler->labelnum++;
							generate_if_condition(block, compiler, desc, cond, skip_label);
						}
						generate_compute(block, compiler, desc);

						UML_ADD(block, I0, PM_I(pmi), PM_M(pmm));

						if (b) // call
						{
							generate_call(block, compiler, desc, j != 0);
						}
						else // jump
						{
							generate_jump(block, compiler, desc, j != 0, la != 0, ci != 0);
						}

						if (has_condition)
							UML_LABEL(block, skip_label);
					}

					return true;
				}

				case 0x09:          // indirect jump|call / compute         |000|01001|
				{
					int la = (opcode >> 38) & 0x1;
					int ci = (opcode >> 24) & 0x1;
					int b = (opcode >> 39) & 0x1;
					int j = (opcode >> 26) & 0x1;
					int e = (opcode >> 25) & 0x1;
					int cond = (opcode >> 33) & 0x1f;

					if (e)
					{
						// IF ... ELSE

						int label_else = compiler->labelnum++;
						generate_if_condition(block, compiler, desc, cond, label_else);

						if (b) // call
						{
							generate_call(block, compiler, desc, j != 0);
						}
						else // jump
						{
							generate_jump(block, compiler, desc, j != 0, la != 0, ci != 0);
						}

						UML_LABEL(block, label_else);
						generate_compute(block, compiler, desc);
					}
					else
					{
						// IF
						bool has_condition = !if_condition_always_true(cond);
						int skip_label = 0;

						if (has_condition)
						{
							skip_label = compiler->labelnum++;
							generate_if_condition(block, compiler, desc, cond, skip_label);
						}
						generate_compute(block, compiler, desc);

						if (b) // call
						{
							generate_call(block, compiler, desc, j != 0);
						}
						else // jump
						{
							generate_jump(block, compiler, desc, j != 0, la != 0, ci != 0);
						}

						if (has_condition)
							UML_LABEL(block, skip_label);
					}

					return true;
				}

				case 0x0a:          // return from subroutine / compute     |000|01010|
				{
					int cond = (opcode >> 33) & 0x1f;
					int j = (opcode >> 26) & 0x1;
					int e = (opcode >> 25) & 0x1;
					//int lr = (opcode >> 24) & 0x1;

					// TODO: loop re-entry

					if (e)
					{
						// IF ... ELSE

						int label_else = compiler->labelnum++;
						generate_if_condition(block, compiler, desc, cond, label_else);

						UML_CALLH(block, *m_pop_pc);
						generate_jump(block, compiler, desc, j != 0, false, false);

						UML_LABEL(block, label_else);
						generate_compute(block, compiler, desc);
					}
					else
					{
						// IF
						bool has_condition = !if_condition_always_true(cond);
						int skip_label = 0;

						if (has_condition)
						{
							skip_label = compiler->labelnum++;
							generate_if_condition(block, compiler, desc, cond, skip_label);
						}
						generate_compute(block, compiler, desc);

						UML_CALLH(block, *m_pop_pc);
						generate_jump(block, compiler, desc, j != 0, false, false);

						if (has_condition)
							UML_LABEL(block, skip_label);
					}

					return true;
				}

				case 0x0b:          // return from interrupt / compute      |000|01011|
				{
					int cond = (opcode >> 33) & 0x1f;
					int j = (opcode >> 26) & 0x1;
					int e = (opcode >> 25) & 0x1;


					code_label skip_pop = compiler->labelnum++;

					UML_MOV(block, mem(&m_core->interrupt_active), 0);          // mov     [interrupt_active],0
					UML_MOV(block, I0, 1);                                      // mov     i0,1
					UML_SHL(block, I0, I0, mem(&m_core->active_irq_num));       // shl     i0,[active_irq_num]
					UML_XOR(block, IRPTL, IRPTL, I0);                           // xor     IRPTL,i0
					UML_CMP(block, mem(&m_core->status_stkp), 0);               // cmp     [status_stkp],0
					UML_JMPc(block, COND_Z, skip_pop);                          // jz      skip_pop
					UML_CALLH(block, *m_pop_status);                            // callh   m_pop_status

					UML_LABEL(block, skip_pop);                                 // skip_pop:

					// TODO: check interrupts

					if (e)
					{
						// IF ... ELSE

						code_label label_else = compiler->labelnum++;
						generate_if_condition(block, compiler, desc, cond, label_else);

						UML_CALLH(block, *m_pop_pc);
						generate_jump(block, compiler, desc, j != 0, false, false);

						UML_LABEL(block, label_else);
						generate_compute(block, compiler, desc);
					}
					else
					{
						// IF
						bool has_condition = !if_condition_always_true(cond);
						code_label skip_label = 0;

						if (has_condition)
						{
							skip_label = compiler->labelnum++;
							generate_if_condition(block, compiler, desc, cond, skip_label);
						}
						generate_compute(block, compiler, desc);

						UML_CALLH(block, *m_pop_pc);
						generate_jump(block, compiler, desc, j != 0, false, false);

						if (has_condition)
							UML_LABEL(block, skip_label);
					}

					return true;
				}

				case 0x0c:          // do until counter expired             |000|01100|
				{
					uint16_t data = (uint16_t)(opcode >> 24);
					int offset = SIGN_EXTEND24(opcode & 0xffffff);
					uint32_t address = desc->pc + offset;

					UML_MOV(block, LCNTR, data);
					if (data > 0)
					{
						// push pc
						UML_MOV(block, I0, desc->pc + 1);
						UML_CALLH(block, *m_push_pc);

						// push loop
						UML_MOV(block, I0, data);
						UML_MOV(block, I1, address);
						UML_CALLH(block, *m_push_loop);
					}
					return true;
				}

				case 0x0d:          // do until counter expired             |000|01101|
				{
					int ureg = (opcode >> 32) & 0xff;
					int offset = SIGN_EXTEND24(opcode & 0xffffff);
					uint32_t address = desc->pc + offset;

					generate_read_ureg(block, compiler, desc, ureg, false);

					UML_MOV(block, I3, I0);
					UML_MOV(block, LCNTR, I3);

					// push pc
					UML_MOV(block, I0, desc->pc + 1);
					UML_CALLH(block, *m_push_pc);

					// push loop
					UML_MOV(block, I0, I3);
					UML_MOV(block, I1, address);
					UML_CALLH(block, *m_push_loop);
					return true;
				}

				case 0x0e:          // do until                             |000|01110|
				{
					int offset = SIGN_EXTEND24(opcode & 0xffffff);
					uint32_t address = desc->pc + offset;

					// push pc
					UML_MOV(block, I0, desc->pc + 1);
					UML_CALLH(block, *m_push_pc);

					// push loop
					UML_MOV(block, I0, 0);
					UML_MOV(block, I1, address);
					UML_CALLH(block, *m_push_loop);
					return true;
				}

				case 0x0f:          // immediate data -> ureg               |000|01111|
				{
					int ureg = (opcode >> 32) & 0xff;
					uint32_t data = (uint32_t)opcode;

					generate_write_ureg(block, compiler, desc, ureg, true, data);
					return true;
				}

				case 0x10:          // ureg <-> DM|PM (direct)              |000|100|G|D|
				case 0x11:
				case 0x12:
				case 0x13:
				{
					int ureg = (opcode >> 32) & 0xff;
					uint32_t address = (uint32_t)(opcode);
					int d = (opcode >> 40) & 1;
					int g = (opcode >> 41) & 1;

					UML_MOV(block, I1, address);
					if (d)
					{
						generate_read_ureg(block, compiler, desc, ureg, false);

						// write
						if (g)
						{
							// PM
							if (ureg == 0xdb)   // PX is 48-bit
								UML_CALLH(block, *m_pm_write48);
							else
								UML_CALLH(block, *m_pm_write32);
						}
						else
						{
							// DM
							UML_CALLH(block, *m_dm_write32);
						}
					}
					else
					{
						// read
						if (g)
						{
							// PM
							if (ureg == 0xdb)   // PX is 48-bit
								UML_CALLH(block, *m_pm_read48);
							else
								UML_CALLH(block, *m_pm_read32);
						}
						else
						{
							// DM
							UML_CALLH(block, *m_dm_read32);
						}

						generate_write_ureg(block, compiler, desc, ureg, false, 0);
					}
					return true;
				}

				case 0x14:          // system register bit manipulation     |000|10100|
				{
					int bop = (opcode >> 37) & 0x7;
					int sreg = (opcode >> 32) & 0xf;
					uint32_t data = (uint32_t)opcode;

					switch (bop)
					{
						case 0:     // SET
						{
							switch (sreg)
							{
								case 0x0: // USTAT1
									UML_OR(block, USTAT1, USTAT1, data);
									break;
								case 0x1: // USTAT2
									UML_OR(block, USTAT2, USTAT2, data);
									break;
								case 0x9: // IRPTL
									UML_OR(block, IRPTL, IRPTL, data);
									break;
								case 0xa: // MODE2
									UML_OR(block, MODE2, MODE2, data);
									break;
								case 0xb: // MODE1
									compiler->mode1_delay.counter = 2;
									compiler->mode1_delay.data = data;
									compiler->mode1_delay.mode = MODE1_SET;
									break;
								case 0xc: // ASTAT
									// TODO: does this need delay?
									if (data & ASTAT_FLAGS::AZ)
										UML_MOV(block, ASTAT_AZ, 1);
									if (data & ASTAT_FLAGS::AV)
										UML_MOV(block, ASTAT_AV, 1);
									if (data & ASTAT_FLAGS::AN)
										UML_MOV(block, ASTAT_AN, 1);
									if (data & ASTAT_FLAGS::AC)
										UML_MOV(block, ASTAT_AC, 1);
									if (data & ASTAT_FLAGS::AS)
										UML_MOV(block, ASTAT_AS, 1);
									if (data & ASTAT_FLAGS::AI)
										UML_MOV(block, ASTAT_AI, 1);
									if (data & ASTAT_FLAGS::MN)
										UML_MOV(block, ASTAT_MN, 1);
									if (data & ASTAT_FLAGS::MV)
										UML_MOV(block, ASTAT_MV, 1);
									if (data & ASTAT_FLAGS::MU)
										UML_MOV(block, ASTAT_MU, 1);
									if (data & ASTAT_FLAGS::MI)
										UML_MOV(block, ASTAT_MI, 1);
									if (data & ASTAT_FLAGS::AF)
										UML_MOV(block, ASTAT_AF, 1);
									if (data & ASTAT_FLAGS::SV)
										UML_MOV(block, ASTAT_SV, 1);
									if (data & ASTAT_FLAGS::SZ)
										UML_MOV(block, ASTAT_SZ, 1);
									if (data & ASTAT_FLAGS::SS)
										UML_MOV(block, ASTAT_SS, 1);
									if (data & ASTAT_FLAGS::BTF)
										UML_MOV(block, ASTAT_BTF, 1);
									if (data & ASTAT_FLAGS::FLG0)
										UML_MOV(block, FLAG0, 1);
									if (data & ASTAT_FLAGS::FLG1)
										UML_MOV(block, FLAG1, 1);
									if (data & ASTAT_FLAGS::FLG2)
										UML_MOV(block, FLAG2, 1);
									if (data & ASTAT_FLAGS::FLG3)
										UML_MOV(block, FLAG3, 1);
									if (data & 0xff000000)
									{
										UML_OR(block, mem(&m_core->astat_drc.cacc), mem(&m_core->astat_drc.cacc), (data >> 24));
									}
									break;
								case 0xd: // IMASK
									UML_OR(block, IMASK, IMASK, data);
									break;
								case 0xe: // STKY
									UML_OR(block, STKY, STKY, data);
									break;
								case 0xf: // IMASKP
									UML_OR(block, IMASKP, IMASKP, data);
									break;

								default:
									return false;
							}
							return true;
						}
						case 1:     // CLEAR
						{
							switch (sreg)
							{
								case 0x0: // USTAT1
									UML_AND(block, USTAT1, USTAT1, ~data);
									break;
								case 0x1: // USTAT2
									UML_AND(block, USTAT2, USTAT2, ~data);
									break;
								case 0x9: // IRPTL
									UML_AND(block, IRPTL, IRPTL, ~data);
									break;
								case 0xa: // MODE2
									UML_AND(block, MODE2, MODE2, ~data);
									break;
								case 0xb: // MODE1
									compiler->mode1_delay.counter = 2;
									compiler->mode1_delay.data = data;
									compiler->mode1_delay.mode = MODE1_CLEAR;
									break;
								case 0xc: // ASTAT
									// TODO: does this need delay?
									if (data & ASTAT_FLAGS::AZ)
										UML_MOV(block, ASTAT_AZ, 0);
									if (data & ASTAT_FLAGS::AV)
										UML_MOV(block, ASTAT_AV, 0);
									if (data & ASTAT_FLAGS::AN)
										UML_MOV(block, ASTAT_AN, 0);
									if (data & ASTAT_FLAGS::AC)
										UML_MOV(block, ASTAT_AC, 0);
									if (data & ASTAT_FLAGS::AS)
										UML_MOV(block, ASTAT_AS, 0);
									if (data & ASTAT_FLAGS::AI)
										UML_MOV(block, ASTAT_AI, 0);
									if (data & ASTAT_FLAGS::MN)
										UML_MOV(block, ASTAT_MN, 0);
									if (data & ASTAT_FLAGS::MV)
										UML_MOV(block, ASTAT_MV, 0);
									if (data & ASTAT_FLAGS::MU)
										UML_MOV(block, ASTAT_MU, 0);
									if (data & ASTAT_FLAGS::MI)
										UML_MOV(block, ASTAT_MI, 0);
									if (data & ASTAT_FLAGS::AF)
										UML_MOV(block, ASTAT_AF, 0);
									if (data & ASTAT_FLAGS::SV)
										UML_MOV(block, ASTAT_SV, 0);
									if (data & ASTAT_FLAGS::SZ)
										UML_MOV(block, ASTAT_SZ, 0);
									if (data & ASTAT_FLAGS::SS)
										UML_MOV(block, ASTAT_SS, 0);
									if (data & ASTAT_FLAGS::BTF)
										UML_MOV(block, ASTAT_BTF, 0);
									if (data & ASTAT_FLAGS::FLG0)
										UML_MOV(block, FLAG0, 0);
									if (data & ASTAT_FLAGS::FLG1)
										UML_MOV(block, FLAG1, 0);
									if (data & ASTAT_FLAGS::FLG2)
										UML_MOV(block, FLAG2, 0);
									if (data & ASTAT_FLAGS::FLG3)
										UML_MOV(block, FLAG3, 0);
									if (data & 0xff000000)
									{
										UML_AND(block, mem(&m_core->astat_drc.cacc), mem(&m_core->astat_drc.cacc), ~(data >> 24));
									}
									break;
								case 0xd: // IMASK
									UML_AND(block, IMASK, IMASK, ~data);
									break;
								case 0xe: // STKY
									UML_AND(block, STKY, STKY, ~data);
									break;
								case 0xf: // IMASKP
									UML_AND(block, IMASKP, IMASKP, ~data);
									break;

								default:
									return false;
							}
							return true;
						}
						case 2:     // TOGGLE
						{
							switch (sreg)
							{
								case 0x0: // USTAT1
									UML_XOR(block, USTAT1, USTAT1, data);
									break;
								case 0x1: // USTAT2
									UML_XOR(block, USTAT2, USTAT2, data);
									break;
								case 0x9: // IRPTL
									UML_XOR(block, IRPTL, IRPTL, data);
									break;
								case 0xa: // MODE2
									UML_XOR(block, MODE2, MODE2, data);
									break;
								case 0xb: // MODE1
									compiler->mode1_delay.counter = 2;
									compiler->mode1_delay.data = data;
									compiler->mode1_delay.mode = MODE1_TOGGLE;
									break;
								case 0xc: // ASTAT
									return false;
								case 0xd: // IMASK
									UML_XOR(block, IMASK, IMASK, data);
									break;
								case 0xe: // STKY
									UML_XOR(block, STKY, STKY, data);
									break;
								case 0xf: // IMASKP
									UML_XOR(block, IMASKP, IMASKP, data);
									break;

								default:
									return false;
							}
							return true;
						}
						case 4:     // TEST
						{
							switch (sreg)
							{
								case 0x0: // USTAT1
									UML_AND(block, I0, USTAT1, data);
									UML_CMP(block, I0, data);
									UML_SETc(block, COND_E, ASTAT_BTF);
									break;
								case 0x1: // USTAT2
									UML_AND(block, I0, USTAT2, data);
									UML_CMP(block, I0, data);
									UML_SETc(block, COND_E, ASTAT_BTF);
									break;
								case 0x9: // IRPTL
									UML_AND(block, I0, IRPTL, data);
									UML_CMP(block, I0, data);
									UML_SETc(block, COND_E, ASTAT_BTF);
									break;
								case 0xa: // MODE2
									UML_AND(block, I0, MODE2, data);
									UML_CMP(block, I0, data);
									UML_SETc(block, COND_E, ASTAT_BTF);
									break;
								case 0xb: // MODE1
									UML_AND(block, I0, MODE1, data);
									UML_CMP(block, I0, data);
									UML_SETc(block, COND_E, ASTAT_BTF);
									break;
								case 0xc: // ASTAT
									return false;
								case 0xd: // IMASK
									UML_AND(block, I0, IMASK, data);
									UML_CMP(block, I0, data);
									UML_SETc(block, COND_E, ASTAT_BTF);
									break;
								case 0xe: // STKY
									UML_AND(block, I0, STKY, data);
									UML_CMP(block, I0, data);
									UML_SETc(block, COND_E, ASTAT_BTF);
									break;
								case 0xf: // IMASKP
									UML_AND(block, I0, IMASKP, data);
									UML_CMP(block, I0, data);
									UML_SETc(block, COND_E, ASTAT_BTF);
									break;

								default:
									return false;
							}
							return true;
						}
						case 5:     // XOR
						{
							return false;
						}

						default:
							return false;
					}
					return true;
				}

				case 0x16:          // I register modify / bit-reverse      |000|10110|
				{
					if (opcode & 0x008000000000U)   // bit reverse
					{
						return false;
					}
					else            // modify
					{
						int g = (opcode >> 38) & 0x1;
						int i = (opcode >> 32) & 0x7;
						int32_t data = (int32_t)(opcode);

						if (g)
						{
							// PM
							UML_ADD(block, PM_I(i), PM_I(i), data);
						}
						else
						{
							// DM
							UML_ADD(block, DM_I(i), DM_I(i), data);
						}
						generate_update_circular_buffer(block, compiler, desc, g, i);
						return true;
					}
				}

				case 0x17:          // push|pop stacks / flush cache        |000|10111|
				{
					if (opcode & 0x008000000000U)
					{
						fatalerror("sharcdrc: push/pop stacks: push loop not implemented\n");
					}
					if (opcode & 0x004000000000U)
					{
						fatalerror("sharcdrc: push/pop stacks: pop loop not implemented\n");
					}
					if (opcode & 0x002000000000U)
					{
						UML_CALLH(block, *m_push_status);
					}
					if (opcode & 0x001000000000U)
					{
						UML_CALLH(block, *m_pop_status);
					}
					if (opcode & 0x000800000000U)
					{
						UML_MOV(block, I0, PCSTK);
						UML_CALLH(block, *m_push_pc);
					}
					if (opcode & 0x000400000000U)
					{
						UML_CALLH(block, *m_pop_pc);
					}
					return true;
				}

				case 0x18:          // cjump                                |000|11000|
					return false;

				case 0x19:          // rframe                               |000|11001|
					return false;

				default:
					return false;
			}
			break;
		}

		case 1:             // compute / dreg <-> DM / dreg <-> PM                                  |001|
		{
			int pm_dreg = (opcode >> 23) & 0xf;
			int pmm = (opcode >> 27) & 0x7;
			int pmi = (opcode >> 30) & 0x7;
			int dm_dreg = (opcode >> 33) & 0xf;
			int dmm = (opcode >> 38) & 0x7;
			int dmi = (opcode >> 41) & 0x7;
			int pmd = (opcode >> 37) & 0x1;
			int dmd = (opcode >> 44) & 0x1;
			int compute = opcode & 0x7fffff;

			bool temp_pm_dreg = false;
			if (compute != 0 && pmd && desc->regout[0] & (1 << pm_dreg))
			{
				UML_MOV(block, mem(&m_core->dreg_temp), REG(pm_dreg));
				temp_pm_dreg = true;
			}
			bool temp_dm_dreg = false;
			if (compute != 0 && dmd && desc->regout[0] & (1 << dm_dreg))
			{
				UML_MOV(block, mem(&m_core->dreg_temp2), REG(dm_dreg));
				temp_dm_dreg = true;
			}

			generate_compute(block, compiler, desc);

			// PM transfer
			if (pmd)
			{
				// dreg -> PM
				if (temp_pm_dreg)
					UML_MOV(block, I0, mem(&m_core->dreg_temp));
				else
					UML_MOV(block, I0, REG(pm_dreg));
				UML_MOV(block, I1, PM_I(pmi));
				UML_CALLH(block, *m_pm_write32);
				UML_ADD(block, PM_I(pmi), PM_I(pmi), PM_M(pmm));
				generate_update_circular_buffer(block, compiler, desc, 1, pmi);
			}
			else
			{
				// PM -> dreg
				UML_MOV(block, I1, PM_I(pmi));
				UML_CALLH(block, *m_pm_read32);
				UML_MOV(block, REG(pm_dreg), I0);
				UML_ADD(block, PM_I(pmi), PM_I(pmi), PM_M(pmm));
				generate_update_circular_buffer(block, compiler, desc, 1, pmi);
			}

			// DM transfer
			if (dmd)
			{
				// dreg -> DM
				if (temp_dm_dreg)
					UML_MOV(block, I0, mem(&m_core->dreg_temp2));
				else
					UML_MOV(block, I0, REG(dm_dreg));
				UML_MOV(block, I1, DM_I(dmi));
				UML_CALLH(block, *m_dm_write32);
				UML_ADD(block, DM_I(dmi), DM_I(dmi), DM_M(dmm));
				generate_update_circular_buffer(block, compiler, desc, 0, dmi);
			}
			else
			{
				// DM -> dreg
				UML_MOV(block, I1, DM_I(dmi));
				UML_CALLH(block, *m_dm_read32);
				UML_MOV(block, REG(dm_dreg), I0);
				UML_ADD(block, DM_I(dmi), DM_I(dmi), DM_M(dmm));
				generate_update_circular_buffer(block, compiler, desc, 0, dmi);
			}
			return true;
		}

		case 2:             // compute / ureg <-> DM|PM, register modify                            |010|
		{
			int u = (opcode >> 44) & 0x1;
			int i = (opcode >> 41) & 0x7;
			int m = (opcode >> 38) & 0x7;
			int cond = (opcode >> 33) & 0x1f;
			int g = (opcode >> 32) & 0x1;
			int d = (opcode >> 31) & 0x1;
			int ureg = (opcode >> 23) & 0xff;
			int compute = opcode & 0x7fffff;

			bool ureg_is_dreg = (ureg >= 0 && ureg < 16);
			bool has_condition = !if_condition_always_true(cond);
			int skip_label = 0;

			bool ureg_is_astat = (ureg == 0x7c);

			if (has_condition)
			{
				skip_label = compiler->labelnum++;
				generate_if_condition(block, compiler, desc, cond, skip_label);
			}

			if (d)
			{
				// UREG -> DM|PM
				bool temp_ureg = false;

				// save UREG if compute writes to it
				if (compute != 0 && ureg_is_dreg && desc->regout[0] & (1 << (ureg & 0xf)))
				{
					UML_MOV(block, mem(&m_core->dreg_temp), REG(ureg & 0xf));
					temp_ureg = true;
				}

				// save a copy of ASTAT if we need to read it
				if (ureg_is_astat)
					generate_astat_copy(block, compiler, desc);

				// compute
				generate_compute(block, compiler, desc);

				// transfer
				UML_MOV(block, I1, (g) ? PM_I(i) : DM_I(i));            // mov    i1,dm|pm[i]
				if (u == 0) // pre-modify without update
					UML_ADD(block, I1, I1, (g) ? PM_M(m) : DM_M(m));    // add    i1,i1,dm|pm[m]
				if (temp_ureg)
					UML_MOV(block, I0, mem(&m_core->dreg_temp));        // mov    i0,[m_core->dreg_temp]
				else
					generate_read_ureg(block, compiler, desc, ureg, ureg_is_astat);

				if (ureg == 0xdb && (g))    // PX is 48-bit when writing to PM
					UML_CALLH(block, *m_pm_write48);                    // callh  pm_write48
				else
					UML_CALLH(block, (g) ? *m_pm_write32 : *m_dm_write32);  // callh  dm|pm_write32
			}
			else
			{
				// DM|PM -> UREG

				// compute
				generate_compute(block, compiler, desc);

				// transfer
				UML_MOV(block, I1, (g) ? PM_I(i) : DM_I(i));            // mov    i1,dm|pm[i]
				if (u == 0) // pre-modify without update
					UML_ADD(block, I1, I1, (g) ? PM_M(m) : DM_M(m));    // add    i1,i1,dm|pm[m]

				if (ureg == 0xdb && (g))    // PX is 48-bit when reading from PM
					UML_CALLH(block, *m_pm_read48);                     // callh  pm_read48
				else
					UML_CALLH(block, (g) ? *m_pm_read32 : *m_dm_read32);    // callh  dm|pm_read32
				generate_write_ureg(block, compiler, desc, ureg, false, 0);
			}

			if (u != 0)     // post-modify with update
			{
				if (g)
					UML_ADD(block, PM_I(i), PM_I(i), PM_M(m));          // add    pm[i],pm[m]
				else
					UML_ADD(block, DM_I(i), DM_I(i), DM_M(m));          // add    dm[i],dm[m]

				generate_update_circular_buffer(block, compiler, desc, g, i);
			}

			if (has_condition)
				UML_LABEL(block, skip_label);

			return true;
		}

		case 3:
		{
			if (opcode & 0x100000000000U)   // compute / ureg <-> ureg                          |011|1|
			{
				int src_ureg = (opcode >> 36) & 0xff;
				int dst_ureg = (opcode >> 23) & 0xff;
				int cond = (opcode >> 31) & 0x1f;
				int compute = opcode & 0x7fffff;

				bool has_condition = !if_condition_always_true(cond);
				bool src_is_dreg = (src_ureg >= 0 && src_ureg < 16);
				int skip_label = 0;

				bool src_ureg_is_astat = (src_ureg == 0x7c);

				if (has_condition)
				{
					skip_label = compiler->labelnum++;
					generate_if_condition(block, compiler, desc, cond, skip_label);
				}

				bool temp_ureg = false;
				// save UREG if compute writes to it
				if (compute != 0 && src_is_dreg && desc->regout[0] & (1 << (src_ureg & 0xf)))
				{
					UML_MOV(block, mem(&m_core->dreg_temp), REG(src_ureg & 0xf));
					temp_ureg = true;
				}

				// save a copy of ASTAT if we need to read it
				if (src_ureg_is_astat)
					generate_astat_copy(block, compiler, desc);

				generate_compute(block, compiler, desc);

				if (temp_ureg)
				{
					UML_MOV(block, I0, mem(&m_core->dreg_temp));
				}
				else
				{
					generate_read_ureg(block, compiler, desc, src_ureg, src_ureg_is_astat);
				}
				generate_write_ureg(block, compiler, desc, dst_ureg, false, 0);

				if (has_condition)
					UML_LABEL(block, skip_label);

				return true;
			}
			else                                // compute / dreg <-> DM|PM, immediate modify       |011|0|
			{
				int cond = (opcode >> 33) & 0x1f;
				int u = (opcode >> 38) & 0x1;
				int d = (opcode >> 39) & 0x1;
				int g = (opcode >> 40) & 0x1;
				int dreg = (opcode >> 23) & 0xf;
				int i = (opcode >> 41) & 0x7;
				int mod = SIGN_EXTEND6((opcode >> 27) & 0x3f);
				int compute = opcode & 0x7fffff;

				bool has_condition = !if_condition_always_true(cond);
				int skip_label = 0;

				if (has_condition)
				{
					skip_label = compiler->labelnum++;
					generate_if_condition(block, compiler, desc, cond, skip_label);
				}
				if (d)
				{
					// DREG -> DM|PM
					bool temp_dreg = false;

					// save dreg if compute writes to it
					if (compute != 0 && desc->regout[0] & (1 << dreg))
					{
						UML_MOV(block, mem(&m_core->dreg_temp), REG(dreg));
						temp_dreg = true;
					}
					// compute
					generate_compute(block, compiler, desc);

					// transfer
					UML_MOV(block, I1, (g) ? PM_I(i) : DM_I(i));            // mov    i1,dm|pm[i]
					if (u == 0) // pre-modify without update
						UML_ADD(block, I1, I1, mod);                        // add    i1,i1,mod
					if (temp_dreg)
						UML_MOV(block, I0, mem(&m_core->dreg_temp));        // mov    i0,[m_core->dreg_temp]
					else
						UML_MOV(block, I0, REG(dreg));                      // mov    i0,reg[dreg]
					UML_CALLH(block, (g) ? *m_pm_write32 : *m_dm_write32);  // callh  dm|pm_write32
				}
				else
				{
					// DM|PM -> DREG

					// compute
					generate_compute(block, compiler, desc);

					// transfer
					UML_MOV(block, I1, (g) ? PM_I(i) : DM_I(i));            // mov    i1,dm|pm[i]
					if (u == 0) // pre-modify without update
						UML_ADD(block, I1, I1, mod);                        // add    i1,i1,mod
					UML_CALLH(block, (g) ? *m_pm_read32 : *m_dm_read32);    // callh  dm|pm_read32
					UML_MOV(block, REG(dreg), I0);                          // mov    reg[dreg],i0
				}

				if (u != 0)     // post-modify with update
				{
					if (g)
						UML_ADD(block, PM_I(i), PM_I(i), mod);              // add    pm[i],mod
					else
						UML_ADD(block, DM_I(i), DM_I(i), mod);              // add    dm[i],mod

					generate_update_circular_buffer(block, compiler, desc, g, i);
				}
				if (has_condition)
					UML_LABEL(block, skip_label);

				return true;
			}
			break;
		}

		case 4:
		{
			if (opcode & 0x100000000000U)   // immediate data -> DM|PM                          |100|1|
			{
				int i = (opcode >> 41) & 0x7;
				int m = (opcode >> 38) & 0x7;
				int g = (opcode >> 37) & 0x1;
				uint32_t data = (uint32_t)opcode;

				if (g)
				{
					// PM
					UML_MOV(block, I0, data);
					UML_MOV(block, I1, PM_I(i));
					UML_CALLH(block, *m_pm_write32);
					UML_ADD(block, PM_I(i), PM_I(i), PM_M(m));
				}
				else
				{
					// DM
					UML_MOV(block, I0, data);
					UML_MOV(block, I1, DM_I(i));
					UML_CALLH(block, *m_dm_write32);
					UML_ADD(block, DM_I(i), DM_I(i), DM_M(m));
				}

				generate_update_circular_buffer(block, compiler, desc, g, i);

				return true;
			}
			else                                // immediate shift / dreg <-> DM|PM                 |100|0|
			{
				int i = (opcode >> 41) & 0x7;
				int m = (opcode >> 38) & 0x7;
				int g = (opcode >> 32) & 0x1;
				int d = (opcode >> 31) & 0x1;
				int dreg = (opcode >> 23) & 0xf;
				int cond = (opcode >> 33) & 0x1f;
				int data = ((opcode >> 8) & 0xff) | ((opcode >> 19) & 0xf00);
				int shiftop = (opcode >> 16) & 0x3f;
				int rn = (opcode >> 4) & 0xf;
				int rx = (opcode & 0xf);

				bool has_condition = !if_condition_always_true(cond);
				int skip_label = 0;

				if (has_condition)
				{
					skip_label = compiler->labelnum++;
					generate_if_condition(block, compiler, desc, cond, skip_label);
				}
				if (d)
				{
					// DREG -> DM|PM
					bool temp_dreg = false;

					// save dreg if shiftop writes to it
					if (desc->regout[0] & (1 << dreg))
					{
						UML_MOV(block, mem(&m_core->dreg_temp), REG(dreg));
						temp_dreg = true;
					}
					// shiftop
					generate_shift_imm(block, compiler, desc, data, shiftop, rn, rx);

					// transfer
					UML_MOV(block, I1, (g) ? PM_I(i) : DM_I(i));            // mov    i1,dm|pm[i]
					if (temp_dreg)
						UML_MOV(block, I0, mem(&m_core->dreg_temp));        // mov    i0,[m_core->dreg_temp]
					else
						UML_MOV(block, I0, REG(dreg));                      // mov    i0,reg[dreg]
					UML_CALLH(block, (g) ? *m_pm_write32 : *m_dm_write32);  // callh  dm|pm_write32
				}
				else
				{
					// DM|PM -> DREG

					// shiftop
					generate_shift_imm(block, compiler, desc, data, shiftop, rn, rx);

					// transfer
					UML_MOV(block, I1, (g) ? PM_I(i) : DM_I(i));            // mov    i1,dm|pm[i]
					UML_CALLH(block, (g) ? *m_pm_read32 : *m_dm_read32);    // callh  dm|pm_read32
					UML_MOV(block, REG(dreg), I0);                          // mov    reg[dreg],i0
				}

				// update I
				if (g)
					UML_ADD(block, PM_I(i), PM_I(i), PM_M(m));
				else
					UML_ADD(block, DM_I(i), DM_I(i), DM_M(m));

				generate_update_circular_buffer(block, compiler, desc, g, i);

				if (has_condition)
					UML_LABEL(block, skip_label);

				return true;
			}
			break;
		}

		case 5:                             // ureg <-> DM|PM (indirect)                            |101|
		{
			int g = (opcode >> 44) & 1;
			int d = (opcode >> 40) & 1;
			int i = (opcode >> 41) & 0x7;
			int ureg = (opcode >> 32) & 0xff;
			uint32_t offset = (uint32_t)opcode;

			if (d)
			{
				// UREG -> DM|PM
				UML_ADD(block, I1, (g) ? PM_I(i) : DM_I(i), offset);        // add    i1,dm|pm[i],offset

				generate_read_ureg(block, compiler, desc, ureg, false);

				if (ureg == 0xdb && (g))    // PX is 48-bit when writing to PM
					UML_CALLH(block, *m_pm_write48);                        // callh  pm_write48
				else
					UML_CALLH(block, (g) ? *m_pm_write32 : *m_dm_write32);  // callh  dm|pm_write32
			}
			else
			{
				// DM|PM -> UREG
				UML_ADD(block, I1, (g) ? PM_I(i) : DM_I(i), offset);        // add    i1,dm|pm[i],offset

				if (ureg == 0xdb && (g))    // PX is 48-bit when reading from PM
					UML_CALLH(block, *m_pm_read48);                         // callh  pm_read48
				else
					UML_CALLH(block, (g) ? *m_pm_read32 : *m_dm_read32);    // callh  dm|pm_read32

				generate_write_ureg(block, compiler, desc, ureg, false, 0);
			}
			return true;
		}

		case 6:                             // indirect jump / compute / dreg <-> DM                |110|
		{
			int d = (opcode >> 44) & 0x1;
			int dmi = (opcode >> 41) & 0x7;
			int dmm = (opcode >> 38) & 0x7;
			int pmi = (opcode >> 30) & 0x7;
			int pmm = (opcode >> 27) & 0x7;
			int cond = (opcode >> 33) & 0x1f;
			int dreg = (opcode >> 23) & 0xf;

			code_label label_else = compiler->labelnum++;
			generate_if_condition(block, compiler, desc, cond, label_else);

			UML_ADD(block, I0, PM_I(pmi), PM_M(pmm));
			generate_jump(block, compiler, desc, false, false, false);

			UML_LABEL(block, label_else);

			if (d)
			{
				// DREG -> DM
				bool temp_dreg = false;
				// save dreg if compute writes to it
				if (desc->regout[0] & (1 << dreg))
				{
					UML_MOV(block, mem(&m_core->dreg_temp), REG(dreg));
					temp_dreg = true;
				}

				// compute
				generate_compute(block, compiler, desc);

				// transfer
				UML_MOV(block, I1, DM_I(dmi));
				if (temp_dreg)
					UML_MOV(block, I0, mem(&m_core->dreg_temp));
				else
					UML_MOV(block, I0, REG(dreg));
				UML_CALLH(block, *m_dm_write32);
			}
			else
			{
				// DM -> DREG

				// compute
				generate_compute(block, compiler, desc);

				// transfer
				UML_MOV(block, I1, DM_I(dmi));
				UML_CALLH(block, *m_dm_read32);
				UML_MOV(block, REG(dreg), I0);
			}

			// update I
			UML_ADD(block, DM_I(dmi), DM_I(dmi), DM_M(dmm));

			generate_update_circular_buffer(block, compiler, desc, 0, dmi);

			return true;
		}

		case 7:                             // indirect jump / compute / dreg <-> DM                |111|
		{
			int d = (opcode >> 44) & 0x1;
			int dmi = (opcode >> 41) & 0x7;
			int dmm = (opcode >> 38) & 0x7;
			int cond = (opcode >> 33) & 0x1f;
			int dreg = (opcode >> 23) & 0xf;

			code_label label_else = compiler->labelnum++;
			generate_if_condition(block, compiler, desc, cond, label_else);

			generate_jump(block, compiler, desc, false, false, false);

			UML_LABEL(block, label_else);

			if (d)
			{
				// DREG -> DM
				bool temp_dreg = false;
				// save dreg if compute writes to it
				if (desc->regout[0] & (1 << dreg))
				{
					UML_MOV(block, mem(&m_core->dreg_temp), REG(dreg));
					temp_dreg = true;
				}

				// compute
				generate_compute(block, compiler, desc);

				// transfer
				UML_MOV(block, I1, DM_I(dmi));
				if (temp_dreg)
					UML_MOV(block, I0, mem(&m_core->dreg_temp));
				else
					UML_MOV(block, I0, REG(dreg));
				UML_CALLH(block, *m_dm_write32);
			}
			else
			{
				// DM -> DREG

				// compute
				generate_compute(block, compiler, desc);

				// transfer
				UML_MOV(block, I1, DM_I(dmi));
				UML_CALLH(block, *m_dm_read32);
				UML_MOV(block, REG(dreg), I0);
			}

			// update I
			UML_ADD(block, DM_I(dmi), DM_I(dmi), DM_M(dmm));

			generate_update_circular_buffer(block, compiler, desc, 0, dmi);

			return true;
		}
	}

	return false;
}

void adsp21062_device::generate_unimplemented_compute(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc)
{
	UML_MOV(block, mem(&m_core->pc), desc->pc);
	UML_DMOV(block, mem(&m_core->arg64), desc->opptr.q[0]);
	UML_CALLC(block, cfunc_unimplemented_compute, this);
}

void adsp21062_device::generate_compute(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc)
{
	uint64_t opcode = desc->opptr.q[0];
	if ((opcode & 0x7fffff) == 0)
		return;

	int rs = (opcode >> 12) & 0xf;
	int rn = (opcode >> 8) & 0xf;
	int ra = rn;
	int rx = (opcode >> 4) & 0xf;
	int ry = (opcode >> 0) & 0xf;
	int ps = (opcode >> 16) & 0xf;

	if (opcode & 0x400000)      // multi-function operation
	{
		uint32_t multiop = (opcode >> 16) & 0x3f;
		int fm = rs;
		int fa = rn;
		int fxm = (opcode >> 6) & 0x3;          // registers 0 - 3
		int fym = ((opcode >> 4) & 0x3) + 4;    // registers 4 - 7
		int fxa = ((opcode >> 2) & 0x3) + 8;    // registers 8 - 11
		int fya = (opcode & 0x3) + 12;          // registers 12 - 15

		switch (multiop)
		{
			case 0x00:          // Rn = MRxx
			{
				generate_unimplemented_compute(block, compiler, desc);
				return;
			}

			case 0x01:          // MRxx = Rn
			{
				int ai = rs;
				switch (ai)
				{
					case 0x00:  // MR0F
						UML_DAND(block, MRF, MRF, 0xffffffff00000000U);
						UML_AND(block, I0, REG(rn), 0xffffffff);
						UML_DOR(block, MRF, MRF, I0);
						break;
					case 0x01:  // MR1F
						UML_DAND(block, MRF, MRF, 0x00000000ffffffffU);
						UML_DSHL(block, I0, REG(rn), 32);
						UML_DOR(block, MRF, MRF, I0);
						break;
					case 0x04:  // MR0B
						UML_DAND(block, MRB, MRB, 0xffffffff00000000U);
						UML_AND(block, I0, REG(rn), 0xffffffff);
						UML_DOR(block, MRB, MRB, I0);
						break;
					case 0x05:  // MR1B
						UML_DAND(block, MRB, MRB, 0x00000000ffffffffU);
						UML_DSHL(block, I0, REG(rn), 32);
						UML_DOR(block, MRB, MRB, I0);
						break;

					case 0x02:  // MR2F
					case 0x06:  // MR2B
						generate_unimplemented_compute(block, compiler, desc);
						return;
				}
				return;
			}

			case 0x07:          // Ra = Rx + Ry,   Rs = Rx - Ry
			case 0x0f:          // Fa = Fx + Fy,   Fs = Fx - Fy
			case 0x06:          // Rm = R3-0 * R7-4 (SSFR),   Ra = (R11-8 + R15-12) / 2
			case 0x08:          // MRF = MRF + R3-0 * R7-4 (SSF),   Ra = R11-8 + R15-12
			case 0x09:          // MRF = MRF + R3-0 * R7-4 (SSF),   Ra = R11-8 - R15-12
			case 0x0a:          // MRF = MRF + R3-0 * R7-4 (SSF),   Ra = (R11-8 + R15-12) / 2
			case 0x0c:          // Rm = MRF + R3-0 * R7-4 (SSFR),   Ra = R11-8 + R15-12
			case 0x0d:          // Rm = MRF + R3-0 * R7-4 (SSFR),   Ra = R11-8 - R15-12
			case 0x0e:          // Rm = MRF + R3-0 * R7-4 (SSFR),   Ra = (R11-8 + R15-12) / 2
			case 0x10:          // MRF = MRF - R3-0 * R7-4 (SSF),   Ra = R11-8 + R15-12
			case 0x11:          // MRF = MRF - R3-0 * R7-4 (SSF),   Ra = R11-8 - R15-12
			case 0x12:          // MRF = MRF - R3-0 * R7-4 (SSF),   Ra = (R11-8 + R15-12) / 2
			case 0x14:          // Rm = MRF - R3-0 * R7-4 (SSFR),   Ra = R11-8 + R15-12
			case 0x15:          // Rm = MRF - R3-0 * R7-4 (SSFR),   Ra = R11-8 - R15-12
			case 0x16:          // Rm = MRF - R3-0 * R7-4 (SSFR),   Ra = (R11-8 + R15-12) / 2
				generate_unimplemented_compute(block, compiler, desc);
				return;

			case 0x1c:          // Fm = F3-0 * F7-4,   Fa = (F11-8 + F15-12) / 2
				generate_unimplemented_compute(block, compiler, desc);
				return;

			case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
			case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
				// Rm = R3-0 * R7-4 (SSFR),   Ra = R11-8 + R15-12,   Rs = R11-8 - R15-12
				generate_unimplemented_compute(block, compiler, desc);
				return;

			case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
			case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
				// Fm = F3-0 * F7-4,   Fa = F11-8 + F15-12,   Fs = F11-8 - F15-12
				// TODO: denormals
				UML_FSCOPYI(block, F0, REG(fxm));
				UML_FSCOPYI(block, F1, REG(fym));
				UML_FSCOPYI(block, F2, REG(fxa));
				UML_FSCOPYI(block, F3, REG(fya));
				UML_FSMUL(block, F0, F0, F1);
				UML_FSADD(block, F4, F2, F3);
				UML_FSSUB(block, F5, F2, F3);

				if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
					UML_FSCMP(block, F4, mem(&m_core->fp0));
				if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
				if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN);

				if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
					UML_FSCMP(block, F5, mem(&m_core->fp0));
				if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, I0);
				if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, I1);
				if (AZ_CALC_REQUIRED) UML_OR(block, ASTAT_AZ, ASTAT_AZ, I0);
				if (AN_CALC_REQUIRED) UML_OR(block, ASTAT_AN, ASTAT_AN, I1);

				if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);  // TODO
				if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
				if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
				if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO

				if (MN_CALC_REQUIRED)
					UML_FSCMP(block, F0, mem(&m_core->fp0));
				if (MN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_MN);
				// TODO: MV, MU, MI flags

				UML_ICOPYFS(block, REG(fm), F0);
				UML_ICOPYFS(block, REG(fa), F4);
				UML_ICOPYFS(block, REG(ps), F5);
				return;

			case 0x04:          // Rm = R3-0 * R7-4 (SSFR),   Ra = R11-8 + R15-12
				UML_DSEXT(block, I0, REG(fxm), SIZE_DWORD);
				UML_DSEXT(block, I1, REG(fym), SIZE_DWORD);
				UML_DMULS(block, I0, I0, I0, I1);
				UML_DSHR(block, I0, I0, 31);

				UML_ADD(block, I2, REG(fxa), REG(fya));
				if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
				if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
				if (AV_CALC_REQUIRED) UML_SETc(block, COND_V, ASTAT_AV);
				if (AC_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AC);
				if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
				if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);

				// TODO: multiplier flags

				UML_MOV(block, REG(fm), I0);
				UML_MOV(block, REG(fa), I2);
				return;

			case 0x05:          // Rm = R3-0 * R7-4 (SSFR),   Ra = R11-8 - R15-12
				UML_DSEXT(block, I0, REG(fxm), SIZE_DWORD);
				UML_DSEXT(block, I1, REG(fym), SIZE_DWORD);
				UML_DMULS(block, I0, I0, I0, I1);
				UML_DSHR(block, I0, I0, 31);

				UML_SUB(block, I2, REG(fxa), REG(fya));
				if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
				if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
				if (AV_CALC_REQUIRED) UML_SETc(block, COND_V, ASTAT_AV);
				if (AC_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AC);
				if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
				if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);

				// TODO: multiplier flags

				UML_MOV(block, REG(fm), I0);
				UML_MOV(block, REG(fa), I2);
				return;

			case 0x18:          // Fm = F3-0 * F7-4,   Fa = F11-8 + F15-12
				// TODO: denormals
				UML_FSCOPYI(block, F0, REG(fxm));
				UML_FSCOPYI(block, F1, REG(fym));
				UML_FSCOPYI(block, F2, REG(fxa));
				UML_FSCOPYI(block, F3, REG(fya));
				UML_FSMUL(block, F0, F0, F1);
				UML_FSADD(block, F2, F2, F3);

				if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
					UML_FSCMP(block, F2, mem(&m_core->fp0));
				if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
				if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN);
				if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);  // TODO
				if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
				if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
				if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO

				if (MN_CALC_REQUIRED)
					UML_FSCMP(block, F0, mem(&m_core->fp0));
				if (MN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_MN);
				// TODO: MV, MU, MI flags

				UML_ICOPYFS(block, REG(fm), F0);
				UML_ICOPYFS(block, REG(fa), F2);
				return;

			case 0x19:          // Fm = F3-0 * F7-4,   Fa = F11-8 - F15-12
				// TODO: denormals
				UML_FSCOPYI(block, F0, REG(fxm));
				UML_FSCOPYI(block, F1, REG(fym));
				UML_FSCOPYI(block, F2, REG(fxa));
				UML_FSCOPYI(block, F3, REG(fya));
				UML_FSMUL(block, F0, F0, F1);
				UML_FSSUB(block, F2, F2, F3);

				if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
					UML_FSCMP(block, F2, mem(&m_core->fp0));
				if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
				if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN);
				if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);  // TODO
				if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
				if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
				if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO

				if (MN_CALC_REQUIRED)
					UML_FSCMP(block, F0, mem(&m_core->fp0));
				if (MN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_MN);
				// TODO: MV, MU, MI flags

				UML_ICOPYFS(block, REG(fm), F0);
				UML_ICOPYFS(block, REG(fa), F2);
				return;

			case 0x1a:          // Fm = F3-0 * F7-4,   Fa = FLOAT F11-8 BY R15-12
			{
				code_label denormal = compiler->labelnum++;
				code_label end = compiler->labelnum++;

				// TODO: denormals
				UML_FSCOPYI(block, F0, REG(fxm));
				UML_FSCOPYI(block, F1, REG(fym));
				UML_FSMUL(block, F0, F0, F1);

				UML_FSFRINT(block, F2, REG(fxa), SIZE_DWORD);
				UML_ICOPYFS(block, I1, F2);
				UML_AND(block, I0, I1, 0x7f800000);
				UML_AND(block, I1, I1, 0x807fffff);
				UML_SHR(block, I0, I0, 23);
				UML_SUB(block, I0, I0, 127);
				UML_ADD(block, I0, I0, REG(fya));
				UML_CMP(block, I0, -126);
				UML_JMPc(block, COND_L, denormal);

				UML_ADD(block, I0, I0, 127);
				UML_AND(block, I0, I0, 0xff);
				UML_SHL(block, I0, I0, 23);
				UML_OR(block, I0, I0, I1);
				if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
				if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
				if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);   // TODO
				if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
				if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
				if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
				UML_JMP(block, end);

				UML_LABEL(block, denormal);
				UML_AND(block, I0, I1, 0x80000000);
				if (AZ_CALC_REQUIRED) UML_MOV(block, ASTAT_AZ, 1);
				if (AN_CALC_REQUIRED) UML_MOV(block, ASTAT_AN, 0);
				if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);   // TODO
				if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
				if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
				if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);

				UML_LABEL(block, end);

				if (MN_CALC_REQUIRED)
					UML_FSCMP(block, F0, mem(&m_core->fp0));
				if (MN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_MN);
				// TODO: MV, MU, MI flags

				UML_ICOPYFS(block, REG(fm), F0);
				UML_MOV(block, REG(fa), I0);
				return;
			}

			case 0x1b:          // Fm = F3-0 * F7-4,   Fa = FIX F11-8 BY R15-12
			{
				code_label denormal = compiler->labelnum++;
				code_label end = compiler->labelnum++;

				// TODO: denormals
				UML_FSCOPYI(block, F0, REG(fxm));
				UML_FSCOPYI(block, F1, REG(fym));
				UML_FSMUL(block, F0, F0, F1);

				UML_MOV(block, I1, REG(fxa));
				UML_AND(block, I0, I1, 0x7f800000);
				UML_AND(block, I1, I1, 0x807fffff);
				UML_SHR(block, I0, I0, 23);
				UML_SUB(block, I0, I0, 127);
				UML_ADD(block, I0, I0, REG(fya));
				UML_CMP(block, I0, -126);
				UML_JMPc(block, COND_L, denormal);

				UML_ADD(block, I0, I0, 127);
				UML_AND(block, I0, I0, 0xff);
				UML_SHL(block, I0, I0, 23);
				UML_OR(block, I0, I0, I1);
				if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
				if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
				if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);   // TODO
				if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
				if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
				if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
				UML_JMP(block, end);

				UML_LABEL(block, denormal);
				UML_AND(block, I0, I1, 0x80000000);
				if (AZ_CALC_REQUIRED) UML_MOV(block, ASTAT_AZ, 1);
				if (AN_CALC_REQUIRED) UML_MOV(block, ASTAT_AN, 0);
				if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);   // TODO
				if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
				if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
				if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);

				UML_LABEL(block, end);

				UML_FSCOPYI(block, F2, I0);
				UML_TEST(block, MODE1, MODE1_TRUNCATE);
				UML_JMPc(block, COND_Z, compiler->labelnum);
				UML_FSTOINT(block, I0, F2, SIZE_DWORD, ROUND_TRUNC);
				UML_JMP(block, compiler->labelnum + 1);
				UML_LABEL(block, compiler->labelnum++);
				UML_FSTOINT(block, I0, F2, SIZE_DWORD, ROUND_ROUND);
				UML_LABEL(block, compiler->labelnum++);

				if (MN_CALC_REQUIRED)
					UML_FSCMP(block, F0, mem(&m_core->fp0));
				if (MN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_MN);
				// TODO: MV, MU, MI flags

				UML_ICOPYFS(block, REG(fm), F0);
				UML_MOV(block, REG(fa), I0);
				return;
			}

			case 0x1d:          // Fm = F3-0 * F7-4,   Fa = ABS F11-8
				UML_FSCOPYI(block, F0, REG(fxm));
				UML_FSCOPYI(block, F1, REG(fym));
				UML_AND(block, I0, REG(fxa), 0x7fffffff);
				UML_FSMUL(block, F0, F0, F1);

				if (AZ_CALC_REQUIRED) UML_MOV(block, ASTAT_AZ, 0);  // TODO
				if (AN_CALC_REQUIRED) UML_MOV(block, ASTAT_AN, 0);
				if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);
				if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
				if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);  // TODO
				if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO

				if (MN_CALC_REQUIRED)
					UML_FSCMP(block, F0, mem(&m_core->fp0));
				if (MN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_MN);
				// TODO: MV, MU, MI flags

				UML_ICOPYFS(block, REG(fm), F0);
				UML_MOV(block, REG(fa), I0);
				return;

			case 0x1e:          // Fm = F3-0 * F7-4,   Fa = MAX(F11-8, F15-12)
				// TODO: denormals
				UML_FSCOPYI(block, F0, REG(fxm));
				UML_FSCOPYI(block, F1, REG(fym));
				UML_FSCOPYI(block, F2, REG(fxa));
				UML_FSCOPYI(block, F3, REG(fya));
				UML_FSMUL(block, F0, F0, F1);

				UML_FSMOV(block, F4, F2);
				UML_FSCMP(block, F2, F3);
				UML_FSMOVc(block, COND_C, F4, F3);

				if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
					UML_FSCMP(block, F4, mem(&m_core->fp0));
				if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
				if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN);
				if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);  // TODO
				if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
				if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
				if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO

				if (MN_CALC_REQUIRED)
					UML_FSCMP(block, F0, mem(&m_core->fp0));
				if (MN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_MN);
				// TODO: MV, MU, MI flags

				UML_ICOPYFS(block, REG(fm), F0);
				UML_ICOPYFS(block, REG(fa), F4);
				return;

			case 0x1f:          // Fm = F3-0 * F7-4,   Fa = MIN(F11-8, F15-12)
				// TODO: denormals
				UML_FSCOPYI(block, F0, REG(fxm));
				UML_FSCOPYI(block, F1, REG(fym));
				UML_FSCOPYI(block, F2, REG(fxa));
				UML_FSCOPYI(block, F3, REG(fya));
				UML_FSMUL(block, F0, F0, F1);

				UML_FSMOV(block, F4, F2);
				UML_FSCMP(block, F3, F2);
				UML_FSMOVc(block, COND_C, F4, F3);

				if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
					UML_FSCMP(block, F4, mem(&m_core->fp0));
				if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
				if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN);
				if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);  // TODO
				if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
				if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
				if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO

				if (MN_CALC_REQUIRED)
					UML_FSCMP(block, F0, mem(&m_core->fp0));
				if (MN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_MN);
				// TODO: MV, MU, MI flags

				UML_ICOPYFS(block, REG(fm), F0);
				UML_ICOPYFS(block, REG(fa), F4);
				return;

			default:
				generate_unimplemented_compute(block, compiler, desc);
				return;
		}
	}
	else                            // single-function operation
	{
		uint32_t operation = (opcode >> 12) & 0xff;

		switch ((opcode >> 20) & 3)
		{
			case 0:             // ALU operations
			{
				switch (operation)
				{
					case 0x09:      // Rn = (Rx + Ry) / 2
					case 0x63:      // Rn = CLIP Rx BY Ry
					case 0x92:      // Fn = ABS(Fx - Fy)
					case 0x89:      // Fn = (Fx + Fy) / 2
					case 0xdd:      // Rn = TRUNC Fx BY Ry
					case 0xe0:      // Fn = Fx COPYSIGN Fy
					case 0x05:      // Rn = Rx + Ry + CI
					case 0x06:      // Rn = Rx - Ry + CI - 1
					case 0x25:      // Rn = Rx + CI
					case 0x26:      // Rn = Rx + CI - 1
					case 0x30:      // Rn = ABS Rx
					case 0x43:      // Rn = NOT Rx
					case 0xa5:      // Fn = RND Fx
					case 0xad:      // Rn = MANT Fx
					case 0xcd:      // Rn = TRUNC Fx
						generate_unimplemented_compute(block, compiler, desc);
						return;

					case 0x01:      // Rn = Rx + Ry
						UML_ADD(block, REG(rn), REG(rx), REG(ry));
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_SETc(block, COND_V, ASTAT_AV);
						if (AC_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AC);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
						return;

					case 0x02:      // Rn = Rx - Ry
						UML_SUB(block, REG(rn), REG(rx), REG(ry));
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_SETc(block, COND_V, ASTAT_AV);
						if (AC_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AC);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
						return;

					case 0x0a:      // COMP(Rx, Ry)
						UML_CMP(block, REG(rx), REG(ry));
						UML_SETc(block, COND_Z, I0);
						UML_SETc(block, COND_L, I1);
						UML_MOV(block, ASTAT_AZ, I0);
						UML_MOV(block, ASTAT_AN, I1);
						UML_XOR(block, I0, I0, 1);
						UML_XOR(block, I1, I1, 1);
						UML_AND(block, I0, I0, I1);
						UML_SHL(block, I0, I0, 7);

						UML_MOV(block, I2, mem(&m_core->astat_drc.cacc));
						UML_SHR(block, I2, I2, 1);
						UML_OR(block, I2, I2, I0);
						UML_MOV(block, mem(&m_core->astat_drc.cacc), I2);

						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
						return;

					case 0x21:      // Rn = PASS Rx
						UML_MOV(block, REG(rn), REG(rx));
						if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
							UML_CMP(block, REG(rn), 0);
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
						return;

					case 0x22:      // Rn = -Rx
						UML_SUB(block, REG(rn), 0, REG(rx));
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_SETc(block, COND_V, ASTAT_AV);
						if (AC_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AC);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
						return;

					case 0x29:      // Rn = Rx + 1
						UML_ADD(block, REG(rn), REG(rx), 1);
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_SETc(block, COND_V, ASTAT_AV);
						if (AC_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AC);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
						return;

					case 0x2a:      // Rn = Rx - 1
						UML_SUB(block, REG(rn), REG(rx), 1);
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_SETc(block, COND_V, ASTAT_AV);
						if (AC_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AC);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
						return;

					case 0x40:      // Rn = Rx AND Ry
						UML_AND(block, REG(rn), REG(rx), REG(ry));
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
						return;

					case 0x41:      // Rn = Rx OR Ry
						UML_OR(block, REG(rn), REG(rx), REG(ry));
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
						return;

					case 0x42:      // Rn = Rx XOR Ry
						UML_XOR(block, REG(rn), REG(rx), REG(ry));
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
						return;

					case 0x61:      // Rn = MIN(Rx, Ry)
						UML_MOV(block, REG(rn), REG(rx));
						UML_CMP(block, REG(rx), REG(ry));
						UML_MOVc(block, COND_G, REG(rn), REG(ry));
						if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
							UML_CMP(block, REG(rn), 0);
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
						return;

					case 0x62:      // Rn = MAX(Rx, Ry)
						UML_MOV(block, REG(rn), REG(rx));
						UML_CMP(block, REG(rx), REG(ry));
						UML_MOVc(block, COND_L, REG(rn), REG(ry));
						if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
							UML_CMP(block, REG(rn), 0);
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
						return;

					case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
					case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:
					{
						/* Fixed-point Dual Add/Subtract */
						UML_ADD(block, I0, REG(rx), REG(ry));
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_SETc(block, COND_V, ASTAT_AV);
						if (AC_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AC);
						UML_SUB(block, I1, REG(rx), REG(ry));
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, mem(&m_core->arg0));
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, mem(&m_core->arg1));
						if (AV_CALC_REQUIRED) UML_SETc(block, COND_V, mem(&m_core->arg2));
						if (AC_CALC_REQUIRED) UML_SETc(block, COND_C, mem(&m_core->arg3));
						if (AZ_CALC_REQUIRED) UML_OR(block, ASTAT_AZ, ASTAT_AZ, mem(&m_core->arg0));
						if (AN_CALC_REQUIRED) UML_OR(block, ASTAT_AN, ASTAT_AN, mem(&m_core->arg1));
						if (AV_CALC_REQUIRED) UML_OR(block, ASTAT_AV, ASTAT_AV, mem(&m_core->arg2));
						if (AC_CALC_REQUIRED) UML_OR(block, ASTAT_AC, ASTAT_AC, mem(&m_core->arg3));
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
						UML_MOV(block, REG(ra), I0);
						UML_MOV(block, REG(rs), I1);
						return;
					}

					case 0x81:      // Fn = Fx + Fy
						// TODO: denormals
						UML_FSCOPYI(block, F0, REG(rx));
						UML_FSCOPYI(block, F1, REG(ry));
						UML_FSADD(block, F0, F0, F1);
						if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
							UML_FSCMP(block, F0, mem(&m_core->fp0));
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);  // TODO
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO
						UML_ICOPYFS(block, REG(rn), F0);
						return;

					case 0x82:      // Fn = Fx - Fy
						// TODO: denormals
						UML_FSCOPYI(block, F0, REG(rx));
						UML_FSCOPYI(block, F1, REG(ry));
						UML_FSSUB(block, F0, F0, F1);
						if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
							UML_FSCMP(block, F0, mem(&m_core->fp0));
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);  // TODO
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO
						UML_ICOPYFS(block, REG(rn), F0);
						return;

					case 0x8a:      // COMP(Fx, Fy)
						UML_FSCOPYI(block, F0, REG(rx));
						UML_FSCOPYI(block, F1, REG(ry));
						UML_FSCMP(block, F0, F1);
						UML_SETc(block, COND_Z, I0);
						UML_SETc(block, COND_C, I1);
						UML_MOV(block, ASTAT_AZ, I0);
						UML_MOV(block, ASTAT_AN, I1);
						UML_XOR(block, I0, I0, 1);
						UML_XOR(block, I1, I1, 1);
						UML_AND(block, I0, I0, I1);
						UML_SHL(block, I0, I0, 7);

						UML_MOV(block, I2, mem(&m_core->astat_drc.cacc));
						UML_SHR(block, I2, I2, 1);
						UML_OR(block, I2, I2, I0);
						UML_MOV(block, mem(&m_core->astat_drc.cacc), I2);

						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO
						return;

					case 0x91:      // Fn = ABS(Fx + Fy)
						// TODO: denormals
						UML_FSCOPYI(block, F0, REG(rx));
						UML_FSCOPYI(block, F1, REG(ry));
						UML_FSADD(block, F0, F0, F1);
						UML_FSABS(block, F0, F0);
						UML_ICOPYFS(block, REG(rn), F0);
						if (AZ_CALC_REQUIRED) UML_MOV(block, ASTAT_AZ, 0);  // TODO
						if (AN_CALC_REQUIRED) UML_MOV(block, ASTAT_AN, 0);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);  // TODO
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO
						return;

					case 0xa1:      // Fn = PASS Fx
						UML_MOV(block, REG(rn), REG(rx));
						if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
						{
							UML_FSCOPYI(block, F0, REG(rn));
							UML_FSCMP(block, F0, mem(&m_core->fp0));
						}
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO
						return;

					case 0xa2:      // Fn = -Fx
						UML_FSCOPYI(block, F0, REG(rx));
						UML_FSNEG(block, F0, F0);
						UML_ICOPYFS(block, REG(rn), F0);
						if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
							UML_FSCMP(block, F0, mem(&m_core->fp0));
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO
						return;

					case 0xb0:      // Fn = ABS(Fx)
						UML_FSCOPYI(block, F0, REG(rx));
						UML_FSABS(block, F0, F0);
						UML_ICOPYFS(block, REG(rn), F0);

						if (AZ_CALC_REQUIRED) UML_MOV(block, ASTAT_AZ, 0);  // TODO
						if (AN_CALC_REQUIRED) UML_MOV(block, ASTAT_AN, 0);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);  // TODO
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO
						return;

					case 0xbd:      // Fn = SCALB Fx BY Ry
						// TODO: source = nan, result = denormal
						UML_MOV(block, I1, REG(rx));
						UML_AND(block, I0, I1, 0x7f800000);
						UML_AND(block, I1, I1, 0x807fffff);
						UML_SHR(block, I0, I0, 23);
						UML_SUB(block, I0, I0, 127);
						UML_ADD(block, I0, I0, REG(ry));
						UML_ADD(block, I0, I0, 127);
						UML_AND(block, I0, I0, 0xff);
						UML_SHL(block, I0, I0, 23);
						UML_OR(block, REG(rn), I0, I1);
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);  // TODO
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO
						return;

					case 0xc1:      // Rn = LOGB Fx
						// TODO: source = zero, infinity, nan
						UML_SHR(block, I0, REG(rx), 23);
						UML_AND(block, I0, I0, 0xff);
						UML_SUB(block, REG(rn), I0, 127);
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);   // TODO
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
						return;

					case 0xc4:      // Fn = RECIPS Fx
						// TODO: denormals
						// TODO: use the bit accurate method from interpreter?
						UML_FSCOPYI(block, F0, REG(rx));
						if (AN_CALC_REQUIRED || AV_CALC_REQUIRED)
							UML_FSCMP(block, F0, mem(&m_core->fp0));
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AV);
						UML_FSCMP(block, F0, mem(&m_core->fp0));
						UML_JMPc(block, COND_Z, compiler->labelnum);
						UML_FSRECIP(block, F0, F0);
						UML_LABEL(block, compiler->labelnum++);
						if (AZ_CALC_REQUIRED)
							UML_FSCMP(block, F0, mem(&m_core->fp0));
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO
						UML_ICOPYFS(block, REG(rn), F0);
						return;

					case 0xc5:      // Fn = RSQRTS Fx
						// TODO: denormals
						// TODO: use the bit accurate method from interpreter?
						UML_FSCOPYI(block, F0, REG(rx));
						UML_FSCMP(block, F0, mem(&m_core->fp0));
						UML_JMPc(block, COND_Z, compiler->labelnum);
						UML_FSRSQRT(block, F0, F0);
						UML_LABEL(block, compiler->labelnum++);
						UML_ICOPYFS(block, REG(rn), F0);
						// TODO: flags!
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						return;

					case 0xca:      // Fn = FLOAT Rx
						UML_FSFRINT(block, F0, REG(rx), SIZE_DWORD);
						UML_ICOPYFS(block, REG(rn), F0);
						if (AZ_CALC_REQUIRED)
							UML_FSCMP(block, F0, mem(&m_core->fp0));
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN);
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
						return;

					case 0xc9:      // Rn = FIX Fx
						UML_FSCOPYI(block, F0, REG(rx));
						UML_TEST(block, MODE1, MODE1_TRUNCATE);
						UML_JMPc(block, COND_Z, compiler->labelnum);
						UML_FSTOINT(block, I0, F0, SIZE_DWORD, ROUND_TRUNC);
						UML_JMP(block, compiler->labelnum + 1);
						UML_LABEL(block, compiler->labelnum++);
						UML_FSTOINT(block, I0, F0, SIZE_DWORD, ROUND_ROUND);
						UML_LABEL(block, compiler->labelnum++);

						if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
							UML_CMP(block, I0, 0);
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);  // TODO
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO
						UML_MOV(block, REG(rn), I0);
						return;

					case 0xd9:      // Rn = FIX Fx BY Ry
					{
						code_label denormal = compiler->labelnum++;
						code_label end = compiler->labelnum++;

						UML_MOV(block, I1, REG(rx));
						UML_AND(block, I0, I1, 0x7f800000);
						UML_AND(block, I1, I1, 0x807fffff);
						UML_SHR(block, I0, I0, 23);
						UML_SUB(block, I0, I0, 127);
						UML_ADD(block, I0, I0, REG(ry));
						UML_CMP(block, I0, -126);
						UML_JMPc(block, COND_L, denormal);

						UML_ADD(block, I0, I0, 127);
						UML_AND(block, I0, I0, 0xff);
						UML_SHL(block, I0, I0, 23);
						UML_OR(block, I0, I0, I1);

						UML_FSCOPYI(block, F2, I0);
						UML_TEST(block, MODE1, MODE1_TRUNCATE);
						UML_JMPc(block, COND_Z, compiler->labelnum);
						UML_FSTOINT(block, I0, F2, SIZE_DWORD, ROUND_TRUNC);
						UML_JMP(block, compiler->labelnum + 1);
						UML_LABEL(block, compiler->labelnum++);
						UML_FSTOINT(block, I0, F2, SIZE_DWORD, ROUND_ROUND);
						UML_LABEL(block, compiler->labelnum++);

						if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
							UML_CMP(block, I0, 0);
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);  // TODO
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO
						UML_MOV(block, REG(rn), I0);
						UML_JMP(block, end);

						UML_LABEL(block, denormal);
						UML_AND(block, I0, I1, 0x80000000);
						if (AZ_CALC_REQUIRED) UML_MOV(block, ASTAT_AZ, 1);
						if (AN_CALC_REQUIRED) UML_MOV(block, ASTAT_AN, 0);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);   // TODO
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
						UML_MOV(block, REG(rn), I0);

						UML_LABEL(block, end);
						return;
					}

					case 0xda:      // Fn = FLOAT Rx BY Ry
					{
						code_label denormal = compiler->labelnum++;
						code_label end = compiler->labelnum++;
						UML_FSFRINT(block, F0, REG(rx), SIZE_DWORD);
						UML_ICOPYFS(block, I1, F0);
						UML_AND(block, I0, I1, 0x7f800000);
						UML_AND(block, I1, I1, 0x807fffff);
						UML_SHR(block, I0, I0, 23);
						UML_SUB(block, I0, I0, 127);
						UML_ADD(block, I0, I0, REG(ry));
						UML_CMP(block, I0, -126);
						UML_JMPc(block, COND_L, denormal);

						UML_ADD(block, I0, I0, 127);
						UML_AND(block, I0, I0, 0xff);
						UML_SHL(block, I0, I0, 23);
						UML_OR(block, REG(rn), I0, I1);
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);   // TODO
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
						UML_JMP(block, end);

						UML_LABEL(block, denormal);
						UML_AND(block, I0, I1, 0x80000000);
						if (AZ_CALC_REQUIRED) UML_MOV(block, ASTAT_AZ, 1);
						if (AN_CALC_REQUIRED) UML_MOV(block, ASTAT_AN, 0);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);   // TODO
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);
						UML_MOV(block, REG(rn), I0);

						UML_LABEL(block, end);
						return;
					}

					case 0xe1:      // Fn = MIN(Fx, Fy)
						UML_FSCOPYI(block, F2, REG(rx));
						UML_FSCOPYI(block, F3, REG(ry));
						UML_FSMOV(block, F4, F2);
						UML_FSCMP(block, F3, F2);
						UML_FSMOVc(block, COND_C, F4, F3);

						if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
							UML_FSCMP(block, F4, mem(&m_core->fp0));
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);  // TODO
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO
						UML_ICOPYFS(block, REG(rn), F4);
						return;

					case 0xe2:      // Fn = MAX(Fx, Fy)
						UML_FSCOPYI(block, F2, REG(rx));
						UML_FSCOPYI(block, F3, REG(ry));
						UML_FSMOV(block, F4, F2);
						UML_FSCMP(block, F2, F3);
						UML_FSMOVc(block, COND_C, F4, F3);

						if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
							UML_FSCMP(block, F4, mem(&m_core->fp0));
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);  // TODO
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO
						UML_ICOPYFS(block, REG(rn), F4);
						return;

					case 0xe3:      // Fn = CLIP Fx BY Fy
					{
						code_label label_1 = compiler->labelnum++;
						code_label label_2 = compiler->labelnum++;
						UML_FSCOPYI(block, F0, REG(rx));
						UML_FSCOPYI(block, F1, REG(ry));
						UML_FSABS(block, F1, F1);
						UML_FSCMP(block, F0, F1);
						UML_JMPc(block, COND_C, label_1);

						UML_FSCMP(block, F0, mem(&m_core->fp0));
						UML_JMPc(block, COND_C, label_2);
						UML_FSMOV(block, F0, F1);
						UML_JMP(block, label_1);
						UML_LABEL(block, label_2);
						UML_FSNEG(block, F0, F1);

						UML_LABEL(block, label_1);
						if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
							UML_FSCMP(block, F0, mem(&m_core->fp0));
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO
						UML_ICOPYFS(block, REG(rn), F0);
						return;
					}

					case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
					case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
					{
						/* Floating-point Dual Add/Subtract */
						UML_FSCOPYI(block, F0, REG(rx));
						UML_FSCOPYI(block, F1, REG(ry));
						UML_FSADD(block, F2, F0, F1);
						if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
							UML_FSCMP(block, F2, mem(&m_core->fp0));
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN);
						UML_FSSUB(block, F3, F0, F1);
						if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
							UML_FSCMP(block, F2, mem(&m_core->fp0));
						if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, I0);
						if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, I1);
						if (AZ_CALC_REQUIRED) UML_OR(block, ASTAT_AZ, ASTAT_AZ, I0);
						if (AN_CALC_REQUIRED) UML_OR(block, ASTAT_AN, ASTAT_AN, I1);
						if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);  // TODO
						if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
						if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
						if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0);  // TODO
						UML_ICOPYFS(block, REG(ra), F2);
						UML_ICOPYFS(block, REG(rs), F3);
						return;
					}

					default:
						generate_unimplemented_compute(block, compiler, desc);
						return;
				}
				break;
			}

			case 1:             // multiplier operations
			{
				switch (operation)
				{
					case 0x48:      // Rn = Rx * Ry (UUF)
					case 0x49:      // Rn = Rx * Ry (UUFR)
					case 0x50:      // Rn = Rx * Ry (SUI)
					case 0x58:      // Rn = Rx * Ry (SUF)
					case 0x59:      // Rn = Rx * Ry (SUFR)
					case 0x60:      // Rn = Rx * Ry (USI)
					case 0x68:      // Rn = Rx * Ry (USF)
					case 0x69:      // Rn = Rx * Ry (USFR)
					case 0x78:      // Rn = Rx * Ry (SSF)
					case 0x79:      // Rn = Rx * Ry (SSFR)
					case 0x44:      // MRF = Rx * Ry (UUI)
					case 0x4c:      // MRF = Rx * Ry (UUF)
					case 0x4d:      // MRF = Rx * Ry (UUFR)
					case 0x54:      // MRF = Rx * Ry (SUI)
					case 0x5c:      // MRF = Rx * Ry (SUF)
					case 0x5d:      // MRF = Rx * Ry (SUFR)
					case 0x64:      // MRF = Rx * Ry (USI)
					case 0x6c:      // MRF = Rx * Ry (USF)
					case 0x6d:      // MRF = Rx * Ry (USFR)
					case 0x74:      // MRF = Rx * Ry (SSI)
					case 0x7c:      // MRF = Rx * Ry (SSF)
					case 0x7d:      // MRF = Rx * Ry (SSFR)
					case 0x46:      // MRB = Rx * Ry (UUI)
					case 0x4e:      // MRB = Rx * Ry (UUF)
					case 0x4f:      // MRB = Rx * Ry (UUFR)
					case 0x56:      // MRB = Rx * Ry (SUI)
					case 0x5e:      // MRB = Rx * Ry (SUF)
					case 0x5f:      // MRB = Rx * Ry (SUFR)
					case 0x66:      // MRB = Rx * Ry (USI)
					case 0x6e:      // MRB = Rx * Ry (USF)
					case 0x6f:      // MRB = Rx * Ry (USFR)
					case 0x76:      // MRB = Rx * Ry (SSI)
					case 0x7e:      // MRB = Rx * Ry (SSF)
					case 0x7f:      // MRB = Rx * Ry (SSFR)
					case 0x80:      // Rn = MRF + Rx * Ry (UUI)
					case 0x88:      // Rn = MRF + Rx * Ry (UUF)
					case 0x89:      // Rn = MRF + Rx * Ry (UUFR)
					case 0x90:      // Rn = MRF + Rx * Ry (SUI)
					case 0x98:      // Rn = MRF + Rx * Ry (SUF)
					case 0x99:      // Rn = MRF + Rx * Ry (SUFR)
					case 0xa0:      // Rn = MRF + Rx * Ry (USI)
					case 0xa8:      // Rn = MRF + Rx * Ry (USF)
					case 0xa9:      // Rn = MRF + Rx * Ry (USFR)
					case 0xb8:      // Rn = MRF + Rx * Ry (SSF)
					case 0xb9:      // Rn = MRF + Rx * Ry (SSFR)
					case 0x82:      // Rn = MRB + Rx * Ry (UUI)
					case 0x8a:      // Rn = MRB + Rx * Ry (UUF)
					case 0x8b:      // Rn = MRB + Rx * Ry (UUFR)
					case 0x92:      // Rn = MRB + Rx * Ry (SUI)
					case 0x9a:      // Rn = MRB + Rx * Ry (SUF)
					case 0x9b:      // Rn = MRB + Rx * Ry (SUFR)
					case 0xa2:      // Rn = MRB + Rx * Ry (USI)
					case 0xaa:      // Rn = MRB + Rx * Ry (USF)
					case 0xab:      // Rn = MRB + Rx * Ry (USFR)
					case 0xba:      // Rn = MRB + Rx * Ry (SSF)
					case 0xbb:      // Rn = MRB + Rx * Ry (SSFR)
					case 0x84:      // MRF = MRF + Rx * Ry (UUI)
					case 0x8c:      // MRF = MRF + Rx * Ry (UUF)
					case 0x8d:      // MRF = MRF + Rx * Ry (UUFR)
					case 0x94:      // MRF = MRF + Rx * Ry (SUI)
					case 0x9c:      // MRF = MRF + Rx * Ry (SUF)
					case 0x9d:      // MRF = MRF + Rx * Ry (SUFR)
					case 0xa4:      // MRF = MRF + Rx * Ry (USI)
					case 0xac:      // MRF = MRF + Rx * Ry (USF)
					case 0xad:      // MRF = MRF + Rx * Ry (USFR)
					case 0xb4:      // MRF = MRF + Rx * Ry (SSI)
					case 0xbc:      // MRF = MRF + Rx * Ry (SSF)
					case 0xbd:      // MRF = MRF + Rx * Ry (SSFR)
					case 0x86:      // MRB = MRB + Rx * Ry (UUI)
					case 0x8e:      // MRB = MRB + Rx * Ry (UUF)
					case 0x8f:      // MRB = MRB + Rx * Ry (UUFR)
					case 0x96:      // MRB = MRB + Rx * Ry (SUI)
					case 0x9e:      // MRB = MRB + Rx * Ry (SUF)
					case 0x9f:      // MRB = MRB + Rx * Ry (SUFR)
					case 0xa6:      // MRB = MRB + Rx * Ry (USI)
					case 0xae:      // MRB = MRB + Rx * Ry (USF)
					case 0xaf:      // MRB = MRB + Rx * Ry (USFR)
					case 0xb6:      // MRB = MRB + Rx * Ry (SSI)
					case 0xbe:      // MRB = MRB + Rx * Ry (SSF)
					case 0xbf:      // MRB = MRB + Rx * Ry (SSFR)
					case 0xc0:      // Rn = MRF - Rx * Ry (UUI)
					case 0xc8:      // Rn = MRF - Rx * Ry (UUF)
					case 0xc9:      // Rn = MRF - Rx * Ry (UUFR)
					case 0xd0:      // Rn = MRF - Rx * Ry (SUI)
					case 0xd8:      // Rn = MRF - Rx * Ry (SUF)
					case 0xd9:      // Rn = MRF - Rx * Ry (SUFR)
					case 0xe0:      // Rn = MRF - Rx * Ry (USI)
					case 0xe8:      // Rn = MRF - Rx * Ry (USF)
					case 0xe9:      // Rn = MRF - Rx * Ry (USFR)
					case 0xf0:      // Rn = MRF - Rx * Ry (SSI)
					case 0xf8:      // Rn = MRF - Rx * Ry (SSF)
					case 0xf9:      // Rn = MRF - Rx * Ry (SSFR)
					case 0xc2:      // Rn = MRB - Rx * Ry (UUI)
					case 0xca:      // Rn = MRB - Rx * Ry (UUF)
					case 0xcb:      // Rn = MRB - Rx * Ry (UUFR)
					case 0xd2:      // Rn = MRB - Rx * Ry (SUI)
					case 0xda:      // Rn = MRB - Rx * Ry (SUF)
					case 0xdb:      // Rn = MRB - Rx * Ry (SUFR)
					case 0xe2:      // Rn = MRB - Rx * Ry (USI)
					case 0xea:      // Rn = MRB - Rx * Ry (USF)
					case 0xeb:      // Rn = MRB - Rx * Ry (USFR)
					case 0xf2:      // Rn = MRB - Rx * Ry (SSI)
					case 0xfa:      // Rn = MRB - Rx * Ry (SSF)
					case 0xfb:      // Rn = MRB - Rx * Ry (SSFR)
					case 0xc4:      // MRF = MRF - Rx * Ry (UUI)
					case 0xcc:      // MRF = MRF - Rx * Ry (UUF)
					case 0xcd:      // MRF = MRF - Rx * Ry (UUFR)
					case 0xd4:      // MRF = MRF - Rx * Ry (SUI)
					case 0xdc:      // MRF = MRF - Rx * Ry (SUF)
					case 0xdd:      // MRF = MRF - Rx * Ry (SUFR)
					case 0xe4:      // MRF = MRF - Rx * Ry (USI)
					case 0xec:      // MRF = MRF - Rx * Ry (USF)
					case 0xed:      // MRF = MRF - Rx * Ry (USFR)
					case 0xf4:      // MRF = MRF - Rx * Ry (SSI)
					case 0xfc:      // MRF = MRF - Rx * Ry (SSF)
					case 0xfd:      // MRF = MRF - Rx * Ry (SSFR)
					case 0xc6:      // MRB = MRB - Rx * Ry (UUI)
					case 0xce:      // MRB = MRB - Rx * Ry (UUF)
					case 0xcf:      // MRB = MRB - Rx * Ry (UUFR)
					case 0xd6:      // MRB = MRB - Rx * Ry (SUI)
					case 0xde:      // MRB = MRB - Rx * Ry (SUF)
					case 0xdf:      // MRB = MRB - Rx * Ry (SUFR)
					case 0xe6:      // MRB = MRB - Rx * Ry (USI)
					case 0xee:      // MRB = MRB - Rx * Ry (USF)
					case 0xef:      // MRB = MRB - Rx * Ry (USFR)
					case 0xf6:      // MRB = MRB - Rx * Ry (SSI)
					case 0xfe:      // MRB = MRB - Rx * Ry (SSF)
					case 0xff:      // MRB = MRB - Rx * Ry (SSFR)
					case 0x00:      // Rn = SAT MRF (UI)
					case 0x01:      // Rn = SAT MRF (SI)
					case 0x08:      // Rn = SAT MRF (UF)
					case 0x09:      // Rn = SAT MRF (SF)
					case 0x02:      // Rn = SAT MRB (UI)
					case 0x03:      // Rn = SAT MRB (SI)
					case 0x0a:      // Rn = SAT MRB (UF)
					case 0x0b:      // Rn = SAT MRB (SF)
					case 0x04:      // MRF = SAT MRF (UI)
					case 0x05:      // MRF = SAT MRF (SI)
					case 0x0c:      // MRF = SAT MRF (UF)
					case 0x0d:      // MRF = SAT MRF (SF)
					case 0x06:      // MRB = SAT MRB (UI)
					case 0x07:      // MRB = SAT MRB (SI)
					case 0x0e:      // MRB = SAT MRB (UF)
					case 0x0f:      // MRB = SAT MRB (SF)
					case 0x18:      // Rn = RND MRF (U)
					case 0x19:      // Rn = RND MRF (S)
					case 0x1a:      // Rn = RND MRB (U)
					case 0x1b:      // Rn = RND MRB (S)
					case 0x1c:      // MRF = RND MRF (U)
					case 0x1d:      // MRF = RND MRF (S)
					case 0x1e:      // MRB = RND MRB (U)
					case 0x1f:      // MRB = RND MRB (S)
						generate_unimplemented_compute(block, compiler, desc);
						return;

					case 0x14:      // MRF = 0
						UML_DMOV(block, mem(&m_core->mrf), 0);
						if (MN_CALC_REQUIRED) UML_MOV(block, ASTAT_MN, 0);
						if (MV_CALC_REQUIRED) UML_MOV(block, ASTAT_MV, 0);
						if (MU_CALC_REQUIRED) UML_MOV(block, ASTAT_MU, 0);
						if (MI_CALC_REQUIRED) UML_MOV(block, ASTAT_MI, 0);
						return;

					case 0x16:      // MRB = 0
						UML_DMOV(block, mem(&m_core->mrb), 0);
						if (MN_CALC_REQUIRED) UML_MOV(block, ASTAT_MN, 0);
						if (MV_CALC_REQUIRED) UML_MOV(block, ASTAT_MV, 0);
						if (MU_CALC_REQUIRED) UML_MOV(block, ASTAT_MU, 0);
						if (MI_CALC_REQUIRED) UML_MOV(block, ASTAT_MI, 0);
						return;

					case 0x30:      // Fn = Fx * Fy
						UML_FSCOPYI(block, F0, REG(rx));
						UML_FSCOPYI(block, F1, REG(ry));
						UML_FSMUL(block, F0, F0, F1);
						UML_ICOPYFS(block, REG(rn), F0);
						if (MN_CALC_REQUIRED)
							UML_FSCMP(block, F0, mem(&m_core->fp0));
						if (MN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_MN);
						// TODO: MV, MU, MI flags
						return;

					case 0x40:      // Rn = Rx * Ry (UUI)
						UML_MULU(block, I0, I0, REG(rx), REG(ry));
						UML_MOV(block, REG(rn), I0);
						// TODO: flags
						return;

					case 0x70:      // Rn = Rx * Ry (SSI)
						UML_MULS(block, I0, I0, REG(rx), REG(ry));
						UML_MOV(block, REG(rn), I0);
						// TODO: flags
						return;

					case 0xb0:      // Rn = MRF + Rx * Ry (SSI)
						UML_DSEXT(block, I0, REG(rx), SIZE_DWORD);
						UML_DSEXT(block, I1, REG(ry), SIZE_DWORD);
						UML_DMULS(block, I0, I0, I0, I1);
						UML_DADD(block, I0, I0, mem(&m_core->mrf));
						UML_MOV(block, REG(rn), I0);
						// TODO: flags!
						return;

					case 0xb2:      // Rn = MRB + Rx * Ry (SSI)
						UML_DSEXT(block, I0, REG(rx), SIZE_DWORD);
						UML_DSEXT(block, I1, REG(ry), SIZE_DWORD);
						UML_DMULS(block, I0, I0, I0, I1);
						UML_DADD(block, I0, I0, mem(&m_core->mrb));
						UML_MOV(block, REG(rn), I0);
						// TODO: flags!
						return;

					default:
						generate_unimplemented_compute(block, compiler, desc);
						return;
				}
				break;
			}

			case 2:             // shifter operations
			{
				switch (operation)
				{
					case 0x04:      // Rn = ASHIFT Rx BY Ry | <data8>
					case 0x44:      // Rn = FDEP Rx BY Ry | <bit6>:<len6>
					case 0x4c:      // Rn = FDEP Rx BY Ry | <bit6>:<len6> (SE)
					case 0x24:      // Rn = Rn OR ASHIFT Rx BY Ry | <data8>
					case 0x6c:      // Rn = Rn OR FDEP Rx BY Ry | <bit6>:<len6> (SE)
					case 0x80:      // Rn = EXP Rx
					case 0x84:      // Rn = EXP Rx (EX)
					case 0x88:      // Rn = LEFTZ Rx
					case 0x8c:      // Rn = LEFTO Rx
					case 0x90:      // Rn = FPACK Fx
					case 0x94:      // Fn = FUNPACK Rx
						generate_unimplemented_compute(block, compiler, desc);
						return;

					case 0x00:      // Rn = LSHIFT Rx BY Ry | <data8>
					{
						code_label shift_neg = compiler->labelnum++;
						code_label shift_end = compiler->labelnum++;

						UML_MOV(block, I0, REG(ry));
						UML_CMP(block, I0, 0);
						UML_JMPc(block, COND_L, shift_neg);
						UML_SHR(block, I1, REG(rx), I0);
						UML_JMP(block, shift_end);
						UML_LABEL(block, shift_neg);
						UML_SUB(block, I2, 0, I0);
						UML_SHR(block, I1, REG(rx), I2);
						UML_LABEL(block, shift_end);
						if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
						if (SV_CALC_REQUIRED)
						{
							UML_CMP(block, I0, 0);
							UML_SETc(block, COND_NE, ASTAT_AV);
						}
						if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
						UML_MOV(block, REG(rn), I1);
						return;
					}

					case 0x08:      // Rn = ROT Rx BY Ry | <data8>
					{
						code_label shift_neg = compiler->labelnum++;
						code_label shift_end = compiler->labelnum++;

						UML_MOV(block, I0, REG(ry));
						UML_CMP(block, I0, 0);
						UML_JMPc(block, COND_L, shift_neg);
						UML_ROL(block, I1, REG(rx), I0);
						UML_JMP(block, shift_end);
						UML_LABEL(block, shift_neg);
						UML_SUB(block, I2, 0, I0);
						UML_ROR(block, I1, REG(rx), I2);
						UML_LABEL(block, shift_end);
						if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
						if (SV_CALC_REQUIRED) UML_MOV(block, ASTAT_SV, 0);
						if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
						UML_MOV(block, REG(rn), I1);
						return;
					}

					case 0x20:      // Rn = Rn OR LSHIFT Rx BY Ry | <data8>
					{
						code_label shift_neg = compiler->labelnum++;
						code_label shift_end = compiler->labelnum++;

						UML_MOV(block, I0, REG(ry));
						UML_CMP(block, I0, 0);
						UML_JMPc(block, COND_L, shift_neg);
						UML_SHL(block, I1, REG(rx), I0);
						UML_JMP(block, shift_end);
						UML_LABEL(block, shift_neg);
						UML_SUB(block, I2, 0, I0);
						UML_SHR(block, I1, REG(rx), I2);
						UML_LABEL(block, shift_end);
						if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
						if (SV_CALC_REQUIRED)
						{
							UML_CMP(block, I0, 0);
							UML_SETc(block, COND_NZ, ASTAT_SV);
						}
						if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
						UML_OR(block, REG(rn), REG(rn), I1);

						return;
					}

					case 0x40:      // Rn = FEXT Rx BY Ry | <bit6>:<len6>
						// extraction mask
						UML_MOV(block, I0, REG(ry));
						UML_SHR(block, I1, I0, 6);
						UML_AND(block, I1, I1, 0x3f);   // i1 = len6
						UML_AND(block, I0, I0, 0x3f);   // i0 = bit6
						UML_MOV(block, I3, 0xffffffff);
						UML_SUB(block, I2, 32, I1);
						UML_SHR(block, I3, I3, I2);
						UML_SHL(block, I3, I3, I0);

						UML_AND(block, I2, REG(rx), I3);
						UML_SHR(block, REG(rn), I2, I0);
						if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
						if (SV_CALC_REQUIRED)
						{
							UML_ADD(block, I0, I0, I1);
							UML_CMP(block, I0, 32);
							UML_SETc(block, COND_G, ASTAT_SV);
						}
						if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
						return;

					case 0x48:      // Rn = FEXT Rx BY Ry | <bit6>:<len6> (SE)
						// extraction mask
						UML_MOV(block, I0, REG(ry));
						UML_SHR(block, I1, I0, 6);
						UML_AND(block, I1, I1, 0x3f);   // i1 = len6
						UML_AND(block, I0, I0, 0x3f);   // i0 = bit6
						UML_MOV(block, I3, 0xffffffff);
						UML_SUB(block, I2, 32, I1);
						UML_SHR(block, I3, I3, I2);
						UML_SHL(block, I3, I3, I0);

						UML_AND(block, I3, REG(rx), I3);

						UML_ADD(block, I2, I0, I1);
						UML_SUB(block, I2, 32, I2);
						UML_SHL(block, I3, I3, I2);
						UML_ADD(block, I2, I2, I0);
						UML_SAR(block, REG(rn), I3, I2);

						if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
						if (SV_CALC_REQUIRED)
						{
							UML_ADD(block, I0, I0, I1);
							UML_CMP(block, I0, 32);
							UML_SETc(block, COND_G, ASTAT_SV);
						}
						if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
						return;

					case 0x64:      // Rn = Rn OR FDEP Rx BY Ry | <bit6>:<len6>
						// extraction mask
						UML_MOV(block, I0, REG(ry));
						UML_SHR(block, I1, I0, 6);
						UML_AND(block, I1, I1, 0x3f);   // i1 = len6
						UML_AND(block, I0, I0, 0x3f);   // i0 = bit6
						UML_MOV(block, I3, 0xffffffff);
						UML_SUB(block, I2, 32, I1);
						UML_SHR(block, I3, I3, I2);

						UML_AND(block, I3, REG(rx), I3);
						UML_SHL(block, I3, I3, I0);
						UML_OR(block, REG(rn), REG(rn), I3);
						if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
						if (SV_CALC_REQUIRED)
						{
							UML_ADD(block, I0, I0, I1);
							UML_CMP(block, I0, 32);
							UML_SETc(block, COND_G, ASTAT_SV);
						}
						if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
						return;

					case 0xc0:      // Rn = BSET Rx BY Ry | <data8>
					{
						UML_MOV(block, I0, REG(ry));
						UML_SHL(block, I1, 1, I0);
						UML_OR(block, REG(rn), REG(rn), I1);
						if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
						if (SV_CALC_REQUIRED)
						{
							UML_CMP(block, I0, 31);
							UML_SETc(block, COND_G, ASTAT_SV);
						}
						if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
						return;
					}

					case 0xc4:      // Rn = BCLR Rx BY Ry | <data8>
					{
						UML_MOV(block, I0, REG(ry));
						UML_SHL(block, I1, 1, I0);
						UML_XOR(block, I1, I1, 0xffffffff);
						UML_AND(block, REG(rn), REG(rn), I1);
						if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
						if (SV_CALC_REQUIRED)
						{
							UML_CMP(block, I0, 31);
							UML_SETc(block, COND_G, ASTAT_SV);
						}
						if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
						return;
					}

					case 0xcc:      // BTST Rx BY Ry | <data8>
					{
						UML_MOV(block, I0, REG(ry));
						UML_SHL(block, I1, 1, I0);
						UML_TEST(block, REG(rx), I1);
						if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
						if (SV_CALC_REQUIRED)
							UML_CMP(block, I0, 31);
						if (SV_CALC_REQUIRED) UML_SETc(block, COND_G, ASTAT_SV);
						if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
						return;
					}

					default:
						generate_unimplemented_compute(block, compiler, desc);
						return;
				}
				break;
			}

			default:
				generate_unimplemented_compute(block, compiler, desc);
				return;
		}
	}
}

void adsp21062_device::generate_if_condition(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int condition, int skip_label)
{
	// Jump to skip_label if condition is not true
	code_label not_skip;

	switch (condition)
	{
		case 0x00:                                    /* EQ */
			UML_TEST(block, ASTAT_AZ, 1);
			UML_JMPc(block, COND_E, skip_label);
			break;
		case 0x01:                                    /* LT */
			UML_TEST(block, ASTAT_AZ, 1);
			UML_JMPc(block, COND_NE, skip_label);
			UML_TEST(block, ASTAT_AN, 1);
			UML_JMPc(block, COND_E, skip_label);
			break;
		case 0x02:                                    /* LE */
			not_skip = compiler->labelnum++;
			UML_TEST(block, ASTAT_AZ, 1);
			UML_JMPc(block, COND_NZ, not_skip);
			UML_TEST(block, ASTAT_AN, 1);
			UML_JMPc(block, COND_NZ, not_skip);
			UML_JMP(block, skip_label);
			UML_LABEL(block, not_skip);
			break;
		case 0x03:                                    /* AC */
			UML_TEST(block, ASTAT_AC, 1);
			UML_JMPc(block, COND_E, skip_label);
			break;
		case 0x04:                                    /* AV */
			UML_TEST(block, ASTAT_AV, 1);
			UML_JMPc(block, COND_E, skip_label);
			break;
		case 0x05:                                    /* MV */
			UML_TEST(block, ASTAT_MV, 1);
			UML_JMPc(block, COND_E, skip_label);
			break;
		case 0x06:                                    /* MS */
			UML_TEST(block, ASTAT_MN, 1);
			UML_JMPc(block, COND_E, skip_label);
			break;
		case 0x07:                                    /* SV */
			UML_TEST(block, ASTAT_SV, 1);
			UML_JMPc(block, COND_E, skip_label);
			break;
		case 0x08:                                    /* SZ */
			UML_TEST(block, ASTAT_SZ, 1);
			UML_JMPc(block, COND_E, skip_label);
			break;
		case 0x09:                                    /* FLAG0 */
			UML_CMP(block, FLAG0, 0);
			UML_JMPc(block, COND_E, skip_label);
			break;
		case 0x0a:                                    /* FLAG1 */
			UML_CMP(block, FLAG1, 0);
			UML_JMPc(block, COND_E, skip_label);
			break;
		case 0x0b:                                    /* FLAG2 */
			UML_CMP(block, FLAG2, 0);
			UML_JMPc(block, COND_E, skip_label);
			break;
		case 0x0c:                                    /* FLAG3 */
			UML_CMP(block, FLAG3, 0);
			UML_JMPc(block, COND_E, skip_label);
			break;
		case 0x0d:                                    /* TF */
			UML_TEST(block, ASTAT_BTF, 1);
			UML_JMPc(block, COND_E, skip_label);
			break;
		case 0x0e:                                    /* BM */
			UML_JMP(block, skip_label);
			break;
		case 0x0f:                                    /* NOT LCE */
			UML_CMP(block, CURLCNTR, 1);
			UML_JMPc(block, COND_E, skip_label);
			break;
		case 0x10:                                    /* NOT EQUAL */
			UML_TEST(block, ASTAT_AZ, 1);
			UML_JMPc(block, COND_NE, skip_label);
			break;
		case 0x11:                                    /* GE */
			not_skip = compiler->labelnum++;
			UML_TEST(block, ASTAT_AZ, 1);
			UML_JMPc(block, COND_NZ, not_skip);
			UML_TEST(block, ASTAT_AN, 1);
			UML_JMPc(block, COND_Z, not_skip);
			UML_JMP(block, skip_label);
			UML_LABEL(block, not_skip);
			break;
		case 0x12:                                    /* GT */
			UML_TEST(block, ASTAT_AZ, 1);
			UML_JMPc(block, COND_NZ, skip_label);
			UML_TEST(block, ASTAT_AN, 1);
			UML_JMPc(block, COND_NZ, skip_label);
			break;
		case 0x13:                                    /* NOT AC */
			UML_TEST(block, ASTAT_AC, 1);
			UML_JMPc(block, COND_NE, skip_label);
			break;
		case 0x14:                                    /* NOT AV */
			UML_TEST(block, ASTAT_AV, 1);
			UML_JMPc(block, COND_NE, skip_label);
			break;
		case 0x15:                                    /* NOT MV */
			UML_TEST(block, ASTAT_MV, 1);
			UML_JMPc(block, COND_NE, skip_label);
			break;
		case 0x16:                                    /* NOT MS */
			UML_TEST(block, ASTAT_MN, 1);
			UML_JMPc(block, COND_NE, skip_label);
			break;
		case 0x17:                                    /* NOT SV */
			UML_TEST(block, ASTAT_SV, 1);
			UML_JMPc(block, COND_NE, skip_label);
			break;
		case 0x18:                                    /* NOT SZ */
			UML_TEST(block, ASTAT_SZ, 1);
			UML_JMPc(block, COND_NE, skip_label);
			break;
		case 0x19:                                    /* NOT FLAG0 */
			UML_CMP(block, FLAG0, 0);
			UML_JMPc(block, COND_NE, skip_label);
			break;
		case 0x1a:                                    /* NOT FLAG1 */
			UML_CMP(block, FLAG1, 0);
			UML_JMPc(block, COND_NE, skip_label);
			break;
		case 0x1b:                                    /* NOT FLAG2 */
			UML_CMP(block, FLAG2, 0);
			UML_JMPc(block, COND_NE, skip_label);
			break;
		case 0x1c:                                    /* NOT FLAG3 */
			UML_CMP(block, FLAG3, 0);
			UML_JMPc(block, COND_NE, skip_label);
			break;
		case 0x1d:                                    /* NOT TF */
			UML_TEST(block, ASTAT_BTF, 1);
			UML_JMPc(block, COND_NE, skip_label);
			break;
		case 0x1e:                                    /* NOT BM */
			fatalerror("generate_if_condition 0x1e"); // should not happen
			break;
		case 0x1f:                                    /* true */
			fatalerror("generate_if_condition 0x1f"); // should not happen
			break;
	}
}

void adsp21062_device::generate_do_condition(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int condition, int skip_label, ASTAT_DRC &astat)
{
	// Jump to skip_label if condition is true
	code_label not_skip;

	switch (condition)
	{
		case 0x00:                                    /* EQ */
			UML_TEST(block, mem(&m_core->astat_delay_copy.az), 1);
			UML_JMPc(block, COND_NZ, skip_label);
			break;
		case 0x01:                                    /* LT */
			not_skip = compiler->labelnum++;
			UML_TEST(block, mem(&m_core->astat_delay_copy.az), 1);
			UML_JMPc(block, COND_NZ, not_skip);
			UML_TEST(block, mem(&m_core->astat_delay_copy.an), 1);
			UML_JMPc(block, COND_Z, not_skip);
			UML_JMP(block, skip_label);
			UML_LABEL(block, not_skip);
			break;
		case 0x02:                                    /* LE */
			UML_TEST(block, mem(&m_core->astat_delay_copy.az), 1);
			UML_JMPc(block, COND_NZ, skip_label);
			UML_TEST(block, mem(&m_core->astat_delay_copy.an), 1);
			UML_JMPc(block, COND_NZ, skip_label);
			break;
		case 0x03:                                    /* AC */
			UML_TEST(block, mem(&m_core->astat_delay_copy.ac), 1);
			UML_JMPc(block, COND_NZ, skip_label);
			break;
		case 0x04:                                    /* AV */
			UML_TEST(block, mem(&m_core->astat_delay_copy.av), 1);
			UML_JMPc(block, COND_NZ, skip_label);
			break;
		case 0x05:                                    /* MV */
			UML_TEST(block, mem(&m_core->astat_delay_copy.mv), 1);
			UML_JMPc(block, COND_NZ, skip_label);
			break;
		case 0x06:                                    /* MS */
			UML_TEST(block, mem(&m_core->astat_delay_copy.mn), 1);
			UML_JMPc(block, COND_NZ, skip_label);
			break;
		case 0x07:                                    /* SV */
			UML_TEST(block, mem(&m_core->astat_delay_copy.sv), 1);
			UML_JMPc(block, COND_NZ, skip_label);
			break;
		case 0x08:                                    /* SZ */
			UML_TEST(block, mem(&m_core->astat_delay_copy.sz), 1);
			UML_JMPc(block, COND_NZ, skip_label);
			break;
		case 0x09:                                    /* FLAG0 */
			UML_CMP(block, FLAG0, 0);
			UML_JMPc(block, COND_NE, skip_label);
			break;
		case 0x0a:                                    /* FLAG1 */
			UML_CMP(block, FLAG1, 0);
			UML_JMPc(block, COND_NE, skip_label);
			break;
		case 0x0b:                                    /* FLAG2 */
			UML_CMP(block, FLAG2, 0);
			UML_JMPc(block, COND_NE, skip_label);
			break;
		case 0x0c:                                    /* FLAG3 */
			UML_CMP(block, FLAG3, 0);
			UML_JMPc(block, COND_NE, skip_label);
			break;
		case 0x0d:                                    /* TF */
			UML_TEST(block, mem(&m_core->astat_delay_copy.btf), 1);
			UML_JMPc(block, COND_NZ, skip_label);
			break;
		case 0x0e:                                    /* BM */
			// infinite loop
			break;
		case 0x0f:                                    /* LCE */
			fatalerror("generate_do_condition 0x0f");   // this should only be used with counter loops
			break;
		case 0x10:                                    /* NOT EQUAL */
			UML_TEST(block, mem(&m_core->astat_delay_copy.az), 1);
			UML_JMPc(block, COND_Z, skip_label);
			break;
		case 0x11:                                    /* GE */
			UML_TEST(block, mem(&m_core->astat_delay_copy.az), 1);
			UML_JMPc(block, COND_NZ, skip_label);
			UML_TEST(block, mem(&m_core->astat_delay_copy.an), 1);
			UML_JMPc(block, COND_Z, skip_label);
			break;
		case 0x12:                                    /* GT */
			not_skip = compiler->labelnum++;
			UML_TEST(block, mem(&m_core->astat_delay_copy.az), 1);
			UML_JMPc(block, COND_NZ, not_skip);
			UML_TEST(block, mem(&m_core->astat_delay_copy.an), 1);
			UML_JMPc(block, COND_NZ, not_skip);
			UML_JMP(block, skip_label);
			UML_LABEL(block, not_skip);
			break;
		case 0x13:                                    /* NOT AC */
			UML_TEST(block, mem(&m_core->astat_delay_copy.ac), 1);
			UML_JMPc(block, COND_Z, skip_label);
			break;
		case 0x14:                                    /* NOT AV */
			UML_TEST(block, mem(&m_core->astat_delay_copy.av), 1);
			UML_JMPc(block, COND_Z, skip_label);
			break;
		case 0x15:                                    /* NOT MV */
			UML_TEST(block, mem(&m_core->astat_delay_copy.mv), 1);
			UML_JMPc(block, COND_Z, skip_label);
			break;
		case 0x16:                                    /* NOT MS */
			UML_TEST(block, mem(&m_core->astat_delay_copy.mn), 1);
			UML_JMPc(block, COND_Z, skip_label);
			break;
		case 0x17:                                    /* NOT SV */
			UML_TEST(block, mem(&m_core->astat_delay_copy.sv), 1);
			UML_JMPc(block, COND_Z, skip_label);
			break;
		case 0x18:                                    /* NOT SZ */
			UML_TEST(block, mem(&m_core->astat_delay_copy.sz), 1);
			UML_JMPc(block, COND_Z, skip_label);
			break;
		case 0x19:                                    /* NOT FLAG0 */
			UML_CMP(block, FLAG0, 0);
			UML_JMPc(block, COND_E, skip_label);
			break;
		case 0x1a:                                    /* NOT FLAG1 */
			UML_CMP(block, FLAG1, 0);
			UML_JMPc(block, COND_E, skip_label);
			break;
		case 0x1b:                                    /* NOT FLAG2 */
			UML_CMP(block, FLAG2, 0);
			UML_JMPc(block, COND_E, skip_label);
			break;
		case 0x1c:                                    /* NOT FLAG3 */
			UML_CMP(block, FLAG3, 0);
			UML_JMPc(block, COND_E, skip_label);
			break;
		case 0x1d:                                    /* NOT TF */
			UML_TEST(block, mem(&m_core->astat_delay_copy.btf), 1);
			UML_JMPc(block, COND_Z, skip_label);
			break;
		case 0x1e:                                    /* NOT BM */
			// always true
			UML_JMP(block, skip_label);
			break;
		case 0x1f:                                    /* false (FOREVER) */
			// infinite loop
			break;
	}
}

void adsp21062_device::generate_shift_imm(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int data, int shiftop, int rn, int rx)
{
	int8_t shift = data & 0xff;
	int bit = data & 0x3f;
	int len = (data >> 6) & 0x3f;

	switch (shiftop)
	{
		case 0x11:      // FDEP Rx BY <bit6>:<len6>
		case 0x13:      // FDEP Rx BY <bit6>:<len6> (SE)
		case 0x1b:      // Rn = Rn OR FDEP Rx BY <bit6>:<len6> (SE)
			UML_MOV(block, mem(&m_core->pc), desc->pc);
			UML_DMOV(block, mem(&m_core->arg64), desc->opptr.q[0]);
			UML_CALLC(block, cfunc_unimplemented_shiftimm, this);
			break;

		case 0x00:      // LSHIFT Rx BY <data8>
			if (abs(shift) >= 32)
			{
				UML_MOV(block, REG(rn), 0);
				if (SZ_CALC_REQUIRED) UML_MOV(block, ASTAT_SZ, 1);
				if (SV_CALC_REQUIRED) UML_MOV(block, ASTAT_SV, 1);
				if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
			}
			else
			{
				if (shift < 0)
					UML_SHR(block, REG(rn), REG(rx), -shift);
				else
					UML_SHL(block, REG(rn), REG(rx), shift);
				if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
				if (SV_CALC_REQUIRED && shift != 0) UML_MOV(block, ASTAT_SV, 1);
				if (SV_CALC_REQUIRED && shift == 0) UML_MOV(block, ASTAT_SV, 0);
				if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
			}
			return;

		case 0x01:      // ASHIFT Rx BY <data8>
			if (abs(shift) >= 32)
			{
				UML_MOV(block, REG(rn), 0);
				UML_TEST(block, REG(rn), 0x80000000);
				UML_MOVc(block, COND_NZ, REG(rn), 0xffffffff);
				if (SZ_CALC_REQUIRED) UML_MOV(block, ASTAT_SZ, 1);
				if (SV_CALC_REQUIRED) UML_MOV(block, ASTAT_SV, 1);
				if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
			}
			else
			{
				if (shift < 0)
					UML_SAR(block, REG(rn), REG(rx), -shift);
				else
					UML_SHL(block, REG(rn), REG(rx), shift);
				if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
				if (SV_CALC_REQUIRED && shift != 0) UML_MOV(block, ASTAT_SV, 1);
				if (SV_CALC_REQUIRED && shift == 0) UML_MOV(block, ASTAT_SV, 0);
				if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
			}
			return;

		case 0x02:      // ROT Rx BY <data8>
			if (shift < 0)
				UML_ROR(block, REG(rn), REG(rx), (-shift) & 0x1f);
			else
				UML_ROL(block, REG(rn), REG(rx), shift & 0x1f);
			if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
			if (SV_CALC_REQUIRED) UML_MOV(block, ASTAT_SV, 0);
			if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
			return;

		case 0x08:      // Rn = Rn OR LSHIFT Rx BY <data8>
			if (abs(shift) >= 32)
			{
				UML_MOV(block, I0, 0);
				if (SZ_CALC_REQUIRED) UML_MOV(block, ASTAT_SZ, 1);
				if (SV_CALC_REQUIRED) UML_MOV(block, ASTAT_SV, 1);
				if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
				UML_OR(block, REG(rn), REG(rn), I0);
			}
			else
			{
				if (shift < 0)
					UML_SHR(block, I0, REG(rx), -shift);
				else
					UML_SHL(block, I0, REG(rx), shift);
				if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
				if (SV_CALC_REQUIRED && shift != 0) UML_MOV(block, ASTAT_SV, 1);
				if (SV_CALC_REQUIRED && shift == 0) UML_MOV(block, ASTAT_SV, 0);
				if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
				UML_OR(block, REG(rn), REG(rn), I0);
			}
			return;

		case 0x10:      // FEXT Rx BY <bit6>:<len6>
			if (bit == 0)
			{
				UML_AND(block, REG(rn), REG(rx), MAKE_EXTRACT_MASK(bit, len));
			}
			else
			{
				UML_AND(block, I0, REG(rx), MAKE_EXTRACT_MASK(bit, len));
				UML_SHR(block, REG(rn), I0, bit);
			}
			if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
			if (SV_CALC_REQUIRED && (bit + len) > 32) UML_MOV(block, ASTAT_SV, 1);
			if (SV_CALC_REQUIRED && (bit + len) <= 32) UML_MOV(block, ASTAT_SV, 0);
			if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
			return;

		case 0x12:      // FEXT Rx BY <bit6>:<len6> (SE)
			UML_AND(block, I0, REG(rx), MAKE_EXTRACT_MASK(bit, len));
			UML_SHL(block, I0, I0, 32 - (bit + len));
			UML_SAR(block, REG(rn), I0, 32 - (bit + len) + bit);
			if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
			if (SV_CALC_REQUIRED && (bit + len) > 32) UML_MOV(block, ASTAT_SV, 1);
			if (SV_CALC_REQUIRED && (bit + len) <= 32) UML_MOV(block, ASTAT_SV, 0);
			if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
			return;

		case 0x19:      // Rn = Rn OR FDEP Rx BY <bit6>:<len6>
			UML_AND(block, I0, REG(rx), MAKE_EXTRACT_MASK(0, len));
			if (bit > 0)
				UML_SHL(block, I0, I0, bit);
			UML_OR(block, REG(rn), REG(rn), I0);

			if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
			if (SV_CALC_REQUIRED && (bit + len) > 32) UML_MOV(block, ASTAT_SV, 1);
			if (SV_CALC_REQUIRED && (bit + len) <= 32) UML_MOV(block, ASTAT_SV, 0);
			if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
			return;

		case 0x30:      // BSET Rx BY <data8>
			UML_OR(block, REG(rn), REG(rx), 1 << data);
			if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
			if (SV_CALC_REQUIRED && data > 31) UML_MOV(block, ASTAT_SV, 1);
			if (SV_CALC_REQUIRED && data <= 31) UML_MOV(block, ASTAT_SV, 0);
			if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
			return;

		case 0x31:      // BCLR Rx By <data8>
			UML_AND(block, REG(rn), REG(rx), ~(1 << data));
			if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
			if (SV_CALC_REQUIRED && data > 31) UML_MOV(block, ASTAT_SV, 1);
			if (SV_CALC_REQUIRED && data <= 31) UML_MOV(block, ASTAT_SV, 0);
			if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
			return;

		case 0x32:      // BTGL Rx BY <data8>
			UML_XOR(block, REG(rn), REG(rx), 1 << data);
			if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
			if (SV_CALC_REQUIRED && data > 31) UML_MOV(block, ASTAT_SV, 1);
			if (SV_CALC_REQUIRED && data <= 31) UML_MOV(block, ASTAT_SV, 0);
			if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
			return;

		case 0x33:      // BTST Rx BY <data8>
			UML_TEST(block, REG(rx), 1 << data);
			if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
			if (SV_CALC_REQUIRED && data > 31) UML_MOV(block, ASTAT_SV, 1);
			if (SV_CALC_REQUIRED && data <= 31) UML_MOV(block, ASTAT_SV, 0);
			if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
			return;

		default:
			UML_MOV(block, mem(&m_core->pc), desc->pc);
			UML_DMOV(block, mem(&m_core->arg64), desc->opptr.q[0]);
			UML_CALLC(block, cfunc_unimplemented_compute, this);
			return;
	}
}
