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#ifndef THUMBULATOR_HXX
26#define THUMBULATOR_HXX
27
28class Cartridge;
29
30#include "bspf.hxx"
31#include "Console.hxx"
32
33#ifdef RETRON77
34 #define UNSAFE_OPTIMIZATIONS
35 #define NO_THUMB_STATS
36#endif
37
38#define ROMADDMASK 0x7FFF
39#define RAMADDMASK 0x1FFF
40
41#define ROMSIZE (ROMADDMASK+1)
42#define RAMSIZE (RAMADDMASK+1)
43
44#define CPSR_N (1u<<31)
45#define CPSR_Z (1u<<30)
46#define CPSR_C (1u<<29)
47#define CPSR_V (1u<<28)
48
49class Thumbulator
50{
51 public:
52 // control cartridge specific features of the Thumbulator class,
53 // such as the start location for calling custom code
54 enum class ConfigureFor {
55 BUS, // cartridges of type BUS
56 CDF, // cartridges of type CDF
57 CDF1, // cartridges of type CDF version 1
58 CDFJ, // cartrdiges of type CDFJ
59 DPCplus // cartridges of type DPC+
60 };
61
62 Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, uInt16 rom_size,
63 bool traponfatal, Thumbulator::ConfigureFor configurefor,
64 Cartridge* cartridge);
65
66 /**
67 Run the ARM code, and return when finished. A runtime_error exception is
68 thrown in case of any fatal errors/aborts (if enabled), containing the
69 actual error, and the contents of the registers at that point in time.
70
71 @return The results of any debugging output (if enabled),
72 otherwise an empty string
73 */
74 string run();
75 string run(uInt32 cycles);
76
77#ifndef UNSAFE_OPTIMIZATIONS
78 /**
79 Normally when a fatal error is encountered, the ARM emulation
80 immediately throws an exception and exits. This method allows execution
81 to continue, and simply log the error.
82
83 Note that this is meant for developers only, and should normally be
84 always enabled. It can be used to temporarily ignore illegal reads
85 and writes, but a ROM which consistently performs these operations
86 should be fixed, as it can cause crashes on real hardware.
87
88 @param enable Enable (the default) or disable exceptions on fatal errors
89 */
90 static void trapFatalErrors(bool enable) { trapOnFatal = enable; }
91#endif
92
93 /**
94 Inform the Thumbulator class about the console currently in use,
95 which is used to accurately determine how many 6507 cycles have
96 passed while ARM code is being executed.
97 */
98 void setConsoleTiming(ConsoleTiming timing);
99
100 private:
101
102 enum class Op : uInt8 {
103 invalid,
104 adc,
105 add1, add2, add3, add4, add5, add6, add7,
106 and_,
107 asr1, asr2,
108 b1, b2,
109 bic,
110 bkpt,
111 blx1, blx2,
112 bx,
113 cmn,
114 cmp1, cmp2, cmp3,
115 cps,
116 cpy,
117 eor,
118 ldmia,
119 ldr1, ldr2, ldr3, ldr4,
120 ldrb1, ldrb2,
121 ldrh1, ldrh2,
122 ldrsb,
123 ldrsh,
124 lsl1, lsl2,
125 lsr1, lsr2,
126 mov1, mov2, mov3,
127 mul,
128 mvn,
129 neg,
130 orr,
131 pop,
132 push,
133 rev,
134 rev16,
135 revsh,
136 ror,
137 sbc,
138 setend,
139 stmia,
140 str1, str2, str3,
141 strb1, strb2,
142 strh1, strh2,
143 sub1, sub2, sub3, sub4,
144 swi,
145 sxtb,
146 sxth,
147 tst,
148 uxtb,
149 uxth
150 };
151
152 private:
153 uInt32 read_register(uInt32 reg);
154 void write_register(uInt32 reg, uInt32 data);
155 uInt32 fetch16(uInt32 addr);
156 uInt32 read16(uInt32 addr);
157 uInt32 read32(uInt32 addr);
158#ifndef UNSAFE_OPTIMIZATIONS
159 bool isProtected(uInt32 addr);
160#endif
161 void write16(uInt32 addr, uInt32 data);
162 void write32(uInt32 addr, uInt32 data);
163 void updateTimer(uInt32 cycles);
164
165 static Op decodeInstructionWord(uint16_t inst);
166
167 void do_zflag(uInt32 x);
168 void do_nflag(uInt32 x);
169 void do_cflag(uInt32 a, uInt32 b, uInt32 c);
170 void do_vflag(uInt32 a, uInt32 b, uInt32 c);
171 void do_cflag_bit(uInt32 x);
172 void do_vflag_bit(uInt32 x);
173
174#ifndef UNSAFE_OPTIMIZATIONS
175 // Throw a runtime_error exception containing an error referencing the
176 // given message and variables
177 // Note that the return value is never used in these methods
178 int fatalError(const char* opcode, uInt32 v1, const char* msg);
179 int fatalError(const char* opcode, uInt32 v1, uInt32 v2, const char* msg);
180
181 void dump_counters();
182 void dump_regs();
183#endif
184 int execute();
185 int reset();
186
187 private:
188 const uInt16* rom;
189 uInt16 romSize;
190 const unique_ptr<Op[]> decodedRom;
191 uInt16* ram;
192
193 uInt32 reg_norm[16]; // normal execution mode, do not have a thread mode
194 uInt32 cpsr, mamcr;
195 bool handler_mode;
196 uInt32 systick_ctrl, systick_reload, systick_count, systick_calibrate;
197#ifndef UNSAFE_OPTIMIZATIONS
198 uInt64 instructions;
199#endif
200#ifndef NO_THUMB_STATS
201 uInt64 fetches, reads, writes;
202#endif
203
204 // For emulation of LPC2103's timer 1, used for NTSC/PAL/SECAM detection.
205 // Register names from documentation:
206 // http://www.nxp.com/documents/user_manual/UM10161.pdf
207 uInt32 T1TCR; // Timer 1 Timer Control Register
208 uInt32 T1TC; // Timer 1 Timer Counter
209 double timing_factor;
210
211#ifndef UNSAFE_OPTIMIZATIONS
212 ostringstream statusMsg;
213
214 static bool trapOnFatal;
215#endif
216
217 ConfigureFor configuration;
218
219 Cartridge* myCartridge;
220
221 private:
222 // Following constructors and assignment operators not supported
223 Thumbulator() = delete;
224 Thumbulator(const Thumbulator&) = delete;
225 Thumbulator(Thumbulator&&) = delete;
226 Thumbulator& operator=(const Thumbulator&) = delete;
227 Thumbulator& operator=(Thumbulator&&) = delete;
228};
229
230#endif // THUMBULATOR_HXX
231