-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathbt.cpp
322 lines (312 loc) · 12.5 KB
/
bt.cpp
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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
#include "m65816.hpp"
#include "bt.hpp"
// ---------------------------------------------------------------------------
#define BTWALK_PREAMBLE(walker_ea, opcode_var, itype_var) \
(walker_ea) = prev_head((walker_ea), (walker_ea) - 4); \
if ( (walker_ea) == BADADDR ) \
break; \
flags_t F = get_flags_novalue(walker_ea); \
if ( isFunc(F) || !isCode(F) ) \
break; \
opcode_var = get_byte(walker_ea); \
itype_var = get_opcode_info(opcode_var).itype;
// ---------------------------------------------------------------------------
// FIXME: The following are lacks in implementation:
// * If the value we asked for is 16bits, and
// at some point we are reduced to an 8-bits one, we should
// fail.
int32 backtrack_value(ea_t from_ea, uint8 size, btsource_t source)
{
// Note: At some point, we were using:
// ---
// const func_t * const func = get_fchunk(from_ea);
// if (func == NULL)
// return -1;
// ea_t chunk_start_ea = func->startEA;
// ---
// in order to determine where we had to stop backtracking
// values.
// Unfortunately, that doesn't work because, during the initial
// analysis, where functions & chunks aren't properly formed yet,
// the 'func' ptr would always be NULL. Therefore, we wouldn't
// be capable of backtracking a value properly; which also
// means that wrong values were propagated to other
// functions.
//
// A particularily interesting example is this: In a certain
// rom, we had the following seq. of instructions:
//
// --------------------------------------------------------------------------
// .C0:0019 SEI
// .C0:001A CLC
// .C0:001B XCE
// .C0:001C SEP #$20 ; ' ' ; .a8, .i16
// .C0:001E REP #$10 ; .a8, .i16
// .C0:0020 LDX #$15FF
// .C0:0023 TXS
// .C0:0024 LDX #0
// .C0:0027 PHX
// .C0:0028 PLD
// .C0:0029 TDC
// .C0:002A PHA
// .C0:002B PLB
// .C0:002C LDA #1
// .C0:002E STA CYCLE_SPEED_DESIGNATION ; 0000000a a: 0 = 2.68 MHz, 1 = 3.58 MHz
// .C0:0031 STZ REGULAR_DMA_CHANNEL_ENABLE ; abcdefgh a = Channel 7...h = Channel 0: 1 = Enable 0 = Disable
// .C0:0034 STZ H_DMA_CHANNEL_ENABLE ; abcdefgh a = Channel 7 .. h = Channel 0: 1 = Enable 0 = Disable
// .C0:0037 LDA #$8F ; ''
// .C0:0039 STA SCREEN_DISPLAY_REGISTER ; a000bbbb a: 0=screen on 1=screen off, b = brightness
// .C0:003C STZ NMI_V_H_COUNT_AND_JOYPAD_ENABLE ; a0bc000d a = NMI b = V-Count c = H-Count d = Joypad
// .C0:003F JSR sub_C00525
// --------------------------------------------------------------------------
//
// And, at 0xc00525:
//
// --------------------------------------------------------------------------
// .C0:0525 sub_C00525: ; CODE XREF: sub_C00019+26p
// .C0:0525 TDC
// .C0:0526 TAX
// .C0:0527 STX WRAM_ADDRESS_LOW_BYTE
// .C0:052A STA WRAM_ADDRESS_HIGH_BYTE
// .C0:052D LDX #$120
// .C0:0530
// .C0:0530 loc_C00530: ; CODE XREF: sub_C00525+3Cj
// .C0:0530 STA WRAM_DATA_READ_WRITE
// .C0:0533 STA WRAM_DATA_READ_WRITE
// .C0:0536 STA WRAM_DATA_READ_WRITE
// .C0:0539 STA WRAM_DATA_READ_WRITE
// .C0:053C STA WRAM_DATA_READ_WRITE
// .C0:053F STA WRAM_DATA_READ_WRITE
// .C0:0542 STA WRAM_DATA_READ_WRITE
// .C0:0545 STA WRAM_DATA_READ_WRITE
// .C0:0548 STA WRAM_DATA_READ_WRITE
// .C0:054B STA WRAM_DATA_READ_WRITE
// .C0:054E STA WRAM_DATA_READ_WRITE
// .C0:0551 STA WRAM_DATA_READ_WRITE
// .C0:0554 STA WRAM_DATA_READ_WRITE
// .C0:0557 STA WRAM_DATA_READ_WRITE
// .C0:055A STA WRAM_DATA_READ_WRITE
// .C0:055D STA WRAM_DATA_READ_WRITE
// .C0:0560 DEX
// .C0:0561 BNE loc_C00530
// .C0:0563 RTS
// --------------------------------------------------------------------------
//
// What would happen is that the 'STA's starting at
// C0:0530 would not reference the proper register:
// The B was 0xffffffff (from a previous
// propagation), and when a later propagation tried to set
// the B value to 0x00, starting at C0:0525, that
// propagation stopped at the next segment start.
// That is, C0:0530,
// which was established because of the BNE that
// appears below.
// Which also makes me think.. should we propagate from a BNE?
uint8 opcode;
ea_t cur_ea = from_ea;
uint8 itype;
switch ( source )
{
case BT_STACK:
while ( true )
{
BTWALK_PREAMBLE(cur_ea, opcode, itype);
if ( M65_ITYPE_PUSH(itype) )
{
switch ( itype )
{
case M65816_pea: // Push effective absolute address
{
uint16 val = get_word(cur_ea + 1);
if ( size == 1 )
val &= 0xff;
return val;
}
case M65816_pei: // Push effective indirect address
return -1;
case M65816_per: // Push effective PC-relative indirect address
{
uint16 val = cur_ea + 3;
val += get_word(cur_ea + 1);
val &= (size == 1 ? 0xff : 0xffff);
return val;
}
case M65816_pha: // Push A
return backtrack_value(cur_ea, size, BT_A);
case M65816_phb: // Push B (data bank register)
return get_segreg(cur_ea, rB);
case M65816_phd: // Push D (direct page register)
return get_segreg(cur_ea, rD);
case M65816_phk: // Push K (program bank register)
return get_segreg(cur_ea, rPB);
case M65816_php: // Push processor status
return -1;
case M65816_phx: // Push X
return backtrack_value(cur_ea, size, BT_X);
case M65816_phy: // Push Y
return backtrack_value(cur_ea, size, BT_Y);
default:
return -1;
}
}
else if ( M65_ITYPE_PULL(itype) )
{
// TODO: keep track of additional displacements in the stack
return -1;
}
}
break;
case BT_A:
while ( true )
{
BTWALK_PREAMBLE(cur_ea, opcode, itype);
uint8 opsize = from_ea - cur_ea;
uint8 cur_ea_acc_is_16 = is_acc_16_bits(cur_ea);
uint8 new_size = cur_ea_acc_is_16 ? 2 : 1;
switch ( itype )
{
// All these modify A in a way we cannot
// easily determine its value anymore.
// We'll thus stop.
case M65816_adc: // Add with carry
case M65816_and: // AND A with memory
case M65816_asl: // Shift memory or A left
case M65816_dec: // Decrement
case M65816_eor: // XOR A with M
case M65816_inc: // Increment
case M65816_mvn: // Block move next
case M65816_mvp: // Block move prev
case M65816_ora: // Or A with memory
case M65816_sbc: // Subtract with borrow from A
case M65816_xba: // Exchange bytes in A
return -1;
// For these next ones, there's hope.
case M65816_lsr: // Logical shift memory or A right
if ( opcode == 0x4a ) // LSR A
return -1;
break;
case M65816_rol: // Rotate memory or A left
case M65816_ror: // Rotate memory or A right
if ( opcode == 0x30 || opcode == 0x70 )
return -1;
break;
case M65816_lda: // Load A from memory
if ( opcode == 0xa9 ) // LDA imm
return opsize == 3 ? get_word(cur_ea + 1) : get_byte(cur_ea + 1);
else
return -1;
case M65816_pla: // Pull A
return backtrack_value(cur_ea, new_size, BT_STACK);
case M65816_tdc: // Transfer 16-bit D to A
return get_segreg(cur_ea, rD);
case M65816_tsc: // Transfer S to A
return get_segreg(cur_ea, rS);
case M65816_txa: // Transfer X to A
return backtrack_value(cur_ea, new_size, BT_X);
case M65816_tya: // Transfer Y to A
return backtrack_value(cur_ea, new_size, BT_Y);
}
}
break;
case BT_X:
while ( true )
{
BTWALK_PREAMBLE(cur_ea, opcode, itype);
uint8 opsize = from_ea - cur_ea;
uint8 cur_ea_xy_is_16 = is_xy_16_bits(cur_ea);
uint8 new_size = cur_ea_xy_is_16 ? 2 : 1;
switch ( itype )
{
// All these modify X in a way we cannot
// easily determine its value anymore.
// We'll thus stop.
case M65816_dex: // Decrement X
case M65816_inx: // Increment X
case M65816_mvn: // Block move next
case M65816_mvp: // Block move prev
return -1;
case M65816_ldx: // Load X from memory
if ( opcode == 0xa2 ) // LDX imm
return opsize == 3 ? get_word(cur_ea + 1) : get_byte(cur_ea + 1);
else
return -1;
case M65816_plx: // Pull X
return backtrack_value(cur_ea, new_size, BT_STACK);
case M65816_tax: // Transfer A to X
return backtrack_value(cur_ea, new_size, BT_A);
case M65816_tsx: // Transfer S to X
return get_segreg(cur_ea, rS);
case M65816_tyx: // Transfer Y to X
return backtrack_value(cur_ea, new_size, BT_Y);
}
}
break;
case BT_Y:
while ( true )
{
BTWALK_PREAMBLE(cur_ea, opcode, itype);
uint8 opsize = from_ea - cur_ea;
uint8 cur_ea_xy_is_16 = is_xy_16_bits(cur_ea);
uint8 new_size = cur_ea_xy_is_16 ? 2 : 1;
switch ( itype )
{
// All these modify X in a way we cannot
// easily determine its value anymore.
// We'll thus stop.
case M65816_dey: // Decrement Y
case M65816_iny: // Increment Y
case M65816_mvn: // Block move next
case M65816_mvp: // Block move prev
return -1;
case M65816_ldy: // Load Y from memory
if ( opcode == 0xa0 ) // LDY imm
return opsize == 3 ? get_word(cur_ea + 1) : get_byte(cur_ea + 1);
else
return -1;
case M65816_ply: // Pull Y
return backtrack_value(cur_ea, new_size, BT_STACK);
case M65816_tay: // Transfer A to Y
return backtrack_value(cur_ea, new_size, BT_A);
case M65816_txy: // Transfer X to Y
return backtrack_value(cur_ea, new_size, BT_X);
}
}
break;
case BT_DP:
while ( true )
{
BTWALK_PREAMBLE(cur_ea, opcode, itype);
switch ( itype )
{
// All these modify D in a way we cannot
// easily determine its value anymore.
// We'll thus stop.
case M65816_pld: // Pull D
return backtrack_value(cur_ea, size, BT_STACK);
case M65816_tcd: // Transfer 16-bit Accumulator to Direct Page Register
return backtrack_value(cur_ea, size, BT_A);
}
}
break;
default:
msg("WARNING: backtrack_value() of unsupported BT-type: %d\n", source);
break;
}
return -1;
}
// ---------------------------------------------------------------------------
ea_t backtrack_prev_ins(ea_t from_ea, m65_itype_t itype)
{
uint8 opcode;
ea_t cur_ea = from_ea;
uint8 candidate_itype;
while ( true )
{
BTWALK_PREAMBLE(cur_ea, opcode, candidate_itype);
if ( candidate_itype == itype )
return cur_ea;
}
return BADADDR;
}
#undef BTWALK_LOOP
#undef BTWALK_PREAMBLE