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 #ifndef THUMBULATOR_HXX 26 #define THUMBULATOR_HXX 27 28 class Cartridge; 29 30 #include "bspf.hxx" 31 #include "Console.hxx" 32 33 #ifdef RETRON77 34 #define UNSAFE_OPTIMIZATIONS 35 #endif 36 37 #define ROMADDMASK 0x7FFFF 38 #define RAMADDMASK 0x7FFF 39 40 #define ROMSIZE (ROMADDMASK+1) // 512KB 41 #define RAMSIZE (RAMADDMASK+1) // 32KB 42 43 #define CPSR_N (1u<<31) 44 #define CPSR_Z (1u<<30) 45 #define CPSR_C (1u<<29) 46 #define CPSR_V (1u<<28) 47 48 #ifdef DEBUGGER_SUPPORT 49 #define THUMB_CYCLE_COUNT 50 //#define COUNT_OPS 51 #define THUMB_STATS 52 #endif 53 54 #ifdef THUMB_CYCLE_COUNT 55 //#define EMULATE_PIPELINE // enable coarse ARM pipeline emulation (TODO) 56 #define TIMER_0 // enable timer 0 support (e.g. for measuring cycle count) 57 #endif 58 59 class Thumbulator 60 { 61 public: 62 // control cartridge specific features of the Thumbulator class, 63 // such as the start location for calling custom code 64 enum class ConfigureFor { 65 BUS, // cartridges of type BUS 66 CDF, // cartridges of type CDF 67 CDF1, // cartridges of type CDF version 1 68 CDFJ, // cartridges of type CDFJ 69 CDFJplus, // cartridges of type CDFJ+ 70 DPCplus // cartridges of type DPC+ 71 }; 72 enum class ChipType { 73 LPC2101, // Harmony (includes LPC2103) 74 LPC2104_OC, // Dev cart overclocked (includes LPC2105) 75 LPC2104, // Dev cart (includes LPC2105) 76 LPC213x, // future use (includes LPC2132) 77 numTypes 78 }; 79 enum class MamModeType { 80 mode0, mode1, mode2, modeX 81 }; 82 struct ChipPropsType { 83 double MHz; 84 uInt32 flashCycles; 85 uInt32 flashBanks; 86 }; 87 struct Stats { 88 uInt32 instructions{0}; 89 #ifdef THUMB_STATS 90 uInt32 reads{0}, writes{0}; 91 uInt32 nCylces{0}, sCylces{0}, iCylces{0}; 92 uInt32 branches{0}, taken{0}; 93 uInt32 mamPrefetchHits{0}, mamPrefetchMisses{0}; 94 uInt32 mamBranchHits{0}, mamBranchMisses{0}; 95 uInt32 mamDataHits{0}, mamDataMisses{0}; 96 #endif 97 }; 98 99 Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, uInt32 rom_size, 100 const uInt32 c_base, const uInt32 c_start, const uInt32 c_stack, 101 bool traponfatal, double cyclefactor, 102 Thumbulator::ConfigureFor configurefor, 103 Cartridge* cartridge); 104 105 /** 106 Run the ARM code, and return when finished. A runtime_error exception is 107 thrown in case of any fatal errors/aborts (if enabled), containing the 108 actual error, and the contents of the registers at that point in time. 109 110 @return The results of any debugging output (if enabled), 111 otherwise an empty string 112 */ 113 string run(uInt32& cycles, bool irqDrivenAudio); enableCycleCount(bool enable)114 void enableCycleCount(bool enable) { _countCycles = enable; } stats() const115 const Stats& stats() const { return _stats; } cycles() const116 uInt32 cycles() const { return _totalCycles; } 117 ChipPropsType setChipType(ChipType type); setMamMode(MamModeType mode)118 void setMamMode(MamModeType mode) { mamcr = mode; } lockMamMode(bool lock)119 void lockMamMode(bool lock) { _lockMamcr = lock; } mamMode() const120 MamModeType mamMode() const { return static_cast<MamModeType>(mamcr); } 121 122 #ifdef THUMB_CYCLE_COUNT cycleFactor(double factor)123 void cycleFactor(double factor) { _armCyclesFactor = factor; } cycleFactor() const124 double cycleFactor() const { return _armCyclesFactor; } 125 #else cycleFactor(double)126 void cycleFactor(double) { } cycleFactor() const127 double cycleFactor() const { return 1.0; } 128 #endif 129 130 #ifndef UNSAFE_OPTIMIZATIONS 131 /** 132 Normally when a fatal error is encountered, the ARM emulation 133 immediately throws an exception and exits. This method allows execution 134 to continue, and simply log the error. 135 136 Note that this is meant for developers only, and should normally be 137 always enabled. It can be used to temporarily ignore illegal reads 138 and writes, but a ROM which consistently performs these operations 139 should be fixed, as it can cause crashes on real hardware. 140 141 @param enable Enable (the default) or disable exceptions on fatal errors 142 */ trapFatalErrors(bool enable)143 void trapFatalErrors(bool enable) { trapOnFatal = enable; } 144 #endif 145 146 /** 147 Inform the Thumbulator class about the console currently in use, 148 which is used to accurately determine how many 6507 cycles have 149 passed while ARM code is being executed. 150 */ 151 void setConsoleTiming(ConsoleTiming timing); 152 153 private: 154 155 enum class Op : uInt8 { 156 invalid, 157 adc, 158 add1, add2, add3, add4, add5, add6, add7, 159 and_, 160 asr1, asr2, 161 b1, b2, 162 bic, 163 bkpt, 164 blx1, blx2, 165 bx, 166 cmn, 167 cmp1, cmp2, cmp3, 168 cps, 169 cpy, 170 eor, 171 ldmia, 172 ldr1, ldr2, ldr3, ldr4, 173 ldrb1, ldrb2, 174 ldrh1, ldrh2, 175 ldrsb, 176 ldrsh, 177 lsl1, lsl2, 178 lsr1, lsr2, 179 mov1, mov2, mov3, 180 mul, 181 mvn, 182 neg, 183 orr, 184 pop, 185 push, 186 rev, 187 rev16, 188 revsh, 189 ror, 190 sbc, 191 setend, 192 stmia, 193 str1, str2, str3, 194 strb1, strb2, 195 strh1, strh2, 196 sub1, sub2, sub3, sub4, 197 swi, 198 sxtb, 199 sxth, 200 tst, 201 uxtb, 202 uxth, 203 numOps 204 }; 205 #ifdef THUMB_CYCLE_COUNT 206 enum class CycleType { 207 S, N, I // Sequential, Non-sequential, Internal 208 }; 209 enum class AccessType { 210 prefetch, branch, data 211 }; 212 #endif 213 const std::array<ChipPropsType, uInt32(ChipType::numTypes)> ChipProps = 214 {{ 215 { 70.0, 4, 1 }, // LPC2101_02_03 216 { 70.0, 4, 2 }, // LPC2104_05_06 Overclocked 217 { 60.0, 3, 2 }, // LPC2104_05_06 218 { 60.0, 3, 1 }, // LPC2132.. 219 }}; 220 221 private: 222 string doRun(uInt32& cycles, bool irqDrivenAudio); 223 uInt32 read_register(uInt32 reg); 224 void write_register(uInt32 reg, uInt32 data, bool isFlowBreak = true); 225 uInt32 fetch16(uInt32 addr); 226 uInt32 read16(uInt32 addr); 227 uInt32 read32(uInt32 addr); 228 #ifndef UNSAFE_OPTIMIZATIONS 229 bool isProtected(uInt32 addr); 230 #endif 231 void write16(uInt32 addr, uInt32 data); 232 void write32(uInt32 addr, uInt32 data); 233 void updateTimer(uInt32 cycles); 234 235 static Op decodeInstructionWord(uint16_t inst); 236 237 void do_zflag(uInt32 x); 238 void do_nflag(uInt32 x); 239 void do_cflag(uInt32 a, uInt32 b, uInt32 c); 240 void do_vflag(uInt32 a, uInt32 b, uInt32 c); 241 void do_cflag_bit(uInt32 x); 242 void do_vflag_bit(uInt32 x); 243 244 #ifndef UNSAFE_OPTIMIZATIONS 245 // Throw a runtime_error exception containing an error referencing the 246 // given message and variables 247 // Note that the return value is never used in these methods 248 int fatalError(const char* opcode, uInt32 v1, const char* msg); 249 int fatalError(const char* opcode, uInt32 v1, uInt32 v2, const char* msg); 250 251 void dump_counters(); 252 void dump_regs(); 253 #endif 254 int execute(); 255 int reset(); 256 257 #ifdef THUMB_CYCLE_COUNT 258 bool isMamBuffered(uInt32 addr, AccessType = AccessType::data); 259 void incCycles(AccessType accessType, uInt32 cycles); 260 void incSCycles(uInt32 addr, AccessType = AccessType::data); 261 void incNCycles(uInt32 addr, AccessType = AccessType::data); 262 void incICycles(uInt32 m = 1); 263 #endif 264 265 private: 266 const uInt16* rom{nullptr}; 267 uInt32 romSize{0}; 268 uInt32 cBase{0}; 269 uInt32 cStart{0}; 270 uInt32 cStack{0}; 271 const unique_ptr<Op[]> decodedRom; // NOLINT 272 uInt16* ram{nullptr}; 273 std::array<uInt32, 16> reg_norm; // normal execution mode, do not have a thread mode 274 uInt32 cpsr{0}; 275 MamModeType mamcr{MamModeType::mode0}; 276 bool handler_mode{false}; 277 uInt32 systick_ctrl{0}, systick_reload{0}, systick_count{0}, systick_calibrate{0}; 278 ChipType _chipType{ChipType::LPC2101}; 279 ConsoleTiming _consoleTiming{ConsoleTiming::ntsc}; 280 double _MHz{70.0}; 281 uInt32 _flashCycles{4}; 282 uInt32 _flashBanks{1}; 283 Stats _stats{0}; 284 bool _irqDrivenAudio{false}; 285 uInt32 _totalCycles{0}; 286 287 // For emulation of LPC2103's timer 1, used for NTSC/PAL/SECAM detection. 288 // Register names from documentation: 289 // http://www.nxp.com/documents/user_manual/UM10161.pdf 290 #ifdef TIMER_0 291 uInt32 T0TCR{0}; // Timer 0 Timer Control Register 292 uInt32 T0TC{0}; // Timer 0 Timer Counter 293 uInt32 tim0Start{0}; // _totalCycles when Timer 0 got started last time 294 uInt32 tim0Total{0}; // total cycles of Timer 0 295 #endif 296 uInt32 T1TCR{0}; // Timer 1 Timer Control Register 297 uInt32 T1TC{0}; // Timer 1 Timer Counter 298 uInt32 tim1Start{0}; // _totalCycles when Timer 1 got started last time 299 uInt32 tim1Total{0}; // total cycles of Timer 1 300 double timing_factor{0.0}; 301 302 #ifndef UNSAFE_OPTIMIZATIONS 303 ostringstream statusMsg; 304 bool trapOnFatal{true}; 305 #endif 306 bool _countCycles{false}; 307 bool _lockMamcr{false}; 308 309 #ifdef THUMB_CYCLE_COUNT 310 double _armCyclesFactor{1.05}; 311 uInt32 _pipeIdx{0}; 312 CycleType _prefetchCycleType[3]{CycleType::S}; 313 CycleType _lastCycleType[3]{CycleType::S}; 314 #if 0 // unused for now 315 AccessType _prefetchAccessType[3]{AccessType::data}; 316 #endif 317 #ifdef EMULATE_PIPELINE 318 uInt32 _fetchPipeline{0}; // reserve fetch cycles resulting from pipelining (execution stage) 319 uInt32 _memory0Pipeline{0}, _memory1Pipeline{0}; 320 #endif 321 uInt32 _prefetchBufferAddr[2]{0}; 322 uInt32 _branchBufferAddr[2]{0}; 323 uInt32 _dataBufferAddr{0}; 324 #endif 325 #ifdef COUNT_OPS 326 uInt32 opCount[size_t(Op::numOps)]{0}; 327 #endif 328 329 ConfigureFor configuration; 330 331 Cartridge* myCartridge; 332 333 private: 334 // Following constructors and assignment operators not supported 335 Thumbulator() = delete; 336 Thumbulator(const Thumbulator&) = delete; 337 Thumbulator(Thumbulator&&) = delete; 338 Thumbulator& operator=(const Thumbulator&) = delete; 339 Thumbulator& operator=(Thumbulator&&) = delete; 340 }; 341 342 #endif // THUMBULATOR_HXX 343