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-2019 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"
29using 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
56Thumbulator::Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, uInt16 rom_size,
57 bool traponfatal, Thumbulator::ConfigureFor configurefor,
58 Cartridge* cartridge)
59 : rom(rom_ptr),
60 romSize(rom_size),
61 decodedRom(new Op[romSize / 2]),
62 ram(ram_ptr),
63 T1TCR(0),
64 T1TC(0),
65 configuration(configurefor),
66 myCartridge(cartridge)
67{
68 for(uInt16 i = 0; i < romSize / 2; ++i)
69 decodedRom[i] = decodeInstructionWord(CONV_RAMROM(rom[i]));
70
71 setConsoleTiming(ConsoleTiming::ntsc);
72#ifndef UNSAFE_OPTIMIZATIONS
73 trapFatalErrors(traponfatal);
74#endif
75 reset();
76}
77
78// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
79string Thumbulator::run()
80{
81 reset();
82 for(;;)
83 {
84 if(execute()) break;
85#ifndef UNSAFE_OPTIMIZATIONS
86 if(instructions > 500000) // way more than would otherwise be possible
87 throw runtime_error("instructions > 500000");
88#endif
89 }
90#if defined(THUMB_DISS) || defined(THUMB_DBUG)
91 dump_counters();
92 cout << statusMsg.str() << endl;
93 return statusMsg.str();
94#else
95 return "";
96#endif
97}
98
99// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
100void Thumbulator::setConsoleTiming(ConsoleTiming timing)
101{
102 // this sets how many ticks of the Harmony/Melody clock
103 // will occur per tick of the 6507 clock
104 constexpr double NTSC = 70.0 / 1.193182; // NTSC 6507 clock rate
105 constexpr double PAL = 70.0 / 1.182298; // PAL 6507 clock rate
106 constexpr double SECAM = 70.0 / 1.187500; // SECAM 6507 clock rate
107
108 switch(timing)
109 {
110 case ConsoleTiming::ntsc: timing_factor = NTSC; break;
111 case ConsoleTiming::secam: timing_factor = SECAM; break;
112 case ConsoleTiming::pal: timing_factor = PAL; break;
113 }
114}
115
116// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
117void Thumbulator::updateTimer(uInt32 cycles)
118{
119 if (T1TCR & 1) // bit 0 controls timer on/off
120 T1TC += uInt32(cycles * timing_factor);
121}
122
123// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
124string Thumbulator::run(uInt32 cycles)
125{
126 updateTimer(cycles);
127 return run();
128}
129
130#ifndef UNSAFE_OPTIMIZATIONS
131// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
132inline int Thumbulator::fatalError(const char* opcode, uInt32 v1, const char* msg)
133{
134 statusMsg << "Thumb ARM emulation fatal error: " << endl
135 << opcode << "(" << Base::HEX8 << v1 << "), " << msg << endl;
136 dump_regs();
137 if(trapOnFatal)
138 throw runtime_error(statusMsg.str());
139 return 0;
140}
141
142// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
143inline int Thumbulator::fatalError(const char* opcode, uInt32 v1, uInt32 v2,
144 const char* msg)
145{
146 statusMsg << "Thumb ARM emulation fatal error: " << endl
147 << opcode << "(" << Base::HEX8 << v1 << "," << v2 << "), " << msg << endl;
148 dump_regs();
149 if(trapOnFatal)
150 throw runtime_error(statusMsg.str());
151 return 0;
152}
153
154// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
155void Thumbulator::dump_counters()
156{
157 cout << endl << endl
158 << "instructions " << instructions << endl
159 << "fetches " << fetches << endl
160 << "reads " << reads << endl
161 << "writes " << writes << endl
162 << "memcycles " << (fetches+reads+writes) << endl;
163}
164
165// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
166void Thumbulator::dump_regs()
167{
168 for (int cnt = 1; cnt < 14; cnt++)
169 {
170 statusMsg << "R" << cnt << " = " << Base::HEX8 << reg_norm[cnt-1] << " ";
171 if(cnt % 4 == 0) statusMsg << endl;
172 }
173 statusMsg << endl
174 << "SP = " << Base::HEX8 << reg_norm[13] << " "
175 << "LR = " << Base::HEX8 << reg_norm[14] << " "
176 << "PC = " << Base::HEX8 << reg_norm[15] << " "
177 << endl;
178}
179#endif
180
181// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
182uInt32 Thumbulator::fetch16(uInt32 addr)
183{
184#ifndef NO_THUMB_STATS
185 ++fetches;
186#endif
187
188#ifndef UNSAFE_OPTIMIZATIONS
189 uInt32 data;
190 switch(addr & 0xF0000000)
191 {
192 case 0x00000000: //ROM
193 addr &= ROMADDMASK;
194 if(addr < 0x50)
195 fatalError("fetch16", addr, "abort");
196 addr >>= 1;
197 data = CONV_RAMROM(rom[addr]);
198 DO_DBUG(statusMsg << "fetch16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl);
199 return data;
200
201 case 0x40000000: //RAM
202 addr &= RAMADDMASK;
203 addr >>= 1;
204 data=CONV_RAMROM(ram[addr]);
205 DO_DBUG(statusMsg << "fetch16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl);
206 return data;
207 }
208 return fatalError("fetch16", addr, "abort");
209#else
210 addr &= ROMADDMASK;
211 addr >>= 1;
212 return CONV_RAMROM(rom[addr]);
213#endif
214}
215
216// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
217void Thumbulator::write16(uInt32 addr, uInt32 data)
218{
219#ifndef UNSAFE_OPTIMIZATIONS
220 if((addr > 0x40001fff) && (addr < 0x50000000))
221 fatalError("write16", addr, "abort - out of range");
222
223 if (isProtected(addr)) fatalError("write16", addr, "to driver area");
224
225 if(addr & 1)
226 fatalError("write16", addr, "abort - misaligned");
227#endif
228#ifndef NO_THUMB_STATS
229 ++writes;
230#endif
231
232 DO_DBUG(statusMsg << "write16(" << Base::HEX8 << addr << "," << Base::HEX8 << data << ")" << endl);
233
234 switch(addr & 0xF0000000)
235 {
236 case 0x40000000: //RAM
237 addr &= RAMADDMASK;
238 addr >>= 1;
239 ram[addr] = CONV_DATA(data);
240 return;
241
242#ifndef UNSAFE_OPTIMIZATIONS
243 case 0xE0000000: //MAMCR
244#else
245 default:
246#endif
247 if(addr == 0xE01FC000)
248 {
249 DO_DBUG(statusMsg << "write16(" << Base::HEX8 << "MAMCR" << "," << Base::HEX8 << data << ") *" << endl);
250 mamcr = data;
251 return;
252 }
253 }
254#ifndef UNSAFE_OPTIMIZATIONS
255 fatalError("write16", addr, data, "abort");
256#endif
257}
258
259// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
260void Thumbulator::write32(uInt32 addr, uInt32 data)
261{
262#ifndef UNSAFE_OPTIMIZATIONS
263 if(addr & 3)
264 fatalError("write32", addr, "abort - misaligned");
265
266 if (isProtected(addr)) fatalError("write32", addr, "to driver area");
267#endif
268 DO_DBUG(statusMsg << "write32(" << Base::HEX8 << addr << "," << Base::HEX8 << data << ")" << endl);
269
270 switch(addr & 0xF0000000)
271 {
272#ifndef UNSAFE_OPTIMIZATIONS
273 case 0xF0000000: //halt
274 dump_counters();
275 throw runtime_error("HALT");
276#endif
277
278 case 0xE0000000: //periph
279 switch(addr)
280 {
281#ifndef UNSAFE_OPTIMIZATIONS
282 case 0xE0000000:
283 DO_DISS(statusMsg << "uart: [" << char(data&0xFF) << "]" << endl);
284 break;
285#endif
286
287 case 0xE0008004: // T1TCR - Timer 1 Control Register
288 T1TCR = data;
289 break;
290
291 case 0xE0008008: // T1TC - Timer 1 Counter
292 T1TC = data;
293 break;
294
295 case 0xE000E010:
296 {
297 uInt32 old = systick_ctrl;
298 systick_ctrl = data & 0x00010007;
299 if(((old & 1) == 0) && (systick_ctrl & 1))
300 {
301 // timer started, load count
302 systick_count = systick_reload;
303 }
304 break;
305 }
306
307 case 0xE000E014:
308 systick_reload = data & 0x00FFFFFF;
309 break;
310
311 case 0xE000E018:
312 systick_count = data & 0x00FFFFFF;
313 break;
314
315 case 0xE000E01C:
316 systick_calibrate = data & 0x00FFFFFF;
317 break;
318 }
319 return;
320
321 case 0xD0000000: //debug
322#ifndef UNSAFE_OPTIMIZATIONS
323 switch(addr & 0xFF)
324 {
325 case 0x00:
326 statusMsg << "[" << Base::HEX8 << read_register(14) << "]["
327 << addr << "] " << data << endl;
328 return;
329
330 case 0x10:
331 statusMsg << Base::HEX8 << data << endl;
332 return;
333
334 case 0x20:
335 statusMsg << Base::HEX8 << data << endl;
336 return;
337 }
338#endif
339 return;
340
341#ifndef UNSAFE_OPTIMIZATIONS
342 case 0x40000000: //RAM
343#else
344 default:
345#endif
346 write16(addr+0, (data >> 0) & 0xFFFF);
347 write16(addr+2, (data >> 16) & 0xFFFF);
348 return;
349 }
350#ifndef UNSAFE_OPTIMIZATIONS
351 fatalError("write32", addr, data, "abort");
352#endif
353}
354
355#ifndef UNSAFE_OPTIMIZATIONS
356// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
357bool Thumbulator::isProtected(uInt32 addr)
358{
359 if (addr < 0x40000000) return false;
360 addr -= 0x40000000;
361
362 switch (configuration) {
363 case ConfigureFor::DPCplus:
364 return (addr < 0x0c00) && (addr > 0x0028);
365
366 case ConfigureFor::CDF:
367 return (addr < 0x0800) && (addr > 0x0028) && !((addr >= 0x06e0) && (addr < (0x0e60 + 284)));
368
369 case ConfigureFor::CDF1:
370 return (addr < 0x0800) && (addr > 0x0028) && !((addr >= 0x00a0) && (addr < (0x00a0 + 284)));
371
372 case ConfigureFor::CDFJ:
373 return (addr < 0x0800) && (addr > 0x0028) && !((addr >= 0x0098) && (addr < (0x0098 + 292)));
374
375 case ConfigureFor::BUS:
376 return (addr < 0x06d8) && (addr > 0x0028);
377 }
378
379 return false;
380}
381#endif
382
383// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
384uInt32 Thumbulator::read16(uInt32 addr)
385{
386 uInt32 data;
387#ifndef UNSAFE_OPTIMIZATIONS
388 if((addr > 0x40001fff) && (addr < 0x50000000))
389 fatalError("read16", addr, "abort - out of range");
390 else if((addr > 0x7fff) && (addr < 0x10000000))
391 fatalError("read16", addr, "abort - out of range");
392 if(addr & 1)
393 fatalError("read16", addr, "abort - misaligned");
394#endif
395#ifndef NO_THUMB_STATS
396 ++reads;
397#endif
398
399 switch(addr & 0xF0000000)
400 {
401 case 0x00000000: //ROM
402 addr &= ROMADDMASK;
403 addr >>= 1;
404 data = CONV_RAMROM(rom[addr]);
405 DO_DBUG(statusMsg << "read16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl);
406 return data;
407
408 case 0x40000000: //RAM
409 addr &= RAMADDMASK;
410 addr >>= 1;
411 data = CONV_RAMROM(ram[addr]);
412 DO_DBUG(statusMsg << "read16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl);
413 return data;
414
415#ifndef UNSAFE_OPTIMIZATIONS
416 case 0xE0000000: //MAMCR
417 if(addr == 0xE01FC000)
418#else
419 default:
420#endif
421 {
422 DO_DBUG(statusMsg << "read16(" << "MAMCR" << addr << ")=" << mamcr << " *");
423 return mamcr;
424 }
425 }
426#ifndef UNSAFE_OPTIMIZATIONS
427 return fatalError("read16", addr, "abort");
428#endif
429}
430
431// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
432uInt32 Thumbulator::read32(uInt32 addr)
433{
434#ifndef UNSAFE_OPTIMIZATIONS
435 if(addr & 3)
436 fatalError("read32", addr, "abort - misaligned");
437#endif
438
439 uInt32 data;
440 switch(addr & 0xF0000000)
441 {
442 case 0x00000000: //ROM
443 case 0x40000000: //RAM
444 data = read16(addr+0);
445 data |= (uInt32(read16(addr+2))) << 16;
446 DO_DBUG(statusMsg << "read32(" << Base::HEX8 << addr << ")=" << Base::HEX8 << data << endl);
447 return data;
448
449#ifndef UNSAFE_OPTIMIZATIONS
450 case 0xE0000000:
451#else
452 default:
453#endif
454 {
455 switch(addr)
456 {
457 case 0xE0008004: // T1TCR - Timer 1 Control Register
458 data = T1TCR;
459 return data;
460
461 case 0xE0008008: // T1TC - Timer 1 Counter
462 data = T1TC;
463 return data;
464
465 case 0xE000E010:
466 data = systick_ctrl;
467 systick_ctrl &= (~0x00010000);
468 return data;
469
470 case 0xE000E014:
471 data = systick_reload;
472 return data;
473
474 case 0xE000E018:
475 data = systick_count;
476 return data;
477
478#ifndef UNSAFE_OPTIMIZATIONS
479 case 0xE000E01C:
480#else
481 default:
482#endif
483 data = systick_calibrate;
484 return data;
485 }
486 }
487 }
488#ifndef UNSAFE_OPTIMIZATIONS
489 return fatalError("read32", addr, "abort");
490#endif
491}
492
493// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
494uInt32 Thumbulator::read_register(uInt32 reg)
495{
496 reg &= 0xF;
497
498 uInt32 data = reg_norm[reg];
499 DO_DBUG(statusMsg << "read_register(" << dec << reg << ")=" << Base::HEX8 << data << endl);
500#ifndef UNSAFE_OPTIMIZATIONS
501 if(reg == 15)
502 {
503 if(data & 1)
504 {
505 DO_DBUG(statusMsg << "pc has lsbit set 0x" << Base::HEX8 << data << endl);
506 }
507 data &= ~1;
508 }
509#endif
510 return data;
511}
512
513// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
514void Thumbulator::write_register(uInt32 reg, uInt32 data)
515{
516 reg &= 0xF;
517
518 DO_DBUG(statusMsg << "write_register(" << dec << reg << "," << Base::HEX8 << data << ")" << endl);
519//#ifndef UNSAFE_OPTIMIZATIONS // this fails when combined with read_register UNSAFE_OPTIMIZATIONS
520 if(reg == 15) data &= ~1;
521//#endif
522 reg_norm[reg] = data;
523}
524
525// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
526void Thumbulator::do_zflag(uInt32 x)
527{
528 if(x == 0) cpsr |= CPSR_Z; else cpsr &= ~CPSR_Z;
529}
530
531// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
532void Thumbulator::do_nflag(uInt32 x)
533{
534 if(x & 0x80000000) cpsr |= CPSR_N; else cpsr &= ~CPSR_N;
535}
536
537// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
538void Thumbulator::do_cflag(uInt32 a, uInt32 b, uInt32 c)
539{
540 uInt32 rc;
541
542 rc = (a & 0x7FFFFFFF) + (b & 0x7FFFFFFF) + c; //carry in
543 rc = (rc >> 31) + (a >> 31) + (b >> 31); //carry out
544 if(rc & 2)
545 cpsr |= CPSR_C;
546 else
547 cpsr &= ~CPSR_C;
548}
549
550// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
551void Thumbulator::do_vflag(uInt32 a, uInt32 b, uInt32 c)
552{
553 uInt32 rc, rd;
554
555 rc = (a & 0x7FFFFFFF) + (b & 0x7FFFFFFF) + c; //carry in
556 rc >>= 31; //carry in in lsbit
557 rd = (rc & 1) + ((a >> 31) & 1) + ((b >> 31) & 1); //carry out
558 rd >>= 1; //carry out in lsbit
559 rc = (rc^rd) & 1; //if carry in != carry out then signed overflow
560 if(rc)
561 cpsr |= CPSR_V;
562 else
563 cpsr &= ~CPSR_V;
564}
565
566// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
567void Thumbulator::do_cflag_bit(uInt32 x)
568{
569 if(x) cpsr |= CPSR_C; else cpsr &= ~CPSR_C;
570}
571
572// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
573void Thumbulator::do_vflag_bit(uInt32 x)
574{
575 if(x) cpsr |= CPSR_V; else cpsr &= ~CPSR_V;
576}
577
578// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
579Thumbulator::Op Thumbulator::decodeInstructionWord(uint16_t inst) {
580 //ADC
581 if((inst & 0xFFC0) == 0x4140) return Op::adc;
582
583 //ADD(1) small immediate two registers
584 if((inst & 0xFE00) == 0x1C00 && (inst >> 6) & 0x7) return Op::add1;
585
586 //ADD(2) big immediate one register
587 if((inst & 0xF800) == 0x3000) return Op::add2;
588
589 //ADD(3) three registers
590 if((inst & 0xFE00) == 0x1800) return Op::add3;
591
592 //ADD(4) two registers one or both high no flags
593 if((inst & 0xFF00) == 0x4400) return Op::add4;
594
595 //ADD(5) rd = pc plus immediate
596 if((inst & 0xF800) == 0xA000) return Op::add5;
597
598 //ADD(6) rd = sp plus immediate
599 if((inst & 0xF800) == 0xA800) return Op::add6;
600
601 //ADD(7) sp plus immediate
602 if((inst & 0xFF80) == 0xB000) return Op::add7;
603
604 //AND
605 if((inst & 0xFFC0) == 0x4000) return Op::and_;
606
607 //ASR(1) two register immediate
608 if((inst & 0xF800) == 0x1000) return Op::asr1;
609
610 //ASR(2) two register
611 if((inst & 0xFFC0) == 0x4100) return Op::asr2;
612
613 //B(1) conditional branch
614 if((inst & 0xF000) == 0xD000) return Op::b1;
615
616 //B(2) unconditional branch
617 if((inst & 0xF800) == 0xE000) return Op::b2;
618
619 //BIC
620 if((inst & 0xFFC0) == 0x4380) return Op::bic;
621
622 //BKPT
623 if((inst & 0xFF00) == 0xBE00) return Op::bkpt;
624
625 //BL/BLX(1)
626 if((inst & 0xE000) == 0xE000) return Op::blx1;
627
628 //BLX(2)
629 if((inst & 0xFF87) == 0x4780) return Op::blx2;
630
631 //BX
632 if((inst & 0xFF87) == 0x4700) return Op::bx;
633
634 //CMN
635 if((inst & 0xFFC0) == 0x42C0) return Op::cmn;
636
637 //CMP(1) compare immediate
638 if((inst & 0xF800) == 0x2800) return Op::cmp1;
639
640 //CMP(2) compare register
641 if((inst & 0xFFC0) == 0x4280) return Op::cmp2;
642
643 //CMP(3) compare high register
644 if((inst & 0xFF00) == 0x4500) return Op::cmp3;
645
646 //CPS
647 if((inst & 0xFFE8) == 0xB660) return Op::cps;
648
649 //CPY copy high register
650 if((inst & 0xFFC0) == 0x4600) return Op::cpy;
651
652 //EOR
653 if((inst & 0xFFC0) == 0x4040) return Op::eor;
654
655 //LDMIA
656 if((inst & 0xF800) == 0xC800) return Op::ldmia;
657
658 //LDR(1) two register immediate
659 if((inst & 0xF800) == 0x6800) return Op::ldr1;
660
661 //LDR(2) three register
662 if((inst & 0xFE00) == 0x5800) return Op::ldr2;
663
664 //LDR(3)
665 if((inst & 0xF800) == 0x4800) return Op::ldr3;
666
667 //LDR(4)
668 if((inst & 0xF800) == 0x9800) return Op::ldr4;
669
670 //LDRB(1)
671 if((inst & 0xF800) == 0x7800) return Op::ldrb1;
672
673 //LDRB(2)
674 if((inst & 0xFE00) == 0x5C00) return Op::ldrb2;
675
676 //LDRH(1)
677 if((inst & 0xF800) == 0x8800) return Op::ldrh1;
678
679 //LDRH(2)
680 if((inst & 0xFE00) == 0x5A00) return Op::ldrh2;
681
682 //LDRSB
683 if((inst & 0xFE00) == 0x5600) return Op::ldrsb;
684
685 //LDRSH
686 if((inst & 0xFE00) == 0x5E00) return Op::ldrsh;
687
688 //LSL(1)
689 if((inst & 0xF800) == 0x0000) return Op::lsl1;
690
691 //LSL(2) two register
692 if((inst & 0xFFC0) == 0x4080) return Op::lsl2;
693
694 //LSR(1) two register immediate
695 if((inst & 0xF800) == 0x0800) return Op::lsr1;
696
697 //LSR(2) two register
698 if((inst & 0xFFC0) == 0x40C0) return Op::lsr2;
699
700 //MOV(1) immediate
701 if((inst & 0xF800) == 0x2000) return Op::mov1;
702
703 //MOV(2) two low registers
704 if((inst & 0xFFC0) == 0x1C00) return Op::mov2;
705
706 //MOV(3)
707 if((inst & 0xFF00) == 0x4600) return Op::mov3;
708
709 //MUL
710 if((inst & 0xFFC0) == 0x4340) return Op::mul;
711
712 //MVN
713 if((inst & 0xFFC0) == 0x43C0) return Op::mvn;
714
715 //NEG
716 if((inst & 0xFFC0) == 0x4240) return Op::neg;
717
718 //ORR
719 if((inst & 0xFFC0) == 0x4300) return Op::orr;
720
721 //POP
722 if((inst & 0xFE00) == 0xBC00) return Op::pop;
723
724 //PUSH
725 if((inst & 0xFE00) == 0xB400) return Op::push;
726
727 //REV
728 if((inst & 0xFFC0) == 0xBA00) return Op::rev;
729
730 //REV16
731 if((inst & 0xFFC0) == 0xBA40) return Op::rev16;
732
733 //REVSH
734 if((inst & 0xFFC0) == 0xBAC0) return Op::revsh;
735
736 //ROR
737 if((inst & 0xFFC0) == 0x41C0) return Op::ror;
738
739 //SBC
740 if((inst & 0xFFC0) == 0x4180) return Op::sbc;
741
742 //SETEND
743 if((inst & 0xFFF7) == 0xB650) return Op::setend;
744
745 //STMIA
746 if((inst & 0xF800) == 0xC000) return Op::stmia;
747
748 //STR(1)
749 if((inst & 0xF800) == 0x6000) return Op::str1;
750
751 //STR(2)
752 if((inst & 0xFE00) == 0x5000) return Op::str2;
753
754 //STR(3)
755 if((inst & 0xF800) == 0x9000) return Op::str3;
756
757 //STRB(1)
758 if((inst & 0xF800) == 0x7000) return Op::strb1;
759
760 //STRB(2)
761 if((inst & 0xFE00) == 0x5400) return Op::strb2;
762
763 //STRH(1)
764 if((inst & 0xF800) == 0x8000) return Op::strh1;
765
766 //STRH(2)
767 if((inst & 0xFE00) == 0x5200) return Op::strh2;
768
769 //SUB(1)
770 if((inst & 0xFE00) == 0x1E00) return Op::sub1;
771
772 //SUB(2)
773 if((inst & 0xF800) == 0x3800) return Op::sub2;
774
775 //SUB(3)
776 if((inst & 0xFE00) == 0x1A00) return Op::sub3;
777
778 //SUB(4)
779 if((inst & 0xFF80) == 0xB080) return Op::sub4;
780
781 //SWI
782 if((inst & 0xFF00) == 0xDF00) return Op::swi;
783
784 //SXTB
785 if((inst & 0xFFC0) == 0xB240) return Op::sxtb;
786
787 //SXTH
788 if((inst & 0xFFC0) == 0xB200) return Op::sxth;
789
790 //TST
791 if((inst & 0xFFC0) == 0x4200) return Op::tst;
792
793 //UXTB
794 if((inst & 0xFFC0) == 0xB2C0) return Op::uxtb;
795
796 //UXTH
797 if((inst & 0xFFC0) == 0xB280) return Op::uxth;
798
799 return Op::invalid;
800}
801
802// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
803int Thumbulator::execute()
804{
805 uInt32 pc, sp, inst, ra, rb, rc, rm, rd, rn, rs, op;
806
807 pc = read_register(15);
808
809 uInt32 instructionPtr = pc - 2;
810 inst = fetch16(instructionPtr);
811
812 pc += 2;
813 write_register(15, pc);
814 DO_DISS(statusMsg << Base::HEX8 << (pc-5) << ": " << Base::HEX4 << inst << " ");
815
816#ifndef UNSAFE_OPTIMIZATIONS
817 ++instructions;
818#endif
819
820 Op decodedOp;
821#ifndef UNSAFE_OPTIMIZATIONS
822 if ((instructionPtr & 0xF0000000) == 0 && instructionPtr < romSize)
823 decodedOp = decodedRom[instructionPtr >> 1];
824 else
825 decodedOp = decodeInstructionWord(inst);
826#else
827 decodedOp = decodedRom[(instructionPtr & ROMADDMASK) >> 1];
828#endif
829
830 switch (decodedOp) {
831 //ADC
832 case Op::adc: {
833 rd = (inst >> 0) & 0x07;
834 rm = (inst >> 3) & 0x07;
835 DO_DISS(statusMsg << "adc r" << dec << rd << ",r" << dec << rm << endl);
836 ra = read_register(rd);
837 rb = read_register(rm);
838 rc = ra + rb;
839 if(cpsr & CPSR_C)
840 ++rc;
841 write_register(rd, rc);
842 do_nflag(rc);
843 do_zflag(rc);
844 if(cpsr & CPSR_C) { do_cflag(ra, rb, 1); do_vflag(ra, rb, 1); }
845 else { do_cflag(ra, rb, 0); do_vflag(ra, rb, 0); }
846 return 0;
847 }
848
849 //ADD(1) small immediate two registers
850 case Op::add1: {
851 rd = (inst >> 0) & 0x7;
852 rn = (inst >> 3) & 0x7;
853 rb = (inst >> 6) & 0x7;
854 if(rb)
855 {
856 DO_DISS(statusMsg << "adds r" << dec << rd << ",r" << dec << rn << ","
857 << "#0x" << Base::HEX2 << rb << endl);
858 ra = read_register(rn);
859 rc = ra + rb;
860 //fprintf(stderr,"0x%08X = 0x%08X + 0x%08X\n",rc,ra,rb);
861 write_register(rd, rc);
862 do_nflag(rc);
863 do_zflag(rc);
864 do_cflag(ra, rb, 0);
865 do_vflag(ra, rb, 0);
866 return 0;
867 }
868 else
869 {
870 //this is a mov
871 }
872
873 break;
874 }
875
876 //ADD(2) big immediate one register
877 case Op::add2: {
878 rb = (inst >> 0) & 0xFF;
879 rd = (inst >> 8) & 0x7;
880 DO_DISS(statusMsg << "adds r" << dec << rd << ",#0x" << Base::HEX2 << rb << endl);
881 ra = read_register(rd);
882 rc = ra + rb;
883 write_register(rd, rc);
884 do_nflag(rc);
885 do_zflag(rc);
886 do_cflag(ra, rb, 0);
887 do_vflag(ra, rb, 0);
888 return 0;
889 }
890
891 //ADD(3) three registers
892 case Op::add3: {
893 rd = (inst >> 0) & 0x7;
894 rn = (inst >> 3) & 0x7;
895 rm = (inst >> 6) & 0x7;
896 DO_DISS(statusMsg << "adds r" << dec << rd << ",r" << dec << rn << ",r" << rm << endl);
897 ra = read_register(rn);
898 rb = read_register(rm);
899 rc = ra + rb;
900 write_register(rd, rc);
901 do_nflag(rc);
902 do_zflag(rc);
903 do_cflag(ra, rb, 0);
904 do_vflag(ra, rb, 0);
905 return 0;
906 }
907
908 //ADD(4) two registers one or both high no flags
909 case Op::add4: {
910 if((inst >> 6) & 3)
911 {
912 //UNPREDICTABLE
913 }
914 rd = (inst >> 0) & 0x7;
915 rd |= (inst >> 4) & 0x8;
916 rm = (inst >> 3) & 0xF;
917 DO_DISS(statusMsg << "add r" << dec << rd << ",r" << dec << rm << endl);
918 ra = read_register(rd);
919 rb = read_register(rm);
920 rc = ra + rb;
921 if(rd == 15)
922 {
923#ifndef UNSAFE_OPTIMIZATIONS
924 if((rc & 1) == 0)
925 fatalError("add pc", pc, rc, " produced an arm address");
926#endif
927 //rc &= ~1; //write_register may do this as well
928 rc += 2; //The program counter is special
929 }
930 //fprintf(stderr,"0x%08X = 0x%08X + 0x%08X\n",rc,ra,rb);
931 write_register(rd, rc);
932 return 0;
933 }
934
935 //ADD(5) rd = pc plus immediate
936 case Op::add5: {
937 rb = (inst >> 0) & 0xFF;
938 rd = (inst >> 8) & 0x7;
939 rb <<= 2;
940 DO_DISS(statusMsg << "add r" << dec << rd << ",PC,#0x" << Base::HEX2 << rb << endl);
941 ra = read_register(15);
942 rc = (ra & (~3u)) + rb;
943 write_register(rd, rc);
944 return 0;
945 }
946
947 //ADD(6) rd = sp plus immediate
948 case Op::add6: {
949 rb = (inst >> 0) & 0xFF;
950 rd = (inst >> 8) & 0x7;
951 rb <<= 2;
952 DO_DISS(statusMsg << "add r" << dec << rd << ",SP,#0x" << Base::HEX2 << rb << endl);
953 ra = read_register(13);
954 rc = ra + rb;
955 write_register(rd, rc);
956 return 0;
957 }
958
959 //ADD(7) sp plus immediate
960 case Op::add7: {
961 rb = (inst >> 0) & 0x7F;
962 rb <<= 2;
963 DO_DISS(statusMsg << "add SP,#0x" << Base::HEX2 << rb << endl);
964 ra = read_register(13);
965 rc = ra + rb;
966 write_register(13, rc);
967 return 0;
968 }
969
970 //AND
971 case Op::and_: {
972 rd = (inst >> 0) & 0x7;
973 rm = (inst >> 3) & 0x7;
974 DO_DISS(statusMsg << "ands r" << dec << rd << ",r" << dec << rm << endl);
975 ra = read_register(rd);
976 rb = read_register(rm);
977 rc = ra & rb;
978 write_register(rd, rc);
979 do_nflag(rc);
980 do_zflag(rc);
981 return 0;
982 }
983
984 //ASR(1) two register immediate
985 case Op::asr1: {
986 rd = (inst >> 0) & 0x07;
987 rm = (inst >> 3) & 0x07;
988 rb = (inst >> 6) & 0x1F;
989 DO_DISS(statusMsg << "asrs r" << dec << rd << ",r" << dec << rm << ",#0x" << Base::HEX2 << rb << endl);
990 rc = read_register(rm);
991 if(rb == 0)
992 {
993 if(rc & 0x80000000)
994 {
995 do_cflag_bit(1);
996 rc = ~0u;
997 }
998 else
999 {
1000 do_cflag_bit(0);
1001 rc = 0;
1002 }
1003 }
1004 else
1005 {
1006 do_cflag_bit(rc & (1 << (rb-1)));
1007 ra = rc & 0x80000000;
1008 rc >>= rb;
1009 if(ra) //asr, sign is shifted in
1010 rc |= (~0u) << (32-rb);
1011 }
1012 write_register(rd, rc);
1013 do_nflag(rc);
1014 do_zflag(rc);
1015 return 0;
1016 }
1017
1018 //ASR(2) two register
1019 case Op::asr2: {
1020 rd = (inst >> 0) & 0x07;
1021 rs = (inst >> 3) & 0x07;
1022 DO_DISS(statusMsg << "asrs r" << dec << rd << ",r" << dec << rs << endl);
1023 rc = read_register(rd);
1024 rb = read_register(rs);
1025 rb &= 0xFF;
1026 if(rb == 0)
1027 {
1028 }
1029 else if(rb < 32)
1030 {
1031 do_cflag_bit(rc & (1 << (rb-1)));
1032 ra = rc & 0x80000000;
1033 rc >>= rb;
1034 if(ra) //asr, sign is shifted in
1035 {
1036 rc |= (~0u) << (32-rb);
1037 }
1038 }
1039 else
1040 {
1041 if(rc & 0x80000000)
1042 {
1043 do_cflag_bit(1);
1044 rc = (~0u);
1045 }
1046 else
1047 {
1048 do_cflag_bit(0);
1049 rc = 0;
1050 }
1051 }
1052 write_register(rd, rc);
1053 do_nflag(rc);
1054 do_zflag(rc);
1055 return 0;
1056 }
1057
1058 //B(1) conditional branch
1059 case Op::b1: {
1060 rb = (inst >> 0) & 0xFF;
1061 if(rb & 0x80)
1062 rb |= (~0u) << 8;
1063 op=(inst >> 8) & 0xF;
1064 rb <<= 1;
1065 rb += pc;
1066 rb += 2;
1067 switch(op)
1068 {
1069 case 0x0: //b eq z set
1070 DO_DISS(statusMsg << "beq 0x" << Base::HEX8 << (rb-3) << endl);
1071 if(cpsr & CPSR_Z)
1072 write_register(15, rb);
1073 return 0;
1074
1075 case 0x1: //b ne z clear
1076 DO_DISS(statusMsg << "bne 0x" << Base::HEX8 << (rb-3) << endl);
1077 if(!(cpsr & CPSR_Z))
1078 write_register(15, rb);
1079 return 0;
1080
1081 case 0x2: //b cs c set
1082 DO_DISS(statusMsg << "bcs 0x" << Base::HEX8 << (rb-3) << endl);
1083 if(cpsr & CPSR_C)
1084 write_register(15, rb);
1085 return 0;
1086
1087 case 0x3: //b cc c clear
1088 DO_DISS(statusMsg << "bcc 0x" << Base::HEX8 << (rb-3) << endl);
1089 if(!(cpsr & CPSR_C))
1090 write_register(15, rb);
1091 return 0;
1092
1093 case 0x4: //b mi n set
1094 DO_DISS(statusMsg << "bmi 0x" << Base::HEX8 << (rb-3) << endl);
1095 if(cpsr & CPSR_N)
1096 write_register(15, rb);
1097 return 0;
1098
1099 case 0x5: //b pl n clear
1100 DO_DISS(statusMsg << "bpl 0x" << Base::HEX8 << (rb-3) << endl);
1101 if(!(cpsr & CPSR_N))
1102 write_register(15, rb);
1103 return 0;
1104
1105 case 0x6: //b vs v set
1106 DO_DISS(statusMsg << "bvs 0x" << Base::HEX8 << (rb-3) << endl);
1107 if(cpsr & CPSR_V)
1108 write_register(15,rb);
1109 return 0;
1110
1111 case 0x7: //b vc v clear
1112 DO_DISS(statusMsg << "bvc 0x" << Base::HEX8 << (rb-3) << endl);
1113 if(!(cpsr & CPSR_V))
1114 write_register(15, rb);
1115 return 0;
1116
1117 case 0x8: //b hi c set z clear
1118 DO_DISS(statusMsg << "bhi 0x" << Base::HEX8 << (rb-3) << endl);
1119 if((cpsr & CPSR_C) && (!(cpsr & CPSR_Z)))
1120 write_register(15, rb);
1121 return 0;
1122
1123 case 0x9: //b ls c clear or z set
1124 DO_DISS(statusMsg << "bls 0x" << Base::HEX8 << (rb-3) << endl);
1125 if((cpsr & CPSR_Z) || (!(cpsr & CPSR_C)))
1126 write_register(15, rb);
1127 return 0;
1128
1129 case 0xA: //b ge N == V
1130 DO_DISS(statusMsg << "bge 0x" << Base::HEX8 << (rb-3) << endl);
1131 if(((cpsr & CPSR_N) && (cpsr & CPSR_V)) ||
1132 ((!(cpsr & CPSR_N)) && (!(cpsr & CPSR_V))))
1133 write_register(15, rb);
1134 return 0;
1135
1136 case 0xB: //b lt N != V
1137 DO_DISS(statusMsg << "blt 0x" << Base::HEX8 << (rb-3) << endl);
1138 if((!(cpsr & CPSR_N) && (cpsr & CPSR_V)) ||
1139 (((cpsr & CPSR_N)) && !(cpsr & CPSR_V)))
1140 write_register(15, rb);
1141 return 0;
1142
1143 case 0xC: //b gt Z==0 and N == V
1144 DO_DISS(statusMsg << "bgt 0x" << Base::HEX8 << (rb-3) << endl);
1145 if(!(cpsr & CPSR_Z))
1146 {
1147 if(((cpsr & CPSR_N) && (cpsr & CPSR_V)) ||
1148 ((!(cpsr & CPSR_N)) && (!(cpsr & CPSR_V))))
1149 write_register(15, rb);
1150 }
1151 return 0;
1152
1153 case 0xD: //b le Z==1 or N != V
1154 DO_DISS(statusMsg << "ble 0x" << Base::HEX8 << (rb-3) << endl);
1155 if((cpsr & CPSR_Z) ||
1156 (!(cpsr & CPSR_N) && (cpsr & CPSR_V)) ||
1157 (((cpsr & CPSR_N)) && !(cpsr & CPSR_V)))
1158 write_register(15, rb);
1159 return 0;
1160
1161 case 0xE:
1162 //undefined instruction
1163 break;
1164
1165 case 0xF:
1166 //swi
1167 break;
1168 }
1169
1170 break;
1171 }
1172
1173 //B(2) unconditional branch
1174 case Op::b2: {
1175 rb = (inst >> 0) & 0x7FF;
1176 if(rb & (1 << 10))
1177 rb |= (~0u) << 11;
1178 rb <<= 1;
1179 rb += pc;
1180 rb += 2;
1181 DO_DISS(statusMsg << "B 0x" << Base::HEX8 << (rb-3) << endl);
1182 write_register(15, rb);
1183 return 0;
1184 }
1185
1186 //BIC
1187 case Op::bic: {
1188 rd = (inst >> 0) & 0x7;
1189 rm = (inst >> 3) & 0x7;
1190 DO_DISS(statusMsg << "bics r" << dec << rd << ",r" << dec << rm << endl);
1191 ra = read_register(rd);
1192 rb = read_register(rm);
1193 rc = ra & (~rb);
1194 write_register(rd, rc);
1195 do_nflag(rc);
1196 do_zflag(rc);
1197 return 0;
1198 }
1199
1200#ifndef UNSAFE_OPTIMIZATIONS
1201 //BKPT
1202 case Op::bkpt: {
1203 rb = (inst >> 0) & 0xFF;
1204 statusMsg << "bkpt 0x" << Base::HEX2 << rb << endl;
1205 return 1;
1206 }
1207#endif
1208
1209 //BL/BLX(1)
1210 case Op::blx1: {
1211 if((inst & 0x1800) == 0x1000) //H=b10
1212 {
1213 DO_DISS(statusMsg << endl);
1214 rb = inst & ((1 << 11) - 1);
1215 if(rb & 1<<10) rb |= (~((1 << 11) - 1)); //sign extend
1216 rb <<= 12;
1217 rb += pc;
1218 write_register(14, rb);
1219 return 0;
1220 }
1221 else if((inst & 0x1800) == 0x1800) //H=b11
1222 {
1223 //branch to thumb
1224 rb = read_register(14);
1225 rb += (inst & ((1 << 11) - 1)) << 1;
1226 rb += 2;
1227 DO_DISS(statusMsg << "bl 0x" << Base::HEX8 << (rb-3) << endl);
1228 write_register(14, (pc-2) | 1);
1229 write_register(15, rb);
1230 return 0;
1231 }
1232 else if((inst & 0x1800) == 0x0800) //H=b01
1233 {
1234 //fprintf(stderr,"cannot branch to arm 0x%08X 0x%04X\n",pc,inst);
1235 // fxq: this should exit the code without having to detect it
1236 rb = read_register(14);
1237 rb += (inst & ((1 << 11) - 1)) << 1;
1238 rb &= 0xFFFFFFFC;
1239 rb += 2;
1240 DO_DISS(statusMsg << "bl 0x" << Base::HEX8 << (rb-3) << endl);
1241 write_register(14, (pc-2) | 1);
1242 write_register(15, rb);
1243 return 0;
1244 }
1245
1246 break;
1247 }
1248
1249 //BLX(2)
1250 case Op::blx2: {
1251 rm = (inst >> 3) & 0xF;
1252 DO_DISS(statusMsg << "blx r" << dec << rm << endl);
1253 rc = read_register(rm);
1254 //fprintf(stderr,"blx r%u 0x%X 0x%X\n",rm,rc,pc);
1255 rc += 2;
1256 if(rc & 1)
1257 {
1258 write_register(14, (pc-2) | 1);
1259 //rc &= ~1;
1260 write_register(15, rc);
1261 return 0;
1262 }
1263 else
1264 {
1265 //fprintf(stderr,"cannot branch to arm 0x%08X 0x%04X\n",pc,inst);
1266 // fxq: this could serve as exit code
1267 return 1;
1268 }
1269 }
1270
1271 //BX
1272 case Op::bx: {
1273 rm = (inst >> 3) & 0xF;
1274 DO_DISS(statusMsg << "bx r" << dec << rm << endl);
1275 rc = read_register(rm);
1276 rc += 2;
1277 //fprintf(stderr,"bx r%u 0x%X 0x%X\n",rm,rc,pc);
1278 if(rc & 1)
1279 {
1280 // branch to odd address denotes 16 bit ARM code
1281 //rc &= ~1;
1282 write_register(15, rc);
1283 return 0;
1284 }
1285 else
1286 {
1287 // branch to even address denotes 32 bit ARM code, which the Thumbulator
1288 // class does not support. So capture relavent information and hand it
1289 // off to the Cartridge class for it to handle.
1290
1291 bool handled = false;
1292
1293 switch(configuration)
1294 {
1295 case ConfigureFor::BUS:
1296 // this subroutine interface is used in the BUS driver,
1297 // it starts at address 0x000006d8
1298 // _SetNote:
1299 // ldr r4, =NoteStore
1300 // bx r4 // bx instruction at 0x000006da
1301 // _ResetWave:
1302 // ldr r4, =ResetWaveStore
1303 // bx r4 // bx instruction at 0x000006de
1304 // _GetWavePtr:
1305 // ldr r4, =WavePtrFetch
1306 // bx r4 // bx instruction at 0x000006e2
1307 // _SetWaveSize:
1308 // ldr r4, =WaveSizeStore
1309 // bx r4 // bx instruction at 0x000006e6
1310
1311 // address to test for is + 4 due to pipelining
1312
1313 #define BUS_SetNote (0x000006da + 4)
1314 #define BUS_ResetWave (0x000006de + 4)
1315 #define BUS_GetWavePtr (0x000006e2 + 4)
1316 #define BUS_SetWaveSize (0x000006e6 + 4)
1317
1318 if (pc == BUS_SetNote)
1319 {
1320 myCartridge->thumbCallback(0, read_register(2), read_register(3));
1321 handled = true;
1322 }
1323 else if (pc == BUS_ResetWave)
1324 {
1325 myCartridge->thumbCallback(1, read_register(2), 0);
1326 handled = true;
1327 }
1328 else if (pc == BUS_GetWavePtr)
1329 {
1330 write_register(2, myCartridge->thumbCallback(2, read_register(2), 0));
1331 handled = true;
1332 }
1333 else if (pc == BUS_SetWaveSize)
1334 {
1335 myCartridge->thumbCallback(3, read_register(2), read_register(3));
1336 handled = true;
1337 }
1338 else if (pc == 0x0000083a)
1339 {
1340 // exiting Custom ARM code, returning to BUS Driver control
1341 }
1342 else
1343 {
1344 #if 0 // uncomment this for testing
1345 uInt32 r0 = read_register(0);
1346 uInt32 r1 = read_register(1);
1347 uInt32 r2 = read_register(2);
1348 uInt32 r3 = read_register(3);
1349 uInt32 r4 = read_register(4);
1350 #endif
1351 myCartridge->thumbCallback(255, 0, 0);
1352 }
1353
1354 break;
1355
1356 case ConfigureFor::CDF:
1357 // this subroutine interface is used in the CDF driver,
1358 // it starts at address 0x000006e0
1359 // _SetNote:
1360 // ldr r4, =NoteStore
1361 // bx r4 // bx instruction at 0x000006e2
1362 // _ResetWave:
1363 // ldr r4, =ResetWaveStore
1364 // bx r4 // bx instruction at 0x000006e6
1365 // _GetWavePtr:
1366 // ldr r4, =WavePtrFetch
1367 // bx r4 // bx instruction at 0x000006ea
1368 // _SetWaveSize:
1369 // ldr r4, =WaveSizeStore
1370 // bx r4 // bx instruction at 0x000006ee
1371
1372 // address to test for is + 4 due to pipelining
1373
1374 #define CDF_SetNote (0x000006e2 + 4)
1375 #define CDF_ResetWave (0x000006e6 + 4)
1376 #define CDF_GetWavePtr (0x000006ea + 4)
1377 #define CDF_SetWaveSize (0x000006ee + 4)
1378
1379 if (pc == CDF_SetNote)
1380 {
1381 myCartridge->thumbCallback(0, read_register(2), read_register(3));
1382 handled = true;
1383 }
1384 else if (pc == CDF_ResetWave)
1385 {
1386 myCartridge->thumbCallback(1, read_register(2), 0);
1387 handled = true;
1388 }
1389 else if (pc == CDF_GetWavePtr)
1390 {
1391 write_register(2, myCartridge->thumbCallback(2, read_register(2), 0));
1392 handled = true;
1393 }
1394 else if (pc == CDF_SetWaveSize)
1395 {
1396 myCartridge->thumbCallback(3, read_register(2), read_register(3));
1397 handled = true;
1398 }
1399 else if (pc == 0x0000083a)
1400 {
1401 // exiting Custom ARM code, returning to BUS Driver control
1402 }
1403 else
1404 {
1405 #if 0 // uncomment this for testing
1406 uInt32 r0 = read_register(0);
1407 uInt32 r1 = read_register(1);
1408 uInt32 r2 = read_register(2);
1409 uInt32 r3 = read_register(3);
1410 uInt32 r4 = read_register(4);
1411 #endif
1412 myCartridge->thumbCallback(255, 0, 0);
1413 }
1414
1415 break;
1416
1417 case ConfigureFor::CDF1:
1418 case ConfigureFor::CDFJ:
1419 // this subroutine interface is used in the CDF driver,
1420 // it starts at address 0x00000750
1421 // _SetNote:
1422 // ldr r4, =NoteStore
1423 // bx r4 // bx instruction at 0x000006e2
1424 // _ResetWave:
1425 // ldr r4, =ResetWaveStore
1426 // bx r4 // bx instruction at 0x000006e6
1427 // _GetWavePtr:
1428 // ldr r4, =WavePtrFetch
1429 // bx r4 // bx instruction at 0x000006ea
1430 // _SetWaveSize:
1431 // ldr r4, =WaveSizeStore
1432 // bx r4 // bx instruction at 0x000006ee
1433
1434 // address to test for is + 4 due to pipelining
1435
1436 #define CDF1_SetNote (0x00000752 + 4)
1437 #define CDF1_ResetWave (0x00000756 + 4)
1438 #define CDF1_GetWavePtr (0x0000075a + 4)
1439 #define CDF1_SetWaveSize (0x0000075e + 4)
1440
1441 if (pc == CDF1_SetNote)
1442 {
1443 myCartridge->thumbCallback(0, read_register(2), read_register(3));
1444 handled = true;
1445 }
1446 else if (pc == CDF1_ResetWave)
1447 {
1448 myCartridge->thumbCallback(1, read_register(2), 0);
1449 handled = true;
1450 }
1451 else if (pc == CDF1_GetWavePtr)
1452 {
1453 write_register(2, myCartridge->thumbCallback(2, read_register(2), 0));
1454 handled = true;
1455 }
1456 else if (pc == CDF1_SetWaveSize)
1457 {
1458 myCartridge->thumbCallback(3, read_register(2), read_register(3));
1459 handled = true;
1460 }
1461 else if (pc == 0x0000083a)
1462 {
1463 // exiting Custom ARM code, returning to BUS Driver control
1464 }
1465 else
1466 {
1467 #if 0 // uncomment this for testing
1468 uInt32 r0 = read_register(0);
1469 uInt32 r1 = read_register(1);
1470 uInt32 r2 = read_register(2);
1471 uInt32 r3 = read_register(3);
1472 uInt32 r4 = read_register(4);
1473 #endif
1474 myCartridge->thumbCallback(255, 0, 0);
1475 }
1476
1477 break;
1478
1479 case ConfigureFor::DPCplus:
1480 // no 32-bit subroutines in DPC+
1481 break;
1482 }
1483
1484 if (handled)
1485 {
1486 rc = read_register(14); // lr
1487 rc += 2;
1488 //rc &= ~1;
1489 write_register(15, rc);
1490 return 0;
1491 }
1492
1493 return 1;
1494 }
1495 }
1496
1497 //CMN
1498 case Op::cmn: {
1499 rn = (inst >> 0) & 0x7;
1500 rm = (inst >> 3) & 0x7;
1501 DO_DISS(statusMsg << "cmns r" << dec << rn << ",r" << dec << rm << endl);
1502 ra = read_register(rn);
1503 rb = read_register(rm);
1504 rc = ra + rb;
1505 do_nflag(rc);
1506 do_zflag(rc);
1507 do_cflag(ra, rb, 0);
1508 do_vflag(ra, rb, 0);
1509 return 0;
1510 }
1511
1512 //CMP(1) compare immediate
1513 case Op::cmp1: {
1514 rb = (inst >> 0) & 0xFF;
1515 rn = (inst >> 8) & 0x07;
1516 DO_DISS(statusMsg << "cmp r" << dec << rn << ",#0x" << Base::HEX2 << rb << endl);
1517 ra = read_register(rn);
1518 rc = ra - rb;
1519 //fprintf(stderr,"0x%08X 0x%08X\n",ra,rb);
1520 do_nflag(rc);
1521 do_zflag(rc);
1522 do_cflag(ra, ~rb, 1);
1523 do_vflag(ra, ~rb, 1);
1524 return 0;
1525 }
1526
1527 //CMP(2) compare register
1528 case Op::cmp2: {
1529 rn = (inst >> 0) & 0x7;
1530 rm = (inst >> 3) & 0x7;
1531 DO_DISS(statusMsg << "cmps r" << dec << rn << ",r" << dec << rm << endl);
1532 ra = read_register(rn);
1533 rb = read_register(rm);
1534 rc = ra - rb;
1535 //fprintf(stderr,"0x%08X 0x%08X\n",ra,rb);
1536 do_nflag(rc);
1537 do_zflag(rc);
1538 do_cflag(ra, ~rb, 1);
1539 do_vflag(ra, ~rb, 1);
1540 return 0;
1541 }
1542
1543 //CMP(3) compare high register
1544 case Op::cmp3: {
1545 if(((inst >> 6) & 3) == 0x0)
1546 {
1547 //UNPREDICTABLE
1548 }
1549 rn = (inst >> 0) & 0x7;
1550 rn |= (inst >> 4) & 0x8;
1551 if(rn == 0xF)
1552 {
1553 //UNPREDICTABLE
1554 }
1555 rm = (inst >> 3) & 0xF;
1556 DO_DISS(statusMsg << "cmps r" << dec << rn << ",r" << dec << rm << endl);
1557 ra = read_register(rn);
1558 rb = read_register(rm);
1559 rc = ra - rb;
1560 do_nflag(rc);
1561 do_zflag(rc);
1562 do_cflag(ra, ~rb, 1);
1563 do_vflag(ra, ~rb, 1);
1564 return 0;
1565 }
1566
1567#ifndef UNSAFE_OPTIMIZATIONS
1568 //CPS
1569 case Op::cps: {
1570 DO_DISS(statusMsg << "cps TODO" << endl);
1571 return 1;
1572 }
1573#endif
1574
1575 //CPY copy high register
1576 case Op::cpy: {
1577 //same as mov except you can use both low registers
1578 //going to let mov handle high registers
1579 rd = (inst >> 0) & 0x7;
1580 rm = (inst >> 3) & 0x7;
1581 DO_DISS(statusMsg << "cpy r" << dec << rd << ",r" << dec << rm << endl);
1582 rc = read_register(rm);
1583 write_register(rd, rc);
1584 return 0;
1585 }
1586
1587 //EOR
1588 case Op::eor: {
1589 rd = (inst >> 0) & 0x7;
1590 rm = (inst >> 3) & 0x7;
1591 DO_DISS(statusMsg << "eors r" << dec << rd << ",r" << dec << rm << endl);
1592 ra = read_register(rd);
1593 rb = read_register(rm);
1594 rc = ra ^ rb;
1595 write_register(rd, rc);
1596 do_nflag(rc);
1597 do_zflag(rc);
1598 return 0;
1599 }
1600
1601 //LDMIA
1602 case Op::ldmia: {
1603 rn = (inst >> 8) & 0x7;
1604 #if defined(THUMB_DISS)
1605 statusMsg << "ldmia r" << dec << rn << "!,{";
1606 for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,++ra)
1607 {
1608 if(inst&rb)
1609 {
1610 if(rc) statusMsg << ",";
1611 statusMsg << "r" << dec << ra;
1612 rc++;
1613 }
1614 }
1615 statusMsg << "}" << endl;
1616 #endif
1617 sp = read_register(rn);
1618 for(ra = 0, rb = 0x01; rb; rb = (rb << 1) & 0xFF, ++ra)
1619 {
1620 if(inst & rb)
1621 {
1622 write_register(ra, read32(sp));
1623 sp += 4;
1624 }
1625 }
1626 //there is a write back exception.
1627 if((inst & (1 << rn)) == 0)
1628 write_register(rn, sp);
1629
1630 return 0;
1631 }
1632
1633 //LDR(1) two register immediate
1634 case Op::ldr1: {
1635 rd = (inst >> 0) & 0x07;
1636 rn = (inst >> 3) & 0x07;
1637 rb = (inst >> 6) & 0x1F;
1638 rb <<= 2;
1639 DO_DISS(statusMsg << "ldr r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
1640 rb = read_register(rn) + rb;
1641 rc = read32(rb);
1642 write_register(rd, rc);
1643 return 0;
1644 }
1645
1646 //LDR(2) three register
1647 case Op::ldr2: {
1648 rd = (inst >> 0) & 0x7;
1649 rn = (inst >> 3) & 0x7;
1650 rm = (inst >> 6) & 0x7;
1651 DO_DISS(statusMsg << "ldr r" << dec << rd << ",[r" << dec << rn << ",r" << dec << "]" << endl);
1652 rb = read_register(rn) + read_register(rm);
1653 rc = read32(rb);
1654 write_register(rd, rc);
1655 return 0;
1656 }
1657
1658 //LDR(3)
1659 case Op::ldr3: {
1660 rb = (inst >> 0) & 0xFF;
1661 rd = (inst >> 8) & 0x07;
1662 rb <<= 2;
1663 DO_DISS(statusMsg << "ldr r" << dec << rd << ",[PC+#0x" << Base::HEX2 << rb << "] ");
1664 ra = read_register(15);
1665 ra &= ~3;
1666 rb += ra;
1667 DO_DISS(statusMsg << ";@ 0x" << Base::HEX2 << rb << endl);
1668 rc = read32(rb);
1669 write_register(rd, rc);
1670 return 0;
1671 }
1672
1673 //LDR(4)
1674 case Op::ldr4: {
1675 rb = (inst >> 0) & 0xFF;
1676 rd = (inst >> 8) & 0x07;
1677 rb <<= 2;
1678 DO_DISS(statusMsg << "ldr r" << dec << rd << ",[SP+#0x" << Base::HEX2 << rb << "]" << endl);
1679 ra = read_register(13);
1680 //ra&=~3;
1681 rb += ra;
1682 rc = read32(rb);
1683 write_register(rd, rc);
1684 return 0;
1685 }
1686
1687 //LDRB(1)
1688 case Op::ldrb1: {
1689 rd = (inst >> 0) & 0x07;
1690 rn = (inst >> 3) & 0x07;
1691 rb = (inst >> 6) & 0x1F;
1692 DO_DISS(statusMsg << "ldrb r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
1693 rb = read_register(rn) + rb;
1694#ifndef UNSAFE_OPTIMIZATIONS
1695 rc = read16(rb & (~1u));
1696#else
1697 rc = read16(rb);
1698#endif
1699 if(rb & 1)
1700 {
1701 rc >>= 8;
1702 }
1703 else
1704 {
1705 }
1706 write_register(rd, rc & 0xFF);
1707 return 0;
1708 }
1709
1710 //LDRB(2)
1711 case Op::ldrb2: {
1712 rd = (inst >> 0) & 0x7;
1713 rn = (inst >> 3) & 0x7;
1714 rm = (inst >> 6) & 0x7;
1715 DO_DISS(statusMsg << "ldrb r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl);
1716 rb = read_register(rn) + read_register(rm);
1717#ifndef UNSAFE_OPTIMIZATIONS
1718 rc = read16(rb & (~1u));
1719#else
1720 rc = read16(rb);
1721#endif
1722 if(rb & 1)
1723 {
1724 rc >>= 8;
1725 }
1726 write_register(rd, rc & 0xFF);
1727 return 0;
1728 }
1729
1730 //LDRH(1)
1731 case Op::ldrh1: {
1732 rd = (inst >> 0) & 0x07;
1733 rn = (inst >> 3) & 0x07;
1734 rb = (inst >> 6) & 0x1F;
1735 rb <<= 1;
1736 DO_DISS(statusMsg << "ldrh r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
1737 rb = read_register(rn) + rb;
1738 rc = read16(rb);
1739 write_register(rd, rc & 0xFFFF);
1740 return 0;
1741 }
1742
1743 //LDRH(2)
1744 case Op::ldrh2: {
1745 rd = (inst >> 0) & 0x7;
1746 rn = (inst >> 3) & 0x7;
1747 rm = (inst >> 6) & 0x7;
1748 DO_DISS(statusMsg << "ldrh r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl);
1749 rb = read_register(rn) + read_register(rm);
1750 rc = read16(rb);
1751 write_register(rd, rc & 0xFFFF);
1752 return 0;
1753 }
1754
1755 //LDRSB
1756 case Op::ldrsb: {
1757 rd = (inst >> 0) & 0x7;
1758 rn = (inst >> 3) & 0x7;
1759 rm = (inst >> 6) & 0x7;
1760 DO_DISS(statusMsg << "ldrsb r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl);
1761 rb = read_register(rn) + read_register(rm);
1762#ifndef UNSAFE_OPTIMIZATIONS
1763 rc = read16(rb & (~1u));
1764#else
1765 rc = read16(rb);
1766#endif
1767 if(rb & 1)
1768 {
1769 rc >>= 8;
1770 }
1771 rc &= 0xFF;
1772 if(rc & 0x80)
1773 rc |= ((~0u) << 8);
1774 write_register(rd, rc);
1775 return 0;
1776 }
1777
1778 //LDRSH
1779 case Op::ldrsh: {
1780 rd = (inst >> 0) & 0x7;
1781 rn = (inst >> 3) & 0x7;
1782 rm = (inst >> 6) & 0x7;
1783 DO_DISS(statusMsg << "ldrsh r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl);
1784 rb = read_register(rn) + read_register(rm);
1785 rc = read16(rb);
1786 rc &= 0xFFFF;
1787 if(rc & 0x8000)
1788 rc |= ((~0u) << 16);
1789 write_register(rd, rc);
1790 return 0;
1791 }
1792
1793 //LSL(1)
1794 case Op::lsl1: {
1795 rd = (inst >> 0) & 0x07;
1796 rm = (inst >> 3) & 0x07;
1797 rb = (inst >> 6) & 0x1F;
1798 DO_DISS(statusMsg << "lsls r" << dec << rd << ",r" << dec << rm << ",#0x" << Base::HEX2 << rb << endl);
1799 rc = read_register(rm);
1800 if(rb == 0)
1801 {
1802 //if immed_5 == 0
1803 //C unaffected
1804 //result not shifted
1805 }
1806 else
1807 {
1808 //else immed_5 > 0
1809 do_cflag_bit(rc & (1 << (32-rb)));
1810 rc <<= rb;
1811 }
1812 write_register(rd, rc);
1813 do_nflag(rc);
1814 do_zflag(rc);
1815 return 0;
1816 }
1817
1818 //LSL(2) two register
1819 case Op::lsl2: {
1820 rd = (inst >> 0) & 0x07;
1821 rs = (inst >> 3) & 0x07;
1822 DO_DISS(statusMsg << "lsls r" << dec << rd << ",r" << dec << rs << endl);
1823 rc = read_register(rd);
1824 rb = read_register(rs);
1825 rb &= 0xFF;
1826 if(rb == 0)
1827 {
1828 }
1829 else if(rb < 32)
1830 {
1831 do_cflag_bit(rc & (1 << (32-rb)));
1832 rc <<= rb;
1833 }
1834 else if(rb == 32)
1835 {
1836 do_cflag_bit(rc & 1);
1837 rc = 0;
1838 }
1839 else
1840 {
1841 do_cflag_bit(0);
1842 rc = 0;
1843 }
1844 write_register(rd, rc);
1845 do_nflag(rc);
1846 do_zflag(rc);
1847 return 0;
1848 }
1849
1850 //LSR(1) two register immediate
1851 case Op::lsr1: {
1852 rd = (inst >> 0) & 0x07;
1853 rm = (inst >> 3) & 0x07;
1854 rb = (inst >> 6) & 0x1F;
1855 DO_DISS(statusMsg << "lsrs r" << dec << rd << ",r" << dec << rm << ",#0x" << Base::HEX2 << rb << endl);
1856 rc = read_register(rm);
1857 if(rb == 0)
1858 {
1859 do_cflag_bit(rc & 0x80000000);
1860 rc = 0;
1861 }
1862 else
1863 {
1864 do_cflag_bit(rc & (1 << (rb-1)));
1865 rc >>= rb;
1866 }
1867 write_register(rd, rc);
1868 do_nflag(rc);
1869 do_zflag(rc);
1870 return 0;
1871 }
1872
1873 //LSR(2) two register
1874 case Op::lsr2: {
1875 rd = (inst >> 0) & 0x07;
1876 rs = (inst >> 3) & 0x07;
1877 DO_DISS(statusMsg << "lsrs r" << dec << rd << ",r" << dec << rs << endl);
1878 rc = read_register(rd);
1879 rb = read_register(rs);
1880 rb &= 0xFF;
1881 if(rb == 0)
1882 {
1883 }
1884 else if(rb < 32)
1885 {
1886 do_cflag_bit(rc & (1 << (rb-1)));
1887 rc >>= rb;
1888 }
1889 else if(rb == 32)
1890 {
1891 do_cflag_bit(rc & 0x80000000);
1892 rc = 0;
1893 }
1894 else
1895 {
1896 do_cflag_bit(0);
1897 rc = 0;
1898 }
1899 write_register(rd, rc);
1900 do_nflag(rc);
1901 do_zflag(rc);
1902 return 0;
1903 }
1904
1905 //MOV(1) immediate
1906 case Op::mov1: {
1907 rb = (inst >> 0) & 0xFF;
1908 rd = (inst >> 8) & 0x07;
1909 DO_DISS(statusMsg << "movs r" << dec << rd << ",#0x" << Base::HEX2 << rb << endl);
1910 write_register(rd, rb);
1911 do_nflag(rb);
1912 do_zflag(rb);
1913 return 0;
1914 }
1915
1916 //MOV(2) two low registers
1917 case Op::mov2: {
1918 rd = (inst >> 0) & 7;
1919 rn = (inst >> 3) & 7;
1920 DO_DISS(statusMsg << "movs r" << dec << rd << ",r" << dec << rn << endl);
1921 rc = read_register(rn);
1922 //fprintf(stderr,"0x%08X\n",rc);
1923 write_register(rd, rc);
1924 do_nflag(rc);
1925 do_zflag(rc);
1926 do_cflag_bit(0);
1927 do_vflag_bit(0);
1928 return 0;
1929 }
1930
1931 //MOV(3)
1932 case Op::mov3: {
1933 rd = (inst >> 0) & 0x7;
1934 rd |= (inst >> 4) & 0x8;
1935 rm = (inst >> 3) & 0xF;
1936 DO_DISS(statusMsg << "mov r" << dec << rd << ",r" << dec << rm << endl);
1937 rc = read_register(rm);
1938 if((rd == 14) && (rm == 15))
1939 {
1940 //printf("mov lr,pc warning 0x%08X\n",pc-2);
1941 //rc|=1;
1942 }
1943 if(rd == 15)
1944 {
1945 //rc &= ~1; //write_register may do this as well
1946 rc += 2; //The program counter is special
1947 }
1948 write_register(rd, rc);
1949 return 0;
1950 }
1951
1952 //MUL
1953 case Op::mul: {
1954 rd = (inst >> 0) & 0x7;
1955 rm = (inst >> 3) & 0x7;
1956 DO_DISS(statusMsg << "muls r" << dec << rd << ",r" << dec << rm << endl);
1957 ra = read_register(rd);
1958 rb = read_register(rm);
1959 rc = ra * rb;
1960 write_register(rd, rc);
1961 do_nflag(rc);
1962 do_zflag(rc);
1963 return 0;
1964 }
1965
1966 //MVN
1967 case Op::mvn: {
1968 rd = (inst >> 0) & 0x7;
1969 rm = (inst >> 3) & 0x7;
1970 DO_DISS(statusMsg << "mvns r" << dec << rd << ",r" << dec << rm << endl);
1971 ra = read_register(rm);
1972 rc = (~ra);
1973 write_register(rd, rc);
1974 do_nflag(rc);
1975 do_zflag(rc);
1976 return 0;
1977 }
1978
1979 //NEG
1980 case Op::neg: {
1981 rd = (inst >> 0) & 0x7;
1982 rm = (inst >> 3) & 0x7;
1983 DO_DISS(statusMsg << "negs r" << dec << rd << ",r" << dec << rm << endl);
1984 ra = read_register(rm);
1985 rc = 0 - ra;
1986 write_register(rd, rc);
1987 do_nflag(rc);
1988 do_zflag(rc);
1989 do_cflag(0, ~ra, 1);
1990 do_vflag(0, ~ra, 1);
1991 return 0;
1992 }
1993
1994 //ORR
1995 case Op::orr: {
1996 rd = (inst >> 0) & 0x7;
1997 rm = (inst >> 3) & 0x7;
1998 DO_DISS(statusMsg << "orrs r" << dec << rd << ",r" << dec << rm << endl);
1999 ra = read_register(rd);
2000 rb = read_register(rm);
2001 rc = ra | rb;
2002 write_register(rd, rc);
2003 do_nflag(rc);
2004 do_zflag(rc);
2005 return 0;
2006 }
2007
2008 //POP
2009 case Op::pop: {
2010 #if defined(THUMB_DISS)
2011 statusMsg << "pop {";
2012 for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,++ra)
2013 {
2014 if(inst&rb)
2015 {
2016 if(rc) statusMsg << ",";
2017 statusMsg << "r" << dec << ra;
2018 rc++;
2019 }
2020 }
2021 if(inst&0x100)
2022 {
2023 if(rc) statusMsg << ",";
2024 statusMsg << "pc";
2025 }
2026 statusMsg << "}" << endl;
2027 #endif
2028
2029 sp = read_register(13);
2030 for(ra = 0, rb = 0x01; rb; rb = (rb << 1) & 0xFF, ++ra)
2031 {
2032 if(inst & rb)
2033 {
2034 write_register(ra, read32(sp));
2035 sp += 4;
2036 }
2037 }
2038 if(inst & 0x100)
2039 {
2040 rc = read32(sp);
2041 rc += 2;
2042 write_register(15, rc);
2043 sp += 4;
2044 }
2045 write_register(13, sp);
2046 return 0;
2047 }
2048
2049 //PUSH
2050 case Op::push: {
2051 #if defined(THUMB_DISS)
2052 statusMsg << "push {";
2053 for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,++ra)
2054 {
2055 if(inst&rb)
2056 {
2057 if(rc) statusMsg << ",";
2058 statusMsg << "r" << dec << ra;
2059 rc++;
2060 }
2061 }
2062 if(inst&0x100)
2063 {
2064 if(rc) statusMsg << ",";
2065 statusMsg << "lr";
2066 }
2067 statusMsg << "}" << endl;
2068 #endif
2069
2070 sp = read_register(13);
2071 //fprintf(stderr,"sp 0x%08X\n",sp);
2072 for(ra = 0, rb = 0x01, rc = 0; rb; rb = (rb << 1) & 0xFF, ++ra)
2073 {
2074 if(inst & rb)
2075 {
2076 ++rc;
2077 }
2078 }
2079 if(inst & 0x100) ++rc;
2080 rc <<= 2;
2081 sp -= rc;
2082 rd = sp;
2083 for(ra = 0, rb = 0x01; rb; rb = (rb << 1) & 0xFF, ++ra)
2084 {
2085 if(inst & rb)
2086 {
2087 write32(rd, read_register(ra));
2088 rd += 4;
2089 }
2090 }
2091 if(inst & 0x100)
2092 {
2093 rc = read_register(14);
2094 write32(rd, rc);
2095 if((rc & 1) == 0)
2096 {
2097 // FIXME fprintf(stderr,"push {lr} with an ARM address pc 0x%08X popped 0x%08X\n",pc,rc);
2098 }
2099 }
2100 write_register(13, sp);
2101 return 0;
2102 }
2103
2104 //REV
2105 case Op::rev: {
2106 rd = (inst >> 0) & 0x7;
2107 rn = (inst >> 3) & 0x7;
2108 DO_DISS(statusMsg << "rev r" << dec << rd << ",r" << dec << rn << endl);
2109 ra = read_register(rn);
2110 rc = ((ra >> 0) & 0xFF) << 24;
2111 rc |= ((ra >> 8) & 0xFF) << 16;
2112 rc |= ((ra >> 16) & 0xFF) << 8;
2113 rc |= ((ra >> 24) & 0xFF) << 0;
2114 write_register(rd, rc);
2115 return 0;
2116 }
2117
2118 //REV16
2119 case Op::rev16: {
2120 rd = (inst >> 0) & 0x7;
2121 rn = (inst >> 3) & 0x7;
2122 DO_DISS(statusMsg << "rev16 r" << dec << rd << ",r" << dec << rn << endl);
2123 ra = read_register(rn);
2124 rc = ((ra >> 0) & 0xFF) << 8;
2125 rc |= ((ra >> 8) & 0xFF) << 0;
2126 rc |= ((ra >> 16) & 0xFF) << 24;
2127 rc |= ((ra >> 24) & 0xFF) << 16;
2128 write_register(rd, rc);
2129 return 0;
2130 }
2131
2132 //REVSH
2133 case Op::revsh: {
2134 rd = (inst >> 0) & 0x7;
2135 rn = (inst >> 3) & 0x7;
2136 DO_DISS(statusMsg << "revsh r" << dec << rd << ",r" << dec << rn << endl);
2137 ra = read_register(rn);
2138 rc = ((ra >> 0) & 0xFF) << 8;
2139 rc |= ((ra >> 8) & 0xFF) << 0;
2140 if(rc & 0x8000) rc |= 0xFFFF0000;
2141 else rc &= 0x0000FFFF;
2142 write_register(rd, rc);
2143 return 0;
2144 }
2145
2146 //ROR
2147 case Op::ror: {
2148 rd = (inst >> 0) & 0x7;
2149 rs = (inst >> 3) & 0x7;
2150 DO_DISS(statusMsg << "rors r" << dec << rd << ",r" << dec << rs << endl);
2151 rc = read_register(rd);
2152 ra = read_register(rs);
2153 ra &= 0xFF;
2154 if(ra == 0)
2155 {
2156 }
2157 else
2158 {
2159 ra &= 0x1F;
2160 if(ra == 0)
2161 {
2162 do_cflag_bit(rc & 0x80000000);
2163 }
2164 else
2165 {
2166 do_cflag_bit(rc & (1 << (ra-1)));
2167 rb = rc << (32-ra);
2168 rc >>= ra;
2169 rc |= rb;
2170 }
2171 }
2172 write_register(rd, rc);
2173 do_nflag(rc);
2174 do_zflag(rc);
2175 return 0;
2176 }
2177
2178 //SBC
2179 case Op::sbc: {
2180 rd = (inst >> 0) & 0x7;
2181 rm = (inst >> 3) & 0x7;
2182 DO_DISS(statusMsg << "sbc r" << dec << rd << ",r" << dec << rm << endl);
2183 ra = read_register(rd);
2184 rb = read_register(rm);
2185 rc = ra - rb;
2186 if(!(cpsr & CPSR_C)) --rc;
2187 write_register(rd, rc);
2188 do_nflag(rc);
2189 do_zflag(rc);
2190 if(cpsr & CPSR_C)
2191 {
2192 do_cflag(ra, ~rb, 1);
2193 do_vflag(ra, ~rb, 1);
2194 }
2195 else
2196 {
2197 do_cflag(ra, ~rb, 0);
2198 do_vflag(ra, ~rb, 0);
2199 }
2200 return 0;
2201 }
2202
2203#ifndef UNSAFE_OPTIMIZATIONS
2204 //SETEND
2205 case Op::setend: {
2206 statusMsg << "setend not implemented" << endl;
2207 return 1;
2208 }
2209#endif
2210
2211 //STMIA
2212 case Op::stmia: {
2213 rn = (inst >> 8) & 0x7;
2214 #if defined(THUMB_DISS)
2215 statusMsg << "stmia r" << dec << rn << "!,{";
2216 for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,++ra)
2217 {
2218 if(inst & rb)
2219 {
2220 if(rc) statusMsg << ",";
2221 statusMsg << "r" << dec << ra;
2222 rc++;
2223 }
2224 }
2225 statusMsg << "}" << endl;
2226 #endif
2227
2228 sp = read_register(rn);
2229 for(ra = 0, rb = 0x01; rb; rb = (rb << 1) & 0xFF, ++ra)
2230 {
2231 if(inst & rb)
2232 {
2233 write32(sp, read_register(ra));
2234 sp += 4;
2235 }
2236 }
2237 write_register(rn, sp);
2238 return 0;
2239 }
2240
2241 //STR(1)
2242 case Op::str1: {
2243 rd = (inst >> 0) & 0x07;
2244 rn = (inst >> 3) & 0x07;
2245 rb = (inst >> 6) & 0x1F;
2246 rb <<= 2;
2247 DO_DISS(statusMsg << "str r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
2248 rb = read_register(rn) + rb;
2249 rc = read_register(rd);
2250 write32(rb, rc);
2251 return 0;
2252 }
2253
2254 //STR(2)
2255 case Op::str2: {
2256 rd = (inst >> 0) & 0x7;
2257 rn = (inst >> 3) & 0x7;
2258 rm = (inst >> 6) & 0x7;
2259 DO_DISS(statusMsg << "str r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl);
2260 rb = read_register(rn) + read_register(rm);
2261 rc = read_register(rd);
2262 write32(rb, rc);
2263 return 0;
2264 }
2265
2266 //STR(3)
2267 case Op::str3: {
2268 rb = (inst >> 0) & 0xFF;
2269 rd = (inst >> 8) & 0x07;
2270 rb <<= 2;
2271 DO_DISS(statusMsg << "str r" << dec << rd << ",[SP,#0x" << Base::HEX2 << rb << "]" << endl);
2272 rb = read_register(13) + rb;
2273 //fprintf(stderr,"0x%08X\n",rb);
2274 rc = read_register(rd);
2275 write32(rb, rc);
2276 return 0;
2277 }
2278
2279 //STRB(1)
2280 case Op::strb1: {
2281 rd = (inst >> 0) & 0x07;
2282 rn = (inst >> 3) & 0x07;
2283 rb = (inst >> 6) & 0x1F;
2284 DO_DISS(statusMsg << "strb r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX8 << rb << "]" << endl);
2285 rb = read_register(rn) + rb;
2286 rc = read_register(rd);
2287#ifndef UNSAFE_OPTIMIZATIONS
2288 ra = read16(rb & (~1u));
2289#else
2290 ra = read16(rb);
2291#endif
2292 if(rb & 1)
2293 {
2294 ra &= 0x00FF;
2295 ra |= rc << 8;
2296 }
2297 else
2298 {
2299 ra &= 0xFF00;
2300 ra |= rc & 0x00FF;
2301 }
2302 write16(rb & (~1u), ra & 0xFFFF);
2303 return 0;
2304 }
2305
2306 //STRB(2)
2307 case Op::strb2: {
2308 rd = (inst >> 0) & 0x7;
2309 rn = (inst >> 3) & 0x7;
2310 rm = (inst >> 6) & 0x7;
2311 DO_DISS(statusMsg << "strb r" << dec << rd << ",[r" << dec << rn << ",r" << rm << "]" << endl);
2312 rb = read_register(rn) + read_register(rm);
2313 rc = read_register(rd);
2314#ifndef UNSAFE_OPTIMIZATIONS
2315 ra = read16(rb & (~1u));
2316#else
2317 ra = read16(rb);
2318#endif
2319 if(rb & 1)
2320 {
2321 ra &= 0x00FF;
2322 ra |= rc << 8;
2323 }
2324 else
2325 {
2326 ra &= 0xFF00;
2327 ra |= rc & 0x00FF;
2328 }
2329 write16(rb & (~1u), ra & 0xFFFF);
2330 return 0;
2331 }
2332
2333 //STRH(1)
2334 case Op::strh1: {
2335 rd = (inst >> 0) & 0x07;
2336 rn = (inst >> 3) & 0x07;
2337 rb = (inst >> 6) & 0x1F;
2338 rb <<= 1;
2339 DO_DISS(statusMsg << "strh r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
2340 rb = read_register(rn) + rb;
2341 rc= read_register(rd);
2342 write16(rb, rc & 0xFFFF);
2343 return 0;
2344 }
2345
2346 //STRH(2)
2347 case Op::strh2: {
2348 rd = (inst >> 0) & 0x7;
2349 rn = (inst >> 3) & 0x7;
2350 rm = (inst >> 6) & 0x7;
2351 DO_DISS(statusMsg << "strh r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl);
2352 rb = read_register(rn) + read_register(rm);
2353 rc = read_register(rd);
2354 write16(rb, rc & 0xFFFF);
2355 return 0;
2356 }
2357
2358 //SUB(1)
2359 case Op::sub1: {
2360 rd = (inst >> 0) & 0x7;
2361 rn = (inst >> 3) & 0x7;
2362 rb = (inst >> 6) & 0x7;
2363 DO_DISS(statusMsg << "subs r" << dec << rd << ",r" << dec << rn << ",#0x" << Base::HEX2 << rb << endl);
2364 ra = read_register(rn);
2365 rc = ra - rb;
2366 write_register(rd, rc);
2367 do_nflag(rc);
2368 do_zflag(rc);
2369 do_cflag(ra, ~rb, 1);
2370 do_vflag(ra, ~rb, 1);
2371 return 0;
2372 }
2373
2374 //SUB(2)
2375 case Op::sub2: {
2376 rb = (inst >> 0) & 0xFF;
2377 rd = (inst >> 8) & 0x07;
2378 DO_DISS(statusMsg << "subs r" << dec << rd << ",#0x" << Base::HEX2 << rb << endl);
2379 ra = read_register(rd);
2380 rc = ra - rb;
2381 write_register(rd, rc);
2382 do_nflag(rc);
2383 do_zflag(rc);
2384 do_cflag(ra, ~rb, 1);
2385 do_vflag(ra, ~rb, 1);
2386 return 0;
2387 }
2388
2389 //SUB(3)
2390 case Op::sub3: {
2391 rd = (inst >> 0) & 0x7;
2392 rn = (inst >> 3) & 0x7;
2393 rm = (inst >> 6) & 0x7;
2394 DO_DISS(statusMsg << "subs r" << dec << rd << ",r" << dec << rn << ",r" << dec << rm << endl);
2395 ra = read_register(rn);
2396 rb = read_register(rm);
2397 rc = ra - rb;
2398 write_register(rd, rc);
2399 do_nflag(rc);
2400 do_zflag(rc);
2401 do_cflag(ra, ~rb, 1);
2402 do_vflag(ra, ~rb, 1);
2403 return 0;
2404 }
2405
2406 //SUB(4)
2407 case Op::sub4: {
2408 rb = inst & 0x7F;
2409 rb <<= 2;
2410 DO_DISS(statusMsg << "sub SP,#0x" << Base::HEX2 << rb << endl);
2411 ra = read_register(13);
2412 ra -= rb;
2413 write_register(13, ra);
2414 return 0;
2415 }
2416
2417 //SWI
2418 case Op::swi: {
2419 rb = inst & 0xFF;
2420 DO_DISS(statusMsg << "swi 0x" << Base::HEX2 << rb << endl);
2421
2422 if((inst & 0xFF) == 0xCC)
2423 {
2424 write_register(0, cpsr);
2425 return 0;
2426 }
2427 else
2428 {
2429#if defined(THUMB_DISS)
2430 statusMsg << endl << endl << "swi 0x" << Base::HEX2 << rb << endl;
2431#endif
2432 return 1;
2433 }
2434 }
2435
2436 //SXTB
2437 case Op::sxtb: {
2438 rd = (inst >> 0) & 0x7;
2439 rm = (inst >> 3) & 0x7;
2440 DO_DISS(statusMsg << "sxtb r" << dec << rd << ",r" << dec << rm << endl);
2441 ra = read_register(rm);
2442 rc = ra & 0xFF;
2443 if(rc & 0x80)
2444 rc |= (~0u) << 8;
2445 write_register(rd, rc);
2446 return 0;
2447 }
2448
2449 //SXTH
2450 case Op::sxth: {
2451 rd = (inst >> 0) & 0x7;
2452 rm = (inst >> 3) & 0x7;
2453 DO_DISS(statusMsg << "sxth r" << dec << rd << ",r" << dec << rm << endl);
2454 ra = read_register(rm);
2455 rc = ra & 0xFFFF;
2456 if(rc & 0x8000)
2457 rc |= (~0u) << 16;
2458 write_register(rd, rc);
2459 return 0;
2460 }
2461
2462 //TST
2463 case Op::tst: {
2464 rn = (inst >> 0) & 0x7;
2465 rm = (inst >> 3) & 0x7;
2466 DO_DISS(statusMsg << "tst r" << dec << rn << ",r" << dec << rm << endl);
2467 ra = read_register(rn);
2468 rb = read_register(rm);
2469 rc = ra & rb;
2470 do_nflag(rc);
2471 do_zflag(rc);
2472 return 0;
2473 }
2474
2475 //UXTB
2476 case Op::uxtb: {
2477 rd = (inst >> 0) & 0x7;
2478 rm = (inst >> 3) & 0x7;
2479 DO_DISS(statusMsg << "uxtb r" << dec << rd << ",r" << dec << rm << endl);
2480 ra = read_register(rm);
2481 rc = ra & 0xFF;
2482 write_register(rd, rc);
2483 return 0;
2484 }
2485
2486 //UXTH
2487 case Op::uxth: {
2488 rd = (inst >> 0) & 0x7;
2489 rm = (inst >> 3) & 0x7;
2490 DO_DISS(statusMsg << "uxth r" << dec << rd << ",r" << dec << rm << endl);
2491 ra = read_register(rm);
2492 rc = ra & 0xFFFF;
2493 write_register(rd, rc);
2494 return 0;
2495 }
2496
2497#ifndef UNSAFE_OPTIMIZATIONS
2498 case Op::invalid:
2499 break;
2500#else
2501 default:
2502 break;
2503#endif
2504 }
2505
2506#ifndef UNSAFE_OPTIMIZATIONS
2507 statusMsg << "invalid instruction " << Base::HEX8 << pc << " " << Base::HEX4 << inst << endl;
2508#endif
2509 return 1;
2510}
2511
2512// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2513int Thumbulator::reset()
2514{
2515 std::fill(reg_norm, reg_norm+12, 0);
2516 reg_norm[13] = 0x40001FB4;
2517
2518 switch(configuration)
2519 {
2520 // future 2K Harmony/Melody drivers will most likely use these settings
2521 case ConfigureFor::BUS:
2522 case ConfigureFor::CDF:
2523 case ConfigureFor::CDF1:
2524 case ConfigureFor::CDFJ:
2525 reg_norm[14] = 0x00000800; // Link Register
2526 reg_norm[15] = 0x0000080B; // Program Counter
2527 break;
2528
2529 // future 3K Harmony/Melody drivers will most likely use these settings
2530 case ConfigureFor::DPCplus:
2531 reg_norm[14] = 0x00000C00; // Link Register
2532 reg_norm[15] = 0x00000C0B; // Program Counter
2533 break;
2534 }
2535
2536 cpsr = mamcr = 0;
2537 handler_mode = false;
2538
2539 systick_ctrl = 0x00000004;
2540 systick_reload = 0x00000000;
2541 systick_count = 0x00000000;
2542 systick_calibrate = 0x00ABCDEF;
2543
2544 // fxq: don't care about below so much (maybe to guess timing???)
2545#ifndef UNSAFE_OPTIMIZATIONS
2546 instructions = 0;
2547 statusMsg.str("");
2548#endif
2549#ifndef NO_THUMB_STATS
2550 fetches = reads = writes = 0;
2551#endif
2552
2553 return 0;
2554}
2555
2556#ifndef UNSAFE_OPTIMIZATIONS
2557// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2558bool Thumbulator::trapOnFatal = true;
2559#endif
2560