use more constexpr and literal classes in UML to give compiler more optimisation opportunities (nw)

This commit is contained in:
Vas Crabb 2018-03-16 19:08:38 +11:00
parent e34faf61ff
commit 245f822e7d
11 changed files with 605 additions and 626 deletions

View File

@ -253,18 +253,18 @@ if (CPUS["APEXC"]~=null or _OPTIONS["with-tools"]) then
end
--------------------------------------------------
-- AT&T DSP16A
--@src/devices/cpu/dsp16/dsp16.h,CPUS["DSP16A"] = true
-- WE|AT&T DSP16
--@src/devices/cpu/dsp16/dsp16.h,CPUS["DSP16"] = true
--------------------------------------------------
if (CPUS["DSP16A"]~=null) then
if (CPUS["DSP16"]~=null) then
files {
MAME_DIR .. "src/devices/cpu/dsp16/dsp16.cpp",
MAME_DIR .. "src/devices/cpu/dsp16/dsp16.h",
}
end
if (CPUS["DSP16A"]~=null or _OPTIONS["with-tools"]) then
if (CPUS["DSP16"]~=null or _OPTIONS["with-tools"]) then
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/dsp16/dsp16dis.cpp")
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/dsp16/dsp16dis.h")
end

View File

@ -61,7 +61,7 @@ CPUS["MIPS"] = true
CPUS["R3000"] = true
CPUS["PSX"] = true
CPUS["SH"] = true
CPUS["DSP16A"] = true
CPUS["DSP16"] = true
CPUS["DSP32C"] = true
CPUS["PIC16C5X"] = true
CPUS["PIC16C62X"] = true

View File

@ -61,7 +61,7 @@ CPUS["MIPS"] = true
CPUS["R3000"] = true
CPUS["PSX"] = true
CPUS["SH"] = true
CPUS["DSP16A"] = true
CPUS["DSP16"] = true
CPUS["DSP32C"] = true
CPUS["PIC16C5X"] = true
CPUS["PIC16C62X"] = true

View File

