|
|
(15 intermediate revisions by the same user not shown) |
Line 59: |
Line 59: |
| Code labels can be branched to via the '''JMP''' instruction, either unconditionally or via one of 16 conditions. | | Code labels can be branched to via the '''JMP''' instruction, either unconditionally or via one of 16 conditions. |
|
| |
|
| == Opcodes == | | == Opcode Conventions == |
|
| |
|
| Below is an exhaustive list of opcodes and their defined behaviors. Before diving into the details, however, there are some general principles and conventions which must be understood:
| | Before diving into the details of the opcodes, it is important to understand some general principles and conventions: |
|
| |
|
| '''Integer Registers'''. There are 10 integer registers, each 64-bits wide. The same registers are used for both 32-bit and 64-bit opcodes; however, unlike many real computer architectures, the upper 32 bits are fully undefined when a 32-bit operation is performed. This means you cannot load a 64-bit value, perform a 32-bit operation, and expect the upper 32 bits to be anything in particular when you are finished. | | '''Integer Registers'''. There are 10 integer registers, each 64-bits wide. The same registers are used for both 32-bit and 64-bit opcodes; however, unlike many real computer architectures, the upper 32 bits are fully undefined when a 32-bit operation is performed. This means you cannot load a 64-bit value, perform a 32-bit operation, and expect the upper 32 bits to be anything in particular when you are finished. |
Line 70: |
Line 70: |
|
| |
|
| '''Floating Point Registers'''. As with the integer registers, there are 10 floating point registers, each 64-bits wide. The same registers are again used for both 32-bit and 64-bit opcodes, and the upper 32 bits are fully undefined when a 32-bit operation is performed. | | '''Floating Point Registers'''. As with the integer registers, there are 10 floating point registers, each 64-bits wide. The same registers are again used for both 32-bit and 64-bit opcodes, and the upper 32 bits are fully undefined when a 32-bit operation is performed. |
| | |
| | Floating point registers ''must not'' perform any conversions when loaded/stored/moved. This means that the floating point register set must support holding arbitrary values without performing any implicit conversion. Back-end architectures that cannot meet this requirement (e.g., the Intel x86 FPU), must keep the 10 floating point registers in memory and only convert data when performing arithmetic operations. |
|
| |
|
| Back-end support for floating point registers is often even more limited than support for integer registers, so dynamic recompilers should focus on using the first few registers as much as possible. | | Back-end support for floating point registers is often even more limited than support for integer registers, so dynamic recompilers should focus on using the first few registers as much as possible. |
Line 91: |
Line 93: |
| '''Conditions'''. Control flow instructions and simple data move instructions support an optional condition, which allows behavior to occur based on the state of the flags. Each flag can be checked for on/off independently. In addition, the usual collection of G/GE/L/LE/A/AE/B/BE conditions are available. | | '''Conditions'''. Control flow instructions and simple data move instructions support an optional condition, which allows behavior to occur based on the state of the flags. Each flag can be checked for on/off independently. In addition, the usual collection of G/GE/L/LE/A/AE/B/BE conditions are available. |
|
| |
|
| == Control Flow Opcodes == | | == Opcodes == |
| | |
| === CALLC ===
| |
| | |
| '''Usage:'''
| |
| CALLC ''function'',''parameter''[,''condition'']
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_CALLC(''block'', ''function'', ''parameter'');
| |
| UML_CALLCc(''block'', ''condition'', ''function'', ''parameter'');
| |
| | |
| '''Parameters:'''
| |
| * ''function'' — a memory pointer to a C function of the form <code>void cfunction(void *parameter)</code>
| |
| * ''parameter'' — a memory pointer that is passed as the argument to the C function
| |
| * ''condition'' — an optional condition which is used to determine whether or not to execute the call
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' The '''CALLC''' opcode is used to execute a C ''function'' from within the generated code. A single ''parameter'' (evaluated at compile time only) may be passed to the function. More data can be effectively passed by using the parameter to point to a communication block. Upon return from the C function, all registers retain their original values; however, all flags are left in an undefined state.
| |
| | |
| Like most control flow opcodes, '''CALLC''' can be used either unconditionally or flagged with a condition that controls whether or not the target function is called.
| |
| | |
| '''Example:'''
| |
| void cfunc_printf_string(void *parameter)
| |
| {
| |
| printf("%s", parameter);
| |
| }
| |
|
| |
| void generate_call_to_print_string(drcuml_block *block)
| |
| {
| |
| UML_CALLC(block, cfunc_printf_string, "My test string");
| |
| }
| |
| | |
| ----
| |
| | |
| === CALLH ===
| |
| | |
| '''Usage:'''
| |
| CALLH ''handle''[,''condition'']
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_CALLH(''block'', ''handle'');
| |
| UML_CALLHc(''block'', ''condition'', ''handle'');
| |
| | |
| '''Parameters:'''
| |
| * ''handle'' — a memory pointer to a previously-allocated code handle
| |
| * ''condition'' — an optional condition which is used to determine whether or not to execute the call
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' The '''CALLH''' function makes a subroutine call to the code referenced by the given ''handle''. Note that although the handle must have already been allocated, it is permitted to pass a handle which has not yet been populated by code. The back-end code generator must support both cases, though it will generally output less efficient code if the handle is not yet populated (since it must fetch the address at runtime from the handle).
| |
| | |
| Like most control flow opcodes, '''CALLH''' can be used either unconditionally or flagged with a condition that controls whether or not the target function is called.
| |
| | |
| '''Example:'''
| |
| drcuml_codehandle *mysubroutine;
| |
|
| |
| void generate_subroutine_code(drcuml_state *drcuml)
| |
| {
| |
| drcuml_block *block;
| |
| jmp_buf errorbuf;
| |
|
| |
| /* allocate a handle */
| |
| mysubroutine = drcuml_handle_alloc(drcuml, "my_subroutine_name");
| |
|
| |
| /* handle a fatal error during codegen */
| |
| if (setjmp(errorbuf) != 0)
| |
| fatalerror("Ran out of cache space generating subroutine!");
| |
|
| |
| /* generate a simple subroutine */
| |
| block = drcuml_block_begin(drcuml, 10, &errorbuf);
| |
| UML_HANDLE(block, mysubroutine);
| |
| UML_RET(block);
| |
|
| |
| /* complete codegen */
| |
| drcuml_block_end(block);
| |
| }
| |
|
| |
| void generate_call_to_subroutine(drcuml_block *block)
| |
| {
| |
| UML_CALLH(block, mysubroutine);
| |
| }
| |
| | |
| ----
| |
| | |
| === COMMENT ===
| |
| | |
| '''Usage:'''
| |
| COMMENT ''string''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_COMMENT(''block'', ''string'');
| |
| | |
| '''Parameters:'''
| |
| * ''string'' — a memory pointer to character string
| |
| | |
| '''Flags:''' unaffected
| |
| | |
| '''Description:''' The '''COMMENT''' opcode exists to provide a means of documenting the UML code. Comments are generally ignored completely by the back-end and typically generate no code. However, they do show up in the disassembly of UML code, and may optionally propogate to disassembly of generated code as well.
| |
| | |
| '''Example:'''
| |
| void generate_comment(drcuml_block *block)
| |
| {
| |
| UML_COMMENT(block, "This is a comment for disassembly");
| |
| }
| |
| | |
| ----
| |
| | |
| === DEBUG ===
| |
| | |
| '''Usage:'''
| |
| DEBUG ''pc''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_DEBUG(''block'', PTYPE(''pc''));
| |
| | |
| '''Parameters:'''
| |
| * ''pc'' — a 32-bit integer register, memory location, map variable, or immediate
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' The '''DEBUG''' opcode indicates that, if the debugger is present, it should be updated with the provided ''pc'' as the current instruction. To properly support the built-in debugger, this opcode should be present before the execution of each instruction. Before issuing a '''DEBUG''' opcode, be sure to flush any cached state (including the PC) to its target memory location so that the debugger can properly examine it or modify it. Upon completion of this opcode, all registers retain their original values; however, all flags are left in an undefined state.
| |
| | |
| '''Example:'''
| |
| offs_t currentpc;
| |
|
| |
| void generate_call_to_debugger(drcuml_block *block)
| |
| {
| |
| UML_DEBUG(block, MEM(¤tpc));
| |
| }
| |
| | |
| ----
| |
| | |
| === EXH ===
| |
| | |
| '''Usage:'''
| |
| EXH ''handle'',''parameter''[,''cond'']
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_EXH(''block'', ''handle'', PTYPE(''parameter''));
| |
| UML_EXHc(''block'', ''condition'', ''handle'', PTYPE(''parameter''));
| |
| | |
| '''Parameters:'''
| |
| * ''handle'' — a memory pointer to a previously-allocated code handle
| |
| * ''parameter'' — a 32-bit integer register, memory location, map variable, or immediate
| |
| * ''condition'' — an optional condition which is used to determine whether or not to generate the exception
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' The '''EXH''' function generates an exception, which is effectively a subroutine call with a special parameter. The code to call is referenced by the given ''handle''. As with the '''CALLH''' opcode, the handle must have already been allocated, though again it is permitted to pass a handle which has not yet been populated by code. The back-end code generator must support both cases, though it will generally output less efficient code if the handle is not yet populated (since it must fetch the address at runtime from the handle). The ''parameter'' is stored in a special internal register called EXP and can be retrieved via the '''GETEXP''' opcode.
| |
| | |
| Like most control flow opcodes, '''EXH''' can be used either unconditionally or flagged with a condition that controls whether or not the exception is generated.
| |
| | |
| '''Example:'''
| |
| drcuml_codehandle *myexceptionhandler;
| |
|
| |
| void generate_exception_handler(drcuml_state *drcuml)
| |
| {
| |
| drcuml_block *block;
| |
| jmp_buf errorbuf;
| |
|
| |
| /* allocate a handle */
| |
| myexceptionhandler = drcuml_handle_alloc(drcuml, "handle_exception");
| |
|
| |
| /* handle a fatal error during codegen */
| |
| if (setjmp(errorbuf) != 0)
| |
| fatalerror("Ran out of cache space generating exception handler!");
| |
|
| |
| /* generate a simple exception handler */
| |
| block = drcuml_block_begin(drcuml, 10, &errorbuf);
| |
| UML_HANDLE(block, myexceptionhandler);
| |
| UML_RET(block);
| |
|
| |
| /* complete codegen */
| |
| drcuml_block_end(block);
| |
| }
| |
|
| |
| void generate_exception_if_non_zero(drcuml_block *block, int parameter)
| |
| {
| |
| UML_EXHc(block, IF_NZ, myexceptionhandler, IMM(parameter));
| |
| }
| |
| | |
| ----
| |
| | |
| === EXIT ===
| |
| | |
| '''Usage:'''
| |
| EXIT ''parameter''[,''condition'']
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_EXIT(''block'', PTYPE(''parameter''));
| |
| UML_EXITc(''block'', ''condition'', PTYPE(''parameter''));
| |
| | |
| '''Parameters:'''
| |
| * ''parameter'' — a 32-bit integer register, memory location, map variable, or immediate
| |
| * ''condition'' — an optional condition which is used to determine whether or not to exit
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' The '''EXIT''' opcode immediately exits from the generated code and returns control back to the back-end, which ultimately returns control to the dynamic recompiler. The exit can be performed even from within a subroutine or exception handler. The ''parameter'' is surfaced as the return value of the execute function.
| |
| | |
| Like most control flow opcodes, '''EXIT''' can be used either unconditionally or flagged with a condition that controls whether or not the exit occurs.
| |
| | |
| '''Example:'''
| |
| void exit_with_return_code_in_i0(drcuml_block *block)
| |
| {
| |
| UML_EXIT(block, IREG(0));
| |
| }
| |
| | |
| ----
| |
| | |
| === HANDLE ===
| |
| | |
| '''Usage:'''
| |
| HANDLE ''handle''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_HANDLE(''block'', ''handle'');
| |
| | |
| '''Parameters:'''
| |
| * ''handle'' — a memory pointer to previously-allocated handle
| |
| | |
| '''Flags:''' unaffected
| |
| | |
| '''Description:''' The '''HANDLE''' opcode connects the current code position to the specified ''handle''. The ''handle'' must have been previously explicitly allocated. By definition only one piece of code can connect itself to a handle; attempts to attach a new piece of code to an existing handle are considered errors and will assert in debug builds.
| |
| | |
| '''Example:'''
| |
| void attach_code_to_handle(drcuml_block *block, drcuml_codehandle *handle)
| |
| {
| |
| UML_HANDLE(block, handle);
| |
| }
| |
| | |
| ----
| |
| | |
| === HASH ===
| |
| | |
| '''Usage:'''
| |
| HASH ''mode'', ''pc''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_HASH(''block'', ''mode'', ''pc'');
| |
| | |
| '''Parameters:'''
| |
| * ''mode'' — a 32-bit immediate value
| |
| * ''pc'' — a 32-bit immediate value
| |
| | |
| '''Flags:''' unaffected
| |
| | |
| '''Description:''' The '''HASH''' opcode connects the current code position to the back-end's hash table. The back-end is free to implement whatever code lookup mechanism it desires, though a standard one is provided by the back-end utilities module. The available number of modes is specified at dynamic recompiler initialization time; it is an error to specify ''mode'' value beyond the number of modes requested at that time.
| |
| | |
| Note that unlike a handle, a hash for a given ''mode''/''pc'' combination can be replaced at any time.
| |
| | |
| '''Example:'''
| |
| void attach_code_to_mode_and_pc(drcuml_block *block, UINT32 mode, UINT32 pc)
| |
| {
| |
| UML_HASH(block, mode, pc);
| |
| }
| |
| | |
| ----
| |
| | |
| === HASHJMP ===
| |
| | |
| '''Usage:'''
| |
| HASHJMP ''mode'',''pc'',''handle''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_HASHJMP(''block'', PTYPE(''mode''), PTYPE(''pc''), ''handle'');
| |
| | |
| '''Parameters:'''
| |
| * ''mode'' — a 32-bit integer register, memory location, map variable, or immediate
| |
| * ''pc'' — a 32-bit integer register, memory location, map variable, or immediate
| |
| * ''handle'' — memory pointer to allocated handle
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' The '''HASHJMP''' opcode transfers control to a block of code that has previously been connected to the provided ''mode''/''pc'' pair. If no code has been registered, an exception is generated by setting the exception parameter EXP to ''pc'' and calling the given ''handle''. The expected response to this is to return to the dynamic recompiler and request that it generate new code for the provided ''mode''/''pc'' pair.
| |
| | |
| '''Example:'''
| |
| drcuml_codehandle *nocode_exception_handler;
| |
| UINT32 current_mode;
| |
|
| |
| void jump_to_code_at_pc_in_current_mode(drcuml_block *block, UINT32 pc)
| |
| {
| |
| UML_HASHJMP(block, MEM(¤tmode), IMM(pc), nocode_exception_handler);
| |
| }
| |
| | |
| ----
| |
| | |
| === JMP ===
| |
| | |
| '''Usage:'''
| |
| JMP ''label''[,''cond'']
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_JMP(''block'', ''label'');
| |
| UML_JMPc(''block'', ''condition'', ''label'');
| |
| | |
| '''Parameters:'''
| |
| * ''label'' — - a 32-bit immediate value
| |
| * ''condition'' — an optional condition which is used to determine whether or not to jump
| |
| | |
| '''Flags:''' unaffected
| |
| | |
| '''Description:''' The '''JMP''' opcode transfers control to another location within the current block. The ''label'' parameter specifies a 32-bit integer label that serves as the jump target. Within the block, a '''LABEL''' opcode must be present to signify what code the ''label'' refers to. In debug builds, attempts to jump to a non-existent label will assert at back-end code generation time (when all the labels are resolved).
| |
| | |
| Like most control flow opcodes, '''JMP''' can be used either unconditionally or flagged with a condition that controls whether or not the jump occurs.
| |
| | |
| '''Example:'''
| |
| void conditional_jump_around_code(drcuml_block *block)
| |
| {
| |
| drcuml_codelabel curlabel = 1;
| |
| drcuml_codelabel skip;
| |
|
| |
| UML_JMPc(block, IF_NZ, skip = curlabel++);
| |
| ''<other code here>''
| |
| UML_LABEL(skip);
| |
| }
| |
| | |
| ----
| |
| | |
| === LABEL ===
| |
| | |
| '''Usage:'''
| |
| LABEL ''label''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_LABEL(''block'', ''label'');
| |
| | |
| '''Parameters:'''
| |
| * ''label'' — 32-bit immediate value
| |
| | |
| '''Flags:''' unaffected
| |
| | |
| '''Description:''' The '''LABEL''' opcode connects the current code position to a block-local label with the value of ''label''. Only one label per block of UML can claim the same ''label'' value, so the dynamic recompiler must set up some conventions to ensure that each label has a unique 32-bit identifier.
| |
| | |
| '''Example:'''
| |
| void attach_code_to_label(drcuml_block *block, drcuml_codelabel label)
| |
| {
| |
| UML_LABEL(block, label);
| |
| }
| |
| | |
| ----
| |
| | |
| === MAPVAR ===
| |
| | |
| '''Usage:'''
| |
| MAPVAR ''mapvar'',''value''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_MAPVAR(''block'', MVAR(''mapvar''), ''value'');
| |
| | |
| '''Parameters:'''
| |
| * ''mapvar'' — a map variable
| |
| * ''value'' — a 32-bit immediate value
| |
| | |
| '''Flags:''' unaffected
| |
| | |
| '''Description:''' The '''MAPVAR''' opcode sets the specified map variable ''mapvar'' to a new value ''value'' starting at the current position within the code. Map variables are encoded into the instruction stream and can be retrieved from within a subroutine or exception handler via the '''RECOVER''' opcode. At the start of a block, all map variables default to 0, and hold that value until a '''MAPVAR''' opcode overrides it, at which point all subsequent code will take on the new ''value''.
| |
| | |
| Note that because the '''RECOVER''' opcode always operates on the outermost return address, it does not make sense to use '''MAPVAR''' within a subroutine.
| |
| | |
| '''Example:'''
| |
| void generate_some_code(drcuml_block *block)
| |
| {
| |
| UML_MAPVAR(block, MVAR(0), 1); /* we are in section 1 of the code */
| |
| ''<section 1 code here>''
| |
| UML_MAPVAR(block, MVAR(0), 2); /* now we are in section 2 of the code */
| |
| ''<section 2 code here>''
| |
| }
| |
| | |
| ----
| |
| | |
| === RECOVER ===
| |
| | |
| '''Usage:'''
| |
| RECOVER ''dest'',''mapvar''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_RECOVER(''block'', PTYPE(''dest''), MVAR(''mapvar''));
| |
| | |
| '''Parameters:'''
| |
| * ''dest'' — a 32-bit integer register or memory location
| |
| * ''mapvar'' — a map variable
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' The '''RECOVER''' opcode retrieves the value of the given ''mapvar'' and stores it in ''dest''. It does this by fetching the outermost return address from the stack and using that value to find the value specified by the most recent '''MAPVAR''' opcode that preceded the point where the subroutine call or exception generation happened. Because of this behavior, it only makes sense to use '''RECOVER''' from within a subroutine or exception handler; using it outside of this context will produce undefined results.
| |
| | |
| '''Example:'''
| |
| void generate_recover_code_section_to_i1(drcuml_block *block)
| |
| {
| |
| UML_RECOVER(block, IREG(0), MVAR(0));
| |
| }
| |
| | |
| ----
| |
| | |
| === RET ===
| |
| | |
| '''Usage:'''
| |
| RET [''cond'']
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_RET(''block'');
| |
| UML_RETc(''block'', ''condition'');
| |
| | |
| '''Parameters:'''
| |
| * ''condition'' — an optional condition which is used to determine whether or not to return
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' Returns control from a subroutine call or exception handler to the instruction following the CALLH or EXH opcode.
| |
| | |
| Like most control flow opcodes, '''RET''' can be used either unconditionally or flagged with a condition that controls whether or not the return occurs.
| |
| | |
| '''Example:'''
| |
| void generate_return_from_function_if_carry(drcuml_block *block)
| |
| {
| |
| UML_RET(block, IF_C);
| |
| }
| |
| | |
| == Internal Register Opcodes ==
| |
| | |
| === GETEXP ===
| |
| | |
| '''Usage:'''
| |
| GETEXP ''dest''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_GETEXP(block, PTYPE(''dest''));
| |
| | |
| '''Parameters:'''
| |
| * ''dest'' — a 32-bit integer register or memory location
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' The '''GETEXP''' opcode fetches the current value of the internal EXP (exception parameter) register. The EXP is set equal to the parameter value that was specified by the most recently executed '''EXH''' opcode, or is set equal to the ''pc'' parameter from a '''HASHJMP''' opcode that failed to find any associated code.
| |
| | |
| '''Example:'''
| |
| void generate_get_exception_parameter_in_i7(drcuml_block *block)
| |
| {
| |
| UML_GETEXP(block, IREG(7));
| |
| }
| |
| | |
| ----
| |
| | |
| === GETFLGS ===
| |
| | |
| '''Usage:'''
| |
| GETFLGS ''dest'',''mask''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_GETFLGS(block, PTYPE(''dest''), ''mask'');
| |
| | |
| '''Parameters:'''
| |
| * ''dest'' — a 32-bit integer register or memory location
| |
| * ''mask'' — an immediate mask of the flags to be retrieved
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' The '''GETFLGS''' opcode retrieves the current value of the UML flags and stores them in the target destination. Although all of the flags are available, it is rare that all flags are required, and often more efficient if the back-end only needs to fetch a subset of the flags. The ''mask'' parameter makes it possible to specify exactly which flags are needed. Bits in ''dest'' representing unrequested flags will be set to zero.
| |
| | |
| '''Example:'''
| |
| void generate_get_sign_and_zero_flags_in_i0(drcuml_block *block)
| |
| {
| |
| UML_GETFLGS(block, IREG(0), DRCUML_FLAG_S | DRCUML_FLAG_Z);
| |
| }
| |
| | |
| ----
| |
| | |
| === GETFMOD ===
| |
| | |
| '''Usage:'''
| |
| GETFMOD ''dest''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_GETFMOD(block, PTYPE(''mode''));
| |
| | |
| '''Parameters:'''
| |
| * ''dest'' — a 32-bit integer register or memory location
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' The '''GETFMOD''' opcode retrieves the current floating point rounding mode. It will produce one of the following values:
| |
| * DRCUML_FMOD_TRUNC (0) means truncate, or round toward zero
| |
| * DRCUML_FMOD_ROUND (1) means round to nearest
| |
| * DRCUML_FMOD_CEIL (2) means round toward positive infinity
| |
| * DRCUML_FMOD_FLOOR (3) means round toward negative infinity
| |
| | |
| '''Example:'''
| |
| UINT32 saved_mode;
| |
|
| |
| void generate_save_rounding_mode(drcuml_block *block)
| |
| {
| |
| UML_GETFMOD(block, MEM(&saved_mode));
| |
| }
| |
| | |
| ----
| |
| | |
| === RESTORE ===
| |
| | |
| '''Usage:'''
| |
| RESTORE ''source''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_RESTORE(block, ''source'');
| |
| | |
| '''Parameters:'''
| |
| * ''source'' — a memory pointer to a <code>drcuml_machine_state</code> structure
| |
| | |
| '''Flags:'''
| |
| * C — set to the value provided in ''source''
| |
| * V — set to the value provided in ''source''
| |
| * Z — set to the value provided in ''source''
| |
| * S — set to the value provided in ''source''
| |
| * U — set to the value provided in ''source''
| |
| | |
| '''Description:''' The '''RESTORE''' opcode copies the provided <code>drcuml_machine_state</code> structure into the live UML machine state.
| |
| | |
| '''Example:'''
| |
| void generate_restore_machine_state(drcuml_block *block, drcuml_machine_state *state)
| |
| {
| |
| UML_RESTORE(block, state);
| |
| }
| |
| | |
| ----
| |
| | |
| === SAVE ===
| |
| | |
| '''Usage:'''
| |
| SAVE ''dest''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_SAVE(block, ''dest'');
| |
| | |
| '''Parameters:'''
| |
| * ''dest'' — a memory pointer to a <code>drcuml_machine_state</code> structure
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' The '''SAVE''' opcode dumps the current UML machine state to the provided <code>drcuml_machine_state</code> structure. This state may be used for debugging or compliance analysis.
| |
| | |
| '''Example:'''
| |
| static drcuml_machine_state state;
| |
|
| |
| void generate_save_machine_state(drcuml_block *block)
| |
| {
| |
| UML_SAVE(block, &state);
| |
| }
| |
| | |
| ----
| |
| | |
| === SETFMOD ===
| |
| | |
| '''Usage:'''
| |
| SETFMOD ''mode''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_SETFMOD(block, PTYPE(''mode''));
| |
| | |
| '''Parameters:'''
| |
| * ''mode'' — a 32-bit integer register, memory location, map variable, or immediate
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' The '''SETFMOD''' opcode sets the currently active floating point rounding mode, which is implicitly used when performing most floating point operations (apart from those which explicitly specify a mode). The mode can be one of four values:
| |
| * DRCUML_FMOD_TRUNC (0) means truncate, or round toward zero
| |
| * DRCUML_FMOD_ROUND (1) means round to nearest
| |
| * DRCUML_FMOD_CEIL (2) means round toward positive infinity
| |
| * DRCUML_FMOD_FLOOR (3) means round toward negative infinity
| |
| Only the two least significant bits of the ''mode'' parameter are considered; all other bits are ignored.
| |
| | |
| '''Example:'''
| |
| void generate_set_fixed_rounding_mode(drcuml_block *block, int mode)
| |
| {
| |
| UML_SETFMOD(block, IMM(mode));
| |
| }
| |
| | |
| == Integer Operations ==
| |
| | |
| === LOAD ===
| |
| | |
| '''Usage:'''
| |
| LOAD1U ''dest'',''base'',''index''
| |
| LOAD1S ''dest'',''base'',''index''
| |
| LOAD2U ''dest'',''base'',''index''
| |
| LOAD2S ''dest'',''base'',''index''
| |
| LOAD4 ''dest'',''base'',''index''
| |
|
| |
| DLOAD1U ''dest'',''base'',''index''
| |
| DLOAD1S ''dest'',''base'',''index''
| |
| DLOAD2U ''dest'',''base'',''index''
| |
| DLOAD2S ''dest'',''base'',''index''
| |
| DLOAD4U ''dest'',''base'',''index''
| |
| DLOAD4S ''dest'',''base'',''index''
| |
| DLOAD8 ''dest'',''base'',''index''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_LOAD1U(block, PTYPE(''dest''), ''base'', PTYPE(''index''));
| |
| UML_LOAD1S(block, PTYPE(''dest''), ''base'', PTYPE(''index''));
| |
| UML_LOAD2U(block, PTYPE(''dest''), ''base'', PTYPE(''index''));
| |
| UML_LOAD2S(block, PTYPE(''dest''), ''base'', PTYPE(''index''));
| |
| UML_LOAD4 (block, PTYPE(''dest''), ''base'', PTYPE(''index''));
| |
|
| |
| UML_DLOAD1U(block, PTYPE(''dest''), ''base'', PTYPE(''index''));
| |
| UML_DLOAD1S(block, PTYPE(''dest''), ''base'', PTYPE(''index''));
| |
| UML_DLOAD2U(block, PTYPE(''dest''), ''base'', PTYPE(''index''));
| |
| UML_DLOAD2S(block, PTYPE(''dest''), ''base'', PTYPE(''index''));
| |
| UML_DLOAD4U(block, PTYPE(''dest''), ''base'', PTYPE(''index''));
| |
| UML_DLOAD4S(block, PTYPE(''dest''), ''base'', PTYPE(''index''));
| |
| UML_DLOAD8 (block, PTYPE(''dest''), ''base'', PTYPE(''index''));
| |
| | |
| '''Parameters:'''
| |
| * ''dest'' — a 32/64-bit integer register or memory location
| |
| * ''base'' — a memory pointer to the base of the table to read from
| |
| * ''index'' — a 32/64-bit integer register, memory location, map variable, or immediate
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' The '''LOAD''' family of opcodes performs a table-lookup memory read to a 32-bit destination; the '''DLOAD''' opcodes do the same to a 64-bit destination. Separate opcodes are provided for reading 1-byte, 2-byte, 4-byte, and 8-byte values from memory. In addition, when reading values that are smaller than the destination size, separate signed and unsigned forms are provided which describe how to populate the remaining bits. For example, the '''LOAD2U''' performs a 2-byte read from memory and zero-extends the result to 32 bits. Another example is the '''DLOAD4S''' opcode, which performs a 4-byte read from memory and sign-extends the result to 64 bits.
| |
| | |
| Unlike a standard memory location parameter (which must reside in the near cache), the ''base'' parameter may point anywhere in memory. Furthermore, the ''index'' parameter is truly an index and not a byte offset; thus the final address read will be ''base'' + (''size'' x ''index'').
| |
| | |
| '''Example:'''
| |
| static const UINT16 lookup_table[] = { 0, 1, 4, 5, 9, 10 };
| |
|
| |
| void generate_lookup_index_i2_to_i0(drcuml_block *block)
| |
| {
| |
| UML_LOAD2U(block, IREG(0), lookup_table, IREG(2));
| |
| }
| |
| | |
| ----
| |
| | |
| === STORE ===
| |
| | |
| '''Usage:'''
| |
| STORE1 ''base'',''index'',''source''
| |
| STORE2 ''base'',''index'',''source''
| |
| STORE4 ''base'',''index'',''source''
| |
|
| |
| DSTORE1 ''base'',''index'',''source''
| |
| DSTORE2 ''base'',''index'',''source''
| |
| DSTORE4 ''base'',''index'',''source''
| |
| DSTORE8 ''base'',''index'',''source''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_STORE1(block, ''base'', PTYPE(''index''), PTYPE(''source''));
| |
| UML_STORE2(block, ''base'', PTYPE(''index''), PTYPE(''source''));
| |
| UML_STORE4(block, ''base'', PTYPE(''index''), PTYPE(''source''));
| |
|
| |
| UML_DSTORE1(block, ''base'', PTYPE(''index''), PTYPE(''source''));
| |
| UML_DSTORE2(block, ''base'', PTYPE(''index''), PTYPE(''source''));
| |
| UML_DSTORE4(block, ''base'', PTYPE(''index''), PTYPE(''source''));
| |
| UML_DSTORE8(block, ''base'', PTYPE(''index''), PTYPE(''source''));
| |
| | |
| '''Parameters:'''
| |
| * ''base'' — a memory pointer to the base of the table to store to
| |
| * ''index'' — a 32/64-bit integer register, memory location, map variable, or immediate
| |
| * ''source'' — a 32/64-bit integer register, memory location, map variable, or immediate
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' The '''STORE''' family of opcodes performs a table-lookup memory write from a 32-bit source; the '''DSTORE''' opcodes do the same from a 64-bit source. Separate opcodes are provided for writing 1-byte, 2-byte, 4-byte, and 8-byte values to memory. For example, the '''STORE2''' performs a 2-byte write to memory from a 32 bit source.
| |
| | |
| Unlike a standard memory location parameter (which must reside in the near cache), the ''base'' parameter may point anywhere in memory. Furthermore, the ''index'' parameter is truly an index and not a byte offset; thus the final address read will be ''base'' + (''size'' x ''index'').
| |
| | |
| '''Example:'''
| |
| static const INT32 register_aray[32];
| |
|
| |
| void generate_store_i0_to_register_array_index_i9(drcuml_block *block)
| |
| {
| |
| UML_STORE4(block, register_array, IREG(9), IREG(0));
| |
| }
| |
| | |
| ----
| |
| | |
| === READ ===
| |
| | |
| '''Usage:'''
| |
| READ1U ''dest'',''space'',''address''
| |
| READ1S ''dest'',''space'',''address''
| |
| READ2U ''dest'',''space'',''address''
| |
| READ2S ''dest'',''space'',''address''
| |
| READ4 ''dest'',''space'',''address''
| |
|
| |
| DREAD1U ''dest'',''space'',''address''
| |
| DREAD1S ''dest'',''space'',''address''
| |
| DREAD2U ''dest'',''space'',''address''
| |
| DREAD2S ''dest'',''space'',''address''
| |
| DREAD4U ''dest'',''space'',''address''
| |
| DREAD4S ''dest'',''space'',''address''
| |
| DREAD8 ''dest'',''space'',''address''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_READ1U(block, PTYPE(''dest''), PROGRAM | DATA | IO, PTYPE(''address''));
| |
| UML_READ1S(block, PTYPE(''dest''), PROGRAM | DATA | IO, PTYPE(''address''));
| |
| UML_READ2U(block, PTYPE(''dest''), PROGRAM | DATA | IO, PTYPE(''address''));
| |
| UML_READ2S(block, PTYPE(''dest''), PROGRAM | DATA | IO, PTYPE(''address''));
| |
| UML_READ4(block, PTYPE(''dest''), PROGRAM | DATA | IO, PTYPE(''address''));
| |
|
| |
| UML_DREAD1U(block, PTYPE(''dest''), PROGRAM | DATA | IO, PTYPE(''address''));
| |
| UML_DREAD1S(block, PTYPE(''dest''), PROGRAM | DATA | IO, PTYPE(''address''));
| |
| UML_DREAD2U(block, PTYPE(''dest''), PROGRAM | DATA | IO, PTYPE(''address''));
| |
| UML_DREAD2S(block, PTYPE(''dest''), PROGRAM | DATA | IO, PTYPE(''address''));
| |
| UML_DREAD4U(block, PTYPE(''dest''), PROGRAM | DATA | IO, PTYPE(''address''));
| |
| UML_DREAD4S(block, PTYPE(''dest''), PROGRAM | DATA | IO, PTYPE(''address''));
| |
| UML_DREAD8(block, PTYPE(''dest''), PROGRAM | DATA | IO, PTYPE(''address''));
| |
| | |
| '''Parameters:'''
| |
| * ''dest'' — a 32/64-bit integer register or memory location
| |
| * ''space'' — an immediate describing which address space to read from
| |
| * ''address'' — a 32-bit integer register, memory location, map variable, or immediate
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' The '''READ''' family of opcodes performs a read from the emulated CPU's memory system to a 32-bit destination; the '''DREAD''' opcodes do the same to a 64-bit destination. Separate opcodes are provided for reading 1-byte, 2-byte, 4-byte, and 8-byte values. In addition, when reading values that are smaller than the destination size, separate signed and unsigned forms are provided which describe how to populate the remaining bits. For example, the '''READ2U''' performs a 2-byte read from memory and zero-extends the result to 32 bits. Another example is the '''DREAD4S''' opcode, which performs a 4-byte read from memory and sign-extends the result to 64 bits.
| |
| | |
| The ''space'' parameter specifies one of three address spaces:
| |
| * ADDRESS_SPACE_PROGRAM — the address space where code resides
| |
| * ADDRESS_SPACE_DATA — the address space where data resides for Harvard architecture CPUs
| |
| * ADDRESS_SPACE_IO — a third peripheral address space generally used for I/O access
| |
| | |
| Note that even in its 64-bit form, the ''DREAD'' opcodes still take a fixed 32-bit size parameter for the ''address''.
| |
| | |
| '''Example:'''
| |
| void generate_load_qword_from_program_space_address_i0(drcuml_block *block)
| |
| {
| |
| UML_DLOAD8(block, IREG(0), PROGRAM, IREG(0));
| |
| }
| |
| | |
| ----
| |
| | |
| === READM ===
| |
| | |
| '''Usage:'''
| |
| READ2M ''dest'',''space'',''address'',''mask''
| |
| READ4M ''dest'',''space'',''address'',''mask''
| |
|
| |
| DREAD2M ''dest'',''space'',''address'',''mask''
| |
| DREAD4M ''dest'',''space'',''address'',''mask''
| |
| DREAD8M ''dest'',''space'',''address'',''mask''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_READ2M(block, PTYPE(''dest''), PROGRAM | DATA | IO, PTYPE(''address''), PTYPE(''mask''));
| |
| UML_READ4M(block, PTYPE(''dest''), PROGRAM | DATA | IO, PTYPE(''address''), PTYPE(''mask''));
| |
|
| |
| UML_DREAD2M(block, PTYPE(''dest''), PROGRAM | DATA | IO, PTYPE(''address''), PTYPE(''mask''));
| |
| UML_DREAD4M(block, PTYPE(''dest''), PROGRAM | DATA | IO, PTYPE(''address''), PTYPE(''mask''));
| |
| UML_DREAD8M(block, PTYPE(''dest''), PROGRAM | DATA | IO, PTYPE(''address''), PTYPE(''mask''));
| |
| | |
| '''Parameters:'''
| |
| * ''dest'' — a 32/64-bit integer register or memory location
| |
| * ''space'' — an immediate describing which address space to read from
| |
| * ''address'' — a 32-bit integer register, memory location, map variable, or immediate
| |
| * ''mask'' — a 32/64-bit integer register, memory location, map variable, or immediate
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' The '''READM''' family of opcodes performs a masked read from the emulated CPU's memory system to a 32-bit destination; the '''DREADM''' opcodes do the same to a 64-bit destination. These opcodes are similar to the '''READ''' and '''DREAD''' opcodes described above, but with two primary differences. First, the additional parameter ''mask'' specifies which bytes within the larger access should be referenced. Second, all masked reads zero-extend their results to the destination.
| |
| | |
| '''Example:'''
| |
| void generate_load_upper_or_lower_word_from_i0(drcuml_block *block, int upper)
| |
| {
| |
| /* big-endian */
| |
| if (upper)
| |
| UML_LOAD4(block, IREG(0), PROGRAM, IREG(0), IMM(0xffff0000));
| |
| else
| |
| UML_LOAD4(block, IREG(0), PROGRAM, IREG(0), IMM(0x0000ffff));
| |
| }
| |
| | |
| ----
| |
| | |
| === WRITE ===
| |
| | |
| '''Usage:'''
| |
| WRITE1 ''space'',''address'',''source''
| |
| WRITE2 ''space'',''address'',''source''
| |
| WRITE4 ''space'',''address'',''source''
| |
|
| |
| DWRITE1 ''space'',''address'',''source''
| |
| DWRITE2 ''space'',''address'',''source''
| |
| DWRITE4 ''space'',''address'',''source''
| |
| DWRITE8 ''space'',''address'',''source''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_WRITE1(block, PROGRAM | DATA | IO, PTYPE(''address''), PTYPE(''source''));
| |
| UML_WRITE2(block, PROGRAM | DATA | IO, PTYPE(''address''), PTYPE(''source''));
| |
| UML_WRITE4(block, PROGRAM | DATA | IO, PTYPE(''address''), PTYPE(''source''));
| |
|
| |
| UML_DWRITE1(block, PROGRAM | DATA | IO, PTYPE(''address''), PTYPE(''source''));
| |
| UML_DWRITE2(block, PROGRAM | DATA | IO, PTYPE(''address''), PTYPE(''source''));
| |
| UML_DWRITE4(block, PROGRAM | DATA | IO, PTYPE(''address''), PTYPE(''source''));
| |
| UML_DWRITE8(block, PROGRAM | DATA | IO, PTYPE(''address''), PTYPE(''source''));
| |
| | |
| '''Parameters:'''
| |
| * ''space'' — an immediate describing which address space to read from
| |
| * ''address'' — a 32-bit integer register, memory location, map variable, or immediate
| |
| * ''source'' — a 32/64-bit integer register, memory location, map variable, or immediate
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' The '''WRITE''' family of opcodes performs a write to the emulated CPU's memory system from a 32-bit source; the '''DWRITE''' opcodes do the same from a 64-bit source. Separate opcodes are provided for writing1-byte, 2-byte, 4-byte, and 8-byte values. For example, the '''WRITE2''' performs a 2-byte write to memory.
| |
| | |
| The ''space'' parameter specifies one of three address spaces:
| |
| * ADDRESS_SPACE_PROGRAM — the address space where code resides
| |
| * ADDRESS_SPACE_DATA — the address space where data resides for Harvard architecture CPUs
| |
| * ADDRESS_SPACE_IO — a third peripheral address space generally used for I/O access
| |
| | |
| Note that even in its 64-bit form, the ''DWRITE'' opcodes still take a fixed 32-bit size parameter for the ''address''.
| |
| | |
| '''Example:'''
| |
| void generate_write_memory_to_byte(drcuml_block *block, UINT32 *memory)
| |
| {
| |
| UML_WRITE1(block, PROGRAM, IREG(0), MEM(memory));
| |
| }
| |
| | |
| ----
| |
| | |
| === WRITM ===
| |
| | |
| '''Usage:'''
| |
| WRIT2M ''space'',''address'',''mask'',''source''
| |
| WRIT4M ''space'',''address'',''mask'',''source''
| |
|
| |
| DWRIT2M ''space'',''address'',''mask'',''source''
| |
| DWRIT4M ''space'',''address'',''mask'',''source''
| |
| DWRIT8M ''space'',''address'',''mask'',''source''
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_WRIT2M(block, PROGRAM | DATA | IO, PTYPE(''address''), PTYPE(''mask''), PTYPE(''source''));
| |
| UML_WRIT4M(block, PROGRAM | DATA | IO, PTYPE(''address''), PTYPE(''mask''), PTYPE(''source''));
| |
|
| |
| UML_DWRIT2M(block, PROGRAM | DATA | IO, PTYPE(''address''), PTYPE(''mask''), PTYPE(''source''));
| |
| UML_DWRIT4M(block, PROGRAM | DATA | IO, PTYPE(''address''), PTYPE(''mask''), PTYPE(''source''));
| |
| UML_DWRIT8M(block, PROGRAM | DATA | IO, PTYPE(''address''), PTYPE(''mask''), PTYPE(''source''));
| |
| | |
| '''Parameters:'''
| |
| * ''space'' — an immediate describing which address space to read from
| |
| * ''address'' — a 32-bit integer register, memory location, map variable, or immediate
| |
| * ''source'' — a 32/64-bit integer register, memory location, map variable, or immediate
| |
| * ''mask'' — a 32/64-bit integer register, memory location, map variable, or immediate
| |
| | |
| '''Flags:''' undefined
| |
| | |
| '''Description:''' The '''WRITM''' family of opcodes performs a masked write to the emulated CPU's memory system from a 32-bit source; the '''DWRITM''' opcodes do the same from a 64-bit source. These opcodes are similar to the '''WRITE''' and '''DWRITE''' opcodes described above, but with one primary differences: the additional parameter ''mask'' specifies which bytes within the larger access should be written.
| |
| | |
| '''Example:'''
| |
| void generate_write_store_masked_byte(drcuml_block *block, UINT8 byte, UINT32 mask)
| |
| {
| |
| UML_WRIT4M(block, PROGRAM, IREG(0), IMM(mask), IMM(byte));
| |
| }
| |
| | |
| ----
| |
| | |
| === Template ===
| |
| | |
| '''Usage:'''
| |
| OPCODE ''param0''[,''param1'']
| |
| | |
| '''Codegen Shorthand:'''
| |
| UML_OPCODE(block, ''param0'', ''param1'');
| |
| | |
| '''Parameters:'''
| |
| * ''param0'' —
| |
| * ''param1'' —
| |
| | |
| '''Flags:'''
| |
| * C — undefined
| |
| * V — undefined
| |
| * Z — undefined
| |
| * S — undefined
| |
| * U — undefined
| |
| | |
| '''Description:'''
| |
|
| |
|
| '''Example:'''
| | For information about particular opcodes, see one of these sections: |
| void generate_opcode(drcuml_block *block)
| |
| {
| |
| UML_OPCODE(block, IREG(0), IMM(1));
| |
| }
| |
|
| |
|
| ----
| | * [[UML Control Flow Opcodes]] |
| | * [[UML Internal Register Opcodes]] |
| | * [[UML Integer Opcodes]] |
| | * [[UML Floating Point Opcodes]] |