1 //============================================================================
2 //
3 // SSSS tt lll lll
4 // SS SS tt ll ll
5 // SS tttttt eeee ll ll aaaa
6 // SSSS tt ee ee ll ll aa
7 // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8 // SS SS tt ee ll ll aa aa
9 // SSSS ttt eeeee llll llll aaaaa
10 //
11 // Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony
12 // and the Stella Team
13 //
14 // See the file "License.txt" for information on usage and redistribution of
15 // this file, and for a DISCLAIMER OF ALL WARRANTIES.
16 //============================================================================
17
18 //============================================================================
19 // This class provides Thumb emulation code ("Thumbulator")
20 // by David Welch (dwelch@dwelch.com)
21 // Modified by Fred Quimby
22 // Code is public domain and used with the author's consent
23 //============================================================================
24
25 #include "bspf.hxx"
26 #include "Base.hxx"
27 #include "Cart.hxx"
28 #include "Thumbulator.hxx"
29 using Common::Base;
30
31 // Uncomment the following to enable specific functionality
32 // WARNING!!! This slows the runtime to a crawl
33 // #define THUMB_DISS
34 // #define THUMB_DBUG
35
36 #if defined(THUMB_DISS)
37 #define DO_DISS(statement) statement
38 #else
39 #define DO_DISS(statement)
40 #endif
41 #if defined(THUMB_DBUG)
42 #define DO_DBUG(statement) statement
43 #else
44 #define DO_DBUG(statement)
45 #endif
46
47 #ifdef __BIG_ENDIAN__
48 #define CONV_DATA(d) (((d & 0xFFFF)>>8) | ((d & 0xffff)<<8)) & 0xffff
49 #define CONV_RAMROM(d) ((d>>8) | (d<<8)) & 0xffff
50 #else
51 #define CONV_DATA(d) (d & 0xFFFF)
52 #define CONV_RAMROM(d) (d)
53 #endif
54
55 #ifdef THUMB_CYCLE_COUNT
56 #define MERGE_I_S
57 #define INC_S_CYCLES(addr, accessType) \
58 if(_countCycles) \
59 incSCycles(addr, accessType)
60 #define INC_N_CYCLES(addr, accessType) \
61 if(_countCycles) \
62 incNCycles(addr, accessType)
63 #define INC_I_CYCLES \
64 if(_countCycles) \
65 incICycles()
66 #define INC_I_CYCLES_M(m) \
67 if(_countCycles) \
68 incICycles(m)
69
70 #define INC_SHIFT_CYCLES \
71 INC_I_CYCLES \
72 //FETCH_TYPE(CycleType::S, AccessType::data)
73
74 #define INC_LDR_CYCLES \
75 INC_N_CYCLES(rb, AccessType::data); \
76 INC_I_CYCLES \
77 /*FETCH_TYPE(CycleType::N, AccessType::data); \
78 FETCH_TYPE_N;*/
79 #define INC_LDRB_CYCLES \
80 INC_N_CYCLES(rb & (~1U), AccessType::data); \
81 INC_I_CYCLES \
82 /*FETCH_TYPE(CycleType::N, AccessType::data); \
83 FETCH_TYPE_N;*/
84
85 #define INC_STR_CYCLES \
86 INC_N_CYCLES(rb, AccessType::data); \
87 FETCH_TYPE_N \
88 //INC_N_CYCLES(rb, AccessType::data);
89 #define INC_STRB_CYCLES \
90 INC_N_CYCLES(rb & (~1U), AccessType::data); \
91 FETCH_TYPE_N \
92 //INC_N_CYCLES(rb & (~1U), AccessType::data);
93
94 #if 0 // unused for now
95 #define FETCH_TYPE(cycleType, accessType) \
96 _prefetchCycleType[_pipeIdx] = cycleType; \
97 _prefetchAccessType[_pipeIdx] = accessType
98 #endif
99 #define FETCH_TYPE_N \
100 _prefetchCycleType[_pipeIdx] = CycleType::N
101
102 // ARM cycles
103 #define INC_ARM_CYCLES(m) \
104 _totalCycles += m
105 #else
106 #define INC_S_CYCLES(addr, accessType)
107 #define INC_N_CYCLES(addr, accessType)
108 #define INC_I_CYCLES
109 #define INC_I_CYCLES_M(m)
110
111 #define INC_SHIFT_CYCLES
112
113 #define INC_LDR_CYCLES
114 #define INC_LDRB_CYCLES
115
116 #define INC_STR_CYCLES
117 #define INC_STRB_CYCLES
118
119 #define FETCH_TYPE(cycleType, accessType)
120 #define FETCH_TYPE_N
121
122 // ARM cycles
123 #define INC_ARM_CYCLES(m)
124 #endif
125
126 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Thumbulator(const uInt16 * rom_ptr,uInt16 * ram_ptr,uInt32 rom_size,const uInt32 c_base,const uInt32 c_start,const uInt32 c_stack,bool traponfatal,double cyclefactor,Thumbulator::ConfigureFor configurefor,Cartridge * cartridge)127 Thumbulator::Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, uInt32 rom_size,
128 const uInt32 c_base, const uInt32 c_start, const uInt32 c_stack,
129 bool traponfatal, double cyclefactor,
130 Thumbulator::ConfigureFor configurefor,
131 Cartridge* cartridge)
132 : rom{rom_ptr},
133 romSize{rom_size},
134 cBase{c_base},
135 cStart{c_start},
136 cStack{c_stack},
137 decodedRom{make_unique<Op[]>(romSize / 2)}, // NOLINT
138 ram{ram_ptr},
139 configuration{configurefor},
140 myCartridge{cartridge}
141 {
142 for(uInt32 i = 0; i < romSize / 2; ++i)
143 decodedRom[i] = decodeInstructionWord(CONV_RAMROM(rom[i]));
144
145 setConsoleTiming(ConsoleTiming::ntsc);
146 #ifndef UNSAFE_OPTIMIZATIONS
147 trapFatalErrors(traponfatal);
148 #endif
149 #ifdef DEBUGGER_SUPPORT
150 cycleFactor(cyclefactor);
151 #endif
152 reset();
153 }
154
155 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
doRun(uInt32 & cycles,bool irqDrivenAudio)156 string Thumbulator::doRun(uInt32& cycles, bool irqDrivenAudio)
157 {
158 _irqDrivenAudio = irqDrivenAudio;
159 reset();
160 for(;;)
161 {
162 if(execute()) break;
163 #ifndef UNSAFE_OPTIMIZATIONS
164 if(_stats.instructions > 500000) // way more than would otherwise be possible
165 throw runtime_error("instructions > 500000");
166 #endif
167 }
168 #ifdef THUMB_CYCLE_COUNT
169 _totalCycles *= _armCyclesFactor;
170
171 // assuming 10% per scanline is spend for audio updates
172 // (equals 5 cycles 6507 code + ~130-155 cycles ARM code)
173 if(_irqDrivenAudio)
174 _totalCycles *= 1.10;
175
176 //_totalCycles = 127148; // VB during Turbo start sequence
177 cycles = _totalCycles / timing_factor;
178 #else
179 cycles = 0;
180 #endif
181 #if defined(THUMB_DISS) || defined(THUMB_DBUG)
182 dump_counters();
183 cout << statusMsg.str() << endl;
184 return statusMsg.str();
185 #else
186 return "";
187 #endif
188 }
189
190 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
setConsoleTiming(ConsoleTiming timing)191 void Thumbulator::setConsoleTiming(ConsoleTiming timing)
192 {
193 // this sets how many ticks of the Harmony/Melody clock
194 // will occur per tick of the 6507 clock
195 constexpr double NTSC = 1.19318166666667; // NTSC 6507 clock rate
196 constexpr double PAL = 1.182298; // PAL 6507 clock rate
197 constexpr double SECAM = 1.187500; // SECAM 6507 clock rate
198
199 _consoleTiming = timing;
200 switch(timing)
201 {
202 case ConsoleTiming::ntsc: timing_factor = _MHz / NTSC; break;
203 case ConsoleTiming::pal: timing_factor = _MHz / PAL; break;
204 case ConsoleTiming::secam: timing_factor = _MHz / SECAM; break;
205 default: break; // satisfy compiler
206 }
207 }
208
209 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
updateTimer(uInt32 cycles)210 void Thumbulator::updateTimer(uInt32 cycles)
211 {
212 #ifdef TIMER_0
213 if(T0TCR & 1) // bit 0 controls timer on/off
214 {
215 T0TC += static_cast<uInt32>(cycles * timing_factor);
216 tim0Total = 0;
217 }
218 #endif
219 if(T1TCR & 1) // bit 0 controls timer on/off
220 {
221 T1TC += static_cast<uInt32>(cycles * timing_factor);
222 tim1Total = 0;
223 }
224 }
225
226 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
run(uInt32 & cycles,bool irqDrivenAudio)227 string Thumbulator::run(uInt32& cycles, bool irqDrivenAudio)
228 {
229 updateTimer(cycles);
230 return doRun(cycles, irqDrivenAudio);
231 }
232
233 #ifndef UNSAFE_OPTIMIZATIONS
234 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fatalError(const char * opcode,uInt32 v1,const char * msg)235 inline int Thumbulator::fatalError(const char* opcode, uInt32 v1, const char* msg)
236 {
237 statusMsg << "Thumb ARM emulation fatal error: " << endl
238 << opcode << "(" << Base::HEX8 << v1 << "), " << msg << endl;
239 dump_regs();
240 if(trapOnFatal)
241 throw runtime_error(statusMsg.str());
242 return 0;
243 }
244
245 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fatalError(const char * opcode,uInt32 v1,uInt32 v2,const char * msg)246 inline int Thumbulator::fatalError(const char* opcode, uInt32 v1, uInt32 v2,
247 const char* msg)
248 {
249 statusMsg << "Thumb ARM emulation fatal error: " << endl
250 << opcode << "(" << Base::HEX8 << v1 << "," << v2 << "), " << msg << endl;
251 dump_regs();
252 if(trapOnFatal)
253 throw runtime_error(statusMsg.str());
254 return 0;
255 }
256
257 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
dump_counters()258 void Thumbulator::dump_counters()
259 {
260 cout << endl << endl
261 << "instructions " << _stats.instructions << endl;
262 #ifdef THUMB_STATS
263 cout << "reads " << _stats.reads << endl
264 << "writes " << _stats.writes << endl
265 << "memcycles " << (_stats.instructions + _stats.reads + _stats.writes) << endl;
266 #endif
267 }
268
269 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
dump_regs()270 void Thumbulator::dump_regs()
271 {
272 for (int cnt = 0; cnt <= 12; cnt++)
273 {
274 statusMsg << "R" << std::dec << std::setfill(' ') << std::setw(2) << std::left << cnt
275 << "= " << Base::HEX8 << reg_norm[cnt];
276 if((cnt + 1) % 4 == 0)
277 statusMsg << endl;
278 else
279 statusMsg << " ";
280 }
281 statusMsg << endl
282 << "SP = " << Base::HEX8 << reg_norm[13] << " "
283 << "LR = " << Base::HEX8 << reg_norm[14] << " "
284 << "PC = " << Base::HEX8 << reg_norm[15] << endl;
285 }
286 #endif
287
288 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fetch16(uInt32 addr)289 uInt32 Thumbulator::fetch16(uInt32 addr)
290 {
291 #ifndef UNSAFE_OPTIMIZATIONS
292 uInt32 data;
293
294 #ifdef THUMB_CYCLE_COUNT
295 _pipeIdx = (_pipeIdx+1) % 3;
296
297 #ifdef MERGE_I_S
298 if(_lastCycleType[2] == CycleType::I)
299 //if(_lastCycleType[_pipeIdx] == CycleType::I)
300 --_totalCycles;
301 #endif
302
303 if(_prefetchCycleType[_pipeIdx] == CycleType::S)
304 {
305 //#ifdef MERGE_I_S
306 // //if(_lastCycleType[2] == CycleType::I)
307 // if(_lastCycleType[_pipeIdx] == CycleType::I)
308 // {
309 // --_totalCycles;
310 // INC_S_CYCLES(addr, AccessType::prefetch); // N?
311 // }
312 // else
313 //#endif
314 INC_S_CYCLES(addr, AccessType::prefetch);
315 //INC_S_CYCLES(addr, _prefetchAccessType[_pipeIdx]);
316 }
317 else
318 {
319 INC_N_CYCLES(addr, AccessType::prefetch); // or ::data ?
320 //INC_N_CYCLES(addr, _prefetchAccessType[_pipeIdx]);
321 }
322 _prefetchCycleType[_pipeIdx] = CycleType::S; // default
323 //_prefetchAccessType[_pipeIdx] = AccessType::prefetch; // default
324 #endif
325
326 switch(addr & 0xF0000000)
327 {
328 case 0x00000000: //ROM
329 addr &= ROMADDMASK;
330 if(addr < 0x50)
331 fatalError("fetch16", addr, "abort");
332 addr >>= 1;
333 data = CONV_RAMROM(rom[addr]);
334 DO_DBUG(statusMsg << "fetch16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl);
335 return data;
336
337 case 0x40000000: //RAM
338 addr &= RAMADDMASK;
339 addr >>= 1;
340 data = CONV_RAMROM(ram[addr]);
341 DO_DBUG(statusMsg << "fetch16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl);
342 return data;
343 }
344 return fatalError("fetch16", addr, "abort");
345 #else
346 addr &= ROMADDMASK;
347 addr >>= 1;
348 return CONV_RAMROM(rom[addr]);
349 #endif
350 }
351
352 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
write16(uInt32 addr,uInt32 data)353 void Thumbulator::write16(uInt32 addr, uInt32 data)
354 {
355 #ifndef UNSAFE_OPTIMIZATIONS
356 if((addr > 0x40007fff) && (addr < 0x50000000))
357 fatalError("write16", addr, "abort - out of range");
358
359 if (isProtected(addr)) fatalError("write16", addr, "to driver area");
360
361 if(addr & 1)
362 fatalError("write16", addr, "abort - misaligned");
363 #endif
364 #ifdef THUMB_STATS
365 ++_stats.writes;
366 #endif
367
368 DO_DBUG(statusMsg << "write16(" << Base::HEX8 << addr << "," << Base::HEX8 << data << ")" << endl);
369
370 switch(addr & 0xF0000000)
371 {
372 case 0x40000000: //RAM
373 addr &= RAMADDMASK;
374 addr >>= 1;
375 ram[addr] = CONV_DATA(data);
376 return;
377
378 #ifndef UNSAFE_OPTIMIZATIONS
379 case 0xE0000000: //MAMCR
380 #else
381 default:
382 #endif
383 if(addr == 0xE01FC000)
384 {
385 DO_DBUG(statusMsg << "write16(" << Base::HEX8 << "MAMCR" << "," << Base::HEX8 << data << ") *" << endl);
386 if(!_lockMamcr)
387 mamcr = static_cast<MamModeType>(data);
388 return;
389 }
390 }
391 #ifndef UNSAFE_OPTIMIZATIONS
392 fatalError("write16", addr, data, "abort");
393 #endif
394 }
395
396 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
write32(uInt32 addr,uInt32 data)397 void Thumbulator::write32(uInt32 addr, uInt32 data)
398 {
399 #ifndef UNSAFE_OPTIMIZATIONS
400 if(addr & 3)
401 fatalError("write32", addr, "abort - misaligned");
402
403 if (isProtected(addr)) fatalError("write32", addr, "to driver area");
404 #endif
405 DO_DBUG(statusMsg << "write32(" << Base::HEX8 << addr << "," << Base::HEX8 << data << ")" << endl);
406
407 switch(addr & 0xF0000000)
408 {
409 #ifndef UNSAFE_OPTIMIZATIONS
410 case 0xF0000000: //halt
411 dump_counters();
412 throw runtime_error("HALT");
413 #endif
414
415 case 0xE0000000: //periph
416 switch(addr)
417 {
418 #ifndef UNSAFE_OPTIMIZATIONS
419 case 0xE0000000:
420 DO_DISS(statusMsg << "uart: [" << char(data&0xFF) << "]" << endl);
421 break;
422 #endif
423 #ifdef TIMER_0
424 case 0xE0004004: // T0TCR - Timer 0 Control Register
425 #ifdef THUMB_CYCLE_COUNT
426 if((T0TCR ^ data) & 1)
427 {
428 // timer changed counter state
429 if(data & 1)
430 // timer switched to counting
431 tim0Start = _totalCycles;
432 else
433 // timer switched to disabled
434 tim0Total += _totalCycles - tim0Start;
435 }
436 #endif
437 T0TCR = data;
438 break;
439
440 case 0xE0004008: // T0TC - Timer 0 Counter
441 #ifdef THUMB_CYCLE_COUNT
442 tim0Start = _totalCycles;
443 tim0Total = data / _armCyclesFactor;
444 #endif
445 T0TC = data;
446 break;
447 #endif
448 case 0xE0008004: // T1TCR - Timer 1 Control Register
449 #ifdef THUMB_CYCLE_COUNT
450 if((T1TCR ^ data) & 1)
451 {
452 // timer changed counter state
453 if(data & 1)
454 // timer switched to counting
455 tim1Start = _totalCycles;
456 else
457 // timer switched to disabled
458 tim1Total += _totalCycles - tim1Start;
459 }
460 #endif
461 T1TCR = data;
462 break;
463
464 case 0xE0008008: // T1TC - Timer 1 Counter
465 #ifdef THUMB_CYCLE_COUNT
466 tim1Start = _totalCycles;
467 tim1Total = data / _armCyclesFactor;
468 #endif
469 T1TC = data;
470 break;
471
472 case 0xE000E010:
473 {
474 uInt32 old = systick_ctrl;
475 systick_ctrl = data & 0x00010007;
476 if(((old & 1) == 0) && (systick_ctrl & 1))
477 {
478 // timer started, load count
479 systick_count = systick_reload;
480 }
481 break;
482 }
483
484 case 0xE000E014:
485 systick_reload = data & 0x00FFFFFF;
486 break;
487
488 case 0xE000E018:
489 systick_count = data & 0x00FFFFFF;
490 break;
491
492 case 0xE000E01C:
493 systick_calibrate = data & 0x00FFFFFF;
494 break;
495
496 #ifdef THUMB_CYCLE_COUNT
497 case 0xE01FC000: //MAMCR
498 DO_DBUG(statusMsg << "write32(" << Base::HEX8 << "MAMCR" << ","
499 << Base::HEX8 << data << ") *" << endl);
500 if(!_lockMamcr)
501 mamcr = static_cast<MamModeType>(data);
502 break;
503 #endif
504
505 default:
506 break;
507 }
508 return;
509
510 case 0xD0000000: //debug
511 #ifndef UNSAFE_OPTIMIZATIONS
512 switch(addr & 0xFF)
513 {
514 case 0x00:
515 statusMsg << "[" << Base::HEX8 << read_register(14) << "]["
516 << addr << "] " << data << endl;
517 return;
518
519 case 0x10:
520 statusMsg << Base::HEX8 << data << endl;
521 return;
522
523 case 0x20:
524 statusMsg << Base::HEX8 << data << endl;
525 return;
526
527 default:
528 break;
529 }
530 #endif
531 return;
532
533 #ifndef UNSAFE_OPTIMIZATIONS
534 case 0x40000000: //RAM
535 #else
536 default:
537 #endif
538 write16(addr+0, (data >> 0) & 0xFFFF);
539 write16(addr+2, (data >> 16) & 0xFFFF);
540 return;
541 }
542 #ifndef UNSAFE_OPTIMIZATIONS
543 fatalError("write32", addr, data, "abort");
544 #endif
545 }
546
547 #ifndef UNSAFE_OPTIMIZATIONS
548 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
isProtected(uInt32 addr)549 bool Thumbulator::isProtected(uInt32 addr)
550 {
551 if (addr < 0x40000000) return false;
552 addr -= 0x40000000;
553
554 switch (configuration) {
555 case ConfigureFor::DPCplus:
556 return (addr < 0x0c00) && (addr > 0x0028);
557
558 case ConfigureFor::CDF:
559 return (addr < 0x0800) && (addr > 0x0028) && !((addr >= 0x06e0) && (addr < (0x0e60 + 284)));
560
561 case ConfigureFor::CDF1:
562 return (addr < 0x0800) && (addr > 0x0028) && !((addr >= 0x00a0) && (addr < (0x00a0 + 284)));
563
564 case ConfigureFor::CDFJ:
565 case ConfigureFor::CDFJplus:
566 return (addr < 0x0800) && (addr > 0x0028) && !((addr >= 0x0098) && (addr < (0x0098 + 292)));
567
568 case ConfigureFor::BUS:
569 return (addr < 0x06d8) && (addr > 0x0028);
570 }
571
572 return false;
573 }
574 #endif
575
576 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
read16(uInt32 addr)577 uInt32 Thumbulator::read16(uInt32 addr)
578 {
579 uInt32 data;
580 #ifndef UNSAFE_OPTIMIZATIONS
581 if((addr > 0x40007fff) && (addr < 0x50000000))
582 fatalError("read16", addr, "abort - out of range");
583 else if((addr > 0x0007ffff) && (addr < 0x10000000))
584 fatalError("read16", addr, "abort - out of range");
585 if(addr & 1)
586 fatalError("read16", addr, "abort - misaligned");
587 #endif
588 #ifdef THUMB_STATS
589 ++_stats.reads;
590 #endif
591
592 switch(addr & 0xF0000000)
593 {
594 case 0x00000000: //ROM
595 addr &= ROMADDMASK;
596 addr >>= 1;
597 data = CONV_RAMROM(rom[addr]);
598 DO_DBUG(statusMsg << "read16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl);
599 return data;
600
601 case 0x40000000: //RAM
602 addr &= RAMADDMASK;
603 addr >>= 1;
604 data = CONV_RAMROM(ram[addr]);
605 DO_DBUG(statusMsg << "read16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl);
606 return data;
607
608 case 0xe0000000: //peripherals
609 #ifdef THUMB_CYCLE_COUNT
610 if(addr == 0xE01FC000) //MAMCR
611 #else
612 default:
613 #endif
614 {
615 DO_DBUG(statusMsg << "read32(" << "MAMCR" << addr << ")=" << mamcr << " *");
616 data = static_cast<uInt32>(mamcr);
617 return data;
618 }
619 }
620 #ifndef UNSAFE_OPTIMIZATIONS
621 return fatalError("read16", addr, "abort");
622 #endif
623 }
624
625 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
read32(uInt32 addr)626 uInt32 Thumbulator::read32(uInt32 addr)
627 {
628 #ifndef UNSAFE_OPTIMIZATIONS
629 if(addr & 3)
630 fatalError("read32", addr, "abort - misaligned");
631 #endif
632
633 uInt32 data;
634 switch(addr & 0xF0000000)
635 {
636 case 0x00000000: //ROM
637 case 0x40000000: //RAM
638 data = read16(addr+0);
639 data |= (uInt32(read16(addr+2))) << 16;
640 DO_DBUG(statusMsg << "read32(" << Base::HEX8 << addr << ")=" << Base::HEX8 << data << endl);
641 return data;
642
643 #ifndef UNSAFE_OPTIMIZATIONS
644 case 0xE0000000:
645 #else
646 default:
647 #endif
648 {
649 switch(addr)
650 {
651 #ifdef THUMB_CYCLE_COUNT
652 case 0xE01FC000: //MAMCR
653 DO_DBUG(statusMsg << "read32(" << "MAMCR" << addr << ")=" << mamcr << " *");
654 data = static_cast<uInt32>(mamcr);
655 return data;
656 #endif
657
658 #ifdef TIMER_0
659 case 0xE0004004: // T0TCR - Timer 0 Control Register
660 data = T0TCR;
661 return data;
662
663 case 0xE0004008: // T0TC - Timer 0 Counter
664 #ifdef THUMB_CYCLE_COUNT
665 if(T0TCR & 1)
666 // timer is counting
667 data = T0TC + (tim0Total + (_totalCycles - tim0Start)) * _armCyclesFactor;
668 else
669 // timer is disabled
670 data = T0TC + tim0Total * _armCyclesFactor;
671 #else
672 data = T0TC;
673 #endif
674 break;
675 #endif
676 case 0xE0008004: // T1TCR - Timer 1 Control Register
677 data = T1TCR;
678 return data;
679
680 case 0xE0008008: // T1TC - Timer 1 Counter
681 #ifdef THUMB_CYCLE_COUNT
682 if(T1TCR & 1)
683 // timer is counting
684 data = T1TC + (tim1Total + (_totalCycles - tim1Start)) * _armCyclesFactor;
685 else
686 // timer is disabled
687 data = T1TC + tim1Total * _armCyclesFactor;
688 #else
689 data = T1TC;
690 #endif
691 return data;
692
693 case 0xE000E010:
694 data = systick_ctrl;
695 systick_ctrl &= (~0x00010000);
696 return data;
697
698 case 0xE000E014:
699 data = systick_reload;
700 return data;
701
702 case 0xE000E018:
703 data = systick_count;
704 return data;
705
706 #ifndef UNSAFE_OPTIMIZATIONS
707 case 0xE000E01C:
708 #else
709 default:
710 #endif
711 data = systick_calibrate;
712 return data;
713 }
714 }
715 }
716 #ifndef UNSAFE_OPTIMIZATIONS
717 return fatalError("read32", addr, "abort");
718 #endif
719 }
720
721 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
read_register(uInt32 reg)722 uInt32 Thumbulator::read_register(uInt32 reg)
723 {
724 reg &= 0xF;
725
726 uInt32 data = reg_norm[reg];
727 DO_DBUG(statusMsg << "read_register(" << dec << reg << ")=" << Base::HEX8 << data << endl);
728 #ifndef UNSAFE_OPTIMIZATIONS
729 if(reg == 15)
730 {
731 if(data & 1)
732 {
733 DO_DBUG(statusMsg << "pc has lsbit set 0x" << Base::HEX8 << data << endl);
734 }
735 data &= ~1;
736 }
737 #endif
738 return data;
739 }
740
741 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
write_register(uInt32 reg,uInt32 data,bool isFlowBreak)742 void Thumbulator::write_register(uInt32 reg, uInt32 data, bool isFlowBreak)
743 {
744 reg &= 0xF;
745
746 DO_DBUG(statusMsg << "write_register(" << dec << reg << "," << Base::HEX8 << data << ")" << endl);
747 //#ifndef UNSAFE_OPTIMIZATIONS // this fails when combined with read_register UNSAFE_OPTIMIZATIONS
748 if(reg == 15)
749 {
750 data &= ~1;
751 if(isFlowBreak)
752 {
753 #ifdef THUMB_STATS
754 ++_stats.taken;
755 #endif
756 // dummy fetch + fill the pipeline
757 //INC_N_CYCLES(reg_norm[15] - 2, AccessType::prefetch);
758 //INC_S_CYCLES(data - 2, AccessType::branch);
759 INC_N_CYCLES(reg_norm[15] + 4, AccessType::prefetch);
760 INC_S_CYCLES(data, AccessType::branch);
761 }
762 }
763 //#endif
764 reg_norm[reg] = data;
765 }
766
767 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
do_zflag(uInt32 x)768 void Thumbulator::do_zflag(uInt32 x)
769 {
770 if(x == 0) cpsr |= CPSR_Z; else cpsr &= ~CPSR_Z;
771 }
772
773 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
do_nflag(uInt32 x)774 void Thumbulator::do_nflag(uInt32 x)
775 {
776 if(x & 0x80000000) cpsr |= CPSR_N; else cpsr &= ~CPSR_N;
777 }
778
779 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
do_cflag(uInt32 a,uInt32 b,uInt32 c)780 void Thumbulator::do_cflag(uInt32 a, uInt32 b, uInt32 c)
781 {
782 uInt32 rc;
783
784 rc = (a & 0x7FFFFFFF) + (b & 0x7FFFFFFF) + c; //carry in
785 rc = (rc >> 31) + (a >> 31) + (b >> 31); //carry out
786 if(rc & 2)
787 cpsr |= CPSR_C;
788 else
789 cpsr &= ~CPSR_C;
790 }
791
792 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
do_vflag(uInt32 a,uInt32 b,uInt32 c)793 void Thumbulator::do_vflag(uInt32 a, uInt32 b, uInt32 c)
794 {
795 uInt32 rc, rd;
796
797 rc = (a & 0x7FFFFFFF) + (b & 0x7FFFFFFF) + c; //carry in
798 rc >>= 31; //carry in in lsbit
799 rd = (rc & 1) + ((a >> 31) & 1) + ((b >> 31) & 1); //carry out
800 rd >>= 1; //carry out in lsbit
801 rc = (rc^rd) & 1; //if carry in != carry out then signed overflow
802 if(rc)
803 cpsr |= CPSR_V;
804 else
805 cpsr &= ~CPSR_V;
806 }
807
808 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
do_cflag_bit(uInt32 x)809 void Thumbulator::do_cflag_bit(uInt32 x)
810 {
811 if(x) cpsr |= CPSR_C; else cpsr &= ~CPSR_C;
812 }
813
814 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
do_vflag_bit(uInt32 x)815 void Thumbulator::do_vflag_bit(uInt32 x)
816 {
817 if(x) cpsr |= CPSR_V; else cpsr &= ~CPSR_V;
818 }
819
820 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
decodeInstructionWord(uint16_t inst)821 Thumbulator::Op Thumbulator::decodeInstructionWord(uint16_t inst) {
822 //ADC add with carry
823 if((inst & 0xFFC0) == 0x4140) return Op::adc;
824
825 //ADD(1) small immediate two registers
826 if((inst & 0xFE00) == 0x1C00 && (inst >> 6) & 0x7) return Op::add1;
827
828 //ADD(2) big immediate one register
829 if((inst & 0xF800) == 0x3000) return Op::add2;
830
831 //ADD(3) three registers
832 if((inst & 0xFE00) == 0x1800) return Op::add3;
833
834 //ADD(4) two registers one or both high no flags
835 if((inst & 0xFF00) == 0x4400) return Op::add4;
836
837 //ADD(5) rd = pc plus immediate
838 if((inst & 0xF800) == 0xA000) return Op::add5;
839
840 //ADD(6) rd = sp plus immediate
841 if((inst & 0xF800) == 0xA800) return Op::add6;
842
843 //ADD(7) sp plus immediate
844 if((inst & 0xFF80) == 0xB000) return Op::add7;
845
846 //AND
847 if((inst & 0xFFC0) == 0x4000) return Op::and_;
848
849 //ASR(1) two register immediate
850 if((inst & 0xF800) == 0x1000) return Op::asr1;
851
852 //ASR(2) two register
853 if((inst & 0xFFC0) == 0x4100) return Op::asr2;
854
855 //B(1) conditional branch
856 if((inst & 0xF000) == 0xD000) return Op::b1;
857
858 //B(2) unconditional branch
859 if((inst & 0xF800) == 0xE000) return Op::b2;
860
861 //BIC
862 if((inst & 0xFFC0) == 0x4380) return Op::bic;
863
864 //BKPT
865 if((inst & 0xFF00) == 0xBE00) return Op::bkpt;
866
867 //BL/BLX(1)
868 if((inst & 0xE000) == 0xE000) return Op::blx1;
869
870 //BLX(2)
871 if((inst & 0xFF87) == 0x4780) return Op::blx2;
872
873 //BX
874 if((inst & 0xFF87) == 0x4700) return Op::bx;
875
876 //CMN
877 if((inst & 0xFFC0) == 0x42C0) return Op::cmn;
878
879 //CMP(1) compare immediate
880 if((inst & 0xF800) == 0x2800) return Op::cmp1;
881
882 //CMP(2) compare register
883 if((inst & 0xFFC0) == 0x4280) return Op::cmp2;
884
885 //CMP(3) compare high register
886 if((inst & 0xFF00) == 0x4500) return Op::cmp3;
887
888 //CPS
889 if((inst & 0xFFE8) == 0xB660) return Op::cps;
890
891 //CPY copy high register
892 if((inst & 0xFFC0) == 0x4600) return Op::cpy;
893
894 //EOR
895 if((inst & 0xFFC0) == 0x4040) return Op::eor;
896
897 //LDMIA
898 if((inst & 0xF800) == 0xC800) return Op::ldmia;
899
900 //LDR(1) two register immediate
901 if((inst & 0xF800) == 0x6800) return Op::ldr1;
902
903 //LDR(2) three register
904 if((inst & 0xFE00) == 0x5800) return Op::ldr2;
905
906 //LDR(3)
907 if((inst & 0xF800) == 0x4800) return Op::ldr3;
908
909 //LDR(4)
910 if((inst & 0xF800) == 0x9800) return Op::ldr4;
911
912 //LDRB(1)
913 if((inst & 0xF800) == 0x7800) return Op::ldrb1;
914
915 //LDRB(2)
916 if((inst & 0xFE00) == 0x5C00) return Op::ldrb2;
917
918 //LDRH(1)
919 if((inst & 0xF800) == 0x8800) return Op::ldrh1;
920
921 //LDRH(2)
922 if((inst & 0xFE00) == 0x5A00) return Op::ldrh2;
923
924 //LDRSB
925 if((inst & 0xFE00) == 0x5600) return Op::ldrsb;
926
927 //LDRSH
928 if((inst & 0xFE00) == 0x5E00) return Op::ldrsh;
929
930 //LSL(1)
931 if((inst & 0xF800) == 0x0000) return Op::lsl1;
932
933 //LSL(2) two register
934 if((inst & 0xFFC0) == 0x4080) return Op::lsl2;
935
936 //LSR(1) two register immediate
937 if((inst & 0xF800) == 0x0800) return Op::lsr1;
938
939 //LSR(2) two register
940 if((inst & 0xFFC0) == 0x40C0) return Op::lsr2;
941
942 //MOV(1) immediate
943 if((inst & 0xF800) == 0x2000) return Op::mov1;
944
945 //MOV(2) two low registers
946 if((inst & 0xFFC0) == 0x1C00) return Op::mov2;
947
948 //MOV(3)
949 if((inst & 0xFF00) == 0x4600) return Op::mov3;
950
951 //MUL
952 if((inst & 0xFFC0) == 0x4340) return Op::mul;
953
954 //MVN
955 if((inst & 0xFFC0) == 0x43C0) return Op::mvn;
956
957 //NEG
958 if((inst & 0xFFC0) == 0x4240) return Op::neg;
959
960 //ORR
961 if((inst & 0xFFC0) == 0x4300) return Op::orr;
962
963 //POP
964 if((inst & 0xFE00) == 0xBC00) return Op::pop;
965
966 //PUSH
967 if((inst & 0xFE00) == 0xB400) return Op::push;
968
969 //REV
970 if((inst & 0xFFC0) == 0xBA00) return Op::rev;
971
972 //REV16
973 if((inst & 0xFFC0) == 0xBA40) return Op::rev16;
974
975 //REVSH
976 if((inst & 0xFFC0) == 0xBAC0) return Op::revsh;
977
978 //ROR
979 if((inst & 0xFFC0) == 0x41C0) return Op::ror;
980
981 //SBC
982 if((inst & 0xFFC0) == 0x4180) return Op::sbc;
983
984 //SETEND
985 if((inst & 0xFFF7) == 0xB650) return Op::setend;
986
987 //STMIA
988 if((inst & 0xF800) == 0xC000) return Op::stmia;
989
990 //STR(1)
991 if((inst & 0xF800) == 0x6000) return Op::str1;
992
993 //STR(2)
994 if((inst & 0xFE00) == 0x5000) return Op::str2;
995
996 //STR(3)
997 if((inst & 0xF800) == 0x9000) return Op::str3;
998
999 //STRB(1)
1000 if((inst & 0xF800) == 0x7000) return Op::strb1;
1001
1002 //STRB(2)
1003 if((inst & 0xFE00) == 0x5400) return Op::strb2;
1004
1005 //STRH(1)
1006 if((inst & 0xF800) == 0x8000) return Op::strh1;
1007
1008 //STRH(2)
1009 if((inst & 0xFE00) == 0x5200) return Op::strh2;
1010
1011 //SUB(1)
1012 if((inst & 0xFE00) == 0x1E00) return Op::sub1;
1013
1014 //SUB(2)
1015 if((inst & 0xF800) == 0x3800) return Op::sub2;
1016
1017 //SUB(3)
1018 if((inst & 0xFE00) == 0x1A00) return Op::sub3;
1019
1020 //SUB(4)
1021 if((inst & 0xFF80) == 0xB080) return Op::sub4;
1022
1023 //SWI SoftWare Interupt
1024 if((inst & 0xFF00) == 0xDF00) return Op::swi;
1025
1026 //SXTB
1027 if((inst & 0xFFC0) == 0xB240) return Op::sxtb;
1028
1029 //SXTH
1030 if((inst & 0xFFC0) == 0xB200) return Op::sxth;
1031
1032 //TST
1033 if((inst & 0xFFC0) == 0x4200) return Op::tst;
1034
1035 //UXTB
1036 if((inst & 0xFFC0) == 0xB2C0) return Op::uxtb;
1037
1038 //UXTH Zero extend Halfword
1039 if((inst & 0xFFC0) == 0xB280) return Op::uxth;
1040
1041 return Op::invalid;
1042 }
1043
1044 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
execute()1045 int Thumbulator::execute()
1046 {
1047 uInt32 pc, sp, inst, ra, rb, rc, rm, rd, rn, rs, op;
1048
1049 pc = read_register(15);
1050
1051 uInt32 instructionPtr = pc - 2;
1052 inst = fetch16(instructionPtr);
1053
1054 pc += 2;
1055 write_register(15, pc, false);
1056 DO_DISS(statusMsg << Base::HEX8 << (pc-5) << ": " << Base::HEX4 << inst << " ");
1057
1058 #ifndef UNSAFE_OPTIMIZATIONS
1059 ++_stats.instructions;
1060 #endif
1061
1062 Op decodedOp;
1063 #ifndef UNSAFE_OPTIMIZATIONS
1064 if ((instructionPtr & 0xF0000000) == 0 && instructionPtr < romSize)
1065 decodedOp = decodedRom[instructionPtr >> 1];
1066 else
1067 decodedOp = decodeInstructionWord(inst);
1068 #else
1069 decodedOp = decodedRom[(instructionPtr & ROMADDMASK) >> 1];
1070 #endif
1071
1072 #ifdef COUNT_OPS
1073 ++opCount[int(decodedOp)];
1074 #endif
1075 switch (decodedOp) {
1076 //ADC
1077 case Op::adc: {
1078 rd = (inst >> 0) & 0x07;
1079 rm = (inst >> 3) & 0x07;
1080 DO_DISS(statusMsg << "adc r" << dec << rd << ",r" << dec << rm << endl);
1081 ra = read_register(rd);
1082 rb = read_register(rm);
1083 rc = ra + rb;
1084 if(cpsr & CPSR_C)
1085 ++rc;
1086 write_register(rd, rc);
1087 do_nflag(rc);
1088 do_zflag(rc);
1089 if(cpsr & CPSR_C) { do_cflag(ra, rb, 1); do_vflag(ra, rb, 1); }
1090 else { do_cflag(ra, rb, 0); do_vflag(ra, rb, 0); }
1091 return 0;
1092 }
1093
1094 //ADD(1) small immediate two registers
1095 case Op::add1: {
1096 rd = (inst >> 0) & 0x7;
1097 rn = (inst >> 3) & 0x7;
1098 rb = (inst >> 6) & 0x7;
1099 if(rb)
1100 {
1101 DO_DISS(statusMsg << "adds r" << dec << rd << ",r" << dec << rn << ","
1102 << "#0x" << Base::HEX2 << rb << endl);
1103 ra = read_register(rn);
1104 rc = ra + rb;
1105 //fprintf(stderr,"0x%08X = 0x%08X + 0x%08X\n",rc,ra,rb);
1106 write_register(rd, rc);
1107 do_nflag(rc);
1108 do_zflag(rc);
1109 do_cflag(ra, rb, 0);
1110 do_vflag(ra, rb, 0);
1111 return 0;
1112 }
1113 else
1114 {
1115 //this is a mov
1116 }
1117 break;
1118 }
1119
1120 //ADD(2) big immediate one register
1121 case Op::add2: {
1122 rb = (inst >> 0) & 0xFF;
1123 rd = (inst >> 8) & 0x7;
1124 DO_DISS(statusMsg << "adds r" << dec << rd << ",#0x" << Base::HEX2 << rb << endl);
1125 ra = read_register(rd);
1126 rc = ra + rb;
1127 write_register(rd, rc);
1128 do_nflag(rc);
1129 do_zflag(rc);
1130 do_cflag(ra, rb, 0);
1131 do_vflag(ra, rb, 0);
1132 return 0;
1133 }
1134
1135 //ADD(3) three registers
1136 case Op::add3: {
1137 rd = (inst >> 0) & 0x7;
1138 rn = (inst >> 3) & 0x7;
1139 rm = (inst >> 6) & 0x7;
1140 DO_DISS(statusMsg << "adds r" << dec << rd << ",r" << dec << rn << ",r" << rm << endl);
1141 ra = read_register(rn);
1142 rb = read_register(rm);
1143 rc = ra + rb;
1144 write_register(rd, rc);
1145 do_nflag(rc);
1146 do_zflag(rc);
1147 do_cflag(ra, rb, 0);
1148 do_vflag(ra, rb, 0);
1149 return 0;
1150 }
1151
1152 //ADD(4) two registers one or both high no flags
1153 case Op::add4: {
1154 if((inst >> 6) & 3)
1155 {
1156 //UNPREDICTABLE
1157 }
1158 rd = (inst >> 0) & 0x7;
1159 rd |= (inst >> 4) & 0x8;
1160 rm = (inst >> 3) & 0xF;
1161 DO_DISS(statusMsg << "add r" << dec << rd << ",r" << dec << rm << endl);
1162 ra = read_register(rd);
1163 rb = read_register(rm);
1164 rc = ra + rb;
1165 if(rd == 15)
1166 {
1167 #ifndef UNSAFE_OPTIMIZATIONS
1168 if((rc & 1) == 0)
1169 fatalError("add pc", pc, rc, " produced an arm address");
1170 #endif
1171 //rc &= ~1; //write_register may do this as well
1172 rc += 2; //The program counter is special
1173 }
1174 //fprintf(stderr,"0x%08X = 0x%08X + 0x%08X\n",rc,ra,rb);
1175 write_register(rd, rc);
1176 return 0;
1177 }
1178
1179 //ADD(5) rd = pc plus immediate
1180 case Op::add5: {
1181 rb = (inst >> 0) & 0xFF;
1182 rd = (inst >> 8) & 0x7;
1183 rb <<= 2;
1184 DO_DISS(statusMsg << "add r" << dec << rd << ",PC,#0x" << Base::HEX2 << rb << endl);
1185 ra = read_register(15);
1186 rc = (ra & (~3U)) + rb;
1187 write_register(rd, rc);
1188 return 0;
1189 }
1190
1191 //ADD(6) rd = sp plus immediate
1192 case Op::add6: {
1193 rb = (inst >> 0) & 0xFF;
1194 rd = (inst >> 8) & 0x7;
1195 rb <<= 2;
1196 DO_DISS(statusMsg << "add r" << dec << rd << ",SP,#0x" << Base::HEX2 << rb << endl);
1197 ra = read_register(13);
1198 rc = ra + rb;
1199 write_register(rd, rc);
1200 return 0;
1201 }
1202
1203 //ADD(7) sp plus immediate
1204 case Op::add7: {
1205 rb = (inst >> 0) & 0x7F;
1206 rb <<= 2;
1207 DO_DISS(statusMsg << "add SP,#0x" << Base::HEX2 << rb << endl);
1208 ra = read_register(13);
1209 rc = ra + rb;
1210 write_register(13, rc);
1211 return 0;
1212 }
1213
1214 //AND
1215 case Op::and_: {
1216 rd = (inst >> 0) & 0x7;
1217 rm = (inst >> 3) & 0x7;
1218 DO_DISS(statusMsg << "ands r" << dec << rd << ",r" << dec << rm << endl);
1219 ra = read_register(rd);
1220 rb = read_register(rm);
1221 rc = ra & rb;
1222 write_register(rd, rc);
1223 do_nflag(rc);
1224 do_zflag(rc);
1225 return 0;
1226 }
1227
1228 //ASR(1) two register immediate
1229 case Op::asr1: {
1230 rd = (inst >> 0) & 0x07;
1231 rm = (inst >> 3) & 0x07;
1232 rb = (inst >> 6) & 0x1F;
1233 DO_DISS(statusMsg << "asrs r" << dec << rd << ",r" << dec << rm << ",#0x" << Base::HEX2 << rb << endl);
1234 rc = read_register(rm);
1235 if(rb == 0)
1236 {
1237 if(rc & 0x80000000)
1238 {
1239 do_cflag_bit(1);
1240 rc = ~0U;
1241 }
1242 else
1243 {
1244 do_cflag_bit(0);
1245 rc = 0;
1246 }
1247 }
1248 else
1249 {
1250 do_cflag_bit(rc & (1 << (rb-1)));
1251 ra = rc & 0x80000000;
1252 rc >>= rb;
1253 if(ra) //asr, sign is shifted in
1254 rc |= (~0U) << (32-rb);
1255 }
1256 write_register(rd, rc);
1257 do_nflag(rc);
1258 do_zflag(rc);
1259 INC_SHIFT_CYCLES;
1260 return 0;
1261 }
1262
1263 //ASR(2) two register
1264 case Op::asr2: {
1265 rd = (inst >> 0) & 0x07;
1266 rs = (inst >> 3) & 0x07;
1267 DO_DISS(statusMsg << "asrs r" << dec << rd << ",r" << dec << rs << endl);
1268 rc = read_register(rd);
1269 rb = read_register(rs);
1270 rb &= 0xFF;
1271 if(rb == 0)
1272 {
1273 }
1274 else if(rb < 32)
1275 {
1276 do_cflag_bit(rc & (1 << (rb-1)));
1277 ra = rc & 0x80000000;
1278 rc >>= rb;
1279 if(ra) //asr, sign is shifted in
1280 {
1281 rc |= (~0U) << (32-rb);
1282 }
1283 }
1284 else
1285 {
1286 if(rc & 0x80000000)
1287 {
1288 do_cflag_bit(1);
1289 rc = (~0U);
1290 }
1291 else
1292 {
1293 do_cflag_bit(0);
1294 rc = 0;
1295 }
1296 }
1297 write_register(rd, rc);
1298 do_nflag(rc);
1299 do_zflag(rc);
1300 INC_SHIFT_CYCLES;
1301 return 0;
1302 }
1303
1304 //B(1) conditional branch
1305 case Op::b1: {
1306 #ifdef THUMB_STATS
1307 ++_stats.branches;
1308 #endif
1309 rb = inst & 0xFF;
1310 if(rb & 0x80)
1311 rb |= (~0U) << 8;
1312 rb <<= 1;
1313 rb += pc;
1314 rb += 2;
1315
1316 op = (inst >> 8) & 0xF;
1317 switch(op)
1318 {
1319 case 0x0: //b eq z set
1320 DO_DISS(statusMsg << "beq 0x" << Base::HEX8 << (rb-3) << endl);
1321 if(cpsr & CPSR_Z)
1322 write_register(15, rb);
1323 return 0;
1324
1325 case 0x1: //b ne z clear
1326 DO_DISS(statusMsg << "bne 0x" << Base::HEX8 << (rb-3) << endl);
1327 if(!(cpsr & CPSR_Z))
1328 write_register(15, rb);
1329 return 0;
1330
1331 case 0x2: //b cs c set
1332 DO_DISS(statusMsg << "bcs 0x" << Base::HEX8 << (rb-3) << endl);
1333 if(cpsr & CPSR_C)
1334 write_register(15, rb);
1335 return 0;
1336
1337 case 0x3: //b cc c clear
1338 DO_DISS(statusMsg << "bcc 0x" << Base::HEX8 << (rb-3) << endl);
1339 if(!(cpsr & CPSR_C))
1340 write_register(15, rb);
1341 return 0;
1342
1343 case 0x4: //b mi n set
1344 DO_DISS(statusMsg << "bmi 0x" << Base::HEX8 << (rb-3) << endl);
1345 if(cpsr & CPSR_N)
1346 write_register(15, rb);
1347 return 0;
1348
1349 case 0x5: //b pl n clear
1350 DO_DISS(statusMsg << "bpl 0x" << Base::HEX8 << (rb-3) << endl);
1351 if(!(cpsr & CPSR_N))
1352 write_register(15, rb);
1353 return 0;
1354
1355 case 0x6: //b vs v set
1356 DO_DISS(statusMsg << "bvs 0x" << Base::HEX8 << (rb-3) << endl);
1357 if(cpsr & CPSR_V)
1358 write_register(15, rb);
1359 return 0;
1360
1361 case 0x7: //b vc v clear
1362 DO_DISS(statusMsg << "bvc 0x" << Base::HEX8 << (rb-3) << endl);
1363 if(!(cpsr & CPSR_V))
1364 write_register(15, rb);
1365 return 0;
1366
1367 case 0x8: //b hi c set z clear
1368 DO_DISS(statusMsg << "bhi 0x" << Base::HEX8 << (rb-3) << endl);
1369 if((cpsr & CPSR_C) && (!(cpsr & CPSR_Z)))
1370 write_register(15, rb);
1371 return 0;
1372
1373 case 0x9: //b ls c clear or z set
1374 DO_DISS(statusMsg << "bls 0x" << Base::HEX8 << (rb-3) << endl);
1375 if((cpsr & CPSR_Z) || (!(cpsr & CPSR_C)))
1376 write_register(15, rb);
1377 return 0;
1378
1379 case 0xA: //b ge N == V
1380 DO_DISS(statusMsg << "bge 0x" << Base::HEX8 << (rb-3) << endl);
1381 if(((cpsr & CPSR_N) && (cpsr & CPSR_V)) ||
1382 ((!(cpsr & CPSR_N)) && (!(cpsr & CPSR_V))))
1383 write_register(15, rb);
1384 return 0;
1385
1386 case 0xB: //b lt N != V
1387 DO_DISS(statusMsg << "blt 0x" << Base::HEX8 << (rb-3) << endl);
1388 if((!(cpsr & CPSR_N) && (cpsr & CPSR_V)) ||
1389 (((cpsr & CPSR_N)) && !(cpsr & CPSR_V)))
1390 write_register(15, rb);
1391 return 0;
1392
1393 case 0xC: //b gt Z==0 and N == V
1394 DO_DISS(statusMsg << "bgt 0x" << Base::HEX8 << (rb-3) << endl);
1395 if(!(cpsr & CPSR_Z))
1396 {
1397 if(((cpsr & CPSR_N) && (cpsr & CPSR_V)) ||
1398 ((!(cpsr & CPSR_N)) && (!(cpsr & CPSR_V))))
1399 write_register(15, rb);
1400 }
1401 return 0;
1402
1403 case 0xD: //b le Z==1 or N != V
1404 DO_DISS(statusMsg << "ble 0x" << Base::HEX8 << (rb-3) << endl);
1405 if((cpsr & CPSR_Z) ||
1406 (!(cpsr & CPSR_N) && (cpsr & CPSR_V)) ||
1407 (((cpsr & CPSR_N)) && !(cpsr & CPSR_V)))
1408 write_register(15, rb);
1409 return 0;
1410
1411 case 0xE:
1412 //undefined instruction
1413 break;
1414
1415 case 0xF:
1416 //swi
1417 break;
1418
1419 default:
1420 break;
1421 }
1422 break;
1423 }
1424
1425 //B(2) unconditional branch
1426 case Op::b2: {
1427 #ifdef THUMB_STATS
1428 ++_stats.branches;
1429 #endif
1430 rb = (inst >> 0) & 0x7FF;
1431 if(rb & (1 << 10))
1432 rb |= (~0U) << 11;
1433 rb <<= 1;
1434 rb += pc;
1435 rb += 2;
1436 DO_DISS(statusMsg << "B 0x" << Base::HEX8 << (rb-3) << endl);
1437 write_register(15, rb);
1438 return 0;
1439 }
1440
1441 //BIC
1442 case Op::bic: {
1443 rd = (inst >> 0) & 0x7;
1444 rm = (inst >> 3) & 0x7;
1445 DO_DISS(statusMsg << "bics r" << dec << rd << ",r" << dec << rm << endl);
1446 ra = read_register(rd);
1447 rb = read_register(rm);
1448 rc = ra & (~rb);
1449 write_register(rd, rc);
1450 do_nflag(rc);
1451 do_zflag(rc);
1452 return 0;
1453 }
1454
1455 #ifndef UNSAFE_OPTIMIZATIONS
1456 //BKPT
1457 case Op::bkpt: {
1458 rb = (inst >> 0) & 0xFF;
1459 statusMsg << "bkpt 0x" << Base::HEX2 << rb << endl;
1460 return 1;
1461 }
1462 #endif
1463
1464 //BL/BLX(1)
1465 case Op::blx1: {
1466 if((inst & 0x1800) == 0x1000) //H=b10
1467 {
1468 DO_DISS(statusMsg << endl);
1469 rb = inst & ((1 << 11) - 1);
1470 if(rb & 1<<10) rb |= (~((1 << 11) - 1)); //sign extend
1471 rb <<= 12;
1472 rb += pc;
1473 write_register(14, rb);
1474 return 0;
1475 }
1476 else if((inst & 0x1800) == 0x1800) //H=b11
1477 {
1478 //branch to thumb
1479 rb = read_register(14);
1480 rb += (inst & ((1 << 11) - 1)) << 1;
1481 rb += 2;
1482 DO_DISS(statusMsg << "bl 0x" << Base::HEX8 << (rb-3) << endl);
1483 write_register(14, (pc-2) | 1);
1484 write_register(15, rb);
1485 return 0;
1486 }
1487 else if((inst & 0x1800) == 0x0800) //H=b01
1488 {
1489 //fprintf(stderr,"cannot branch to arm 0x%08X 0x%04X\n",pc,inst);
1490 // fxq: this should exit the code without having to detect it
1491 // TJ: seems to be not used
1492 rb = read_register(14);
1493 rb += (inst & ((1 << 11) - 1)) << 1;
1494 rb &= 0xFFFFFFFC;
1495 rb += 2;
1496 DO_DISS(statusMsg << "bl 0x" << Base::HEX8 << (rb-3) << endl);
1497 write_register(14, (pc-2) | 1);
1498 write_register(15, rb);
1499 return 0;
1500 }
1501 break;
1502 }
1503
1504 //BLX(2)
1505 case Op::blx2: {
1506 rm = (inst >> 3) & 0xF;
1507 DO_DISS(statusMsg << "blx r" << dec << rm << endl);
1508 rc = read_register(rm);
1509 //fprintf(stderr,"blx r%u 0x%X 0x%X\n",rm,rc,pc);
1510 rc += 2;
1511 if(rc & 1)
1512 {
1513 write_register(14, (pc-2) | 1);
1514 //rc &= ~1;
1515 write_register(15, rc);
1516 return 0;
1517 }
1518 else
1519 {
1520 //fprintf(stderr,"cannot branch to arm 0x%08X 0x%04X\n",pc,inst);
1521 // fxq: this could serve as exit code
1522 return 1;
1523 }
1524 }
1525
1526 //BX
1527 case Op::bx: {
1528 rm = (inst >> 3) & 0xF;
1529 DO_DISS(statusMsg << "bx r" << dec << rm << endl);
1530 rc = read_register(rm);
1531 rc += 2;
1532 //fprintf(stderr,"bx r%u 0x%X 0x%X\n",rm,rc,pc);
1533 if(rc & 1)
1534 {
1535 // branch to odd address denotes 16 bit ARM code
1536 //rc &= ~1;
1537 write_register(15, rc);
1538 return 0;
1539 }
1540 else
1541 {
1542 // branch to even address denotes 32 bit ARM code, which the Thumbulator
1543 // class does not support. So capture relevant information and hand it
1544 // off to the Cartridge class for it to handle.
1545
1546 bool handled = false;
1547
1548 switch(configuration)
1549 {
1550 case ConfigureFor::BUS:
1551 // this subroutine interface is used in the BUS driver,
1552 // it starts at address 0x000006d8
1553 // _SetNote:
1554 // ldr r4, =NoteStore
1555 // bx r4 // bx instruction at 0x000006da
1556 // _ResetWave:
1557 // ldr r4, =ResetWaveStore
1558 // bx r4 // bx instruction at 0x000006de
1559 // _GetWavePtr:
1560 // ldr r4, =WavePtrFetch
1561 // bx r4 // bx instruction at 0x000006e2
1562 // _SetWaveSize:
1563 // ldr r4, =WaveSizeStore
1564 // bx r4 // bx instruction at 0x000006e6
1565
1566 // address to test for is + 4 due to pipelining
1567
1568 #define BUS_SetNote (0x000006da + 4)
1569 #define BUS_ResetWave (0x000006de + 4)
1570 #define BUS_GetWavePtr (0x000006e2 + 4)
1571 #define BUS_SetWaveSize (0x000006e6 + 4)
1572
1573 if (pc == BUS_SetNote)
1574 {
1575 myCartridge->thumbCallback(0, read_register(2), read_register(3));
1576 handled = true;
1577 }
1578 else if (pc == BUS_ResetWave)
1579 {
1580 myCartridge->thumbCallback(1, read_register(2), 0);
1581 handled = true;
1582 }
1583 else if (pc == BUS_GetWavePtr)
1584 {
1585 write_register(2, myCartridge->thumbCallback(2, read_register(2), 0));
1586 handled = true;
1587 }
1588 else if (pc == BUS_SetWaveSize)
1589 {
1590 myCartridge->thumbCallback(3, read_register(2), read_register(3));
1591 handled = true;
1592 }
1593 else if (pc == 0x0000083a)
1594 {
1595 // exiting Custom ARM code, returning to BUS Driver control
1596 }
1597 else
1598 {
1599 #if 0 // uncomment this for testing
1600 uInt32 r0 = read_register(0);
1601 uInt32 r1 = read_register(1);
1602 uInt32 r2 = read_register(2);
1603 uInt32 r3 = read_register(3);
1604 uInt32 r4 = read_register(4);
1605 #endif
1606 myCartridge->thumbCallback(255, 0, 0);
1607 }
1608
1609 break;
1610
1611 case ConfigureFor::CDF:
1612 // this subroutine interface is used in the CDF driver,
1613 // it starts at address 0x000006e0
1614 // _SetNote:
1615 // ldr r4, =NoteStore
1616 // bx r4 // bx instruction at 0x000006e2
1617 // _ResetWave:
1618 // ldr r4, =ResetWaveStore
1619 // bx r4 // bx instruction at 0x000006e6
1620 // _GetWavePtr:
1621 // ldr r4, =WavePtrFetch
1622 // bx r4 // bx instruction at 0x000006ea
1623 // _SetWaveSize:
1624 // ldr r4, =WaveSizeStore
1625 // bx r4 // bx instruction at 0x000006ee
1626
1627 // address to test for is + 4 due to pipelining
1628
1629 #define CDF_SetNote (0x000006e2 + 4)
1630 #define CDF_ResetWave (0x000006e6 + 4)
1631 #define CDF_GetWavePtr (0x000006ea + 4)
1632 #define CDF_SetWaveSize (0x000006ee + 4)
1633
1634 if (pc == CDF_SetNote)
1635 {
1636 myCartridge->thumbCallback(0, read_register(2), read_register(3));
1637 handled = true;
1638 }
1639 else if (pc == CDF_ResetWave)
1640 {
1641 myCartridge->thumbCallback(1, read_register(2), 0);
1642 handled = true;
1643 }
1644 else if (pc == CDF_GetWavePtr)
1645 {
1646 write_register(2, myCartridge->thumbCallback(2, read_register(2), 0));
1647 handled = true;
1648 }
1649 else if (pc == CDF_SetWaveSize)
1650 {
1651 myCartridge->thumbCallback(3, read_register(2), read_register(3));
1652 handled = true;
1653 }
1654 else if (pc == 0x0000083a)
1655 {
1656 // exiting Custom ARM code, returning to CDF Driver control
1657 }
1658 else
1659 {
1660 #if 0 // uncomment this for testing
1661 uInt32 r0 = read_register(0);
1662 uInt32 r1 = read_register(1);
1663 uInt32 r2 = read_register(2);
1664 uInt32 r3 = read_register(3);
1665 uInt32 r4 = read_register(4);
1666 #endif
1667 myCartridge->thumbCallback(255, 0, 0);
1668 }
1669
1670 break;
1671
1672 case ConfigureFor::CDF1:
1673 case ConfigureFor::CDFJ:
1674 case ConfigureFor::CDFJplus:
1675 // this subroutine interface is used in the CDF driver,
1676 // it starts at address 0x00000750
1677 // _SetNote:
1678 // ldr r4, =NoteStore
1679 // bx r4 // bx instruction at 0x000006e2
1680 // _ResetWave:
1681 // ldr r4, =ResetWaveStore
1682 // bx r4 // bx instruction at 0x000006e6
1683 // _GetWavePtr:
1684 // ldr r4, =WavePtrFetch
1685 // bx r4 // bx instruction at 0x000006ea
1686 // _SetWaveSize:
1687 // ldr r4, =WaveSizeStore
1688 // bx r4 // bx instruction at 0x000006ee
1689
1690 // address to test for is + 4 due to pipelining
1691
1692 #define CDF1_SetNote (0x00000752 + 4)
1693 #define CDF1_ResetWave (0x00000756 + 4)
1694 #define CDF1_GetWavePtr (0x0000075a + 4)
1695 #define CDF1_SetWaveSize (0x0000075e + 4)
1696
1697 if (pc == CDF1_SetNote)
1698 {
1699 myCartridge->thumbCallback(0, read_register(2), read_register(3));
1700 // approximated cycles
1701 INC_ARM_CYCLES(_flashCycles + 1); // this instruction
1702 INC_ARM_CYCLES(6); // ARM code NoteStore
1703 INC_ARM_CYCLES(2 + _flashCycles + 2); // ARM code ReturnC
1704 handled = true;
1705 }
1706 else if (pc == CDF1_ResetWave)
1707 {
1708 myCartridge->thumbCallback(1, read_register(2), 0);
1709 // approximated cycles
1710 INC_ARM_CYCLES(_flashCycles + 1); // this instruction
1711 INC_ARM_CYCLES(6 + _flashCycles + 2); // ARM code ResetWaveStore
1712 INC_ARM_CYCLES(2 + _flashCycles + 2); // ARM code ReturnC
1713 handled = true;
1714 }
1715 else if (pc == CDF1_GetWavePtr)
1716 {
1717 write_register(2, myCartridge->thumbCallback(2, read_register(2), 0));
1718 // approximated cycles
1719 INC_ARM_CYCLES(_flashCycles + 1); // this instruction
1720 INC_ARM_CYCLES(6 + _flashCycles + 2); // ARM code WavePtrFetch
1721 INC_ARM_CYCLES(2 + _flashCycles + 2); // ARM code ReturnC
1722 handled = true;
1723 }
1724 else if (pc == CDF1_SetWaveSize)
1725 {
1726 myCartridge->thumbCallback(3, read_register(2), read_register(3));
1727 // approximated cycles
1728 INC_ARM_CYCLES(_flashCycles + 1); // this instruction
1729 INC_ARM_CYCLES(18 + _flashCycles * 3 + 2); // ARM code WaveSizeStore
1730 INC_ARM_CYCLES(2 + _flashCycles + 2); // ARM code ReturnC
1731 handled = true;
1732 }
1733 else if (pc == 0x0000083a)
1734 {
1735 // exiting Custom ARM code, returning to CDFJ Driver control
1736 }
1737 else
1738 {
1739 #if 0 // uncomment this for testing
1740 uInt32 r0 = read_register(0);
1741 uInt32 r1 = read_register(1);
1742 uInt32 r2 = read_register(2);
1743 uInt32 r3 = read_register(3);
1744 uInt32 r4 = read_register(4);
1745 #endif
1746 myCartridge->thumbCallback(255, 0, 0);
1747 }
1748
1749 break;
1750
1751 case ConfigureFor::DPCplus:
1752 // no 32-bit subroutines in DPC+
1753 break;
1754 }
1755
1756 if (handled)
1757 {
1758 rc = read_register(14); // lr
1759 rc += 2;
1760 //rc &= ~1;
1761 write_register(15, rc);
1762 //_totalCycles += 100; // just a wild guess
1763 return 0;
1764 }
1765 return 1;
1766 }
1767 }
1768
1769 //CMN
1770 case Op::cmn: {
1771 rn = (inst >> 0) & 0x7;
1772 rm = (inst >> 3) & 0x7;
1773 DO_DISS(statusMsg << "cmns r" << dec << rn << ",r" << dec << rm << endl);
1774 ra = read_register(rn);
1775 rb = read_register(rm);
1776 rc = ra + rb;
1777 do_nflag(rc);
1778 do_zflag(rc);
1779 do_cflag(ra, rb, 0);
1780 do_vflag(ra, rb, 0);
1781 return 0;
1782 }
1783
1784 //CMP(1) compare immediate
1785 case Op::cmp1: {
1786 rb = (inst >> 0) & 0xFF;
1787 rn = (inst >> 8) & 0x07;
1788 DO_DISS(statusMsg << "cmp r" << dec << rn << ",#0x" << Base::HEX2 << rb << endl);
1789 ra = read_register(rn);
1790 rc = ra - rb;
1791 //fprintf(stderr,"0x%08X 0x%08X\n",ra,rb);
1792 do_nflag(rc);
1793 do_zflag(rc);
1794 do_cflag(ra, ~rb, 1);
1795 do_vflag(ra, ~rb, 1);
1796 return 0;
1797 }
1798
1799 //CMP(2) compare register
1800 case Op::cmp2: {
1801 rn = (inst >> 0) & 0x7;
1802 rm = (inst >> 3) & 0x7;
1803 DO_DISS(statusMsg << "cmps r" << dec << rn << ",r" << dec << rm << endl);
1804 ra = read_register(rn);
1805 rb = read_register(rm);
1806 rc = ra - rb;
1807 //fprintf(stderr,"0x%08X 0x%08X\n",ra,rb);
1808 do_nflag(rc);
1809 do_zflag(rc);
1810 do_cflag(ra, ~rb, 1);
1811 do_vflag(ra, ~rb, 1);
1812 return 0;
1813 }
1814
1815 //CMP(3) compare high register
1816 case Op::cmp3: {
1817 if(((inst >> 6) & 3) == 0x0)
1818 {
1819 //UNPREDICTABLE
1820 }
1821 rn = (inst >> 0) & 0x7;
1822 rn |= (inst >> 4) & 0x8;
1823 if(rn == 0xF)
1824 {
1825 //UNPREDICTABLE
1826 }
1827 rm = (inst >> 3) & 0xF;
1828 DO_DISS(statusMsg << "cmps r" << dec << rn << ",r" << dec << rm << endl);
1829 ra = read_register(rn);
1830 rb = read_register(rm);
1831 rc = ra - rb;
1832 do_nflag(rc);
1833 do_zflag(rc);
1834 do_cflag(ra, ~rb, 1);
1835 do_vflag(ra, ~rb, 1);
1836 return 0;
1837 }
1838
1839 #ifndef UNSAFE_OPTIMIZATIONS
1840 //CPS
1841 case Op::cps: {
1842 DO_DISS(statusMsg << "cps TODO" << endl);
1843 return 1;
1844 }
1845 #endif
1846
1847 //CPY copy high register
1848 case Op::cpy: {
1849 //same as mov except you can use both low registers
1850 //going to let mov handle high registers
1851 rd = (inst >> 0) & 0x7;
1852 rm = (inst >> 3) & 0x7;
1853 DO_DISS(statusMsg << "cpy r" << dec << rd << ",r" << dec << rm << endl);
1854 rc = read_register(rm);
1855 write_register(rd, rc);
1856 return 0;
1857 }
1858
1859 //EOR
1860 case Op::eor: {
1861 rd = (inst >> 0) & 0x7;
1862 rm = (inst >> 3) & 0x7;
1863 DO_DISS(statusMsg << "eors r" << dec << rd << ",r" << dec << rm << endl);
1864 ra = read_register(rd);
1865 rb = read_register(rm);
1866 rc = ra ^ rb;
1867 write_register(rd, rc);
1868 do_nflag(rc);
1869 do_zflag(rc);
1870 return 0;
1871 }
1872
1873 //LDMIA
1874 case Op::ldmia: {
1875 rn = (inst >> 8) & 0x7;
1876 #if defined(THUMB_DISS)
1877 statusMsg << "ldmia r" << dec << rn << "!,{";
1878 for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,++ra)
1879 {
1880 if(inst&rb)
1881 {
1882 if(rc) statusMsg << ",";
1883 statusMsg << "r" << dec << ra;
1884 rc++;
1885 }
1886 }
1887 statusMsg << "}" << endl;
1888 #endif
1889 bool first = true;
1890
1891 sp = read_register(rn);
1892 for(ra = 0, rb = 0x01; rb; rb = (rb << 1) & 0xFF, ++ra)
1893 {
1894 if(inst & rb)
1895 {
1896 write_register(ra, read32(sp));
1897 if(first)
1898 {
1899 INC_N_CYCLES(sp, AccessType::data);
1900 first = false;
1901 }
1902 else
1903 {
1904 INC_S_CYCLES(sp, AccessType::data);
1905 }
1906 sp += 4;
1907 }
1908 }
1909 INC_I_CYCLES; // Note: destination PC not possible, see pop instead
1910 //there is a write back exception.
1911 if((inst & (1 << rn)) == 0)
1912 write_register(rn, sp);
1913 return 0;
1914 }
1915
1916 //LDR(1) two register immediate
1917 case Op::ldr1: {
1918 rd = (inst >> 0) & 0x07;
1919 rn = (inst >> 3) & 0x07;
1920 rb = (inst >> 6) & 0x1F;
1921 rb <<= 2;
1922 DO_DISS(statusMsg << "ldr r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
1923 rb = read_register(rn) + rb;
1924 rc = read32(rb);
1925 write_register(rd, rc);
1926 INC_LDR_CYCLES;
1927 return 0;
1928 }
1929
1930 //LDR(2) three register
1931 case Op::ldr2: {
1932 rd = (inst >> 0) & 0x7;
1933 rn = (inst >> 3) & 0x7;
1934 rm = (inst >> 6) & 0x7;
1935 DO_DISS(statusMsg << "ldr r" << dec << rd << ",[r" << dec << rn << ",r" << dec << "]" << endl);
1936 rb = read_register(rn) + read_register(rm);
1937 rc = read32(rb);
1938 write_register(rd, rc);
1939 INC_LDR_CYCLES;
1940 return 0;
1941 }
1942
1943 //LDR(3)
1944 case Op::ldr3: {
1945 rb = (inst >> 0) & 0xFF;
1946 rd = (inst >> 8) & 0x07;
1947 rb <<= 2;
1948 DO_DISS(statusMsg << "ldr r" << dec << rd << ",[PC+#0x" << Base::HEX2 << rb << "] ");
1949 ra = read_register(15);
1950 ra &= ~3;
1951 rb += ra;
1952 DO_DISS(statusMsg << ";@ 0x" << Base::HEX2 << rb << endl);
1953 rc = read32(rb);
1954 write_register(rd, rc);
1955 INC_LDR_CYCLES;
1956 return 0;
1957 }
1958
1959 //LDR(4)
1960 case Op::ldr4: {
1961 rb = (inst >> 0) & 0xFF;
1962 rd = (inst >> 8) & 0x07;
1963 rb <<= 2;
1964 DO_DISS(statusMsg << "ldr r" << dec << rd << ",[SP+#0x" << Base::HEX2 << rb << "]" << endl);
1965 ra = read_register(13);
1966 //ra&=~3;
1967 rb += ra;
1968 rc = read32(rb);
1969 write_register(rd, rc);
1970 INC_LDR_CYCLES;
1971 return 0;
1972 }
1973
1974 //LDRB(1)
1975 case Op::ldrb1: {
1976 rd = (inst >> 0) & 0x07;
1977 rn = (inst >> 3) & 0x07;
1978 rb = (inst >> 6) & 0x1F;
1979 DO_DISS(statusMsg << "ldrb r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
1980 rb = read_register(rn) + rb;
1981 #ifndef UNSAFE_OPTIMIZATIONS
1982 rc = read16(rb & (~1U));
1983 #else
1984 rc = read16(rb);
1985 #endif
1986 if(rb & 1)
1987 {
1988 rc >>= 8;
1989 }
1990 else
1991 {
1992 }
1993 write_register(rd, rc & 0xFF);
1994 INC_LDRB_CYCLES;
1995 return 0;
1996 }
1997
1998 //LDRB(2)
1999 case Op::ldrb2: {
2000 rd = (inst >> 0) & 0x7;
2001 rn = (inst >> 3) & 0x7;
2002 rm = (inst >> 6) & 0x7;
2003 DO_DISS(statusMsg << "ldrb r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl);
2004 rb = read_register(rn) + read_register(rm);
2005 #ifndef UNSAFE_OPTIMIZATIONS
2006 rc = read16(rb & (~1U));
2007 #else
2008 rc = read16(rb);
2009 #endif
2010 if(rb & 1)
2011 {
2012 rc >>= 8;
2013 }
2014 write_register(rd, rc & 0xFF);
2015 INC_LDRB_CYCLES;
2016 return 0;
2017 }
2018
2019 //LDRH(1)
2020 case Op::ldrh1: {
2021 rd = (inst >> 0) & 0x07;
2022 rn = (inst >> 3) & 0x07;
2023 rb = (inst >> 6) & 0x1F;
2024 rb <<= 1;
2025 DO_DISS(statusMsg << "ldrh r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
2026 rb = read_register(rn) + rb;
2027 rc = read16(rb);
2028 write_register(rd, rc & 0xFFFF);
2029 INC_LDR_CYCLES;
2030 return 0;
2031 }
2032
2033 //LDRH(2)
2034 case Op::ldrh2: {
2035 rd = (inst >> 0) & 0x7;
2036 rn = (inst >> 3) & 0x7;
2037 rm = (inst >> 6) & 0x7;
2038 DO_DISS(statusMsg << "ldrh r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl);
2039 rb = read_register(rn) + read_register(rm);
2040 rc = read16(rb);
2041 write_register(rd, rc & 0xFFFF);
2042 INC_LDR_CYCLES;
2043 return 0;
2044 }
2045
2046 //LDRSB
2047 case Op::ldrsb: {
2048 rd = (inst >> 0) & 0x7;
2049 rn = (inst >> 3) & 0x7;
2050 rm = (inst >> 6) & 0x7;
2051 DO_DISS(statusMsg << "ldrsb r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl);
2052 rb = read_register(rn) + read_register(rm);
2053 #ifndef UNSAFE_OPTIMIZATIONS
2054 rc = read16(rb & (~1U));
2055 #else
2056 rc = read16(rb);
2057 #endif
2058 if(rb & 1)
2059 {
2060 rc >>= 8;
2061 }
2062 rc &= 0xFF;
2063 if(rc & 0x80)
2064 rc |= ((~0U) << 8);
2065 write_register(rd, rc);
2066 INC_LDRB_CYCLES;
2067 return 0;
2068 }
2069
2070 //LDRSH
2071 case Op::ldrsh: {
2072 rd = (inst >> 0) & 0x7;
2073 rn = (inst >> 3) & 0x7;
2074 rm = (inst >> 6) & 0x7;
2075 DO_DISS(statusMsg << "ldrsh r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl);
2076 rb = read_register(rn) + read_register(rm);
2077 rc = read16(rb);
2078 rc &= 0xFFFF;
2079 if(rc & 0x8000)
2080 rc |= ((~0U) << 16);
2081 write_register(rd, rc);
2082 INC_LDR_CYCLES;
2083 return 0;
2084 }
2085
2086 //LSL(1)
2087 case Op::lsl1: {
2088 rd = (inst >> 0) & 0x07;
2089 rm = (inst >> 3) & 0x07;
2090 rb = (inst >> 6) & 0x1F;
2091 DO_DISS(statusMsg << "lsls r" << dec << rd << ",r" << dec << rm << ",#0x" << Base::HEX2 << rb << endl);
2092 rc = read_register(rm);
2093 if(rb == 0)
2094 {
2095 //if immed_5 == 0
2096 //C unaffected
2097 //result not shifted
2098 }
2099 else
2100 {
2101 //else immed_5 > 0
2102 do_cflag_bit(rc & (1 << (32-rb)));
2103 rc <<= rb;
2104 }
2105 write_register(rd, rc);
2106 do_nflag(rc);
2107 do_zflag(rc);
2108 INC_SHIFT_CYCLES;
2109 return 0;
2110 }
2111
2112 //LSL(2) two register
2113 case Op::lsl2: {
2114 rd = (inst >> 0) & 0x07;
2115 rs = (inst >> 3) & 0x07;
2116 DO_DISS(statusMsg << "lsls r" << dec << rd << ",r" << dec << rs << endl);
2117 rc = read_register(rd);
2118 rb = read_register(rs);
2119 rb &= 0xFF;
2120 if(rb == 0)
2121 {
2122 }
2123 else if(rb < 32)
2124 {
2125 do_cflag_bit(rc & (1 << (32-rb)));
2126 rc <<= rb;
2127 }
2128 else if(rb == 32)
2129 {
2130 do_cflag_bit(rc & 1);
2131 rc = 0;
2132 }
2133 else
2134 {
2135 do_cflag_bit(0);
2136 rc = 0;
2137 }
2138 write_register(rd, rc);
2139 do_nflag(rc);
2140 do_zflag(rc);
2141 INC_SHIFT_CYCLES;
2142 return 0;
2143 }
2144
2145 //LSR(1) two register immediate
2146 case Op::lsr1: {
2147 rd = (inst >> 0) & 0x07;
2148 rm = (inst >> 3) & 0x07;
2149 rb = (inst >> 6) & 0x1F;
2150 DO_DISS(statusMsg << "lsrs r" << dec << rd << ",r" << dec << rm << ",#0x" << Base::HEX2 << rb << endl);
2151 rc = read_register(rm);
2152 if(rb == 0)
2153 {
2154 do_cflag_bit(rc & 0x80000000);
2155 rc = 0;
2156 }
2157 else
2158 {
2159 do_cflag_bit(rc & (1 << (rb-1)));
2160 rc >>= rb;
2161 }
2162 write_register(rd, rc);
2163 do_nflag(rc);
2164 do_zflag(rc);
2165 INC_SHIFT_CYCLES;
2166 return 0;
2167 }
2168
2169 //LSR(2) two register
2170 case Op::lsr2: {
2171 rd = (inst >> 0) & 0x07;
2172 rs = (inst >> 3) & 0x07;
2173 DO_DISS(statusMsg << "lsrs r" << dec << rd << ",r" << dec << rs << endl);
2174 rc = read_register(rd);
2175 rb = read_register(rs);
2176 rb &= 0xFF;
2177 if(rb == 0)
2178 {
2179 }
2180 else if(rb < 32)
2181 {
2182 do_cflag_bit(rc & (1 << (rb-1)));
2183 rc >>= rb;
2184 }
2185 else if(rb == 32)
2186 {
2187 do_cflag_bit(rc & 0x80000000);
2188 rc = 0;
2189 }
2190 else
2191 {
2192 do_cflag_bit(0);
2193 rc = 0;
2194 }
2195 write_register(rd, rc);
2196 do_nflag(rc);
2197 do_zflag(rc);
2198 INC_SHIFT_CYCLES;
2199 return 0;
2200 }
2201
2202 //MOV(1) immediate
2203 case Op::mov1: {
2204 rb = (inst >> 0) & 0xFF;
2205 rd = (inst >> 8) & 0x07;
2206 DO_DISS(statusMsg << "movs r" << dec << rd << ",#0x" << Base::HEX2 << rb << endl);
2207 write_register(rd, rb);
2208 do_nflag(rb);
2209 do_zflag(rb);
2210 return 0;
2211 }
2212
2213 //MOV(2) two low registers
2214 case Op::mov2: {
2215 rd = (inst >> 0) & 7;
2216 rn = (inst >> 3) & 7;
2217 DO_DISS(statusMsg << "movs r" << dec << rd << ",r" << dec << rn << endl);
2218 rc = read_register(rn);
2219 //fprintf(stderr,"0x%08X\n",rc);
2220 write_register(rd, rc);
2221 do_nflag(rc);
2222 do_zflag(rc);
2223 do_cflag_bit(0);
2224 do_vflag_bit(0);
2225 return 0;
2226 }
2227
2228 //MOV(3)
2229 case Op::mov3: {
2230 rd = (inst >> 0) & 0x7;
2231 rd |= (inst >> 4) & 0x8;
2232 rm = (inst >> 3) & 0xF;
2233 DO_DISS(statusMsg << "mov r" << dec << rd << ",r" << dec << rm << endl);
2234 rc = read_register(rm);
2235 if((rd == 14) && (rm == 15))
2236 {
2237 //printf("mov lr,pc warning 0x%08X\n",pc-2);
2238 //rc|=1;
2239 }
2240 if(rd == 15)
2241 {
2242 //rc &= ~1; //write_register may do this as well
2243 rc += 2; //The program counter is special
2244 }
2245 write_register(rd, rc);
2246 return 0;
2247 }
2248
2249 //MUL
2250 case Op::mul: {
2251 rd = (inst >> 0) & 0x7;
2252 rm = (inst >> 3) & 0x7;
2253 DO_DISS(statusMsg << "muls r" << dec << rd << ",r" << dec << rm << endl);
2254 ra = read_register(rd);
2255 rb = read_register(rm);
2256 #ifdef DEBUGGER_SUPPORT
2257 if((rb & 0xffffff00) == 0 || (rb & 0xffffff00) == 0xffffff00) // -2^8 <= rb < 2^8
2258 {
2259 INC_I_CYCLES;
2260 }
2261 else if((rb & 0xffff0000) == 0 || (rb & 0xffff0000) == 0xffff0000) // -2^16 <= rb < 2^16
2262 {
2263 INC_I_CYCLES_M(2);
2264 }
2265 else if((rb & 0xff000000) == 0 || (rb & 0xff000000) == 0xff000000) // -2^24 <= rb < 2^24
2266 {
2267 INC_I_CYCLES_M(3);
2268 }
2269 else
2270 {
2271 INC_I_CYCLES_M(4);
2272 }
2273 #endif
2274 rc = ra * rb;
2275 write_register(rd, rc);
2276 do_nflag(rc);
2277 do_zflag(rc);
2278 return 0;
2279 }
2280
2281 //MVN
2282 case Op::mvn: {
2283 rd = (inst >> 0) & 0x7;
2284 rm = (inst >> 3) & 0x7;
2285 DO_DISS(statusMsg << "mvns r" << dec << rd << ",r" << dec << rm << endl);
2286 ra = read_register(rm);
2287 rc = (~ra);
2288 write_register(rd, rc);
2289 do_nflag(rc);
2290 do_zflag(rc);
2291 return 0;
2292 }
2293
2294 //NEG
2295 case Op::neg: {
2296 rd = (inst >> 0) & 0x7;
2297 rm = (inst >> 3) & 0x7;
2298 DO_DISS(statusMsg << "negs r" << dec << rd << ",r" << dec << rm << endl);
2299 ra = read_register(rm);
2300 rc = 0 - ra;
2301 write_register(rd, rc);
2302 do_nflag(rc);
2303 do_zflag(rc);
2304 do_cflag(0, ~ra, 1);
2305 do_vflag(0, ~ra, 1);
2306 return 0;
2307 }
2308
2309 //ORR
2310 case Op::orr: {
2311 rd = (inst >> 0) & 0x7;
2312 rm = (inst >> 3) & 0x7;
2313 DO_DISS(statusMsg << "orrs r" << dec << rd << ",r" << dec << rm << endl);
2314 ra = read_register(rd);
2315 rb = read_register(rm);
2316 rc = ra | rb;
2317 write_register(rd, rc);
2318 do_nflag(rc);
2319 do_zflag(rc);
2320 return 0;
2321 }
2322
2323 //POP
2324 case Op::pop: {
2325 #if defined(THUMB_DISS)
2326 statusMsg << "pop {";
2327 for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,++ra)
2328 {
2329 if(inst&rb)
2330 {
2331 if(rc) statusMsg << ",";
2332 statusMsg << "r" << dec << ra;
2333 rc++;
2334 }
2335 }
2336 if(inst&0x100)
2337 {
2338 if(rc) statusMsg << ",";
2339 statusMsg << "pc";
2340 }
2341 statusMsg << "}" << endl;
2342 #endif
2343 bool first = true;
2344
2345 sp = read_register(13);
2346 for(ra = 0, rb = 0x01; rb; rb = (rb << 1) & 0xFF, ++ra)
2347 {
2348 if(inst & rb)
2349 {
2350 write_register(ra, read32(sp));
2351 if(first)
2352 {
2353 INC_N_CYCLES(sp, AccessType::data);
2354 first = false;
2355 }
2356 else
2357 {
2358 INC_S_CYCLES(sp, AccessType::data);
2359 }
2360 sp += 4;
2361 }
2362 }
2363 INC_I_CYCLES; // ??? (copied from ldmia)
2364 if(inst & 0x100)
2365 {
2366 rc = read32(sp);
2367 if(first)
2368 {
2369 INC_N_CYCLES(sp, AccessType::data);
2370 }
2371 else
2372 {
2373 INC_S_CYCLES(sp, AccessType::data);
2374 }
2375 rc += 2;
2376 write_register(15, rc);
2377 sp += 4;
2378 }
2379 write_register(13, sp);
2380 return 0;
2381 }
2382
2383 //PUSH
2384 case Op::push: {
2385 #if defined(THUMB_DISS)
2386 statusMsg << "push {";
2387 for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,++ra)
2388 {
2389 if(inst&rb)
2390 {
2391 if(rc) statusMsg << ",";
2392 statusMsg << "r" << dec << ra;
2393 rc++;
2394 }
2395 }
2396 if(inst&0x100)
2397 {
2398 if(rc) statusMsg << ",";
2399 statusMsg << "lr";
2400 }
2401 statusMsg << "}" << endl;
2402 #endif
2403
2404 sp = read_register(13);
2405 //fprintf(stderr,"sp 0x%08X\n",sp);
2406 for(ra = 0, rb = 0x01, rc = 0; rb; rb = (rb << 1) & 0xFF, ++ra)
2407 {
2408 if(inst & rb)
2409 {
2410 ++rc;
2411 }
2412 }
2413 if(inst & 0x100) ++rc;
2414 rc <<= 2;
2415 sp -= rc;
2416 bool first = true;
2417
2418 rd = sp;
2419 for(ra = 0, rb = 0x01; rb; rb = (rb << 1) & 0xFF, ++ra)
2420 {
2421 if(inst & rb)
2422 {
2423 write32(rd, read_register(ra));
2424 if(first)
2425 {
2426 INC_N_CYCLES(rd, AccessType::data);
2427 first = false;
2428 }
2429 else
2430 {
2431 INC_S_CYCLES(rd, AccessType::data);
2432 }
2433 rd += 4;
2434 }
2435 }
2436 if(inst & 0x100)
2437 {
2438 rc = read_register(14);
2439 write32(rd, rc);
2440 if(first)
2441 {
2442 INC_N_CYCLES(rd, AccessType::data);
2443 }
2444 else
2445 {
2446 INC_S_CYCLES(rd, AccessType::data);
2447 }
2448 if((rc & 1) == 0)
2449 {
2450 // FIXME fprintf(stderr,"push {lr} with an ARM address pc 0x%08X popped 0x%08X\n",pc,rc);
2451 }
2452 }
2453 write_register(13, sp);
2454 FETCH_TYPE_N; // ??? (copied from stmia)
2455 return 0;
2456 }
2457
2458 //REV
2459 case Op::rev: {
2460 rd = (inst >> 0) & 0x7;
2461 rn = (inst >> 3) & 0x7;
2462 DO_DISS(statusMsg << "rev r" << dec << rd << ",r" << dec << rn << endl);
2463 ra = read_register(rn);
2464 rc = ((ra >> 0) & 0xFF) << 24;
2465 rc |= ((ra >> 8) & 0xFF) << 16;
2466 rc |= ((ra >> 16) & 0xFF) << 8;
2467 rc |= ((ra >> 24) & 0xFF) << 0;
2468 write_register(rd, rc);
2469 return 0;
2470 }
2471
2472 //REV16
2473 case Op::rev16: {
2474 rd = (inst >> 0) & 0x7;
2475 rn = (inst >> 3) & 0x7;
2476 DO_DISS(statusMsg << "rev16 r" << dec << rd << ",r" << dec << rn << endl);
2477 ra = read_register(rn);
2478 rc = ((ra >> 0) & 0xFF) << 8;
2479 rc |= ((ra >> 8) & 0xFF) << 0;
2480 rc |= ((ra >> 16) & 0xFF) << 24;
2481 rc |= ((ra >> 24) & 0xFF) << 16;
2482 write_register(rd, rc);
2483 return 0;
2484 }
2485
2486 //REVSH
2487 case Op::revsh: {
2488 rd = (inst >> 0) & 0x7;
2489 rn = (inst >> 3) & 0x7;
2490 DO_DISS(statusMsg << "revsh r" << dec << rd << ",r" << dec << rn << endl);
2491 ra = read_register(rn);
2492 rc = ((ra >> 0) & 0xFF) << 8;
2493 rc |= ((ra >> 8) & 0xFF) << 0;
2494 if(rc & 0x8000) rc |= 0xFFFF0000;
2495 else rc &= 0x0000FFFF;
2496 write_register(rd, rc);
2497 return 0;
2498 }
2499
2500 //ROR
2501 case Op::ror: {
2502 rd = (inst >> 0) & 0x7;
2503 rs = (inst >> 3) & 0x7;
2504 DO_DISS(statusMsg << "rors r" << dec << rd << ",r" << dec << rs << endl);
2505 rc = read_register(rd);
2506 ra = read_register(rs);
2507 ra &= 0xFF;
2508 if(ra == 0)
2509 {
2510 }
2511 else
2512 {
2513 ra &= 0x1F;
2514 if(ra == 0)
2515 {
2516 do_cflag_bit(rc & 0x80000000);
2517 }
2518 else
2519 {
2520 do_cflag_bit(rc & (1 << (ra-1)));
2521 rb = rc << (32-ra);
2522 rc >>= ra;
2523 rc |= rb;
2524 }
2525 }
2526 write_register(rd, rc);
2527 do_nflag(rc);
2528 do_zflag(rc);
2529 INC_SHIFT_CYCLES;
2530 return 0;
2531 }
2532
2533 //SBC
2534 case Op::sbc: {
2535 rd = (inst >> 0) & 0x7;
2536 rm = (inst >> 3) & 0x7;
2537 DO_DISS(statusMsg << "sbc r" << dec << rd << ",r" << dec << rm << endl);
2538 ra = read_register(rd);
2539 rb = read_register(rm);
2540 rc = ra - rb;
2541 if(!(cpsr & CPSR_C)) --rc;
2542 write_register(rd, rc);
2543 do_nflag(rc);
2544 do_zflag(rc);
2545 if(cpsr & CPSR_C)
2546 {
2547 do_cflag(ra, ~rb, 1);
2548 do_vflag(ra, ~rb, 1);
2549 }
2550 else
2551 {
2552 do_cflag(ra, ~rb, 0);
2553 do_vflag(ra, ~rb, 0);
2554 }
2555 return 0;
2556 }
2557
2558 #ifndef UNSAFE_OPTIMIZATIONS
2559 //SETEND
2560 case Op::setend: {
2561 statusMsg << "setend not implemented" << endl;
2562 return 1;
2563 }
2564 #endif
2565
2566 //STMIA
2567 case Op::stmia: {
2568 rn = (inst >> 8) & 0x7;
2569 #if defined(THUMB_DISS)
2570 statusMsg << "stmia r" << dec << rn << "!,{";
2571 for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,++ra)
2572 {
2573 if(inst & rb)
2574 {
2575 if(rc) statusMsg << ",";
2576 statusMsg << "r" << dec << ra;
2577 rc++;
2578 }
2579 }
2580 statusMsg << "}" << endl;
2581 #endif
2582 bool first = true;
2583
2584 sp = read_register(rn);
2585 for(ra = 0, rb = 0x01; rb; rb = (rb << 1) & 0xFF, ++ra)
2586 {
2587 if(inst & rb)
2588 {
2589 write32(sp, read_register(ra));
2590 if(first)
2591 {
2592 INC_N_CYCLES(sp, AccessType::data);
2593 first = false;
2594 }
2595 else
2596 {
2597 INC_S_CYCLES(sp, AccessType::data);
2598 }
2599 sp += 4;
2600 }
2601 }
2602 write_register(rn, sp);
2603 FETCH_TYPE_N;
2604 return 0;
2605 }
2606
2607 //STR(1)
2608 case Op::str1: {
2609 rd = (inst >> 0) & 0x07;
2610 rn = (inst >> 3) & 0x07;
2611 rb = (inst >> 6) & 0x1F;
2612 rb <<= 2;
2613 DO_DISS(statusMsg << "str r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
2614 rb = read_register(rn) + rb;
2615 rc = read_register(rd);
2616 write32(rb, rc);
2617 INC_STR_CYCLES;
2618 return 0;
2619 }
2620
2621 //STR(2)
2622 case Op::str2: {
2623 rd = (inst >> 0) & 0x7;
2624 rn = (inst >> 3) & 0x7;
2625 rm = (inst >> 6) & 0x7;
2626 DO_DISS(statusMsg << "str r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl);
2627 rb = read_register(rn) + read_register(rm);
2628 rc = read_register(rd);
2629 write32(rb, rc);
2630 INC_STR_CYCLES;
2631 return 0;
2632 }
2633
2634 //STR(3)
2635 case Op::str3: {
2636 rb = (inst >> 0) & 0xFF;
2637 rd = (inst >> 8) & 0x07;
2638 rb <<= 2;
2639 DO_DISS(statusMsg << "str r" << dec << rd << ",[SP,#0x" << Base::HEX2 << rb << "]" << endl);
2640 rb = read_register(13) + rb;
2641 //fprintf(stderr,"0x%08X\n",rb);
2642 rc = read_register(rd);
2643 write32(rb, rc);
2644 INC_STR_CYCLES;
2645 return 0;
2646 }
2647
2648 //STRB(1)
2649 case Op::strb1: {
2650 rd = (inst >> 0) & 0x07;
2651 rn = (inst >> 3) & 0x07;
2652 rb = (inst >> 6) & 0x1F;
2653 DO_DISS(statusMsg << "strb r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX8 << rb << "]" << endl);
2654 rb = read_register(rn) + rb;
2655 rc = read_register(rd);
2656 #ifndef UNSAFE_OPTIMIZATIONS
2657 ra = read16(rb & (~1U));
2658 #else
2659 ra = read16(rb);
2660 #endif
2661 if(rb & 1)
2662 {
2663 ra &= 0x00FF;
2664 ra |= rc << 8;
2665 }
2666 else
2667 {
2668 ra &= 0xFF00;
2669 ra |= rc & 0x00FF;
2670 }
2671 write16(rb & (~1U), ra & 0xFFFF);
2672 INC_STRB_CYCLES;
2673 return 0;
2674 }
2675
2676 //STRB(2)
2677 case Op::strb2: {
2678 rd = (inst >> 0) & 0x7;
2679 rn = (inst >> 3) & 0x7;
2680 rm = (inst >> 6) & 0x7;
2681 DO_DISS(statusMsg << "strb r" << dec << rd << ",[r" << dec << rn << ",r" << rm << "]" << endl);
2682 rb = read_register(rn) + read_register(rm);
2683 rc = read_register(rd);
2684 #ifndef UNSAFE_OPTIMIZATIONS
2685 ra = read16(rb & (~1U));
2686 #else
2687 ra = read16(rb);
2688 #endif
2689 if(rb & 1)
2690 {
2691 ra &= 0x00FF;
2692 ra |= rc << 8;
2693 }
2694 else
2695 {
2696 ra &= 0xFF00;
2697 ra |= rc & 0x00FF;
2698 }
2699 write16(rb & (~1U), ra & 0xFFFF);
2700 INC_STRB_CYCLES;
2701 return 0;
2702 }
2703
2704 //STRH(1)
2705 case Op::strh1: {
2706 rd = (inst >> 0) & 0x07;
2707 rn = (inst >> 3) & 0x07;
2708 rb = (inst >> 6) & 0x1F;
2709 rb <<= 1;
2710 DO_DISS(statusMsg << "strh r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
2711 rb = read_register(rn) + rb;
2712 rc= read_register(rd);
2713 write16(rb, rc & 0xFFFF);
2714 INC_STR_CYCLES;
2715 return 0;
2716 }
2717
2718 //STRH(2)
2719 case Op::strh2: {
2720 rd = (inst >> 0) & 0x7;
2721 rn = (inst >> 3) & 0x7;
2722 rm = (inst >> 6) & 0x7;
2723 DO_DISS(statusMsg << "strh r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl);
2724 rb = read_register(rn) + read_register(rm);
2725 rc = read_register(rd);
2726 write16(rb, rc & 0xFFFF);
2727 INC_STR_CYCLES;
2728 return 0;
2729 }
2730
2731 //SUB(1)
2732 case Op::sub1: {
2733 rd = (inst >> 0) & 0x7;
2734 rn = (inst >> 3) & 0x7;
2735 rb = (inst >> 6) & 0x7;
2736 DO_DISS(statusMsg << "subs r" << dec << rd << ",r" << dec << rn << ",#0x" << Base::HEX2 << rb << endl);
2737 ra = read_register(rn);
2738 rc = ra - rb;
2739 write_register(rd, rc);
2740 do_nflag(rc);
2741 do_zflag(rc);
2742 do_cflag(ra, ~rb, 1);
2743 do_vflag(ra, ~rb, 1);
2744 return 0;
2745 }
2746
2747 //SUB(2)
2748 case Op::sub2: {
2749 rb = (inst >> 0) & 0xFF;
2750 rd = (inst >> 8) & 0x07;
2751 DO_DISS(statusMsg << "subs r" << dec << rd << ",#0x" << Base::HEX2 << rb << endl);
2752 ra = read_register(rd);
2753 rc = ra - rb;
2754 write_register(rd, rc);
2755 do_nflag(rc);
2756 do_zflag(rc);
2757 do_cflag(ra, ~rb, 1);
2758 do_vflag(ra, ~rb, 1);
2759 return 0;
2760 }
2761
2762 //SUB(3)
2763 case Op::sub3: {
2764 rd = (inst >> 0) & 0x7;
2765 rn = (inst >> 3) & 0x7;
2766 rm = (inst >> 6) & 0x7;
2767 DO_DISS(statusMsg << "subs r" << dec << rd << ",r" << dec << rn << ",r" << dec << rm << endl);
2768 ra = read_register(rn);
2769 rb = read_register(rm);
2770 rc = ra - rb;
2771 write_register(rd, rc);
2772 do_nflag(rc);
2773 do_zflag(rc);
2774 do_cflag(ra, ~rb, 1);
2775 do_vflag(ra, ~rb, 1);
2776 return 0;
2777 }
2778
2779 //SUB(4)
2780 case Op::sub4: {
2781 rb = inst & 0x7F;
2782 rb <<= 2;
2783 DO_DISS(statusMsg << "sub SP,#0x" << Base::HEX2 << rb << endl);
2784 ra = read_register(13);
2785 ra -= rb;
2786 write_register(13, ra);
2787 return 0;
2788 }
2789
2790 //SWI
2791 case Op::swi: {
2792 rb = inst & 0xFF;
2793 DO_DISS(statusMsg << "swi 0x" << Base::HEX2 << rb << endl);
2794
2795 if(rb == 0xCC)
2796 {
2797 write_register(0, cpsr);
2798 return 0;
2799 }
2800 else
2801 {
2802 #if defined(THUMB_DISS)
2803 statusMsg << endl << endl << "swi 0x" << Base::HEX2 << rb << endl;
2804 #endif
2805 return 1;
2806 }
2807 }
2808
2809 //SXTB
2810 case Op::sxtb: {
2811 rd = (inst >> 0) & 0x7;
2812 rm = (inst >> 3) & 0x7;
2813 DO_DISS(statusMsg << "sxtb r" << dec << rd << ",r" << dec << rm << endl);
2814 ra = read_register(rm);
2815 rc = ra & 0xFF;
2816 if(rc & 0x80)
2817 rc |= (~0U) << 8;
2818 write_register(rd, rc);
2819 return 0;
2820 }
2821
2822 //SXTH
2823 case Op::sxth: {
2824 rd = (inst >> 0) & 0x7;
2825 rm = (inst >> 3) & 0x7;
2826 DO_DISS(statusMsg << "sxth r" << dec << rd << ",r" << dec << rm << endl);
2827 ra = read_register(rm);
2828 rc = ra & 0xFFFF;
2829 if(rc & 0x8000)
2830 rc |= (~0U) << 16;
2831 write_register(rd, rc);
2832 return 0;
2833 }
2834
2835 //TST
2836 case Op::tst: {
2837 rn = (inst >> 0) & 0x7;
2838 rm = (inst >> 3) & 0x7;
2839 DO_DISS(statusMsg << "tst r" << dec << rn << ",r" << dec << rm << endl);
2840 ra = read_register(rn);
2841 rb = read_register(rm);
2842 rc = ra & rb;
2843 do_nflag(rc);
2844 do_zflag(rc);
2845 return 0;
2846 }
2847
2848 //UXTB
2849 case Op::uxtb: {
2850 rd = (inst >> 0) & 0x7;
2851 rm = (inst >> 3) & 0x7;
2852 DO_DISS(statusMsg << "uxtb r" << dec << rd << ",r" << dec << rm << endl);
2853 ra = read_register(rm);
2854 rc = ra & 0xFF;
2855 write_register(rd, rc);
2856 return 0;
2857 }
2858
2859 //UXTH
2860 case Op::uxth: {
2861 rd = (inst >> 0) & 0x7;
2862 rm = (inst >> 3) & 0x7;
2863 DO_DISS(statusMsg << "uxth r" << dec << rd << ",r" << dec << rm << endl);
2864 ra = read_register(rm);
2865 rc = ra & 0xFFFF;
2866 write_register(rd, rc);
2867 return 0;
2868 }
2869
2870 // Silence compiler
2871 case Op::numOps:
2872 break;
2873
2874 #ifndef UNSAFE_OPTIMIZATIONS
2875 case Op::invalid:
2876 break;
2877 #else
2878 default:
2879 break;
2880 #endif
2881 }
2882
2883 #ifndef UNSAFE_OPTIMIZATIONS
2884 statusMsg << "invalid instruction " << Base::HEX8 << pc << " " << Base::HEX4 << inst << endl;
2885 #endif
2886 return 1;
2887 }
2888
2889 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
reset()2890 int Thumbulator::reset()
2891 {
2892 reg_norm.fill(0);
2893
2894 reg_norm[13] = cStack; // SP
2895 reg_norm[14] = cBase; // LR
2896 reg_norm[15] = (cStart + 2) | 1; // PC (+2 for pipeline, lower bit for THUMB)
2897
2898 cpsr = 0;
2899 handler_mode = false;
2900
2901 systick_ctrl = 0x00000004;
2902 systick_reload = 0x00000000;
2903 systick_count = 0x00000000;
2904 systick_calibrate = 0x00ABCDEF;
2905
2906 // fxq: don't care about below so much (maybe to guess timing???)
2907 #ifndef UNSAFE_OPTIMIZATIONS
2908 _stats.instructions = 0;
2909 statusMsg.str("");
2910 #endif
2911 #ifdef THUMB_STATS
2912 _stats.reads = _stats.writes
2913 = _stats.nCylces = _stats.sCylces = _stats.iCylces
2914 = _stats.branches = _stats.taken
2915 = _stats.mamPrefetchHits = _stats.mamPrefetchMisses
2916 = _stats.mamBranchHits = _stats.mamBranchMisses
2917 = _stats.mamDataHits = _stats.mamDataMisses = 0;
2918 #endif
2919 #ifdef THUMB_CYCLE_COUNT
2920 _totalCycles = 0;
2921 #ifdef EMULATE_PIPELINE
2922 _fetchPipeline = _memory0Pipeline = _memory1Pipeline = 0;
2923 #endif
2924 #endif
2925 #ifdef COUNT_OPS
2926 //memset(opCount, 0, sizeof(opCount));
2927 #endif
2928 return 0;
2929 }
2930
2931 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
setChipType(ChipType type)2932 Thumbulator::ChipPropsType Thumbulator::setChipType(ChipType type)
2933 {
2934 ChipPropsType props = ChipProps[static_cast<uInt32>(type)];
2935
2936 _chipType = type;
2937 _MHz = props.MHz;
2938 #ifdef THUMB_CYCLE_COUNT
2939 _flashCycles = props.flashCycles;
2940 _flashBanks = props.flashBanks;
2941 #endif
2942
2943 setConsoleTiming(_consoleTiming);
2944
2945 return props;
2946 }
2947
2948 #ifdef THUMB_CYCLE_COUNT
2949 // Notes:
2950 // For exact cylce counting we have to
2951 // - emulate the LPC21xx prefetch, branch and data buffers
2952 // - differentiate between S and N cycles
2953 // - simulation the pipeline (including stalls)
2954
2955 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2956 /*
2957 This simulates the MAM of the LPC2101_02_03. It has three 128-bits buffers:
2958 - prefetch buffer
2959 - branch trail buffer
2960 - data buffer
2961
2962 Instruction prefetches are checking the prefetch and the branch trail buffer.
2963 - If a prefetch cannot be found in the two buffers a new line of 128 bits is read from memory
2964 and put into the prefetch buffer. This causes wait states.
2965 - If a branch target cannot be found in the two buffers a new line of 128 bits is read from
2966 memory and put into the branch trail buffer. This causes wait states.
2967
2968 Data access is only checking and updating the data buffer.
2969
2970 The function returns true in case of a buffer hit.
2971 */
isMamBuffered(uInt32 addr,AccessType accessType)2972 bool Thumbulator::isMamBuffered(uInt32 addr, AccessType accessType)
2973 {
2974 if(_flashBanks == 1) // e.g. LPC2101_02_03
2975 {
2976 // single Flash bank
2977 addr &= ~0x7F; // 128-bit address line
2978
2979 switch(accessType)
2980 {
2981 case AccessType::prefetch:
2982 if(addr != _prefetchBufferAddr[0] && addr != _branchBufferAddr[0])
2983 {
2984 #ifdef THUMB_STATS
2985 ++_stats.mamPrefetchMisses;
2986 #endif
2987 _prefetchBufferAddr[0] = addr;
2988 return false;
2989 }
2990 #ifdef THUMB_STATS
2991 ++_stats.mamPrefetchHits;
2992 #endif
2993 break;
2994
2995 case AccessType::branch:
2996 if(addr != _prefetchBufferAddr[0] && addr != _branchBufferAddr[0])
2997 {
2998 #ifdef THUMB_STATS
2999 ++_stats.mamBranchMisses;
3000 #endif
3001 _branchBufferAddr[0] = addr;
3002 return false;
3003 }
3004 #ifdef THUMB_STATS
3005 ++_stats.mamBranchHits;
3006 #endif
3007
3008 break;
3009
3010 default: // AccessType::data
3011 if(addr != _dataBufferAddr)
3012 {
3013 #ifdef THUMB_STATS
3014 ++_stats.mamDataMisses;
3015 #endif
3016 _dataBufferAddr = addr;
3017 return false;
3018 }
3019 #ifdef THUMB_STATS
3020 ++_stats.mamDataHits;
3021 #endif
3022 break;
3023 }
3024 }
3025 else // e.g. LPC2104_05_06
3026 {
3027 // dual Flash bank
3028 uInt32 bank = (addr & 0x80) ? 1 : 0;
3029
3030 addr &= ~0x7F; // 128-bit address line
3031
3032 switch(accessType)
3033 {
3034 case AccessType::prefetch:
3035 // speculative load, executed after last instrucution has been executed
3036 _prefetchBufferAddr[bank ^ 1] = addr + 0x80;
3037 if(addr != _prefetchBufferAddr[bank] && addr != _branchBufferAddr[bank])
3038 {
3039 #ifdef THUMB_STATS
3040 ++_stats.mamPrefetchMisses;
3041 #endif
3042 _prefetchBufferAddr[bank] = addr;
3043 return false;
3044 }
3045 #ifdef THUMB_STATS
3046 ++_stats.mamPrefetchHits;
3047 #endif
3048 break;
3049
3050 case AccessType::branch:
3051 if(addr != _prefetchBufferAddr[bank] && addr != _branchBufferAddr[bank])
3052 {
3053 #ifdef THUMB_STATS
3054 ++_stats.mamBranchMisses;
3055 #endif
3056 // load both branch trail buffers at once
3057 _branchBufferAddr[bank] = addr;
3058 _branchBufferAddr[bank ^ 1] = addr + 0x80;
3059 return false;
3060 }
3061 #ifdef THUMB_STATS
3062 ++_stats.mamBranchHits;
3063 #endif
3064 break;
3065
3066 default: // AccessType::data
3067 if(addr != _dataBufferAddr)
3068 {
3069 #ifdef THUMB_STATS
3070 ++_stats.mamDataMisses;
3071 #endif
3072 _dataBufferAddr = addr;
3073 return false;
3074 }
3075 #ifdef THUMB_STATS
3076 ++_stats.mamDataHits;
3077 #endif
3078 break;
3079 }
3080 }
3081 return true;
3082 }
3083
3084 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
incCycles(AccessType accessType,uInt32 cycles)3085 void Thumbulator::incCycles(AccessType accessType, uInt32 cycles)
3086 {
3087 #ifdef EMULATE_PIPELINE
3088 // simulate the pipeline effects
3089 //if(_memory0Pipeline)
3090 //{
3091 // --_memory0Pipeline; // == 0
3092 // ++_fetchPipeline;
3093 //}
3094 if(_memory1Pipeline)
3095 {
3096 --_memory1Pipeline;
3097 ++_memory0Pipeline; // == 1
3098 }
3099
3100 switch(accessType)
3101 {
3102 case AccessType::branch:
3103 _fetchPipeline = _memory0Pipeline = _memory1Pipeline = 0; // flush pipeline
3104 break;
3105
3106 case AccessType::data:
3107 if(cycles == 1) // no Flash access
3108 ++_fetchPipeline;
3109 else
3110 _memory1Pipeline += cycles;
3111 break;
3112
3113 default: // AccessType::prefetch
3114 {
3115 // Reduce cycles by pipelined cycles
3116 // Cart (Turbo start sequence): 1F0AC
3117 // None: 1FF2E @ 90% (22989 @ 100%)
3118 #if 1
3119 // Version 1: 1ECFC @ 90% (223C3 @ 100%)
3120 if(cycles == _flashCycles)
3121 {
3122 if(!_memory1Pipeline) // there must be no pending memory access
3123 {
3124 uInt32 newCycles = std::max(1, Int32(cycles - _fetchPipeline));
3125
3126 _fetchPipeline -= (cycles - newCycles);
3127 cycles = newCycles;
3128 }
3129 }
3130 #endif
3131 #if 0
3132 // Version 2: 1ED23 @ 90% (223EF @ 100%)
3133 // considers that partial fetches are not allowed
3134 if(cycles == _flashCycles)
3135 {
3136 //_memory0Pipeline = _memory1Pipeline = 0;
3137 if(!_memory1Pipeline && _fetchPipeline >= _flashCycles)
3138 {
3139 _fetchPipeline -= (_flashCycles - 1);
3140 cycles = 1;
3141 }
3142 //else
3143 // _fetchPipeline = 0; // Flash prefetch abort (makes 0 difference!)
3144 }
3145 #endif
3146 break;
3147 }
3148 };
3149 #endif
3150
3151 //#ifdef MERGE_I_S
3152 // TODO
3153 // if(accessType == AccessType::branch)
3154 // _lastCycleType[2] = _lastCycleType[1] = _lastCycleType[0] = CycleType::S;
3155 //#endif
3156
3157 _totalCycles += cycles;
3158 }
3159
3160 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
incSCycles(uInt32 addr,AccessType accessType)3161 void Thumbulator::incSCycles(uInt32 addr, AccessType accessType)
3162 {
3163 #ifdef THUMB_STATS
3164 ++_stats.sCylces;
3165 #endif
3166
3167 uInt32 cycles;
3168
3169
3170 if(addr & 0xC0000000) // RAM, peripherals
3171 cycles = 1;
3172 else // Flash
3173 {
3174 if(mamcr == MamModeType::mode0 ||
3175 (mamcr == MamModeType::mode1 && accessType == AccessType::data))
3176 {
3177 cycles = _flashCycles; // 3|4
3178 }
3179 else
3180 {
3181 if(isMamBuffered(addr, accessType) || mamcr == MamModeType::modeX)
3182 cycles = 1;
3183 else
3184 cycles = _flashCycles;
3185 }
3186 }
3187
3188 #ifdef MERGE_I_S
3189 //if(accessType != AccessType::prefetch)
3190 //{
3191 // if(_lastCycleType[0] == CycleType::I)
3192 // {
3193 // _lastCycleType[0] = CycleType::S; // merge cannot be used twice!
3194 // --cycles;
3195 // }
3196 //}
3197 //else if(_lastCycleType[2] == CycleType::I)
3198 // --cycles;
3199
3200 //if(accessType == AccessType::prefetch &&
3201 // _lastCycleType[_pipeIdx] == CycleType::I)
3202 // --cycles;
3203
3204
3205 _lastCycleType[2] = _lastCycleType[1];
3206 _lastCycleType[1] = _lastCycleType[0];
3207 _lastCycleType[0] = CycleType::S;
3208 //_lastCycleType[_pipeIdx] = CycleType::S;
3209 #endif
3210 incCycles(accessType, cycles);
3211
3212
3213 #ifdef MERGE_I_S
3214 if(accessType == AccessType::branch)
3215 {
3216 if(_lastCycleType[1] == CycleType::I || _lastCycleType[2] == CycleType::I)
3217 _lastCycleType[1] = _lastCycleType[2] = CycleType::S;
3218 //if(_lastCycleType[_pipeIdx ^ 1] == CycleType::I || _lastCycleType[_pipeIdx ^ 2] == CycleType::I)
3219 // _lastCycleType[_pipeIdx ^ 1] = _lastCycleType[_pipeIdx ^ 2] = CycleType::S;
3220 }
3221 #endif // MERGE_I_S
3222 }
3223
3224 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
incNCycles(uInt32 addr,AccessType accessType)3225 void Thumbulator::incNCycles(uInt32 addr, AccessType accessType)
3226 {
3227 #ifdef THUMB_STATS
3228 ++_stats.nCylces;
3229 #endif
3230
3231 uInt32 cycles;
3232
3233 if(addr & 0xC0000000) // RAM, peripherals
3234 cycles = 1;
3235 else // Flash
3236 {
3237 if(mamcr < MamModeType::mode2)
3238 cycles = _flashCycles; // 3|4
3239 else
3240 if(isMamBuffered(addr, accessType) || mamcr == MamModeType::modeX)
3241 cycles = 1;
3242 else
3243 cycles = _flashCycles;
3244 }
3245 #ifdef MERGE_I_S
3246 _lastCycleType[2] = _lastCycleType[1];
3247 _lastCycleType[1] = _lastCycleType[0];
3248 _lastCycleType[0] = CycleType::N;
3249 //_lastCycleType[_pipeIdx] = CycleType::N;
3250 #endif
3251 incCycles(accessType, cycles);
3252 }
3253
3254 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
incICycles(uInt32 m)3255 void Thumbulator::incICycles(uInt32 m)
3256 {
3257 #ifdef THUMB_STATS
3258 ++_stats.iCylces;
3259 #endif
3260
3261 #ifdef EMULATE_PIPELINE
3262 _fetchPipeline += m;
3263 //if(_memory0Pipeline)
3264 //{
3265 // --_memory0Pipeline; // == 0
3266 // ++_fetchPipeline;
3267 //}
3268
3269 // TODO: m!
3270 if(_memory1Pipeline)
3271 {
3272 --_memory1Pipeline;
3273 ++_memory0Pipeline; // == 1
3274 }
3275 #endif
3276 #ifdef MERGE_I_S
3277 _lastCycleType[2] = _lastCycleType[1];
3278 _lastCycleType[1] = _lastCycleType[0];
3279 _lastCycleType[0] = CycleType::I;
3280 //_lastCycleType[_pipeIdx] = CycleType::I;
3281 #endif
3282 _totalCycles += m;
3283 }
3284
3285 #endif // THUMB_CYCLE_COUNT
3286