@ -19,11 +19,13 @@
#include "drcfe.h"
namespace {
//**************************************************************************
// CONSTANTS
//**************************************************************************
const uint32_t MAX_STACK_DEPTH = 100;
constexpr u32 MAX_STACK_DEPTH = 100;
@ -38,6 +40,8 @@ struct pc_stack_entry
offs_t srcpc;
};
} // anonymous namespace
//**************************************************************************
@ -48,14 +52,14 @@ struct pc_stack_entry
// drc_frontend - constructor
//-------------------------------------------------
drc_frontend::drc_frontend(device_t &cpu, uint32_t window_start, uint32_t window_end, uint32_t max_sequence)
: m_window_start(window_start),
m_window_end(window_end),
m_max_sequence(max_sequence),
m_cpudevice(downcast<cpu_device &>(cpu)),
m_program(m_cpudevice.space(AS_PROGRAM)),
m_pageshift(m_cpudevice.space_config(AS_PROGRAM)->m_page_shift),
m_desc_array(window_end + window_start + 2, nullptr)
drc_frontend::drc_frontend(device_t &cpu, u32 window_start, u32 window_end, u32 max_sequence)
: m_window_start(window_start)
, m_window_end(window_end)
, m_max_sequence(max_sequence)
, m_cpudevice(downcast<cpu_device &>(cpu))
, m_program(m_cpudevice.space(AS_PROGRAM))
, m_pageshift(m_cpudevice.space_config(AS_PROGRAM)->m_page_shift)
, m_desc_array(window_end + window_start + 2, nullptr)
{
}
@ -90,12 +94,12 @@ const opcode_desc *drc_frontend::describe_code(offs_t startpc)
pcstackptr++;
// loop while we still have a stack
offs_t minpc = startpc - std::min(m_window_start, startpc);
offs_t maxpc = startpc + std::min(m_window_end, 0xffffffff - startpc);
offs_t const minpc = startpc - (std::min)(m_window_start, startpc);
offs_t const maxpc = startpc + (std::min)(m_window_end, 0xffffffff - startpc);
while (pcstackptr != &pcstack[0])
{
// if we've already hit this PC, just mark it a branch target and continue
pc_stack_entry *curstack = --pcstackptr;
pc_stack_entry *const curstack = --pcstackptr;
opcode_desc *curdesc = m_desc_array[curstack->targetpc - minpc];
if (curdesc != nullptr)
{
@ -156,10 +160,10 @@ const opcode_desc *drc_frontend::describe_code(offs_t startpc)
// slots of branches as well
//-------------------------------------------------
opcode_desc *drc_frontend::describe_one(offs_t curpc, const opcode_desc *prevdesc, bool in_delay_slot)
opcode_desc *drc_frontend::describe_one(offs_t curpc, opcode_desc const *prevdesc, bool in_delay_slot)
{
// initialize the description
opcode_desc *desc = m_desc_allocator.alloc();
opcode_desc *const desc = m_desc_allocator.alloc();
desc->m_next = nullptr;
desc->branch = nullptr;
desc->delay.reset();
@ -208,7 +212,7 @@ opcode_desc *drc_frontend::describe_one(offs_t curpc, const opcode_desc *prevdes
}
}
opcode_desc *prev = desc;
for (uint8_t slotnum = 0; slotnum < desc->delayslots; slotnum++)
for (u8 slotnum = 0; slotnum < desc->delayslots; slotnum++)
{
// recursively describe the next instruction
opcode_desc *delaydesc = describe_one(delaypc, prev, true);
@ -237,7 +241,7 @@ opcode_desc *drc_frontend::describe_one(offs_t curpc, const opcode_desc *prevdes
// of instructions
//-------------------------------------------------
void drc_frontend::build_sequence(int start, int end, uint32_t endflag)
void drc_frontend::build_sequence(int start, int end, u32 endflag)
{
// iterate in order from start to end, picking up all non-NULL instructions
int consecutive = 0;
@ -250,7 +254,7 @@ void drc_frontend::build_sequence(int start, int end, uint32_t endflag)
opcode_desc *curdesc = m_desc_array[descnum];
int nextdescnum = descnum + curdesc->length;
opcode_desc *nextdesc = (nextdescnum < end) ? m_desc_array[nextdescnum] : nullptr;
for (uint8_t skipnum = 0; skipnum < curdesc->skipslots && nextdesc != nullptr; skipnum++)
for (u8 skipnum = 0; skipnum < curdesc->skipslots && nextdesc != nullptr; skipnum++)
{
nextdescnum = nextdescnum + nextdesc->length;
nextdesc = (nextdescnum < end) ? m_desc_array[nextdescnum] : nullptr;
@ -302,7 +306,7 @@ void drc_frontend::build_sequence(int start, int end, uint32_t endflag)
if (curdesc->flags & OPFLAG_END_SEQUENCE)
{
// figure out which registers we *must* generate, assuming at the end all must be
uint32_t reqmask[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
u32 reqmask[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
if (seqstart != -1)
for (int backdesc = descnum; backdesc != seqstart - 1; backdesc--)
if (m_desc_array[backdesc] != nullptr)
@ -342,7 +346,7 @@ void drc_frontend::build_sequence(int start, int end, uint32_t endflag)
// walking in a backwards direction
//-------------------------------------------------
void drc_frontend::accumulate_required_backwards(opcode_desc &desc, uint32_t *reqmask)
void drc_frontend::accumulate_required_backwards(opcode_desc &desc, u32 *reqmask)
{
// recursively handle delay slots
if (desc.delay.first() != nullptr)

View File

@ -28,55 +28,54 @@
a linked list and returned for further processing by the backend.
***************************************************************************/
#ifndef MAME_CPU_DRCFE_H
#define MAME_CPU_DRCFE_H
#pragma once
#ifndef __DRCFE_H__
#define __DRCFE_H__
//**************************************************************************
// CONSTANTS
//**************************************************************************
// this defines a branch targetpc that is dynamic at runtime
const offs_t BRANCH_TARGET_DYNAMIC = ~0;
constexpr offs_t BRANCH_TARGET_DYNAMIC = ~offs_t(0);
// opcode branch flags
const uint32_t OPFLAG_IS_UNCONDITIONAL_BRANCH = 0x00000001; // instruction is unconditional branch
const uint32_t OPFLAG_IS_CONDITIONAL_BRANCH = 0x00000002; // instruction is conditional branch
const uint32_t OPFLAG_IS_BRANCH = (OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_IS_CONDITIONAL_BRANCH);
const uint32_t OPFLAG_IS_BRANCH_TARGET = 0x00000004; // instruction is the target of a branch
const uint32_t OPFLAG_IN_DELAY_SLOT = 0x00000008; // instruction is in the delay slot of a branch
const uint32_t OPFLAG_INTRABLOCK_BRANCH = 0x00000010; // instruction branches within the block
constexpr u32 OPFLAG_IS_UNCONDITIONAL_BRANCH = 0x00000001; // instruction is unconditional branch
constexpr u32 OPFLAG_IS_CONDITIONAL_BRANCH = 0x00000002; // instruction is conditional branch
constexpr u32 OPFLAG_IS_BRANCH = (OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_IS_CONDITIONAL_BRANCH);
constexpr u32 OPFLAG_IS_BRANCH_TARGET = 0x00000004; // instruction is the target of a branch
constexpr u32 OPFLAG_IN_DELAY_SLOT = 0x00000008; // instruction is in the delay slot of a branch
constexpr u32 OPFLAG_INTRABLOCK_BRANCH = 0x00000010; // instruction branches within the block
// opcode exception flags
const uint32_t OPFLAG_CAN_TRIGGER_SW_INT = 0x00000020; // instruction can trigger a software interrupt
const uint32_t OPFLAG_CAN_EXPOSE_EXTERNAL_INT = 0x00000040; // instruction can expose an external interrupt
const uint32_t OPFLAG_CAN_CAUSE_EXCEPTION = 0x00000080; // instruction may generate exception
const uint32_t OPFLAG_WILL_CAUSE_EXCEPTION = 0x00000100; // instruction will generate exception
const uint32_t OPFLAG_PRIVILEGED = 0x00000200; // instruction is privileged
constexpr u32 OPFLAG_CAN_TRIGGER_SW_INT = 0x00000020; // instruction can trigger a software interrupt
constexpr u32 OPFLAG_CAN_EXPOSE_EXTERNAL_INT = 0x00000040; // instruction can expose an external interrupt
constexpr u32 OPFLAG_CAN_CAUSE_EXCEPTION = 0x00000080; // instruction may generate exception
constexpr u32 OPFLAG_WILL_CAUSE_EXCEPTION = 0x00000100; // instruction will generate exception
constexpr u32 OPFLAG_PRIVILEGED = 0x00000200; // instruction is privileged
// opcode virtual->physical translation flags
const uint32_t OPFLAG_VALIDATE_TLB = 0x00000400; // instruction must validate TLB before execution
const uint32_t OPFLAG_MODIFIES_TRANSLATION = 0x00000800; // instruction modifies the TLB
const uint32_t OPFLAG_COMPILER_PAGE_FAULT = 0x00001000; // compiler hit a page fault when parsing
const uint32_t OPFLAG_COMPILER_UNMAPPED = 0x00002000; // compiler hit unmapped memory when parsing
constexpr u32 OPFLAG_VALIDATE_TLB = 0x00000400; // instruction must validate TLB before execution
constexpr u32 OPFLAG_MODIFIES_TRANSLATION = 0x00000800; // instruction modifies the TLB
constexpr u32 OPFLAG_COMPILER_PAGE_FAULT = 0x00001000; // compiler hit a page fault when parsing
constexpr u32 OPFLAG_COMPILER_UNMAPPED = 0x00002000; // compiler hit unmapped memory when parsing
// opcode flags
const uint32_t OPFLAG_INVALID_OPCODE = 0x00004000; // instruction is invalid
const uint32_t OPFLAG_VIRTUAL_NOOP = 0x00008000; // instruction is a virtual no-op
constexpr u32 OPFLAG_INVALID_OPCODE = 0x00004000; // instruction is invalid
constexpr u32 OPFLAG_VIRTUAL_NOOP = 0x00008000; // instruction is a virtual no-op
// opcode sequence flow flags
const uint32_t OPFLAG_REDISPATCH = 0x00010000; // instruction must redispatch after completion
const uint32_t OPFLAG_RETURN_TO_START = 0x00020000; // instruction must jump back to the beginning after completion
const uint32_t OPFLAG_END_SEQUENCE = 0x00040000; // this is the last instruction in a sequence
const uint32_t OPFLAG_CAN_CHANGE_MODES = 0x00080000; // instruction can change modes
constexpr u32 OPFLAG_REDISPATCH = 0x00010000; // instruction must redispatch after completion
constexpr u32 OPFLAG_RETURN_TO_START = 0x00020000; // instruction must jump back to the beginning after completion
constexpr u32 OPFLAG_END_SEQUENCE = 0x00040000; // this is the last instruction in a sequence
constexpr u32 OPFLAG_CAN_CHANGE_MODES = 0x00080000; // instruction can change modes
// execution semantics
const uint32_t OPFLAG_READS_MEMORY = 0x00100000; // instruction reads memory
const uint32_t OPFLAG_WRITES_MEMORY = 0x00200000; // instruction writes memory
constexpr u32 OPFLAG_READS_MEMORY = 0x00100000; // instruction reads memory
constexpr u32 OPFLAG_WRITES_MEMORY = 0x00200000; // instruction writes memory
@ -102,25 +101,25 @@ struct opcode_desc
// copy of up to 16 bytes of opcode
union
{
uint8_t b[16];
uint16_t w[8];
uint32_t l[4];
uint64_t q[2];
u8 b[16];
u16 w[8];
u32 l[4];
u64 q[2];
} opptr; // pointer to opcode memory
// information about this instruction's execution
uint8_t length; // length in bytes of this opcode
uint8_t delayslots; // number of delay slots (for branches)
uint8_t skipslots; // number of skip slots (for branches)
uint32_t flags; // OPFLAG_* opcode flags
uint32_t userflags; // core specific flags
uint32_t userdata0; // core specific data
uint32_t cycles; // number of cycles needed to execute
u8 length; // length in bytes of this opcode
u8 delayslots; // number of delay slots (for branches)
u8 skipslots; // number of skip slots (for branches)
u32 flags; // OPFLAG_* opcode flags
u32 userflags; // core specific flags
u32 userdata0; // core specific data
u32 cycles; // number of cycles needed to execute
// register usage information
uint32_t regin[4]; // input registers
uint32_t regout[4]; // output registers
uint32_t regreq[4]; // required output registers
u32 regin[4]; // input registers
u32 regout[4]; // output registers
u32 regreq[4]; // required output registers
};
@ -129,27 +128,27 @@ class drc_frontend
{
public:
// construction/destruction
drc_frontend(device_t &cpu, uint32_t window_start, uint32_t window_end, uint32_t max_sequence);
drc_frontend(device_t &cpu, u32 window_start, u32 window_end, u32 max_sequence);
virtual ~drc_frontend();
// describe a block
const opcode_desc *describe_code(offs_t startpc);
opcode_desc const *describe_code(offs_t startpc);
protected:
// required overrides
virtual bool describe(opcode_desc &desc, const opcode_desc *prev) = 0;
virtual bool describe(opcode_desc &desc, opcode_desc const *prev) = 0;
private:
// internal helpers
opcode_desc *describe_one(offs_t curpc, const opcode_desc *prevdesc, bool in_delay_slot = false);
void build_sequence(int start, int end, uint32_t endflag);
void accumulate_required_backwards(opcode_desc &desc, uint32_t *reqmask);
opcode_desc *describe_one(offs_t curpc, opcode_desc const *prevdesc, bool in_delay_slot = false);
void build_sequence(int start, int end, u32 endflag);
void accumulate_required_backwards(opcode_desc &desc, u32 *reqmask);
void release_descriptions();
// configuration parameters
uint32_t m_window_start; // code window start offset = startpc - window_start
uint32_t m_window_end; // code window end offset = startpc + window_end
uint32_t m_max_sequence; // maximum instructions to include in a sequence
u32 m_window_start; // code window start offset = startpc - window_start
u32 m_window_end; // code window end offset = startpc + window_end
u32 m_max_sequence; // maximum instructions to include in a sequence
// CPU parameters
cpu_device & m_cpudevice; // CPU device object
@ -159,8 +158,7 @@ private:
// opcode descriptor arrays
simple_list<opcode_desc> m_desc_live_list; // list of live descriptions
fixed_allocator<opcode_desc> m_desc_allocator; // fixed allocator for descriptions
std::vector<opcode_desc *> m_desc_array; // array of descriptions in PC order
std::vector<opcode_desc *> m_desc_array; // array of descriptions in PC order
};
#endif /* __DRCFE_H__ */
#endif // MAME_CPU_DRCFE_H

View File

@ -622,7 +622,7 @@ void dsp16_device_base::state_export(device_state_entry const &entry)
util::disasm_interface *dsp16_device_base::create_disassembler()
{
return new dsp16a_disassembler;
return new dsp16_disassembler;
}
template <offs_t Base> READ16_MEMBER(dsp16_device_base::external_memory_r)

View File

@ -3,7 +3,7 @@
#include "emu.h"
#include "dsp16dis.h"
std::string dsp16a_disassembler::disasmF1Field(u8 F1, u8 D, u8 S)
std::string dsp16_disassembler::disasmF1Field(u8 F1, u8 D, u8 S)
{
switch (F1)
{
@ -27,7 +27,7 @@ std::string dsp16a_disassembler::disasmF1Field(u8 F1, u8 D, u8 S)
return "UNKNOWN";
}
std::string dsp16a_disassembler::disasmYField(u8 Y)
std::string dsp16_disassembler::disasmYField(u8 Y)
{
switch (Y & 0x03U)
{
@ -39,7 +39,7 @@ std::string dsp16a_disassembler::disasmYField(u8 Y)
return "UNKNOWN";
}
std::string dsp16a_disassembler::disasmZField(u8 Z)
std::string dsp16_disassembler::disasmZField(u8 Z)
{
switch (Z & 0x03U)
{
@ -51,7 +51,7 @@ std::string dsp16a_disassembler::disasmZField(u8 Z)
return "UNKNOWN";
}
std::string dsp16a_disassembler::disasmF2Field(u8 F2, u8 D, u8 S)
std::string dsp16_disassembler::disasmF2Field(u8 F2, u8 D, u8 S)
{
switch (F2)
{
@ -75,7 +75,7 @@ std::string dsp16a_disassembler::disasmF2Field(u8 F2, u8 D, u8 S)
return "UNKNOWN";
}
std::string dsp16a_disassembler::disasmCONField(u8 CON)
std::string dsp16_disassembler::disasmCONField(u8 CON)
{
switch (CON)
{
@ -102,7 +102,7 @@ std::string dsp16a_disassembler::disasmCONField(u8 CON)
}
}
std::string dsp16a_disassembler::disasmBField(u8 B, uint32_t &dasmflags)
std::string dsp16_disassembler::disasmBField(u8 B, u32 &dasmflags)
{
switch (B)
{
@ -118,7 +118,7 @@ std::string dsp16a_disassembler::disasmBField(u8 B, uint32_t &dasmflags)
return "UNKNOWN";
}
std::string dsp16a_disassembler::disasmRImmediateField(u8 R)
std::string dsp16_disassembler::disasmRImmediateField(u8 R)
{
switch (R)
{
@ -134,7 +134,7 @@ std::string dsp16a_disassembler::disasmRImmediateField(u8 R)
return "UNKNOWN";
}
std::string dsp16a_disassembler::disasmRField(u8 R)
std::string dsp16_disassembler::disasmRField(u8 R)
{
switch (R)
{
@ -170,7 +170,7 @@ std::string dsp16a_disassembler::disasmRField(u8 R)
}
}
std::string dsp16a_disassembler::disasmIField(u8 I)
std::string dsp16_disassembler::disasmIField(u8 I)
{
switch (I)
{
@ -183,7 +183,7 @@ std::string dsp16a_disassembler::disasmIField(u8 I)
}
}
bool dsp16a_disassembler::disasmSIField(u8 SI)
bool dsp16_disassembler::disasmSIField(u8 SI)
{
switch (SI)
{
@ -194,27 +194,27 @@ bool dsp16a_disassembler::disasmSIField(u8 SI)
}
u32 dsp16a_disassembler::interface_flags() const
u32 dsp16_disassembler::interface_flags() const
{
return PAGED;
}
u32 dsp16a_disassembler::page_address_bits() const
u32 dsp16_disassembler::page_address_bits() const
{
return 12U;
}
u32 dsp16a_disassembler::opcode_alignment() const
u32 dsp16_disassembler::opcode_alignment() const
{
return 1U;
}
offs_t dsp16a_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
offs_t dsp16_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
{
u8 opSize = 1;
uint32_t dasmflags = 0;
uint16_t op = opcodes.r16(pc);
uint16_t op2 = opcodes.r16(pc+1);
u32 dasmflags = 0;
u16 op = opcodes.r16(pc);
u16 op2 = opcodes.r16(pc+1);
// TODO: Test for previous "if CON" instruction and tab the next instruction in?
@ -394,13 +394,13 @@ offs_t dsp16a_disassembler::disassemble(std::ostream &stream, offs_t pc, const d
// Format 4: Branch Direct Group
case 0x00: case 0x01: // goto JA
{
const uint16_t JA = (op & 0x0fff) | (pc & 0xf000);
const u16 JA = (op & 0x0fff) | (pc & 0xf000);
util::stream_format(stream, "goto 0x%04x", JA);
}
break;
case 0x10: case 0x11: // call JA
{
const uint16_t JA = (op & 0x0fff) | (pc & 0xf000);
const u16 JA = (op & 0x0fff) | (pc & 0xf000);
util::stream_format(stream, "call 0x%04x", JA);
dasmflags |= STEP_OVER;
}
@ -492,7 +492,7 @@ offs_t dsp16a_disassembler::disassemble(std::ostream &stream, offs_t pc, const d
// Format 9: Short Immediate Group
case 0x02: case 0x03: // R = M
{
const uint16_t M = (op & 0x01ff);
const u16 M = (op & 0x01ff);
const u8 R = (op & 0x0e00) >> 9;
std::string rString = disasmRImmediateField(R);
util::stream_format(stream, "set %s = 0x%04x", rString, M);

View File

@ -5,11 +5,11 @@
#pragma once
class dsp16a_disassembler : public util::disasm_interface
class dsp16_disassembler : public util::disasm_interface
{
public:
dsp16a_disassembler() = default;
virtual ~dsp16a_disassembler() = default;
dsp16_disassembler() = default;
virtual ~dsp16_disassembler() = default;
virtual u32 interface_flags() const override;
virtual u32 page_address_bits() const override;
@ -22,7 +22,7 @@ private:
std::string disasmZField(u8 Z);
std::string disasmF2Field(u8 F2, u8 D, u8 S);
std::string disasmCONField(u8 CON);
std::string disasmBField(u8 B, uint32_t &dasmflags);
std::string disasmBField(u8 B, u32 &dasmflags);
std::string disasmRImmediateField(u8 R);
std::string disasmRField(u8 R);
std::string disasmIField(u8 I);

View File

@ -124,7 +124,7 @@ using namespace uml;
#define OPINFO4(op,str,sizes,cond,iflag,oflag,mflag,p0,p1,p2,p3) { OP_##op, str, sizes, cond, OPFLAGS_##iflag, OPFLAGS_##oflag, OPFLAGS_##mflag, { p0, p1, p2, p3 } },
// opcode validation table
const opcode_info instruction::s_opcode_info_table[OP_MAX] =
opcode_info const instruction::s_opcode_info_table[OP_MAX] =
{
OPINFO0(INVALID, "invalid", 4, false, NONE, NONE, NONE)
@ -227,7 +227,7 @@ const opcode_info instruction::s_opcode_info_table[OP_MAX] =
// rol32 - perform a 32-bit left rotate
//-------------------------------------------------
inline uint32_t rol32(uint32_t source, uint8_t count)
inline u32 rol32(u32 source, u8 count)
{
count &= 31;
return (source << count) | (source >> (32 - count));
@ -238,7 +238,7 @@ inline uint32_t rol32(uint32_t source, uint8_t count)
// rol64 - perform a 64-bit left rotate
//-------------------------------------------------
inline uint64_t rol64(uint64_t source, uint8_t count)
inline u64 rol64(u64 source, u8 count)
{
count &= 63;
return (source << count) | (source >> (64 - count));
@ -255,10 +255,10 @@ inline uint64_t rol64(uint64_t source, uint8_t count)
//-------------------------------------------------
uml::code_handle::code_handle(drcuml_state &drcuml, const char *name)
: m_code(reinterpret_cast<drccodeptr *>(drcuml.cache().alloc_near(sizeof(drccodeptr)))),
m_string(name),
m_next(nullptr),
m_drcuml(drcuml)
: m_code(reinterpret_cast<drccodeptr *>(drcuml.cache().alloc_near(sizeof(drccodeptr))))
, m_string(name)
, m_next(nullptr)
, m_drcuml(drcuml)
{
if (m_code == nullptr)
throw std::bad_alloc();
@ -283,29 +283,15 @@ void uml::code_handle::set_codeptr(drccodeptr code)
// UML INSTRUCTION
//**************************************************************************
//-------------------------------------------------
// instruction - constructor
//-------------------------------------------------
uml::instruction::instruction()
: m_opcode(OP_INVALID),
m_condition(COND_ALWAYS),
m_flags(0),
m_size(4),
m_numparams(0)
{
}
//-------------------------------------------------
// configure - configure an opcode with no
// parameters
//-------------------------------------------------
void uml::instruction::configure(opcode_t op, uint8_t size, condition_t condition)
void uml::instruction::configure(opcode_t op, u8 size, condition_t condition)
{
// fill in the instruction
m_opcode = (opcode_t)(uint8_t)op;
m_opcode = opcode_t(u8(op));
m_size = size;
m_condition = condition;
m_flags = 0;
@ -321,10 +307,10 @@ void uml::instruction::configure(opcode_t op, uint8_t size, condition_t conditio
// parameter
//-------------------------------------------------
void uml::instruction::configure(opcode_t op, uint8_t size, parameter p0, condition_t condition)
void uml::instruction::configure(opcode_t op, u8 size, parameter p0, condition_t condition)
{
// fill in the instruction
m_opcode = (opcode_t)(uint8_t)op;
m_opcode = opcode_t(u8(op));
m_size = size;
m_condition = condition;
m_flags = 0;
@ -341,10 +327,10 @@ void uml::instruction::configure(opcode_t op, uint8_t size, parameter p0, condit
// parameters
//-------------------------------------------------
void uml::instruction::configure(opcode_t op, uint8_t size, parameter p0, parameter p1, condition_t condition)
void uml::instruction::configure(opcode_t op, u8 size, parameter p0, parameter p1, condition_t condition)
{
// fill in the instruction
m_opcode = (opcode_t)(uint8_t)op;
m_opcode = opcode_t(u8(op));
m_size = size;
m_condition = condition;
m_flags = 0;
@ -362,10 +348,10 @@ void uml::instruction::configure(opcode_t op, uint8_t size, parameter p0, parame
// parameters
//-------------------------------------------------
void uml::instruction::configure(opcode_t op, uint8_t size, parameter p0, parameter p1, parameter p2, condition_t condition)
void uml::instruction::configure(opcode_t op, u8 size, parameter p0, parameter p1, parameter p2, condition_t condition)
{
// fill in the instruction
m_opcode = (opcode_t)(uint8_t)op;
m_opcode = opcode_t(u8(op));
m_size = size;
m_condition = condition;
m_flags = 0;
@ -384,10 +370,10 @@ void uml::instruction::configure(opcode_t op, uint8_t size, parameter p0, parame
// parameters
//-------------------------------------------------
void uml::instruction::configure(opcode_t op, uint8_t size, parameter p0, parameter p1, parameter p2, parameter p3, condition_t condition)
void uml::instruction::configure(opcode_t op, u8 size, parameter p0, parameter p1, parameter p2, parameter p3, condition_t condition)
{
// fill in the instruction
m_opcode = (opcode_t)(uint8_t)op;
m_opcode = opcode_t(u8(op));
m_size = size;
m_condition = condition;
m_flags = 0;
@ -414,8 +400,8 @@ void uml::instruction::simplify()
if (m_flags != 0)
return;
static const uint64_t instsizemask[] = { 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0xffffffffffffffffU };
static const uint64_t paramsizemask[] = { 0xff, 0xffff, 0xffffffff, 0xffffffffffffffffU };
static constexpr u64 instsizemask[] = { 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0xffffffffffffffffU };
static constexpr u64 paramsizemask[] = { 0xff, 0xffff, 0xffffffff, 0xffffffffffffffffU };
// loop until we've simplified all we can
opcode_t origop;
@ -425,316 +411,316 @@ void uml::instruction::simplify()
origop = m_opcode;
switch (m_opcode)
{
// READM: convert to READ if the mask is wide open
case OP_READM:
if (m_param[2].is_immediate_value(paramsizemask[m_param[3].size()]))
// READM: convert to READ if the mask is wide open
case OP_READM:
if (m_param[2].is_immediate_value(paramsizemask[m_param[3].size()]))
{
m_opcode = OP_READ;
m_numparams = 2;
m_param[2] = m_param[3];
}
break;
// WRITEM: convert to WRITE if the mask is wide open
case OP_WRITEM:
if (m_param[2].is_immediate_value(paramsizemask[m_param[3].size()]))
{
m_opcode = OP_WRITE;
m_numparams = 2;
m_param[2] = m_param[3];
}
break;
// SET: convert to MOV if constant condition
case OP_SET:
if (m_condition == COND_ALWAYS)
convert_to_mov_immediate(1);
break;
// MOV: convert to NOP if move-to-self
case OP_MOV:
if (m_param[0] == m_param[1])
nop();
break;
// SEXT: convert immediates to MOV
case OP_SEXT:
if (m_param[1].is_immediate())
switch (m_param[2].size())
{
m_opcode = OP_READ;
m_numparams = 2;
m_param[2] = m_param[3];
case SIZE_BYTE: convert_to_mov_immediate(s8(m_param[1].immediate())); break;
case SIZE_WORD: convert_to_mov_immediate(s16(m_param[1].immediate())); break;
case SIZE_DWORD: convert_to_mov_immediate(s32(m_param[1].immediate())); break;
case SIZE_QWORD: convert_to_mov_immediate(s64(m_param[1].immediate())); break;
case SIZE_DQWORD: fatalerror("Invalid SEXT target size\n");
}
break;
break;
// WRITEM: convert to WRITE if the mask is wide open
case OP_WRITEM:
if (m_param[2].is_immediate_value(paramsizemask[m_param[3].size()]))
{
m_opcode = OP_WRITE;
m_numparams = 2;
m_param[2] = m_param[3];
}
break;
// ROLAND: convert to MOV if all immediate, or to ROL or AND if one is not needed, or to SHL/SHR if the mask is right
case OP_ROLAND:
if (m_param[1].is_immediate() && m_param[2].is_immediate() && m_param[3].is_immediate())
{
assert(m_size == 4 || m_size == 8);
if (m_size == 4)
convert_to_mov_immediate(rol32(m_param[1].immediate(), m_param[2].immediate()) & m_param[3].immediate());
else
convert_to_mov_immediate(rol64(m_param[1].immediate(), m_param[2].immediate()) & m_param[3].immediate());
}
else if (m_param[2].is_immediate_value(0))
{
m_opcode = OP_AND;
m_numparams = 3;
m_param[2] = m_param[3];
}
else if (m_param[3].is_immediate_value(instsizemask[m_size]))
{
m_opcode = OP_ROL;
m_numparams = 3;
}
else if (m_param[2].is_immediate() && m_param[3].is_immediate_value((0xffffffffffffffffU << m_param[2].immediate()) & instsizemask[m_size]))
{
m_opcode = OP_SHL;
m_numparams = 3;
}
else if (m_param[2].is_immediate() && m_param[3].is_immediate_value(instsizemask[m_size] >> (8 * m_size - m_param[2].immediate())))
{
m_opcode = OP_SHR;
m_numparams = 3;
m_param[2] = 8 * m_size - m_param[2].immediate();
}
break;
// SET: convert to MOV if constant condition
case OP_SET:
if (m_condition == COND_ALWAYS)
convert_to_mov_immediate(1);
break;
// ROLINS: convert to ROLAND if the mask is full
case OP_ROLINS:
if (m_param[3].is_immediate_value(instsizemask[m_size]))
m_opcode = OP_ROLAND;
break;
// MOV: convert to NOP if move-to-self
case OP_MOV:
if (m_param[0] == m_param[1])
nop();
break;
// ADD: convert to MOV if immediate, or if adding 0
case OP_ADD:
if (m_param[1].is_immediate() && m_param[2].is_immediate())
convert_to_mov_immediate(m_param[1].immediate() + m_param[2].immediate());
else if (m_param[1].is_immediate_value(0))
convert_to_mov_param(2);
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
// SEXT: convert immediates to MOV
case OP_SEXT:
if (m_param[1].is_immediate())
switch (m_param[2].size())
{
case SIZE_BYTE: convert_to_mov_immediate((int8_t)m_param[1].immediate()); break;
case SIZE_WORD: convert_to_mov_immediate((int16_t)m_param[1].immediate()); break;
case SIZE_DWORD: convert_to_mov_immediate((int32_t)m_param[1].immediate()); break;
case SIZE_QWORD: convert_to_mov_immediate((int64_t)m_param[1].immediate()); break;
case SIZE_DQWORD: fatalerror("Invalid SEXT target size\n");
}
break;
// SUB: convert to MOV if immediate, or if subtracting 0
case OP_SUB:
if (m_param[1].is_immediate() && m_param[2].is_immediate())
convert_to_mov_immediate(m_param[1].immediate() - m_param[2].immediate());
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
// ROLAND: convert to MOV if all immediate, or to ROL or AND if one is not needed, or to SHL/SHR if the mask is right
case OP_ROLAND:
if (m_param[1].is_immediate() && m_param[2].is_immediate() && m_param[3].is_immediate())
{
assert(m_size == 4 || m_size == 8);
if (m_size == 4)
convert_to_mov_immediate(rol32(m_param[1].immediate(), m_param[2].immediate()) & m_param[3].immediate());
else
convert_to_mov_immediate(rol64(m_param[1].immediate(), m_param[2].immediate()) & m_param[3].immediate());
}
else if (m_param[2].is_immediate_value(0))
{
m_opcode = OP_AND;
m_numparams = 3;
m_param[2] = m_param[3];
}
else if (m_param[3].is_immediate_value(instsizemask[m_size]))
{
m_opcode = OP_ROL;
m_numparams = 3;
}
else if (m_param[2].is_immediate() && m_param[3].is_immediate_value((0xffffffffffffffffU << m_param[2].immediate()) & instsizemask[m_size]))
{
m_opcode = OP_SHL;
m_numparams = 3;
}
else if (m_param[2].is_immediate() && m_param[3].is_immediate_value(instsizemask[m_size] >> (8 * m_size - m_param[2].immediate())))
{
m_opcode = OP_SHR;
m_numparams = 3;
m_param[2] = 8 * m_size - m_param[2].immediate();
}
break;
// CMP: no-op if no flags needed, compare i0 to i0 if the parameters are equal
case OP_CMP:
if (m_flags == 0)
nop();
else if (m_param[0] == m_param[1])
cmp(I0, I0);
break;
// ROLINS: convert to ROLAND if the mask is full
case OP_ROLINS:
if (m_param[3].is_immediate_value(instsizemask[m_size]))
m_opcode = OP_ROLAND;
break;
// ADD: convert to MOV if immediate, or if adding 0
case OP_ADD:
if (m_param[1].is_immediate() && m_param[2].is_immediate())
convert_to_mov_immediate(m_param[1].immediate() + m_param[2].immediate());
else if (m_param[1].is_immediate_value(0))
convert_to_mov_param(2);
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
// SUB: convert to MOV if immediate, or if subtracting 0
case OP_SUB:
if (m_param[1].is_immediate() && m_param[2].is_immediate())
convert_to_mov_immediate(m_param[1].immediate() - m_param[2].immediate());
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
// CMP: no-op if no flags needed, compare i0 to i0 if the parameters are equal
case OP_CMP:
if (m_flags == 0)
nop();
else if (m_param[0] == m_param[1])
cmp(I0, I0);
break;
// MULU: convert simple form to MOV if immediate, or if multiplying by 0
case OP_MULU:
if (m_param[0] == m_param[1])
{
if (m_param[2].is_immediate_value(0) || m_param[3].is_immediate_value(0))
convert_to_mov_immediate(0);
else if (m_param[2].is_immediate() && m_param[3].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate((uint32_t)((uint32_t)m_param[1].immediate() * (uint32_t)m_param[2].immediate()));
else if (m_size == 8)
convert_to_mov_immediate((uint64_t)((uint64_t)m_param[1].immediate() * (uint64_t)m_param[2].immediate()));
}
}
break;
// MULS: convert simple form to MOV if immediate, or if multiplying by 0
case OP_MULS:
if (m_param[0] == m_param[1])
{
if (m_param[2].is_immediate_value(0) || m_param[3].is_immediate_value(0))
convert_to_mov_immediate(0);
else if (m_param[2].is_immediate() && m_param[3].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate((int32_t)((int32_t)m_param[1].immediate() * (int32_t)m_param[2].immediate()));
else if (m_size == 8)
convert_to_mov_immediate((int64_t)((int64_t)m_param[1].immediate() * (int64_t)m_param[2].immediate()));
}
}
break;
// DIVU: convert simple form to MOV if immediate, or if dividing with 0
case OP_DIVU:
if (m_param[0] == m_param[1] && !m_param[3].is_immediate_value(0))
{
if (m_param[2].is_immediate_value(0))
convert_to_mov_immediate(0);
else if (m_param[2].is_immediate() && m_param[3].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate((uint32_t)((uint32_t)m_param[1].immediate() / (uint32_t)m_param[2].immediate()));
else if (m_size == 8)
convert_to_mov_immediate((uint64_t)((uint64_t)m_param[1].immediate() / (uint64_t)m_param[2].immediate()));
}
}
break;
// DIVS: convert simple form to MOV if immediate, or if dividing with 0
case OP_DIVS:
if (m_param[0] == m_param[1] && !m_param[3].is_immediate_value(0))
{
if (m_param[2].is_immediate_value(0))
convert_to_mov_immediate(0);
else if (m_param[2].is_immediate() && m_param[3].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate((int32_t)((int32_t)m_param[1].immediate() / (int32_t)m_param[2].immediate()));
else if (m_size == 8)
convert_to_mov_immediate((int64_t)((int64_t)m_param[1].immediate() / (int64_t)m_param[2].immediate()));
}
}
break;
// AND: convert to MOV if immediate, or if anding against 0 or 0xffffffff
case OP_AND:
if (m_param[1].is_immediate_value(0) || m_param[2].is_immediate_value(0))
// MULU: convert simple form to MOV if immediate, or if multiplying by 0
case OP_MULU:
if (m_param[0] == m_param[1])
{
if (m_param[2].is_immediate_value(0) || m_param[3].is_immediate_value(0))
convert_to_mov_immediate(0);
else if (m_param[1].is_immediate() && m_param[2].is_immediate())
convert_to_mov_immediate(m_param[1].immediate() & m_param[2].immediate());
else if (m_param[1].is_immediate_value(instsizemask[m_size]))
convert_to_mov_param(2);
else if (m_param[2].is_immediate_value(instsizemask[m_size]))
convert_to_mov_param(1);
break;
// TEST: no-op if no flags needed
case OP_TEST:
if (m_flags == 0)
nop();
break;
// OR: convert to MOV if immediate, or if oring against 0 or 0xffffffff
case OP_OR:
if (m_param[1].is_immediate_value(instsizemask[m_size]) || m_param[2].is_immediate_value(instsizemask[m_size]))
convert_to_mov_immediate(instsizemask[m_size]);
else if (m_param[1].is_immediate() && m_param[2].is_immediate())
convert_to_mov_immediate(m_param[1].immediate() | m_param[2].immediate());
else if (m_param[1].is_immediate_value(0))
convert_to_mov_param(2);
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
// XOR: convert to MOV if immediate, or if xoring against 0
case OP_XOR:
if (m_param[1].is_immediate() && m_param[2].is_immediate())
convert_to_mov_immediate(m_param[1].immediate() ^ m_param[2].immediate());
else if (m_param[1].is_immediate_value(0))
convert_to_mov_param(2);
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
// LZCNT: convert to MOV if immediate
case OP_LZCNT:
if (m_param[1].is_immediate())
else if (m_param[2].is_immediate() && m_param[3].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(count_leading_zeros(m_param[1].immediate()));
convert_to_mov_immediate(u32(u32(m_param[1].immediate()) * u32(m_param[2].immediate())));
else if (m_size == 8)
{
if ((m_param[1].immediate() >> 32) == 0)
convert_to_mov_immediate(32 + count_leading_zeros(m_param[1].immediate()));
else
convert_to_mov_immediate(count_leading_zeros(m_param[1].immediate() >> 32));
}
convert_to_mov_immediate(u64(u64(m_param[1].immediate()) * u64(m_param[2].immediate())));
}
break;
}
break;
// BSWAP: convert to MOV if immediate
case OP_BSWAP:
if (m_param[1].is_immediate())
// MULS: convert simple form to MOV if immediate, or if multiplying by 0
case OP_MULS:
if (m_param[0] == m_param[1])
{
if (m_param[2].is_immediate_value(0) || m_param[3].is_immediate_value(0))
convert_to_mov_immediate(0);
else if (m_param[2].is_immediate() && m_param[3].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(flipendian_int32(m_param[1].immediate()));
convert_to_mov_immediate(s32(s32(m_param[1].immediate()) * s32(m_param[2].immediate())));
else if (m_size == 8)
convert_to_mov_immediate(flipendian_int64(m_param[1].immediate()));
convert_to_mov_immediate(s64(s64(m_param[1].immediate()) * s64(m_param[2].immediate())));
}
break;
}
break;
// SHL: convert to MOV if immediate or shifting by 0
case OP_SHL:
if (m_param[1].is_immediate() && m_param[2].is_immediate())
convert_to_mov_immediate(m_param[1].immediate() << m_param[2].immediate());
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
// SHR: convert to MOV if immediate or shifting by 0
case OP_SHR:
if (m_param[1].is_immediate() && m_param[2].is_immediate())
// DIVU: convert simple form to MOV if immediate, or if dividing with 0
case OP_DIVU:
if (m_param[0] == m_param[1] && !m_param[3].is_immediate_value(0))
{
if (m_param[2].is_immediate_value(0))
convert_to_mov_immediate(0);
else if (m_param[2].is_immediate() && m_param[3].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate((uint32_t)m_param[1].immediate() >> m_param[2].immediate());
convert_to_mov_immediate(u32(u32(m_param[1].immediate()) / u32(m_param[2].immediate())));
else if (m_size == 8)
convert_to_mov_immediate((uint64_t)m_param[1].immediate() >> m_param[2].immediate());
convert_to_mov_immediate(u64(u64(m_param[1].immediate()) / u64(m_param[2].immediate())));
}
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
}
break;
// SAR: convert to MOV if immediate or shifting by 0
case OP_SAR:
if (m_param[1].is_immediate() && m_param[2].is_immediate())
// DIVS: convert simple form to MOV if immediate, or if dividing with 0
case OP_DIVS:
if (m_param[0] == m_param[1] && !m_param[3].is_immediate_value(0))
{
if (m_param[2].is_immediate_value(0))
convert_to_mov_immediate(0);
else if (m_param[2].is_immediate() && m_param[3].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate((int32_t)m_param[1].immediate() >> m_param[2].immediate());
convert_to_mov_immediate(s32(s32(m_param[1].immediate()) / s32(m_param[2].immediate())));
else if (m_size == 8)
convert_to_mov_immediate((int64_t)m_param[1].immediate() >> m_param[2].immediate());
convert_to_mov_immediate(s64(s64(m_param[1].immediate()) / s64(m_param[2].immediate())));
}
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
}
break;
// ROL: convert to NOP if immediate or rotating by 0
case OP_ROL:
if (m_param[1].is_immediate() && m_param[2].is_immediate())
// AND: convert to MOV if immediate, or if anding against 0 or 0xffffffff
case OP_AND:
if (m_param[1].is_immediate_value(0) || m_param[2].is_immediate_value(0))
convert_to_mov_immediate(0);
else if (m_param[1].is_immediate() && m_param[2].is_immediate())
convert_to_mov_immediate(m_param[1].immediate() & m_param[2].immediate());
else if (m_param[1].is_immediate_value(instsizemask[m_size]))
convert_to_mov_param(2);
else if (m_param[2].is_immediate_value(instsizemask[m_size]))
convert_to_mov_param(1);
break;
// TEST: no-op if no flags needed
case OP_TEST:
if (m_flags == 0)
nop();
break;
// OR: convert to MOV if immediate, or if oring against 0 or 0xffffffff
case OP_OR:
if (m_param[1].is_immediate_value(instsizemask[m_size]) || m_param[2].is_immediate_value(instsizemask[m_size]))
convert_to_mov_immediate(instsizemask[m_size]);
else if (m_param[1].is_immediate() && m_param[2].is_immediate())
convert_to_mov_immediate(m_param[1].immediate() | m_param[2].immediate());
else if (m_param[1].is_immediate_value(0))
convert_to_mov_param(2);
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
// XOR: convert to MOV if immediate, or if xoring against 0
case OP_XOR:
if (m_param[1].is_immediate() && m_param[2].is_immediate())
convert_to_mov_immediate(m_param[1].immediate() ^ m_param[2].immediate());
else if (m_param[1].is_immediate_value(0))
convert_to_mov_param(2);
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
// LZCNT: convert to MOV if immediate
case OP_LZCNT:
if (m_param[1].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(count_leading_zeros(m_param[1].immediate()));
else if (m_size == 8)
{
if (m_size == 4)
convert_to_mov_immediate(rol32(m_param[1].immediate(), m_param[2].immediate()));
else if (m_size == 8)
convert_to_mov_immediate(rol64(m_param[1].immediate(), m_param[2].immediate()));
if ((m_param[1].immediate() >> 32) == 0)
convert_to_mov_immediate(32 + count_leading_zeros(m_param[1].immediate()));
else
convert_to_mov_immediate(count_leading_zeros(m_param[1].immediate() >> 32));
}
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
}
break;
// ROR: convert to NOP if immediate or rotating by 0
case OP_ROR:
if (m_param[1].is_immediate() && m_param[2].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(rol32(m_param[1].immediate(), 32 - m_param[2].immediate()));
else if (m_size == 8)
convert_to_mov_immediate(rol64(m_param[1].immediate(), 64 - m_param[2].immediate()));
}
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
// BSWAP: convert to MOV if immediate
case OP_BSWAP:
if (m_param[1].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(flipendian_int32(m_param[1].immediate()));
else if (m_size == 8)
convert_to_mov_immediate(flipendian_int64(m_param[1].immediate()));
}
break;
// FMOV: convert to NOP if move-to-self
case OP_FMOV:
if (m_param[0] == m_param[1])
nop();
break;
// SHL: convert to MOV if immediate or shifting by 0
case OP_SHL:
if (m_param[1].is_immediate() && m_param[2].is_immediate())
convert_to_mov_immediate(m_param[1].immediate() << m_param[2].immediate());
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
default:
break;
// SHR: convert to MOV if immediate or shifting by 0
case OP_SHR:
if (m_param[1].is_immediate() && m_param[2].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(u32(m_param[1].immediate()) >> m_param[2].immediate());
else if (m_size == 8)
convert_to_mov_immediate(u64(m_param[1].immediate()) >> m_param[2].immediate());
}
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
// SAR: convert to MOV if immediate or shifting by 0
case OP_SAR:
if (m_param[1].is_immediate() && m_param[2].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(s32(m_param[1].immediate()) >> m_param[2].immediate());
else if (m_size == 8)
convert_to_mov_immediate(s64(m_param[1].immediate()) >> m_param[2].immediate());
}
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
// ROL: convert to NOP if immediate or rotating by 0
case OP_ROL:
if (m_param[1].is_immediate() && m_param[2].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(rol32(m_param[1].immediate(), m_param[2].immediate()));
else if (m_size == 8)
convert_to_mov_immediate(rol64(m_param[1].immediate(), m_param[2].immediate()));
}
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
// ROR: convert to NOP if immediate or rotating by 0
case OP_ROR:
if (m_param[1].is_immediate() && m_param[2].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(rol32(m_param[1].immediate(), 32 - m_param[2].immediate()));
else if (m_size == 8)
convert_to_mov_immediate(rol64(m_param[1].immediate(), 64 - m_param[2].immediate()));
}
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
// FMOV: convert to NOP if move-to-self
case OP_FMOV:
if (m_param[0] == m_param[1])
nop();
break;
default:
break;
}
/*
@ -782,7 +768,7 @@ void uml::instruction::validate()
// make sure we aren't missing any parameters
if (m_numparams < ARRAY_LENGTH(opinfo.param))
assert(opinfo.param[m_numparams].typemask == 0);
#endif
#endif // MAME_DEBUG
}
@ -792,9 +778,9 @@ void uml::instruction::validate()
// instruction
//-------------------------------------------------
uint8_t uml::instruction::input_flags() const
u8 uml::instruction::input_flags() const
{
static const uint8_t flags_for_condition[] =
static constexpr u8 flags_for_condition[] =
{
FLAG_Z, // COND_Z
FLAG_Z, // COND_NZ
@ -814,7 +800,7 @@ uint8_t uml::instruction::input_flags() const
FLAG_S | FLAG_V // COND_GE
};
uint8_t flags = s_opcode_info_table[m_opcode].inflags;
u8 flags = s_opcode_info_table[m_opcode].inflags;
if (flags & 0x80)
flags = m_param[flags - OPFLAGS_P1].immediate() & OPFLAGS_ALL;
if (m_condition != COND_ALWAYS)
@ -829,9 +815,9 @@ uint8_t uml::instruction::input_flags() const
// instruction
//-------------------------------------------------
uint8_t uml::instruction::output_flags() const
u8 uml::instruction::output_flags() const
{
uint8_t flags = s_opcode_info_table[m_opcode].outflags;
u8 flags = s_opcode_info_table[m_opcode].outflags;
if (flags & 0x80)
flags = m_param[flags - OPFLAGS_P1].immediate() & OPFLAGS_ALL;
return flags;
@ -844,7 +830,7 @@ uint8_t uml::instruction::output_flags() const
// instruction
//-------------------------------------------------
uint8_t uml::instruction::modified_flags() const
u8 uml::instruction::modified_flags() const
{
return s_opcode_info_table[m_opcode].modflags;
}
@ -857,20 +843,20 @@ uint8_t uml::instruction::modified_flags() const
std::string uml::instruction::disasm(drcuml_state *drcuml) const
{
static const char *const conditions[] = { "z", "nz", "s", "ns", "c", "nc", "v", "nv", "u", "nu", "a", "be", "g", "le", "l", "ge" };
static const char *const pound_size[] = { "?", "?", "?", "?", "s", "?", "?", "?", "d" };
static const char *const bang_size[] = { "?", "b", "h", "?", "", "?", "?", "?", "d" };
static const char *const fmods[] = { "trunc", "round", "ceil", "floor", "default" };
static const char *const spaces[] = { "program", "data", "io", "3", "4", "5", "6", "7" };
static const char *const sizes[] = { "byte", "word", "dword", "qword" };
const opcode_info &opinfo = s_opcode_info_table[m_opcode];
static char const *const conditions[] = { "z", "nz", "s", "ns", "c", "nc", "v", "nv", "u", "nu", "a", "be", "g", "le", "l", "ge" };
static char const *const pound_size[] = { "?", "?", "?", "?", "s", "?", "?", "?", "d" };
static char const *const bang_size[] = { "?", "b", "h", "?", "", "?", "?", "?", "d" };
static char const *const fmods[] = { "trunc", "round", "ceil", "floor", "default" };
static char const *const spaces[] = { "program", "data", "io", "3", "4", "5", "6", "7" };
static char const *const sizes[] = { "byte", "word", "dword", "qword" };
assert(m_opcode != OP_INVALID && m_opcode < OP_MAX);
opcode_info const &opinfo = s_opcode_info_table[m_opcode];
// start with the raw mnemonic and substitute sizes
std::ostringstream buffer;
for (const char *opsrc = opinfo.mnemonic; *opsrc != 0; opsrc++)
for (char const *opsrc = opinfo.mnemonic; *opsrc != 0; opsrc++)
if (*opsrc == '!')
util::stream_format(buffer, "%s", bang_size[m_size]);
else if (*opsrc == '#')
@ -879,12 +865,8 @@ std::string uml::instruction::disasm(drcuml_state *drcuml) const
util::stream_format(buffer, "%c", *opsrc);
// pad to 8 spaces
int pad = 8 - buffer.tellp();
while (pad > 0)
{
for (int pad = 8 - buffer.tellp(); (pad > 0); --pad)
buffer.put(' ');
pad--;
}
// iterate through parameters
for (int pnum = 0; pnum < m_numparams; pnum++)
@ -898,82 +880,79 @@ std::string uml::instruction::disasm(drcuml_state *drcuml) const
// ouput based on type
switch (param.type())
{
// immediates have several special cases
case parameter::PTYPE_IMMEDIATE:
// immediates have several special cases
case parameter::PTYPE_IMMEDIATE:
{
// determine the size of the immediate
int size;
switch (opinfo.param[pnum].size)
{
// determine the size of the immediate
int size;
switch (opinfo.param[pnum].size)
{
case PSIZE_4: size = 4; break;
case PSIZE_8: size = 8; break;
case PSIZE_P1: size = 1 << m_param[0].size(); break;
case PSIZE_P2: size = 1 << m_param[1].size(); break;
case PSIZE_P3: size = 1 << m_param[2].size(); break;
case PSIZE_P4: size = 1 << m_param[3].size(); break;
default:
case PSIZE_OP: size = m_size; break;
}
// truncate to size
uint64_t value = param.immediate();
if (size == 1) value = (uint8_t)value;
if (size == 2) value = (uint16_t)value;
if (size == 4) value = (uint32_t)value;
if ((uint32_t)value == value)
util::stream_format(buffer, "$%X", (uint32_t)value);
else
util::stream_format(buffer, "$%X%08X", (uint32_t)(value >> 32), (uint32_t)value);
case PSIZE_4: size = 4; break;
case PSIZE_8: size = 8; break;
case PSIZE_P1: size = 1 << m_param[0].size(); break;
case PSIZE_P2: size = 1 << m_param[1].size(); break;
case PSIZE_P3: size = 1 << m_param[2].size(); break;
case PSIZE_P4: size = 1 << m_param[3].size(); break;
default:
case PSIZE_OP: size = m_size; break;
}
break;
// immediates have several special cases
case parameter::PTYPE_SIZE:
util::stream_format(buffer, "%s", sizes[param.size()]);
break;
// truncate to size
u64 value = param.immediate();
if (size == 1) value = u8(value);
if (size == 2) value = u16(value);
if (size == 4) value = u32(value);
util::stream_format(buffer, "$%X", value);
}
break;
// size + address space immediate
case parameter::PTYPE_SIZE_SPACE:
util::stream_format(buffer, "%s_%s", spaces[param.space()], sizes[param.size()]);
break;
// immediates have several special cases
case parameter::PTYPE_SIZE:
util::stream_format(buffer, "%s", sizes[param.size()]);
break;
// size + scale immediate
case parameter::PTYPE_SIZE_SCALE:
{
int scale = param.scale();
int size = param.size();
if (scale == size)
util::stream_format(buffer, "%s", sizes[size]);
else
util::stream_format(buffer, "%s_x%d", sizes[size], 1 << scale);
}
break;
// size + address space immediate
case parameter::PTYPE_SIZE_SPACE:
util::stream_format(buffer, "%s_%s", spaces[param.space()], sizes[param.size()]);
break;
// fmod immediate
case parameter::PTYPE_ROUNDING:
util::stream_format(buffer, "%s", fmods[param.rounding()]);
break;
// size + scale immediate
case parameter::PTYPE_SIZE_SCALE:
{
int const scale = param.scale();
int const size = param.size();
if (scale == size)
util::stream_format(buffer, "%s", sizes[size]);
else
util::stream_format(buffer, "%s_x%d", sizes[size], 1 << scale);
}
break;
// integer registers
case parameter::PTYPE_INT_REGISTER:
util::stream_format(buffer, "i%d", param.ireg() - REG_I0);
break;
// fmod immediate
case parameter::PTYPE_ROUNDING:
util::stream_format(buffer, "%s", fmods[param.rounding()]);
break;
// floating point registers
case parameter::PTYPE_FLOAT_REGISTER:
util::stream_format(buffer, "f%d", param.freg() - REG_F0);
break;
// integer registers
case parameter::PTYPE_INT_REGISTER:
util::stream_format(buffer, "i%d", param.ireg() - REG_I0);
break;
// map variables
case parameter::PTYPE_MAPVAR:
util::stream_format(buffer, "m%d", param.mapvar() - MAPVAR_M0);
break;
// floating point registers
case parameter::PTYPE_FLOAT_REGISTER:
util::stream_format(buffer, "f%d", param.freg() - REG_F0);
break;
// memory
case parameter::PTYPE_MEMORY:
// map variables
case parameter::PTYPE_MAPVAR:
util::stream_format(buffer, "m%d", param.mapvar() - MAPVAR_M0);
break;
// memory
case parameter::PTYPE_MEMORY:
{
const char *symbol;
uint32_t symoffset;
u32 symoffset;
// symbol
if (drcuml != nullptr && (symbol = drcuml->symbol_find(param.memory(), &symoffset)) != nullptr)
@ -986,32 +965,32 @@ std::string uml::instruction::disasm(drcuml_state *drcuml) const
// cache memory
else if (drcuml != nullptr && drcuml->cache().contains_pointer(param.memory()))
util::stream_format(buffer, "[+$%X]", (uint32_t)(uintptr_t)((drccodeptr)param.memory() - drcuml->cache().near()));
util::stream_format(buffer, "[+$%X]", u32(uintptr_t(drccodeptr(param.memory()) - drcuml->cache().near())));
// general memory
else
util::stream_format(buffer, "[[$%p]]", param.memory());
break;
}
break;
// string pointer
case parameter::PTYPE_STRING:
util::stream_format(buffer, "%s", (const char *)(uintptr_t)param.string());
break;
// string pointer
case parameter::PTYPE_STRING:
util::stream_format(buffer, "%s", reinterpret_cast<char const *>(uintptr_t(param.string())));
break;
// handle pointer
case parameter::PTYPE_CODE_HANDLE:
util::stream_format(buffer, "%s", param.handle().string());
break;
// handle pointer
case parameter::PTYPE_CODE_HANDLE:
util::stream_format(buffer, "%s", param.handle().string());
break;
// label
case parameter::PTYPE_CODE_LABEL:
util::stream_format(buffer, "$%8X", param.label().label());
break;
// label
case parameter::PTYPE_CODE_LABEL:
util::stream_format(buffer, "$%8X", param.label().label());
break;
default:
util::stream_format(buffer, "???");
break;
default:
util::stream_format(buffer, "???");
break;
}
}

View File

@ -7,12 +7,11 @@
Universal machine language definitions and classes.
***************************************************************************/
#ifndef MAME_CPU_UML_H
#define MAME_CPU_UML_H
#pragma once
#ifndef __UML_H__
#define __UML_H__
#include "drccache.h"
@ -31,31 +30,31 @@ struct drcuml_machine_state;
namespace uml
{
// integer registers
const int REG_I0 = 0x400;
const int REG_I_COUNT = 10;
const int REG_I_END = REG_I0 + REG_I_COUNT;
constexpr int REG_I0 = 0x400;
constexpr int REG_I_COUNT = 10;
constexpr int REG_I_END = REG_I0 + REG_I_COUNT;
// floating point registers
const int REG_F0 = 0x800;
const int REG_F_COUNT = 10;
const int REG_F_END = REG_F0 + REG_F_COUNT;
constexpr int REG_F0 = 0x800;
constexpr int REG_F_COUNT = 10;
constexpr int REG_F_END = REG_F0 + REG_F_COUNT;
// vector registers
const int REG_V0 = 0xc00;
const int REG_V_COUNT = 10;
const int REG_V_END = REG_V0 + REG_V_COUNT;
constexpr int REG_V0 = 0xc00;
constexpr int REG_V_COUNT = 10;
constexpr int REG_V_END = REG_V0 + REG_V_COUNT;
// map variables
const int MAPVAR_M0 = 0x1000;
const int MAPVAR_COUNT = 10;
const int MAPVAR_END = MAPVAR_M0 + MAPVAR_COUNT;
constexpr int MAPVAR_M0 = 0x1000;
constexpr int MAPVAR_COUNT = 10;
constexpr int MAPVAR_END = MAPVAR_M0 + MAPVAR_COUNT;
// flag definitions
const uint8_t FLAG_C = 0x01; // carry flag
const uint8_t FLAG_V = 0x02; // overflow flag (defined for integer only)
const uint8_t FLAG_Z = 0x04; // zero flag
const uint8_t FLAG_S = 0x08; // sign flag (defined for integer only)
const uint8_t FLAG_U = 0x10; // unordered flag (defined for FP only)
constexpr u8 FLAG_C = 0x01; // carry flag
constexpr u8 FLAG_V = 0x02; // overflow flag (defined for integer only)
constexpr u8 FLAG_Z = 0x04; // zero flag
constexpr u8 FLAG_S = 0x08; // sign flag (defined for integer only)
constexpr u8 FLAG_U = 0x10; // unordered flag (defined for FP only)
// testable conditions; note that these are defined such that (condition ^ 1) is
// always the opposite
@ -242,7 +241,7 @@ namespace uml
code_handle *next() const { return m_next; }
drccodeptr codeptr() const { return *m_code; }
drccodeptr *codeptr_addr() { return m_code; }
const char *string() const { return m_string.c_str(); }
char const *string() const { return m_string.c_str(); }
// setters
void set_codeptr(drccodeptr code);
@ -260,18 +259,18 @@ namespace uml
{
public:
// construction
code_label(uint32_t label = 0) : m_label(label) { }
constexpr code_label(u32 label = 0) : m_label(label) { }
// operators
operator uint32_t &() { return m_label; }
bool operator==(const code_label &rhs) const { return (m_label == rhs.m_label); }
bool operator!=(const code_label &rhs) const { return (m_label != rhs.m_label); }
operator u32 &() { return m_label; }
constexpr bool operator==(code_label const &rhs) const { return (m_label == rhs.m_label); }
constexpr bool operator!=(code_label const &rhs) const { return (m_label != rhs.m_label); }
// getters
uint32_t label() const { return m_label; }
constexpr u32 label() const { return m_label; }
private:
uint32_t m_label;
u32 m_label;
};
// a parameter for a UML instruction is encoded like this
@ -300,36 +299,36 @@ namespace uml
};
// represents the value of an opcode parameter
typedef uint64_t parameter_value;
typedef u64 parameter_value;
// construction
parameter() : m_type(PTYPE_NONE), m_value(0) { }
parameter(const parameter &param) : m_type(param.m_type), m_value(param.m_value) { }
parameter(uint64_t val) : m_type(PTYPE_IMMEDIATE), m_value(val) { }
constexpr parameter() : m_type(PTYPE_NONE), m_value(0) { }
constexpr parameter(parameter const &param) : m_type(param.m_type), m_value(param.m_value) { }
constexpr parameter(u64 val) : m_type(PTYPE_IMMEDIATE), m_value(val) { }
parameter(operand_size size, memory_scale scale) : m_type(PTYPE_SIZE_SCALE), m_value((scale << 4) | size) { assert(size >= SIZE_BYTE && size <= SIZE_DQWORD); assert(scale >= SCALE_x1 && scale <= SCALE_x8); }
parameter(operand_size size, memory_space space) : m_type(PTYPE_SIZE_SPACE), m_value((space << 4) | size) { assert(size >= SIZE_BYTE && size <= SIZE_DQWORD); assert(space >= SPACE_PROGRAM && space <= SPACE_IO); }
parameter(code_handle &handle) : m_type(PTYPE_CODE_HANDLE), m_value(reinterpret_cast<parameter_value>(&handle)) { }
parameter(code_label &label) : m_type(PTYPE_CODE_LABEL), m_value(label) { }
constexpr parameter(code_label &label) : m_type(PTYPE_CODE_LABEL), m_value(label) { }
// creators for types that don't safely default
static inline parameter make_ireg(int regnum) { assert(regnum >= REG_I0 && regnum < REG_I_END); return parameter(PTYPE_INT_REGISTER, regnum); }
static inline parameter make_freg(int regnum) { assert(regnum >= REG_F0 && regnum < REG_F_END); return parameter(PTYPE_FLOAT_REGISTER, regnum); }
static inline parameter make_vreg(int regnum) { assert(regnum >= REG_V0 && regnum < REG_V_END); return parameter(PTYPE_VECTOR_REGISTER, regnum); }
static inline parameter make_mapvar(int mvnum) { assert(mvnum >= MAPVAR_M0 && mvnum < MAPVAR_END); return parameter(PTYPE_MAPVAR, mvnum); }
static inline parameter make_memory(void *base) { return parameter(PTYPE_MEMORY, reinterpret_cast<parameter_value>(base)); }
static inline parameter make_memory(const void *base) { return parameter(PTYPE_MEMORY, reinterpret_cast<parameter_value>(const_cast<void *>(base))); }
static inline parameter make_size(operand_size size) { assert(size >= SIZE_BYTE && size <= SIZE_DQWORD); return parameter(PTYPE_SIZE, size); }
static inline parameter make_string(const char *string) { return parameter(PTYPE_STRING, reinterpret_cast<parameter_value>(const_cast<char *>(string))); }
static inline parameter make_cfunc(c_function func) { return parameter(PTYPE_C_FUNCTION, reinterpret_cast<parameter_value>(func)); }
static inline parameter make_rounding(float_rounding_mode mode) { assert(mode >= ROUND_TRUNC && mode <= ROUND_DEFAULT); return parameter(PTYPE_ROUNDING, mode); }
static parameter make_ireg(int regnum) { assert(regnum >= REG_I0 && regnum < REG_I_END); return parameter(PTYPE_INT_REGISTER, regnum); }
static parameter make_freg(int regnum) { assert(regnum >= REG_F0 && regnum < REG_F_END); return parameter(PTYPE_FLOAT_REGISTER, regnum); }
static parameter make_vreg(int regnum) { assert(regnum >= REG_V0 && regnum < REG_V_END); return parameter(PTYPE_VECTOR_REGISTER, regnum); }
static parameter make_mapvar(int mvnum) { assert(mvnum >= MAPVAR_M0 && mvnum < MAPVAR_END); return parameter(PTYPE_MAPVAR, mvnum); }
static parameter make_memory(void *base) { return parameter(PTYPE_MEMORY, reinterpret_cast<parameter_value>(base)); }
static parameter make_memory(void const *base) { return parameter(PTYPE_MEMORY, reinterpret_cast<parameter_value>(const_cast<void *>(base))); }
static parameter make_size(operand_size size) { assert(size >= SIZE_BYTE && size <= SIZE_DQWORD); return parameter(PTYPE_SIZE, size); }
static parameter make_string(char const *string) { return parameter(PTYPE_STRING, reinterpret_cast<parameter_value>(const_cast<char *>(string))); }
static parameter make_cfunc(c_function func) { return parameter(PTYPE_C_FUNCTION, reinterpret_cast<parameter_value>(func)); }
static parameter make_rounding(float_rounding_mode mode) { assert(mode >= ROUND_TRUNC && mode <= ROUND_DEFAULT); return parameter(PTYPE_ROUNDING, mode); }
// operators
bool operator==(const parameter &rhs) const { return (m_type == rhs.m_type && m_value == rhs.m_value); }
bool operator!=(const parameter &rhs) const { return (m_type != rhs.m_type || m_value != rhs.m_value); }
constexpr bool operator==(parameter const &rhs) const { return (m_type == rhs.m_type) && (m_value == rhs.m_value); }
constexpr bool operator!=(parameter const &rhs) const { return (m_type != rhs.m_type) || (m_value != rhs.m_value); }
// getters
parameter_type type() const { return m_type; }
uint64_t immediate() const { assert(m_type == PTYPE_IMMEDIATE); return m_value; }
constexpr parameter_type type() const { return m_type; }
u64 immediate() const { assert(m_type == PTYPE_IMMEDIATE); return m_value; }
int ireg() const { assert(m_type == PTYPE_INT_REGISTER); assert(m_value >= REG_I0 && m_value < REG_I_END); return m_value; }
int freg() const { assert(m_type == PTYPE_FLOAT_REGISTER); assert(m_value >= REG_F0 && m_value < REG_F_END); return m_value; }
int vreg() const { assert(m_type == PTYPE_VECTOR_REGISTER); assert(m_value >= REG_V0 && m_value < REG_V_END); return m_value; }
@ -342,26 +341,26 @@ namespace uml
code_label label() const { assert(m_type == PTYPE_CODE_LABEL); return code_label(m_value); }
c_function cfunc() const { assert(m_type == PTYPE_C_FUNCTION); return reinterpret_cast<c_function>(m_value); }
float_rounding_mode rounding() const { assert(m_type == PTYPE_ROUNDING); return float_rounding_mode(m_value); }
const char *string() const { assert(m_type == PTYPE_STRING); return reinterpret_cast<const char *>(m_value); }
char const *string() const { assert(m_type == PTYPE_STRING); return reinterpret_cast<char const *>(m_value); }
// type queries
bool is_immediate() const { return (m_type == PTYPE_IMMEDIATE); }
bool is_int_register() const { return (m_type == PTYPE_INT_REGISTER); }
bool is_float_register() const { return (m_type == PTYPE_FLOAT_REGISTER); }
bool is_vector_register() const { return (m_type == PTYPE_VECTOR_REGISTER); }
bool is_mapvar() const { return (m_type == PTYPE_MAPVAR); }
bool is_memory() const { return (m_type == PTYPE_MEMORY); }
bool is_size() const { return (m_type == PTYPE_SIZE); }
bool is_size_scale() const { return (m_type == PTYPE_SIZE_SCALE); }
bool is_size_space() const { return (m_type == PTYPE_SIZE_SPACE); }
bool is_code_handle() const { return (m_type == PTYPE_CODE_HANDLE); }
bool is_code_label() const { return (m_type == PTYPE_CODE_LABEL); }
bool is_c_function() const { return (m_type == PTYPE_C_FUNCTION); }
bool is_rounding() const { return (m_type == PTYPE_ROUNDING); }
bool is_string() const { return (m_type == PTYPE_STRING); }
constexpr bool is_immediate() const { return m_type == PTYPE_IMMEDIATE; }
constexpr bool is_int_register() const { return m_type == PTYPE_INT_REGISTER; }
constexpr bool is_float_register() const { return m_type == PTYPE_FLOAT_REGISTER; }
constexpr bool is_vector_register() const { return m_type == PTYPE_VECTOR_REGISTER; }
constexpr bool is_mapvar() const { return m_type == PTYPE_MAPVAR; }
constexpr bool is_memory() const { return m_type == PTYPE_MEMORY; }
constexpr bool is_size() const { return m_type == PTYPE_SIZE; }
constexpr bool is_size_scale() const { return m_type == PTYPE_SIZE_SCALE; }
constexpr bool is_size_space() const { return m_type == PTYPE_SIZE_SPACE; }
constexpr bool is_code_handle() const { return m_type == PTYPE_CODE_HANDLE; }
constexpr bool is_code_label() const { return m_type == PTYPE_CODE_LABEL; }
constexpr bool is_c_function() const { return m_type == PTYPE_C_FUNCTION; }
constexpr bool is_rounding() const { return m_type == PTYPE_ROUNDING; }
constexpr bool is_string() const { return m_type == PTYPE_STRING; }
// other queries
bool is_immediate_value(uint64_t value) const { return (m_type == PTYPE_IMMEDIATE && m_value == value); }
constexpr bool is_immediate_value(u64 value) const { return (m_type == PTYPE_IMMEDIATE) && (m_value == value); }
private:
// private constructor
@ -377,18 +376,18 @@ namespace uml
{
struct parameter_info
{
uint8_t output; // input or output?
uint8_t size; // size of the parameter
uint16_t typemask; // types allowed
u8 output; // input or output?
u8 size; // size of the parameter
u16 typemask; // types allowed
};
opcode_t opcode; // the opcode itself
const char * mnemonic; // mnemonic string
uint8_t sizes; // allowed sizes
char const * mnemonic; // mnemonic string
u8 sizes; // allowed sizes
bool condition; // conditions allowed?
uint8_t inflags; // input flags
uint8_t outflags; // output flags
uint8_t modflags; // modified flags
u8 inflags; // input flags
u8 outflags; // output flags
u8 modflags; // modified flags
parameter_info param[4]; // information about parameters
};
@ -397,37 +396,37 @@ namespace uml
{
public:
// construction/destruction
instruction();
constexpr instruction() { }
// getters
opcode_t opcode() const { return m_opcode; }
condition_t condition() const { return m_condition; }
uint8_t flags() const { return m_flags; }
uint8_t size() const { return m_size; }
uint8_t numparams() const { return m_numparams; }
constexpr opcode_t opcode() const { return m_opcode; }
constexpr condition_t condition() const { return m_condition; }
constexpr u8 flags() const { return m_flags; }
constexpr u8 size() const { return m_size; }
constexpr u8 numparams() const { return m_numparams; }
const parameter &param(int index) const { assert(index < m_numparams); return m_param[index]; }
// setters
void set_flags(uint8_t flags) { m_flags = flags; }
void set_mapvar(int paramnum, uint32_t value) { assert(paramnum < m_numparams); assert(m_param[paramnum].is_mapvar()); m_param[paramnum] = value; }
void set_flags(u8 flags) { m_flags = flags; }
void set_mapvar(int paramnum, u32 value) { assert(paramnum < m_numparams); assert(m_param[paramnum].is_mapvar()); m_param[paramnum] = value; }
// misc
std::string disasm(drcuml_state *drcuml = nullptr) const;
uint8_t input_flags() const;
uint8_t output_flags() const;
uint8_t modified_flags() const;
u8 input_flags() const;
u8 output_flags() const;
u8 modified_flags() const;
void simplify();
// compile-time opcodes
void handle(code_handle &hand) { configure(OP_HANDLE, 4, hand); }
void hash(uint32_t mode, uint32_t pc) { configure(OP_HASH, 4, mode, pc); }
void hash(u32 mode, u32 pc) { configure(OP_HASH, 4, mode, pc); }
void label(code_label lab) { configure(OP_LABEL, 4, lab); }
void comment(const char *string) { configure(OP_COMMENT, 4, parameter::make_string(string)); }
void mapvar(parameter mapvar, uint32_t value) { assert(mapvar.is_mapvar()); configure(OP_MAPVAR, 4, mapvar, value); }
void comment(char const *string) { configure(OP_COMMENT, 4, parameter::make_string(string)); }
void mapvar(parameter mapvar, u32 value) { assert(mapvar.is_mapvar()); configure(OP_MAPVAR, 4, mapvar, value); }
// control flow operations
void nop() { configure(OP_NOP, 4); }
void debug(uint32_t pc) { configure(OP_DEBUG, 4, pc); }
void debug(u32 pc) { configure(OP_DEBUG, 4, pc); }
void exit(parameter param) { configure(OP_EXIT, 4, param); }
void exit(condition_t cond, parameter param) { configure(OP_EXIT, 4, param, cond); }
void hashjmp(parameter mode, parameter pc, code_handle &handle) { configure(OP_HASHJMP, 4, mode, pc, handle); }
@ -447,13 +446,13 @@ namespace uml
void setfmod(parameter mode) { configure(OP_SETFMOD, 4, mode); }
void getfmod(parameter dst) { configure(OP_GETFMOD, 4, dst); }
void getexp(parameter dst) { configure(OP_GETEXP, 4, dst); }
void getflgs(parameter dst, uint32_t flags) { configure(OP_GETFLGS, 4, dst, flags); }
void getflgs(parameter dst, u32 flags) { configure(OP_GETFLGS, 4, dst, flags); }
void save(drcuml_machine_state *dst) { configure(OP_SAVE, 4, parameter::make_memory(dst)); }
void restore(drcuml_machine_state *src) { configure(OP_RESTORE, 4, parameter::make_memory(src)); }
// 32-bit integer operations
void load(parameter dst, const void *base, parameter index, operand_size size, memory_scale scale = SCALE_DEFAULT) { configure(OP_LOAD, 4, dst, parameter::make_memory(base), index, parameter(size, scale)); }
void loads(parameter dst, const void *base, parameter index, operand_size size, memory_scale scale = SCALE_DEFAULT) { configure(OP_LOADS, 4, dst, parameter::make_memory(base), index, parameter(size, scale)); }
void load(parameter dst, void const *base, parameter index, operand_size size, memory_scale scale = SCALE_DEFAULT) { configure(OP_LOAD, 4, dst, parameter::make_memory(base), index, parameter(size, scale)); }
void loads(parameter dst, void const *base, parameter index, operand_size size, memory_scale scale = SCALE_DEFAULT) { configure(OP_LOADS, 4, dst, parameter::make_memory(base), index, parameter(size, scale)); }
void store(void *base, parameter index, parameter src1, operand_size size, memory_scale scale = SCALE_DEFAULT) { configure(OP_STORE, 4, parameter::make_memory(base), index, src1, parameter(size, scale)); }
void read(parameter dst, parameter src1, operand_size size, memory_space space = SPACE_PROGRAM) { configure(OP_READ, 4, dst, src1, parameter(size, space)); }
void readm(parameter dst, parameter src1, parameter mask, operand_size size, memory_space space = SPACE_PROGRAM) { configure(OP_READM, 4, dst, src1, mask, parameter(size, space)); }
@ -491,8 +490,8 @@ namespace uml
void rorc(parameter dst, parameter src, parameter count) { configure(OP_RORC, 4, dst, src, count); }
// 64-bit integer operations
void dload(parameter dst, const void *base, parameter index, operand_size size, memory_scale scale = SCALE_DEFAULT) { configure(OP_LOAD, 8, dst, parameter::make_memory(base), index, parameter(size, scale)); }
void dloads(parameter dst, const void *base, parameter index, operand_size size, memory_scale scale = SCALE_DEFAULT) { configure(OP_LOADS, 8, dst, parameter::make_memory(base), index, parameter(size, scale)); }
void dload(parameter dst, void const *base, parameter index, operand_size size, memory_scale scale = SCALE_DEFAULT) { configure(OP_LOAD, 8, dst, parameter::make_memory(base), index, parameter(size, scale)); }
void dloads(parameter dst, void const *base, parameter index, operand_size size, memory_scale scale = SCALE_DEFAULT) { configure(OP_LOADS, 8, dst, parameter::make_memory(base), index, parameter(size, scale)); }
void dstore(void *base, parameter index, parameter src1, operand_size size, memory_scale scale = SCALE_DEFAULT) { configure(OP_STORE, 8, parameter::make_memory(base), index, src1, parameter(size, scale)); }
void dread(parameter dst, parameter src1, operand_size size, memory_space space = SPACE_PROGRAM) { configure(OP_READ, 8, dst, src1, parameter(size, space)); }
void dreadm(parameter dst, parameter src1, parameter mask, operand_size size, memory_space space = SPACE_PROGRAM) { configure(OP_READM, 8, dst, src1, mask, parameter(size, space)); }
@ -530,7 +529,7 @@ namespace uml
void drorc(parameter dst, parameter src, parameter count) { configure(OP_RORC, 8, dst, src, count); }
// 32-bit floating point operations
void fsload(parameter dst, const void *base, parameter index) { configure(OP_FLOAD, 4, dst, parameter::make_memory(base), index); }
void fsload(parameter dst, void const *base, parameter index) { configure(OP_FLOAD, 4, dst, parameter::make_memory(base), index); }
void fsstore(void *base, parameter index, parameter src1) { configure(OP_FSTORE, 4, parameter::make_memory(base), index, src1); }
void fsread(parameter dst, parameter src1, memory_space space) { configure(OP_FREAD, 4, dst, src1, parameter(SIZE_SHORT, space)); }
void fswrite(parameter dst, parameter src1, memory_space space) { configure(OP_FWRITE, 4, dst, src1, parameter(SIZE_SHORT, space)); }
@ -553,7 +552,7 @@ namespace uml
void icopyfs(parameter dst, parameter src) { configure(OP_ICOPYF, 4, dst, src); }
// 64-bit floating point operations
void fdload(parameter dst, const void *base, parameter index) { configure(OP_FLOAD, 8, dst, parameter::make_memory(base), index); }
void fdload(parameter dst, void const *base, parameter index) { configure(OP_FLOAD, 8, dst, parameter::make_memory(base), index); }
void fdstore(void *base, parameter index, parameter src1) { configure(OP_FSTORE, 8, parameter::make_memory(base), index, src1); }
void fdread(parameter dst, parameter src1, memory_space space) { configure(OP_FREAD, 8, dst, src1, parameter(SIZE_DOUBLE, space)); }
void fdwrite(parameter dst, parameter src1, memory_space space) { configure(OP_FWRITE, 8, dst, src1, parameter(SIZE_DOUBLE, space)); }
@ -577,38 +576,38 @@ namespace uml
void icopyfd(parameter dst, parameter src) { configure(OP_ICOPYF, 8, dst, src); }
// constants
static const int MAX_PARAMS = 4;
static constexpr int MAX_PARAMS = 4;
private:
// internal configuration
void configure(opcode_t op, uint8_t size, condition_t cond = COND_ALWAYS);
void configure(opcode_t op, uint8_t size, parameter p0, condition_t cond = COND_ALWAYS);
void configure(opcode_t op, uint8_t size, parameter p0, parameter p1, condition_t cond = COND_ALWAYS);
void configure(opcode_t op, uint8_t size, parameter p0, parameter p1, parameter p2, condition_t cond = COND_ALWAYS);
void configure(opcode_t op, uint8_t size, parameter p0, parameter p1, parameter p2, parameter p3, condition_t cond = COND_ALWAYS);
void configure(opcode_t op, u8 size, condition_t cond = COND_ALWAYS);
void configure(opcode_t op, u8 size, parameter p0, condition_t cond = COND_ALWAYS);
void configure(opcode_t op, u8 size, parameter p0, parameter p1, condition_t cond = COND_ALWAYS);
void configure(opcode_t op, u8 size, parameter p0, parameter p1, parameter p2, condition_t cond = COND_ALWAYS);
void configure(opcode_t op, u8 size, parameter p0, parameter p1, parameter p2, parameter p3, condition_t cond = COND_ALWAYS);
// opcode validation and simplification
void validate();
void convert_to_mov_immediate(uint64_t immediate) { m_opcode = OP_MOV; m_numparams = 2; m_param[1] = immediate; }
void convert_to_mov_immediate(u64 immediate) { m_opcode = OP_MOV; m_numparams = 2; m_param[1] = immediate; }
void convert_to_mov_param(int pnum) { m_opcode = OP_MOV; m_numparams = 2; m_param[1] = m_param[pnum]; }
// internal state
opcode_t m_opcode; // opcode
condition_t m_condition; // condition
uint8_t m_flags; // flags
uint8_t m_size; // operation size
uint8_t m_numparams; // number of parameters
parameter m_param[MAX_PARAMS];// up to 4 parameters
opcode_t m_opcode = OP_INVALID; // opcode
condition_t m_condition = COND_ALWAYS; // condition
u8 m_flags = 0; // flags
u8 m_size = 4; // operation size
u8 m_numparams = 0; // number of parameters
parameter m_param[MAX_PARAMS]; // up to 4 parameters
static const opcode_info s_opcode_info_table[OP_MAX];
static opcode_info const s_opcode_info_table[OP_MAX];
};
// structure describing rules for parameter encoding
struct parameter_info
{
uint8_t output; // input or output?
uint8_t size; // size of the parameter
uint16_t typemask; // types allowed
u8 output; // input or output?
u8 size; // size of the parameter
u16 typemask; // types allowed
};
// global inline functions to specify a register parameter by index
@ -666,5 +665,4 @@ namespace uml
const parameter M9(parameter::make_mapvar(MAPVAR_M0 + 9));
}
#endif /* __UML_H__ */
#endif // MAME_CPU_UML_H

View File

@ -313,7 +313,7 @@ static const dasm_table_entry dasm_table[] =
{ "cquestrot", be, -3, []() -> util::disasm_interface * { return new cquestrot_disassembler; } },
{ "cquestsnd", be, -3, []() -> util::disasm_interface * { return new cquestsnd_disassembler; } },
{ "ds5002fp", le, 0, []() -> util::disasm_interface * { return new ds5002fp_disassembler; } },
{ "dsp16a", le, -1, []() -> util::disasm_interface * { return new dsp16a_disassembler; } },
{ "dsp16", le, -1, []() -> util::disasm_interface * { return new dsp16_disassembler; } },
{ "dsp32c", le, 0, []() -> util::disasm_interface * { return new dsp32c_disassembler; } },
{ "dsp56k", le, -1, []() -> util::disasm_interface * { return new dsp56k_disassembler; } },
{ "e0c6200", be, -1, []() -> util::disasm_interface * { return new e0c6200_disassembler; } },