diff options
Diffstat (limited to 'src/devices')
-rw-r--r-- | src/devices/cpu/drcuml.cpp | 646 | ||||
-rw-r--r-- | src/devices/cpu/uml.cpp | 57 | ||||
-rw-r--r-- | src/devices/cpu/uml.h | 28 |
3 files changed, 69 insertions, 662 deletions
diff --git a/src/devices/cpu/drcuml.cpp b/src/devices/cpu/drcuml.cpp index 47de628574e..9a345f8e41a 100644 --- a/src/devices/cpu/drcuml.cpp +++ b/src/devices/cpu/drcuml.cpp @@ -52,7 +52,6 @@ // DEBUGGING //************************************************************************** -#define VALIDATE_BACKEND (0) #define LOG_SIMPLIFICATIONS (0) @@ -70,17 +69,6 @@ #define make_drcbe_native MAKE_DRCBE(NATIVE_DRC) -// structure describing back-end validation test -struct bevalidate_test -{ - uml::opcode_t opcode; - u8 size; - u8 iflags; - u8 flags; - u64 param[4]; -}; - - //************************************************************************** // DRC BACKEND INTERFACE @@ -178,19 +166,6 @@ void drcuml_state::reset() // call the backend to reset m_beintf->reset(); - - // do a one-time validation if requested -#if 0 - if (VALIDATE_BACKEND) - { - static bool validated = false; - if (!validated) - { - validated = true; - validate_backend(this); - } - } -#endif } catch (drcuml_block::abort_compilation &) { @@ -416,18 +391,30 @@ void drcuml_block::optimize() } inst.set_flags(accumflags); - // track mapvars if (inst.opcode() == uml::OP_MAPVAR) + { + // track mapvars mapvar[inst.param(0).mapvar() - uml::MAPVAR_M0] = inst.param(1).immediate(); - - // convert all mapvar parameters to immediates + } else if (inst.opcode() != uml::OP_RECOVER) + { + // convert all mapvar parameters to immediates for (int pnum = 0; pnum < inst.numparams(); pnum++) + { if (inst.param(pnum).is_mapvar()) inst.set_mapvar(pnum, mapvar[inst.param(pnum).mapvar() - uml::MAPVAR_M0]); + } + } // now that flags are correct, simplify the instruction +#if LOG_SIMPLIFICATIONS + uml::instruction const orig = inst; +#endif inst.simplify(); +#if LOG_SIMPLIFICATIONS + if (orig != inst) + osd_printf_debug("Simplified: %-50.50s -> %s\n", orig.disasm(&m_drcuml), inst.disasm(&m_drcuml)); +#endif } } @@ -522,606 +509,3 @@ char const *drcuml_block::get_comment_text(uml::instruction const &inst, std::st return nullptr; } } - - - -#if 0 - -/*************************************************************************** - BACK-END VALIDATION -***************************************************************************/ - -//------------------------------------------------- -// effective_test_psize - return the effective -// parameter size based on the size and fixed -// array of parameter values -//------------------------------------------------- - -inline uint8_t effective_test_psize(const opcode_info &opinfo, int pnum, int instsize, const uint64_t *params) -{ - switch (opinfo.param[pnum].size) - { - case PSIZE_4: return 4; - case PSIZE_8: return 8; - case PSIZE_OP: return instsize; - case PSIZE_P1: return 1 << (params[0] & 3); - case PSIZE_P2: return 1 << (params[1] & 3); - case PSIZE_P3: return 1 << (params[2] & 3); - case PSIZE_P4: return 1 << (params[3] & 3); - } - return instsize; -} - -#define TEST_ENTRY_2(op, size, p1, p2, flags) { OP_##op, size, 0, flags, { u64(p1), u64(p2) } }, -#define TEST_ENTRY_2F(op, size, p1, p2, iflags, flags) { OP_##op, size, iflags, flags, { u64(p1), u64(p2) } }, -#define TEST_ENTRY_3(op, size, p1, p2, p3, flags) { OP_##op, size, 0, flags, { u64(p1), u64(p2), u64(p3) } }, -#define TEST_ENTRY_3F(op, size, p1, p2, p3, iflags, flags) { OP_##op, size, iflags, flags, { u64(p1), u64(p2), u64(p3) } }, -#define TEST_ENTRY_4(op, size, p1, p2, p3, p4, flags) { OP_##op, size, 0, flags, { u64(p1), u64(p2), u64(p3), u64(p4) } }, -#define TEST_ENTRY_4F(op, size, p1, p2, p3, p4, iflags, flags) { OP_##op, size, iflags, flags, { u64(p1), u64(p2), u64(p3), u64(p4) } }, - -static const bevalidate_test bevalidate_test_list[] = -{ - TEST_ENTRY_3(ADD, 4, 0x7fffffff, 0x12345678, 0x6dcba987, 0) - TEST_ENTRY_3(ADD, 4, 0x80000000, 0x12345678, 0x6dcba988, FLAG_V | FLAG_S) - TEST_ENTRY_3(ADD, 4, 0xffffffff, 0x92345678, 0x6dcba987, FLAG_S) - TEST_ENTRY_3(ADD, 4, 0x00000000, 0x92345678, 0x6dcba988, FLAG_C | FLAG_Z) - - TEST_ENTRY_3(ADD, 8, 0x7fffffffffffffff, 0x0123456789abcdef, 0x7edcba9876543210, 0) - TEST_ENTRY_3(ADD, 8, 0x8000000000000000, 0x0123456789abcdef, 0x7edcba9876543211, FLAG_V | FLAG_S) - TEST_ENTRY_3(ADD, 8, 0xffffffffffffffff, 0x8123456789abcdef, 0x7edcba9876543210, FLAG_S) - TEST_ENTRY_3(ADD, 8, 0x0000000000000000, 0x8123456789abcdef, 0x7edcba9876543211, FLAG_C | FLAG_Z) - - TEST_ENTRY_3F(ADDC, 4, 0x7fffffff, 0x12345678, 0x6dcba987, 0, 0) - TEST_ENTRY_3F(ADDC, 4, 0x7fffffff, 0x12345678, 0x6dcba986, FLAG_C, 0) - TEST_ENTRY_3F(ADDC, 4, 0x80000000, 0x12345678, 0x6dcba988, 0, FLAG_V | FLAG_S) - TEST_ENTRY_3F(ADDC, 4, 0x80000000, 0x12345678, 0x6dcba987, FLAG_C, FLAG_V | FLAG_S) - TEST_ENTRY_3F(ADDC, 4, 0xffffffff, 0x92345678, 0x6dcba987, 0, FLAG_S) - TEST_ENTRY_3F(ADDC, 4, 0xffffffff, 0x92345678, 0x6dcba986, FLAG_C, FLAG_S) - TEST_ENTRY_3F(ADDC, 4, 0x00000000, 0x92345678, 0x6dcba988, 0, FLAG_C | FLAG_Z) - TEST_ENTRY_3F(ADDC, 4, 0x00000000, 0x92345678, 0x6dcba987, FLAG_C, FLAG_C | FLAG_Z) - TEST_ENTRY_3F(ADDC, 4, 0x12345678, 0x12345678, 0xffffffff, FLAG_C, FLAG_C) - - TEST_ENTRY_3F(ADDC, 8, 0x7fffffffffffffff, 0x0123456789abcdef, 0x7edcba9876543210, 0, 0) - TEST_ENTRY_3F(ADDC, 8, 0x7fffffffffffffff, 0x0123456789abcdef, 0x7edcba987654320f, FLAG_C, 0) - TEST_ENTRY_3F(ADDC, 8, 0x8000000000000000, 0x0123456789abcdef, 0x7edcba9876543211, 0, FLAG_V | FLAG_S) - TEST_ENTRY_3F(ADDC, 8, 0x8000000000000000, 0x0123456789abcdef, 0x7edcba9876543210, FLAG_C, FLAG_V | FLAG_S) - TEST_ENTRY_3F(ADDC, 8, 0xffffffffffffffff, 0x8123456789abcdef, 0x7edcba9876543210, 0, FLAG_S) - TEST_ENTRY_3F(ADDC, 8, 0xffffffffffffffff, 0x8123456789abcdef, 0x7edcba987654320f, FLAG_C, FLAG_S) - TEST_ENTRY_3F(ADDC, 8, 0x0000000000000000, 0x8123456789abcdef, 0x7edcba9876543211, 0, FLAG_C | FLAG_Z) - TEST_ENTRY_3F(ADDC, 8, 0x0000000000000000, 0x8123456789abcdef, 0x7edcba9876543210, FLAG_C, FLAG_C | FLAG_Z) - TEST_ENTRY_3F(ADDC, 8, 0x123456789abcdef0, 0x123456789abcdef0, 0xffffffffffffffff, FLAG_C, FLAG_C) - - TEST_ENTRY_3(SUB, 4, 0x12345678, 0x7fffffff, 0x6dcba987, 0) - TEST_ENTRY_3(SUB, 4, 0x12345678, 0x80000000, 0x6dcba988, FLAG_V) - TEST_ENTRY_3(SUB, 4, 0x92345678, 0xffffffff, 0x6dcba987, FLAG_S) - TEST_ENTRY_3(SUB, 4, 0x92345678, 0x00000000, 0x6dcba988, FLAG_C | FLAG_S) - TEST_ENTRY_3(SUB, 4, 0x00000000, 0x12345678, 0x12345678, FLAG_Z) - - TEST_ENTRY_3(SUB, 8, 0x0123456789abcdef, 0x7fffffffffffffff, 0x7edcba9876543210, 0) - TEST_ENTRY_3(SUB, 8, 0x0123456789abcdef, 0x8000000000000000, 0x7edcba9876543211, FLAG_V) - TEST_ENTRY_3(SUB, 8, 0x8123456789abcdef, 0xffffffffffffffff, 0x7edcba9876543210, FLAG_S) - TEST_ENTRY_3(SUB, 8, 0x8123456789abcdef, 0x0000000000000000, 0x7edcba9876543211, FLAG_C | FLAG_S) - TEST_ENTRY_3(SUB, 8, 0x0000000000000000, 0x0123456789abcdef, 0x0123456789abcdef, FLAG_Z) - - TEST_ENTRY_3F(SUBB, 4, 0x12345678, 0x7fffffff, 0x6dcba987, 0, 0) - TEST_ENTRY_3F(SUBB, 4, 0x12345678, 0x7fffffff, 0x6dcba986, FLAG_C, 0) - TEST_ENTRY_3F(SUBB, 4, 0x12345678, 0x80000000, 0x6dcba988, 0, FLAG_V) - TEST_ENTRY_3F(SUBB, 4, 0x12345678, 0x80000000, 0x6dcba987, FLAG_C, FLAG_V) - TEST_ENTRY_3F(SUBB, 4, 0x92345678, 0xffffffff, 0x6dcba987, 0, FLAG_S) - TEST_ENTRY_3F(SUBB, 4, 0x92345678, 0xffffffff, 0x6dcba986, FLAG_C, FLAG_S) - TEST_ENTRY_3F(SUBB, 4, 0x92345678, 0x00000000, 0x6dcba988, 0, FLAG_C | FLAG_S) - TEST_ENTRY_3F(SUBB, 4, 0x92345678, 0x00000000, 0x6dcba987, FLAG_C, FLAG_C | FLAG_S) - TEST_ENTRY_3F(SUBB, 4, 0x12345678, 0x12345678, 0xffffffff, FLAG_C, FLAG_C) - TEST_ENTRY_3F(SUBB, 4, 0x00000000, 0x12345678, 0x12345677, FLAG_C, FLAG_Z) - - TEST_ENTRY_3F(SUBB, 8, 0x0123456789abcdef, 0x7fffffffffffffff, 0x7edcba9876543210, 0, 0) - TEST_ENTRY_3F(SUBB, 8, 0x0123456789abcdef, 0x7fffffffffffffff, 0x7edcba987654320f, FLAG_C, 0) - TEST_ENTRY_3F(SUBB, 8, 0x0123456789abcdef, 0x8000000000000000, 0x7edcba9876543211, 0, FLAG_V) - TEST_ENTRY_3F(SUBB, 8, 0x0123456789abcdef, 0x8000000000000000, 0x7edcba9876543210, FLAG_C, FLAG_V) - TEST_ENTRY_3F(SUBB, 8, 0x8123456789abcdef, 0xffffffffffffffff, 0x7edcba9876543210, 0, FLAG_S) - TEST_ENTRY_3F(SUBB, 8, 0x8123456789abcdef, 0xffffffffffffffff, 0x7edcba987654320f, FLAG_C, FLAG_S) - TEST_ENTRY_3F(SUBB, 8, 0x8123456789abcdef, 0x0000000000000000, 0x7edcba9876543211, 0, FLAG_C | FLAG_S) - TEST_ENTRY_3F(SUBB, 8, 0x8123456789abcdef, 0x0000000000000000, 0x7edcba9876543210, FLAG_C, FLAG_C | FLAG_S) - TEST_ENTRY_3F(SUBB, 8, 0x123456789abcdef0, 0x123456789abcdef0, 0xffffffffffffffff, FLAG_C, FLAG_C) - TEST_ENTRY_3F(SUBB, 8, 0x0000000000000000, 0x123456789abcdef0, 0x123456789abcdeef, FLAG_C, FLAG_Z) - - TEST_ENTRY_2(CMP, 4, 0x7fffffff, 0x6dcba987, 0) - TEST_ENTRY_2(CMP, 4, 0x80000000, 0x6dcba988, FLAG_V) - TEST_ENTRY_2(CMP, 4, 0xffffffff, 0x6dcba987, FLAG_S) - TEST_ENTRY_2(CMP, 4, 0x00000000, 0x6dcba988, FLAG_C | FLAG_S) - TEST_ENTRY_2(CMP, 4, 0x12345678, 0x12345678, FLAG_Z) - - TEST_ENTRY_2(CMP, 8, 0x7fffffffffffffff, 0x7edcba9876543210, 0) - TEST_ENTRY_2(CMP, 8, 0x8000000000000000, 0x7edcba9876543211, FLAG_V) - TEST_ENTRY_2(CMP, 8, 0xffffffffffffffff, 0x7edcba9876543210, FLAG_S) - TEST_ENTRY_2(CMP, 8, 0x0000000000000000, 0x7edcba9876543211, FLAG_C | FLAG_S) - TEST_ENTRY_2(CMP, 8, 0x0123456789abcdef, 0x0123456789abcdef, FLAG_Z) - - TEST_ENTRY_4(MULU, 4, 0x77777777, 0x00000000, 0x11111111, 0x00000007, 0) - TEST_ENTRY_4(MULU, 4, 0xffffffff, 0x00000000, 0x11111111, 0x0000000f, 0) - TEST_ENTRY_4(MULU, 4, 0x00000000, 0x00000000, 0x11111111, 0x00000000, FLAG_Z) - TEST_ENTRY_4(MULU, 4, 0xea61d951, 0x37c048d0, 0x77777777, 0x77777777, FLAG_V) - TEST_ENTRY_4(MULU, 4, 0x32323233, 0xcdcdcdcc, 0xcdcdcdcd, 0xffffffff, FLAG_V | FLAG_S) - - TEST_ENTRY_4(MULU, 8, 0x7777777777777777, 0x0000000000000000, 0x1111111111111111, 0x0000000000000007, 0) - TEST_ENTRY_4(MULU, 8, 0xffffffffffffffff, 0x0000000000000000, 0x1111111111111111, 0x000000000000000f, 0) - TEST_ENTRY_4(MULU, 8, 0x0000000000000000, 0x0000000000000000, 0x1111111111111111, 0x0000000000000000, FLAG_Z) - TEST_ENTRY_4(MULU, 8, 0x0c83fb72ea61d951, 0x37c048d159e26af3, 0x7777777777777777, 0x7777777777777777, FLAG_V) - TEST_ENTRY_4(MULU, 8, 0x3232323232323233, 0xcdcdcdcdcdcdcdcc, 0xcdcdcdcdcdcdcdcd, 0xffffffffffffffff, FLAG_V | FLAG_S) - - TEST_ENTRY_4(MULS, 4, 0x77777777, 0x00000000, 0x11111111, 0x00000007, 0) - TEST_ENTRY_4(MULS, 4, 0xffffffff, 0x00000000, 0x11111111, 0x0000000f, FLAG_V) - TEST_ENTRY_4(MULS, 4, 0x00000000, 0x00000000, 0x11111111, 0x00000000, FLAG_Z) - TEST_ENTRY_4(MULS, 4, 0x9e26af38, 0xc83fb72e, 0x77777777, 0x88888888, FLAG_V | FLAG_S) - TEST_ENTRY_4(MULS, 4, 0x32323233, 0x00000000, 0xcdcdcdcd, 0xffffffff, 0) - - TEST_ENTRY_4(MULS, 8, 0x7777777777777777, 0x0000000000000000, 0x1111111111111111, 0x0000000000000007, 0) - TEST_ENTRY_4(MULS, 8, 0xffffffffffffffff, 0x0000000000000000, 0x1111111111111111, 0x000000000000000f, FLAG_V) - TEST_ENTRY_4(MULS, 8, 0x0000000000000000, 0x0000000000000000, 0x1111111111111111, 0x0000000000000000, FLAG_Z) - TEST_ENTRY_4(MULS, 8, 0x7c048d159e26af38, 0xc83fb72ea61d950c, 0x7777777777777777, 0x8888888888888888, FLAG_V | FLAG_S) - TEST_ENTRY_4(MULS, 8, 0x3232323232323233, 0x0000000000000000, 0xcdcdcdcdcdcdcdcd, 0xffffffffffffffff, 0) - - TEST_ENTRY_4(DIVU, 4, 0x02702702, 0x00000003, 0x11111111, 0x00000007, 0) - TEST_ENTRY_4(DIVU, 4, 0x00000000, 0x11111111, 0x11111111, 0x11111112, FLAG_Z) - TEST_ENTRY_4(DIVU, 4, 0x7fffffff, 0x00000000, 0xfffffffe, 0x00000002, 0) - TEST_ENTRY_4(DIVU, 4, 0xfffffffe, 0x00000000, 0xfffffffe, 0x00000001, FLAG_S) - TEST_ENTRY_4(DIVU, 4, UNDEFINED, UNDEFINED, 0xffffffff, 0x00000000, FLAG_V) - - TEST_ENTRY_4(DIVU, 8, 0x0270270270270270, 0x0000000000000001, 0x1111111111111111, 0x0000000000000007, 0) - TEST_ENTRY_4(DIVU, 8, 0x0000000000000000, 0x1111111111111111, 0x1111111111111111, 0x1111111111111112, FLAG_Z) - TEST_ENTRY_4(DIVU, 8, 0x7fffffffffffffff, 0x0000000000000000, 0xfffffffffffffffe, 0x0000000000000002, 0) - TEST_ENTRY_4(DIVU, 8, 0xfffffffffffffffe, 0x0000000000000000, 0xfffffffffffffffe, 0x0000000000000001, FLAG_S) - TEST_ENTRY_4(DIVU, 8, UNDEFINED, UNDEFINED, 0xffffffffffffffff, 0x0000000000000000, FLAG_V) - - TEST_ENTRY_4(DIVS, 4, 0x02702702, 0x00000003, 0x11111111, 0x00000007, 0) - TEST_ENTRY_4(DIVS, 4, 0x00000000, 0x11111111, 0x11111111, 0x11111112, FLAG_Z) - TEST_ENTRY_4(DIVS, 4, 0xffffffff, 0x00000000, 0xfffffffe, 0x00000002, FLAG_S) - TEST_ENTRY_4(DIVS, 4, UNDEFINED, UNDEFINED, 0xffffffff, 0x00000000, FLAG_V) - - TEST_ENTRY_4(DIVS, 8, 0x0270270270270270, 0x0000000000000001, 0x1111111111111111, 0x0000000000000007, 0) - TEST_ENTRY_4(DIVS, 8, 0x0000000000000000, 0x1111111111111111, 0x1111111111111111, 0x1111111111111112, FLAG_Z) - TEST_ENTRY_4(DIVS, 8, 0xffffffffffffffff, 0x0000000000000000, 0xfffffffffffffffe, 0x0000000000000002, FLAG_S) - TEST_ENTRY_4(DIVS, 8, UNDEFINED, UNDEFINED, 0xffffffffffffffff, 0x0000000000000000, FLAG_V) -}; - - -/*------------------------------------------------- - validate_backend - execute a number of - generic tests on the backend code generator --------------------------------------------------*/ - -static void validate_backend(drcuml_state *drcuml) -{ - uml::code_handle *handles[3]; - int tnum; - - // allocate handles for the code - handles[0] = drcuml->handle_alloc("test_entry"); - handles[1] = drcuml->handle_alloc("code_start"); - handles[2] = drcuml->handle_alloc("code_end"); - - // iterate over test entries - printf("Backend validation....\n"); - for (tnum = 31; tnum < std::size(bevalidate_test_list); tnum++) - { - const bevalidate_test *test = &bevalidate_test_list[tnum]; - parameter param[std::size(test->param)]; - char mnemonic[20], *dst; - const char *src; - - // progress - dst = mnemonic; - for (src = opcode_info_table[test->opcode()]->mnemonic; *src != 0; src++) - { - if (*src == '!') - { - if (test->size == 8) - *dst++ = 'd'; - } - else if (*src == '#') - *dst++ = (test->size == 8) ? 'd' : 's'; - else - *dst++ = *src; - } - *dst = 0; - printf("Executing test %d/%d (%s)", tnum + 1, (int)std::size(bevalidate_test_list), mnemonic); - - // reset parameter list and iterate - memset(param, 0, sizeof(param)); - bevalidate_iterate_over_params(drcuml, handles, test, param, 0); - printf("\n"); - } - fatalerror("All tests passed!\n"); -} - - -/*------------------------------------------------- - bevalidate_iterate_over_params - iterate over - all supported types and values of a parameter - and recursively hand off to the next parameter, - or else move on to iterate over the flags --------------------------------------------------*/ - -static void bevalidate_iterate_over_params(drcuml_state *drcuml, uml::code_handle **handles, const bevalidate_test *test, parameter *paramlist, int pnum) -{ - const opcode_info *opinfo = opcode_info_table[test->opcode()]; - drcuml_ptype ptype; - - // if no parameters, execute now - if (pnum >= std::size(opinfo->param) || opinfo->param[pnum].typemask == PTYPES_NONE) - { - bevalidate_iterate_over_flags(drcuml, handles, test, paramlist); - return; - } - - // iterate over valid parameter types - for (ptype = parameter::PTYPE_IMMEDIATE; ptype < parameter::PTYPE_MAX; ptype++) - if (opinfo->param[pnum].typemask & (1 << ptype)) - { - int pindex, pcount; - - // mapvars can only do 32-bit tests - if (ptype == parameter::PTYPE_MAPVAR && effective_test_psize(opinfo, pnum, test->size, test->param) == 8) - continue; - - // for some parameter types, we wish to iterate over all possibilities - switch (ptype) - { - case parameter::PTYPE_INT_REGISTER: pcount = REG_I_END - REG_I0; break; - case parameter::PTYPE_FLOAT_REGISTER: pcount = REG_F_END - REG_F0; break; - default: pcount = 1; break; - } - - // iterate over possibilities - for (pindex = 0; pindex < pcount; pindex++) - { - bool skip = false; - int pscannum; - - // for param 0, print a dot - if (pnum == 0) - printf("."); - - // can't duplicate multiple source parameters unless they are immediates - if (ptype != parameter::PTYPE_IMMEDIATE && (opinfo->param[pnum].output & PIO_IN)) - - // loop over all parameters we've done before; if the parameter is a source and matches us, skip this case - for (pscannum = 0; pscannum < pnum; pscannum++) - if ((opinfo->param[pscannum].output & PIO_IN) && ptype == paramlist[pscannum].type && pindex == paramlist[pscannum].value) - skip = true; - - // can't duplicate multiple dest parameters - if (opinfo->param[pnum].output & PIO_OUT) - - // loop over all parameters we've done before; if the parameter is a source and matches us, skip this case - for (pscannum = 0; pscannum < pnum; pscannum++) - if ((opinfo->param[pscannum].output & PIO_OUT) && ptype == paramlist[pscannum].type && pindex == paramlist[pscannum].value) - skip = true; - - // iterate over the next parameter in line - if (!skip) - { - paramlist[pnum].type = ptype; - paramlist[pnum].value = pindex; - bevalidate_iterate_over_params(drcuml, handles, test, paramlist, pnum + 1); - } - } - } -} - - -/*------------------------------------------------- - bevalidate_iterate_over_flags - iterate over - all supported flag masks --------------------------------------------------*/ - -static void bevalidate_iterate_over_flags(drcuml_state *drcuml, uml::code_handle **handles, const bevalidate_test *test, parameter *paramlist) -{ - const opcode_info *opinfo = opcode_info_table[test->opcode()]; - uint8_t flagmask = opinfo->outflags; - uint8_t curmask; - - // iterate over all possible flag combinations - for (curmask = 0; curmask <= flagmask; curmask++) - if ((curmask & flagmask) == curmask) - bevalidate_execute(drcuml, handles, test, paramlist, curmask); -} - - -/*------------------------------------------------- - bevalidate_execute - execute a single instance - of a test, generating code and verifying the - results --------------------------------------------------*/ - -static void bevalidate_execute(drcuml_state *drcuml, uml::code_handle **handles, const bevalidate_test *test, const parameter *paramlist, uint8_t flagmask) -{ - parameter params[std::size(test->param)]; - drcuml_machine_state istate, fstate; - instruction testinst; - drcuml_block *block; - uint64_t *parammem; - int numparams; - - // allocate memory for parameters - parammem = (uint64_t *)drcuml->cache->alloc_near(sizeof(uint64_t) * (std::size(test->param) + 1)); - - // flush the cache - drcuml->reset(); - - // start a new block - block = drcuml->block_begin(30); - UML_HANDLE(block, handles[0]); - - // set up a random initial state - bevalidate_initialize_random_state(drcuml, block, &istate); - - // then populate the state with the parameters - numparams = bevalidate_populate_state(block, &istate, test, paramlist, params, parammem); - - // generate the code - UML_RESTORE(block, &istate); - UML_HANDLE(block, handles[1]); - switch (numparams) - { - case 0: - block->append(test->opcode(), test->size); - break; - - case 1: - block->append(test->opcode(), test->size, params[0]); - break; - - case 2: - block->append(test->opcode(), test->size, params[0], params[1]); - break; - - case 3: - block->append(test->opcode(), test->size, params[0], params[1], params[2]); - break; - - case 4: - block->append(test->opcode(), test->size, params[0], params[1], params[2], params[3]); - break; - } - testinst = block->inst[block->nextinst - 1]; - UML_HANDLE(block, handles[2]); - UML_GETFLGS(block, MEM(¶mmem[std::size(test->param)]), flagmask); - UML_SAVE(block, &fstate); - UML_EXIT(block, IMM(0)); - - // end the block - block->end(); - - // execute - drcuml->execute(*handles[0]); - - // verify the results - bevalidate_verify_state(drcuml, &istate, &fstate, test, *(uint32_t *)¶mmem[std::size(test->param)], params, &testinst, handles[1]->code, handles[2]->code, flagmask); - - // free memory - drcuml->cache->dealloc(parammem, sizeof(uint64_t) * (std::size(test->param) + 1)); -} - - -/*------------------------------------------------- - bevalidate_initialize_random_state - - initialize the machine state to randomness --------------------------------------------------*/ - -static void bevalidate_initialize_random_state(drcuml_state *drcuml, drcuml_block *block, drcuml_machine_state *state) -{ - running_machine &machine = drcuml->device->machine(); - int regnum; - - // initialize core state to random values - state->fmod = machine.rand() & 0x03; - state->flags = machine.rand() & 0x1f; - state->exp = machine.rand(); - - // initialize integer registers to random values - for (regnum = 0; regnum < std::size(state->r); regnum++) - { - state->r[regnum].w.h = machine.rand(); - state->r[regnum].w.l = machine.rand(); - } - - // initialize float registers to random values - for (regnum = 0; regnum < std::size(state->f); regnum++) - { - *(uint32_t *)&state->f[regnum].s.h = machine.rand(); - *(uint32_t *)&state->f[regnum].s.l = machine.rand(); - } - - // initialize map variables to random values - for (regnum = 0; regnum < MAPVAR_COUNT; regnum++) - UML_MAPVAR(block, MVAR(regnum), machine.rand()); -} - - -/*------------------------------------------------- - bevalidate_populate_state - populate the - machine state with the proper values prior - to executing a test --------------------------------------------------*/ - -static int bevalidate_populate_state(drcuml_block *block, drcuml_machine_state *state, const bevalidate_test *test, const parameter *paramlist, parameter *params, uint64_t *parammem) -{ - const opcode_info *opinfo = opcode_info_table[test->opcode()]; - int numparams = std::size(test->param); - int pnum; - - // copy flags as-is - state->flags = test->iflags; - - // iterate over parameters - for (pnum = 0; pnum < std::size(test->param); pnum++) - { - int psize = effective_test_psize(opinfo, pnum, test->size, test->param); - parameter *curparam = ¶ms[pnum]; - - // start with a copy of the parameter from the list - *curparam = paramlist[pnum]; - - // switch off the type - switch (curparam->type) - { - // immediate parameters: take the value from the test entry - case parameter::PTYPE_IMMEDIATE: - curparam->value = test->param[pnum]; - break; - - // register parameters: set the register value in the state and set the parameter value to the register index - case parameter::PTYPE_INT_REGISTER: - state->r[curparam->value].d = test->param[pnum]; - curparam->value += REG_I0; - break; - - // register parameters: set the register value in the state and set the parameter value to the register index - case parameter::PTYPE_FLOAT_REGISTER: - state->f[curparam->value].d = test->param[pnum]; - curparam->value += REG_F0; - break; - - // memory parameters: set the memory value in the parameter space and set the parameter value to point to it - case parameter::PTYPE_MEMORY: - curparam->value = (uintptr_t)¶mmem[pnum]; - if (psize == 4) - *(uint32_t *)(uintptr_t)curparam->value = test->param[pnum]; - else - *(uint64_t *)(uintptr_t)curparam->value = test->param[pnum]; - break; - - // map variables: issue a MAPVAR instruction to set the value and set the parameter value to the mapvar index - case parameter::PTYPE_MAPVAR: - UML_MAPVAR(block, MVAR(curparam->value), test->param[pnum]); - curparam->value += MAPVAR_M0; - break; - - // use anything else to count the number of parameters - default: - numparams = MIN(numparams, pnum); - break; - } - } - - // return the total number of parameters - return numparams; -} - - -/*------------------------------------------------- - bevalidate_verify_state - verify the final - state after executing a test, and report any - discrepancies --------------------------------------------------*/ - -static int bevalidate_verify_state(drcuml_state *drcuml, const drcuml_machine_state *istate, drcuml_machine_state *state, const bevalidate_test *test, uint32_t flags, const parameter *params, const instruction *testinst, drccodeptr codestart, drccodeptr codeend, uint8_t flagmask) -{ - const opcode_info *opinfo = opcode_info_table[test->opcode()]; - uint8_t ireg[REG_I_END - REG_I0] = { 0 }; - uint8_t freg[REG_F_END - REG_F0] = { 0 }; - char errorbuf[1024]; - char *errend = errorbuf; - int pnum, regnum; - - *errend = 0; - - // check flags - if (flags != (test->flags & flagmask)) - { - errend += sprintf(errend, " Flags ... result:%c%c%c%c%c expected:%c%c%c%c%c\n", - (flagmask & FLAG_U) ? ((flags & FLAG_U) ? 'U' : '.') : '-', - (flagmask & FLAG_S) ? ((flags & FLAG_S) ? 'S' : '.') : '-', - (flagmask & FLAG_Z) ? ((flags & FLAG_Z) ? 'Z' : '.') : '-', - (flagmask & FLAG_V) ? ((flags & FLAG_V) ? 'V' : '.') : '-', - (flagmask & FLAG_C) ? ((flags & FLAG_C) ? 'C' : '.') : '-', - (flagmask & FLAG_U) ? ((test->flags & FLAG_U) ? 'U' : '.') : '-', - (flagmask & FLAG_S) ? ((test->flags & FLAG_S) ? 'S' : '.') : '-', - (flagmask & FLAG_Z) ? ((test->flags & FLAG_Z) ? 'Z' : '.') : '-', - (flagmask & FLAG_V) ? ((test->flags & FLAG_V) ? 'V' : '.') : '-', - (flagmask & FLAG_C) ? ((test->flags & FLAG_C) ? 'C' : '.') : '-'); - } - - // check destination parameters - for (pnum = 0; pnum < std::size(test->param); pnum++) - if (opinfo->param[pnum].output & PIO_OUT) - { - int psize = effective_test_psize(opinfo, pnum, test->size, test->param); - uint64_t mask = u64(0xffffffffffffffff) >> (64 - 8 * psize); - uint64_t result = 0; - - // fetch the result from the parameters - switch (params[pnum].type) - { - // integer registers fetch from the state - case parameter::PTYPE_INT_REGISTER: - ireg[params[pnum].value - REG_I0] = 1; - result = state->r[params[pnum].value - REG_I0].d; - break; - - // float registers fetch from the state - case parameter::PTYPE_FLOAT_REGISTER: - freg[params[pnum].value - REG_I0] = 1; - result = state->f[params[pnum].value - REG_F0].d; - break; - - // memory registers fetch from the memory address - case parameter::PTYPE_MEMORY: - if (psize == 4) - result = *(uint32_t *)(uintptr_t)params[pnum].value; - else - result = *(uint64_t *)(uintptr_t)params[pnum].value; - break; - - default: - break; - } - - // check against the mask - if (test->param[pnum] != UNDEFINED_U64 && (result & mask) != (test->param[pnum] & mask)) - { - if ((uint32_t)mask == mask) - errend += sprintf(errend, " Parameter %d ... result:%08X expected:%08X\n", pnum, - (uint32_t)(result & mask), (uint32_t)(test->param[pnum] & mask)); - else - errend += sprintf(errend, " Parameter %d ... result:%08X%08X expected:%08X%08X\n", pnum, - (uint32_t)((result & mask) >> 32), (uint32_t)(result & mask), - (uint32_t)((test->param[pnum] & mask) >> 32), (uint32_t)(test->param[pnum] & mask)); - } - } - - // check source integer parameters for unexpected alterations - for (regnum = 0; regnum < std::size(state->r); regnum++) - if (ireg[regnum] == 0 && istate->r[regnum].d != state->r[regnum].d) - errend += sprintf(errend, " Register i%d ... result:%08X%08X originally:%08X%08X\n", regnum, - (uint32_t)(state->r[regnum].d >> 32), (uint32_t)state->r[regnum].d, - (uint32_t)(istate->r[regnum].d >> 32), (uint32_t)istate->r[regnum].d); - - // check source float parameters for unexpected alterations - for (regnum = 0; regnum < std::size(state->f); regnum++) - if (freg[regnum] == 0 && *(uint64_t *)&istate->f[regnum].d != *(uint64_t *)&state->f[regnum].d) - errend += sprintf(errend, " Register f%d ... result:%08X%08X originally:%08X%08X\n", regnum, - (uint32_t)(*(uint64_t *)&state->f[regnum].d >> 32), (uint32_t)*(uint64_t *)&state->f[regnum].d, - (uint32_t)(*(uint64_t *)&istate->f[regnum].d >> 32), (uint32_t)*(uint64_t *)&istate->f[regnum].d); - - // output the error if we have one - if (errend != errorbuf) - { - // disassemble the test instruction - std::string disasm = testinst->disasm(drcuml); - - // output a description of what went wrong - printf("\n"); - printf("----------------------------------------------\n"); - printf("Backend validation error:\n"); - printf(" %s\n", disasm.c_str()); - printf("\n"); - printf("Errors:\n"); - printf("%s\n", errorbuf); - fatalerror("Error during validation\n"); - } - return errend != errorbuf; -} - -#endif diff --git a/src/devices/cpu/uml.cpp b/src/devices/cpu/uml.cpp index fbc3dc2b035..1a1b29d6f67 100644 --- a/src/devices/cpu/uml.cpp +++ b/src/devices/cpu/uml.cpp @@ -47,7 +47,6 @@ using namespace uml; // DEBUGGING //************************************************************************** -#define VALIDATE_BACKEND (0) #define LOG_SIMPLIFICATIONS (0) @@ -57,19 +56,19 @@ using namespace uml; //************************************************************************** // opcode validation condition/flag valid bitmasks -#define OPFLAGS_NONE 0x00 -#define OPFLAGS_C FLAG_C -#define OPFLAGS_Z FLAG_Z -#define OPFLAGS_SZ (FLAG_S | FLAG_Z) -#define OPFLAGS_SZC (FLAG_S | FLAG_Z | FLAG_C) -#define OPFLAGS_SZV (FLAG_S | FLAG_Z | FLAG_V) -#define OPFLAGS_SZVC (FLAG_S | FLAG_Z | FLAG_V | FLAG_C) -#define OPFLAGS_UZC (FLAG_U | FLAG_Z | FLAG_C) -#define OPFLAGS_ALL 0x1f -#define OPFLAGS_P1 0x81 -#define OPFLAGS_P2 0x82 -#define OPFLAGS_P3 0x83 -#define OPFLAGS_P4 0x84 +constexpr u8 OPFLAGS_NONE = FLAGS_NONE; +constexpr u8 OPFLAGS_C = FLAG_C; +constexpr u8 OPFLAGS_Z = FLAG_Z; +constexpr u8 OPFLAGS_SZ = FLAG_S | FLAG_Z; +constexpr u8 OPFLAGS_SZC = FLAG_S | FLAG_Z | FLAG_C; +constexpr u8 OPFLAGS_SZV = FLAG_S | FLAG_Z | FLAG_V; +constexpr u8 OPFLAGS_SZVC = FLAG_S | FLAG_Z | FLAG_V | FLAG_C; +constexpr u8 OPFLAGS_UZC = FLAG_U | FLAG_Z | FLAG_C; +constexpr u8 OPFLAGS_ALL = FLAGS_ALL; +constexpr u8 OPFLAGS_P1 = 0x81; +constexpr u8 OPFLAGS_P2 = 0x82; +constexpr u8 OPFLAGS_P3 = 0x83; +constexpr u8 OPFLAGS_P4 = 0x84; // parameter input/output states #define PIO_IN 0x01 @@ -1204,6 +1203,10 @@ void uml::instruction::simplify() opcode_t origop; do { +#if LOG_SIMPLIFICATIONS + uml::instruction const orig = *this; +#endif + // switch off the opcode origop = m_opcode; switch (m_opcode) @@ -1251,13 +1254,9 @@ void uml::instruction::simplify() default: break; } -#if 0 - if (LOG_SIMPLIFICATIONS && memcmp(&orig, inst, sizeof(orig)) != 0) - { - std::string disasm1 = orig.disasm(block->drcuml); - std::string disasm2 = inst->disasm(block->drcuml); - osd_printf_debug("Simplified: %-50.50s -> %s\n", disasm1, disasm2); - } +#if LOG_SIMPLIFICATIONS + if (orig != *this) + osd_printf_debug("Simplified: %-50.50s -> %s\n", orig.disasm(), disasm()); #endif // loop until we stop changing opcodes @@ -1483,22 +1482,24 @@ std::string uml::instruction::disasm(drcuml_state *drcuml) const const char *symbol; u32 symoffset; - // symbol - if (drcuml != nullptr && (symbol = drcuml->symbol_find(param.memory(), &symoffset)) != nullptr) + if (drcuml && (symbol = drcuml->symbol_find(param.memory(), &symoffset)) != nullptr) { + // symbol if (symoffset == 0) util::stream_format(buffer, "[%s]", symbol); else util::stream_format(buffer, "[%s+$%X]", symbol, symoffset); } - - // cache memory else if (drcuml != nullptr && drcuml->cache().contains_pointer(param.memory())) + { + // cache memory util::stream_format(buffer, "[+$%X]", u32(uintptr_t(drccodeptr(param.memory()) - drcuml->cache().near()))); - - // general memory + } else + { + // general memory util::stream_format(buffer, "[[$%p]]", param.memory()); + } } break; @@ -1542,5 +1543,5 @@ std::string uml::instruction::disasm(drcuml_state *drcuml) const if (m_flags & FLAG_C) buffer.put('C'); } - return buffer.str(); + return std::move(buffer).str(); } diff --git a/src/devices/cpu/uml.h b/src/devices/cpu/uml.h index cbc4a82a205..23b6b238c3e 100644 --- a/src/devices/cpu/uml.h +++ b/src/devices/cpu/uml.h @@ -14,6 +14,8 @@ #include "drccache.h" +#include <algorithm> + //************************************************************************** // TYPE DEFINITIONS @@ -50,6 +52,10 @@ namespace uml constexpr u8 FLAG_S = 0x08; // sign flag (defined for integer only) constexpr u8 FLAG_U = 0x10; // unordered flag (defined for FP only) + // flag combinations + constexpr u8 FLAGS_NONE = 0x00; + constexpr u8 FLAGS_ALL = FLAG_U | FLAG_S | FLAG_Z | FLAG_V | FLAG_C; + // testable conditions; note that these are defined such that (condition ^ 1) is // always the opposite enum condition_t @@ -384,6 +390,9 @@ namespace uml class instruction { public: + // constants + static constexpr int MAX_PARAMS = 4; + // construction/destruction constexpr instruction() : m_param{ } { } @@ -408,6 +417,22 @@ namespace uml u8 modified_flags() const; void simplify(); + // operators + bool operator==(instruction const &that) const + { + if ((m_opcode != that.m_opcode) || (m_condition != that.m_condition) || (m_flags != that.m_flags) || (m_size != that.m_size) || (m_numparams != that.m_numparams)) + return false; + auto const last = m_param + m_numparams; + return std::mismatch(std::begin(m_param), last, std::begin(that.m_param)).first == last; + } + bool operator!=(instruction const &that) const + { + if ((m_opcode != that.m_opcode) || (m_condition != that.m_condition) || (m_flags != that.m_flags) || (m_size != that.m_size) || (m_numparams != that.m_numparams)) + return true; + auto const last = m_param + m_numparams; + return std::mismatch(std::begin(m_param), last, std::begin(that.m_param)).first != last; + } + // compile-time opcodes void handle(code_handle &hand) { configure(OP_HANDLE, 4, hand); } void hash(u32 mode, u32 pc) { configure(OP_HASH, 4, mode, pc); } @@ -572,9 +597,6 @@ namespace uml void fdcopyi(parameter dst, parameter src) { configure(OP_FCOPYI, 8, dst, src); } void icopyfd(parameter dst, parameter src) { configure(OP_ICOPYF, 8, dst, src); } - // constants - static constexpr int MAX_PARAMS = 4; - private: // internal configuration void configure(opcode_t op, u8 size, condition_t cond = COND_ALWAYS); |