1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
/***************************************************************************
drcfe.h
Generic dynamic recompiler frontend structures and utilities.
Copyright Aaron Giles
Released for general non-commercial use under the MAME license
Visit http://mamedev.org for licensing and usage restrictions.
****************************************************************************
Concepts:
Dynamic recompiling cores are generally broken into a platform-neutral
"frontend", which performs some level of analysis on the code, and a
platform-specific "backend", which generates the recompiled machine
code.
The frontend's job is generally to walk through the instruction stream,
identifying basic blocks, or "sequences" of code that can be compiled
and optimized as a unit. This scanning involves recursively walking
the instruction stream, following branches, etc., within a specific
"code window", relative to the current PC.
As the frontend walks through the code, it generates a list of opcode
"descriptions", one per visited opcode, providing information about
code flow, exception handling, and other characteristics. Once the
walkthrough is finished, these descriptions are assembled together into
a linked list and returned for further processing by the backend.
***************************************************************************/
#ifndef __DRCFE_H__
#define __DRCFE_H__
/***************************************************************************
CONSTANTS
***************************************************************************/
/* this defines a branch targetpc that is dynamic at runtime */
#define BRANCH_TARGET_DYNAMIC (~0)
/* opcode branch flags */
#define OPFLAG_IS_UNCONDITIONAL_BRANCH 0x00000001 /* instruction is unconditional branch */
#define OPFLAG_IS_CONDITIONAL_BRANCH 0x00000002 /* instruction is conditional branch */
#define OPFLAG_IS_BRANCH (OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_IS_CONDITIONAL_BRANCH)
#define OPFLAG_IS_BRANCH_TARGET 0x00000004 /* instruction is the target of a branch */
#define OPFLAG_IN_DELAY_SLOT 0x00000008 /* instruction is in the delay slot of a branch */
#define OPFLAG_INTRABLOCK_BRANCH 0x00000010 /* instruction branches within the block */
/* opcode exception flags */
#define OPFLAG_CAN_TRIGGER_SW_INT 0x00000020 /* instruction can trigger a software interrupt */
#define OPFLAG_CAN_EXPOSE_EXTERNAL_INT 0x00000040 /* instruction can expose an external interrupt */
#define OPFLAG_CAN_CAUSE_EXCEPTION 0x00000080 /* instruction may generate exception */
#define OPFLAG_WILL_CAUSE_EXCEPTION 0x00000100 /* instruction will generate exception */
/* opcode virtual->physical translation flags */
#define OPFLAG_VALIDATE_TLB 0x00000200 /* instruction must validate TLB before execution */
#define OPFLAG_MODIFIES_TRANSLATION 0x00000400 /* instruction modifies the TLB */
#define OPFLAG_COMPILER_PAGE_FAULT 0x00000800 /* compiler hit a page fault when parsing */
#define OPFLAG_COMPILER_UNMAPPED 0x00001000 /* compiler hit unmapped memory when parsing */
/* opcode flags */
#define OPFLAG_INVALID_OPCODE 0x00002000 /* instruction is invalid */
#define OPFLAG_VIRTUAL_NOOP 0x00004000 /* instruction is a virtual no-op */
/* opcode sequence flow flags */
#define OPFLAG_REDISPATCH 0x00008000 /* instruction must redispatch after completion */
#define OPFLAG_RETURN_TO_START 0x00010000 /* instruction must jump back to the beginning after completion */
#define OPFLAG_END_SEQUENCE 0x00020000 /* this is the last instruction in a sequence */
#define OPFLAG_CAN_CHANGE_MODES 0x00040000 /* instruction can change modes */
/* execution semantics */
#define OPFLAG_READS_MEMORY 0x00080000 /* instruction reads memory */
#define OPFLAG_WRITES_MEMORY 0x00100000 /* instruction writes memory */
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
/* opaque internal state */
typedef struct _drcfe_state drcfe_state;
/* register information as bitmasks */
typedef struct _drc_reginfo drc_reginfo;
struct _drc_reginfo
{
UINT64 used; /* bitmask of used registers */
UINT64 modified; /* bitmask of modified registers */
UINT64 constant; /* bitmask of constant registers */
UINT64 liveread; /* bitmask of registers that are live for reading */
UINT64 livewrite; /* bitmask of registers that are live for writing */
};
/* description of a given opcode */
typedef struct _opcode_desc opcode_desc;
struct _opcode_desc
{
/* links to other descriptions */
opcode_desc * next; /* pointer to next description */
opcode_desc * branch; /* pointer back to branch description for delay slots */
opcode_desc * delay; /* pointer to delay slot description */
/* information about the current PC */
offs_t pc; /* PC of this opcode */
offs_t physpc; /* physical PC of this opcode */
offs_t targetpc; /* target PC if we are a branch, or BRANCH_TARGET_DYNAMIC */
/* pointer to the current opcode */
union
{
void * v;
UINT8 * b;
UINT16 * w;
UINT32 * l;
UINT64 * q;
} opptr; /* pointer to opcode memory */
/* information about this instruction's execution */
UINT8 length; /* length in bytes of this opcode */
UINT8 delayslots; /* number of delay slots (for branches) */
UINT8 skipslots; /* number of skip slots (for branches) */
UINT32 flags; /* OPFLAG_* opcode flags */
UINT32 cycles; /* number of cycles needed to execute */
/* register usage information */
drc_reginfo gpr; /* register info for GPRs */
drc_reginfo fpr; /* register info for FPRs */
};
/* callback function that is used to describe a single opcode */
typedef int (*drcfe_describe_func)(void *param, opcode_desc *desc);
/* description of a given opcode */
typedef struct _drcfe_config drcfe_config;
struct _drcfe_config
{
UINT32 window_start; /* code window start offset = startpc - window_start */
UINT32 window_end; /* code window end offset = startpc + window_end */
UINT32 max_sequence; /* maximum instructions to include in a sequence */
drcfe_describe_func describe; /* callback to describe a single instruction */
};
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
/* initializate the drcfe state */
drcfe_state *drcfe_init(const drcfe_config *config, void *param);
/* clean up after ourselves */
void drcfe_exit(drcfe_state *drcfe);
/* describe a sequence of code that falls within the configured window relative to the specified startpc */
const opcode_desc *drcfe_describe_code(drcfe_state *drcfe, offs_t startpc);
#endif
|