mirror of https://github.com/stella-emu/stella.git
231 lines
6.4 KiB
C++
231 lines
6.4 KiB
C++
//============================================================================
|
|
//
|
|
// SSSS tt lll lll
|
|
// SS SS tt ll ll
|
|
// SS tttttt eeee ll ll aaaa
|
|
// SSSS tt ee ee ll ll aa
|
|
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
|
// SS SS tt ee ll ll aa aa
|
|
// SSSS ttt eeeee llll llll aaaaa
|
|
//
|
|
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
|
|
// and the Stella Team
|
|
//
|
|
// See the file "License.txt" for information on usage and redistribution of
|
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
|
//============================================================================
|
|
|
|
//============================================================================
|
|
// This class provides Thumb emulation code ("Thumbulator")
|
|
// by David Welch (dwelch@dwelch.com)
|
|
// Modified by Fred Quimby
|
|
// Code is public domain and used with the author's consent
|
|
//============================================================================
|
|
|
|
#ifndef THUMBULATOR_HXX
|
|
#define THUMBULATOR_HXX
|
|
|
|
class Cartridge;
|
|
|
|
#include "bspf.hxx"
|
|
#include "Console.hxx"
|
|
|
|
#ifdef RETRON77
|
|
#define UNSAFE_OPTIMIZATIONS
|
|
#define NO_THUMB_STATS
|
|
#endif
|
|
|
|
#define ROMADDMASK 0x7FFF
|
|
#define RAMADDMASK 0x1FFF
|
|
|
|
#define ROMSIZE (ROMADDMASK+1)
|
|
#define RAMSIZE (RAMADDMASK+1)
|
|
|
|
#define CPSR_N (1u<<31)
|
|
#define CPSR_Z (1u<<30)
|
|
#define CPSR_C (1u<<29)
|
|
#define CPSR_V (1u<<28)
|
|
|
|
class Thumbulator
|
|
{
|
|
public:
|
|
// control cartridge specific features of the Thumbulator class,
|
|
// such as the start location for calling custom code
|
|
enum class ConfigureFor {
|
|
BUS, // cartridges of type BUS
|
|
CDF, // cartridges of type CDF
|
|
CDF1, // cartridges of type CDF version 1
|
|
CDFJ, // cartrdiges of type CDFJ
|
|
DPCplus // cartridges of type DPC+
|
|
};
|
|
|
|
Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, uInt16 rom_size,
|
|
bool traponfatal, Thumbulator::ConfigureFor configurefor,
|
|
Cartridge* cartridge);
|
|
|
|
/**
|
|
Run the ARM code, and return when finished. A runtime_error exception is
|
|
thrown in case of any fatal errors/aborts (if enabled), containing the
|
|
actual error, and the contents of the registers at that point in time.
|
|
|
|
@return The results of any debugging output (if enabled),
|
|
otherwise an empty string
|
|
*/
|
|
string run();
|
|
string run(uInt32 cycles);
|
|
|
|
#ifndef UNSAFE_OPTIMIZATIONS
|
|
/**
|
|
Normally when a fatal error is encountered, the ARM emulation
|
|
immediately throws an exception and exits. This method allows execution
|
|
to continue, and simply log the error.
|
|
|
|
Note that this is meant for developers only, and should normally be
|
|
always enabled. It can be used to temporarily ignore illegal reads
|
|
and writes, but a ROM which consistently performs these operations
|
|
should be fixed, as it can cause crashes on real hardware.
|
|
|
|
@param enable Enable (the default) or disable exceptions on fatal errors
|
|
*/
|
|
static void trapFatalErrors(bool enable) { trapOnFatal = enable; }
|
|
#endif
|
|
|
|
/**
|
|
Inform the Thumbulator class about the console currently in use,
|
|
which is used to accurately determine how many 6507 cycles have
|
|
passed while ARM code is being executed.
|
|
*/
|
|
void setConsoleTiming(ConsoleTiming timing);
|
|
|
|
private:
|
|
|
|
enum class Op : uInt8 {
|
|
invalid,
|
|
adc,
|
|
add1, add2, add3, add4, add5, add6, add7,
|
|
and_,
|
|
asr1, asr2,
|
|
b1, b2,
|
|
bic,
|
|
bkpt,
|
|
blx1, blx2,
|
|
bx,
|
|
cmn,
|
|
cmp1, cmp2, cmp3,
|
|
cps,
|
|
cpy,
|
|
eor,
|
|
ldmia,
|
|
ldr1, ldr2, ldr3, ldr4,
|
|
ldrb1, ldrb2,
|
|
ldrh1, ldrh2,
|
|
ldrsb,
|
|
ldrsh,
|
|
lsl1, lsl2,
|
|
lsr1, lsr2,
|
|
mov1, mov2, mov3,
|
|
mul,
|
|
mvn,
|
|
neg,
|
|
orr,
|
|
pop,
|
|
push,
|
|
rev,
|
|
rev16,
|
|
revsh,
|
|
ror,
|
|
sbc,
|
|
setend,
|
|
stmia,
|
|
str1, str2, str3,
|
|
strb1, strb2,
|
|
strh1, strh2,
|
|
sub1, sub2, sub3, sub4,
|
|
swi,
|
|
sxtb,
|
|
sxth,
|
|
tst,
|
|
uxtb,
|
|
uxth
|
|
};
|
|
|
|
private:
|
|
uInt32 read_register(uInt32 reg);
|
|
void write_register(uInt32 reg, uInt32 data);
|
|
uInt32 fetch16(uInt32 addr);
|
|
uInt32 read16(uInt32 addr);
|
|
uInt32 read32(uInt32 addr);
|
|
#ifndef UNSAFE_OPTIMIZATIONS
|
|
bool isProtected(uInt32 addr);
|
|
#endif
|
|
void write16(uInt32 addr, uInt32 data);
|
|
void write32(uInt32 addr, uInt32 data);
|
|
void updateTimer(uInt32 cycles);
|
|
|
|
static Op decodeInstructionWord(uint16_t inst);
|
|
|
|
void do_zflag(uInt32 x);
|
|
void do_nflag(uInt32 x);
|
|
void do_cflag(uInt32 a, uInt32 b, uInt32 c);
|
|
void do_vflag(uInt32 a, uInt32 b, uInt32 c);
|
|
void do_cflag_bit(uInt32 x);
|
|
void do_vflag_bit(uInt32 x);
|
|
|
|
#ifndef UNSAFE_OPTIMIZATIONS
|
|
// Throw a runtime_error exception containing an error referencing the
|
|
// given message and variables
|
|
// Note that the return value is never used in these methods
|
|
int fatalError(const char* opcode, uInt32 v1, const char* msg);
|
|
int fatalError(const char* opcode, uInt32 v1, uInt32 v2, const char* msg);
|
|
|
|
void dump_counters();
|
|
void dump_regs();
|
|
#endif
|
|
int execute();
|
|
int reset();
|
|
|
|
private:
|
|
const uInt16* rom{nullptr};
|
|
uInt16 romSize{0};
|
|
const unique_ptr<Op[]> decodedRom; // NOLINT
|
|
uInt16* ram{nullptr};
|
|
|
|
std::array<uInt32, 16> reg_norm; // normal execution mode, do not have a thread mode
|
|
uInt32 cpsr{0}, mamcr{0};
|
|
bool handler_mode{false};
|
|
uInt32 systick_ctrl{0}, systick_reload{0}, systick_count{0}, systick_calibrate{0};
|
|
#ifndef UNSAFE_OPTIMIZATIONS
|
|
uInt64 instructions{0};
|
|
#endif
|
|
#ifndef NO_THUMB_STATS
|
|
uInt64 fetches{0}, reads{0}, writes{0};
|
|
#endif
|
|
|
|
// For emulation of LPC2103's timer 1, used for NTSC/PAL/SECAM detection.
|
|
// Register names from documentation:
|
|
// http://www.nxp.com/documents/user_manual/UM10161.pdf
|
|
uInt32 T1TCR{0}; // Timer 1 Timer Control Register
|
|
uInt32 T1TC{0}; // Timer 1 Timer Counter
|
|
double timing_factor{0.0};
|
|
|
|
#ifndef UNSAFE_OPTIMIZATIONS
|
|
ostringstream statusMsg;
|
|
|
|
static bool trapOnFatal;
|
|
#endif
|
|
|
|
ConfigureFor configuration;
|
|
|
|
Cartridge* myCartridge;
|
|
|
|
private:
|
|
// Following constructors and assignment operators not supported
|
|
Thumbulator() = delete;
|
|
Thumbulator(const Thumbulator&) = delete;
|
|
Thumbulator(Thumbulator&&) = delete;
|
|
Thumbulator& operator=(const Thumbulator&) = delete;
|
|
Thumbulator& operator=(Thumbulator&&) = delete;
|
|
};
|
|
|
|
#endif // THUMBULATOR_HXX
|