From 061b0124a444f57ea2e52cf9ef1d3ff7321fd397 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Sun, 21 Jul 2024 22:21:45 +0200 Subject: [PATCH] Start to adapt thumbulator. --- .vscode/settings.json | 15 +- src/emucore/CortexM0.cxx | 623 ++++++++++++++++++++++++++ src/emucore/CortexM0.hxx | 152 +++++++ src/emucore/module.mk | 1 + src/os/windows/Stella.vcxproj | 2 + src/os/windows/Stella.vcxproj.filters | 6 + 6 files changed, 798 insertions(+), 1 deletion(-) create mode 100644 src/emucore/CortexM0.cxx create mode 100644 src/emucore/CortexM0.hxx diff --git a/.vscode/settings.json b/.vscode/settings.json index c5dd15c03..c351cccc8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,6 +14,7 @@ "C_Cpp.intelliSenseEngine": "Default", "files.insertFinalNewline": true, "files.associations": { + "*.h": "cpp", "__functional_base": "cpp", "array": "cpp", "istream": "cpp", @@ -103,6 +104,18 @@ "version": "cpp", "shared_mutex": "cpp", "compare": "cpp", - "concepts": "cpp" + "concepts": "cpp", + "__verbose_abort": "cpp", + "any": "cpp", + "charconv": "cpp", + "csignal": "cpp", + "execution": "cpp", + "numbers": "cpp", + "span": "cpp", + "unordered_set": "cpp", + "variant": "cpp", + "hash_map": "cpp", + "format": "cpp", + "*.inc": "cpp" } } diff --git a/src/emucore/CortexM0.cxx b/src/emucore/CortexM0.cxx new file mode 100644 index 000000000..e7f79b488 --- /dev/null +++ b/src/emucore/CortexM0.cxx @@ -0,0 +1,623 @@ +//============================================================================ +// +// 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-2024 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 code is based on the "Thumbulator" by David Welch (dwelch@dwelch.com) +// Code is public domain and used with the author's consent +//============================================================================ + +#include "CortexM0.hxx" + +#ifdef __BIG_ENDIAN__ + #define READ32(data, addr) ( \ + (((uInt8*)(data))[(addr)]) | \ + (((uInt8*)(data))[(addr) + 1] << 8) | \ + (((uInt8*)(data))[(addr) + 2] << 16) | \ + (((uInt8*)(data))[(addr) + 3] << 24) \ + ) + + #define READ16(data, addr) ( \ + (((uInt8*)(data))[(addr)]) | \ + (((uInt8*)(data))[(addr) + 1] << 8) \ + ) + + #define WRITE32(data, addr, value) \ + ((uInt8*)(data))[(addr)] = (value); \ + ((uInt8*)(data))[(addr) + 1] = (value) >> 8; \ + ((uInt8*)(data))[(addr) + 2] = (value) >> 16; \ + ((uInt8*)(data))[(addr) + 3] = (value) >> 24; + + #define WRITE16(data, addr, value) \ + ((uInt8*)(data))[(addr)] = value; \ + ((uInt8*)(data))[(addr) + 1] = (value) >> 8; +#else + #define READ32(data, addr) (((uInt32*)(data))[(addr) >> 2]) + #define READ16(data, addr) (((uInt16*)(data))[(addr) >> 1]) + + #define WRITE32(data, addr, value) ((uInt32*)(data))[(addr) >> 2] = value; + #define WRITE16(data, addr, value) ((uInt16*)(data))[(addr) >> 1] = value; +#endif + +#define read_register(reg) reg_norm[reg] +#define write_register(reg, data) reg_norm[reg]=(data) + +namespace { + constexpr uInt32 PAGEMAP_SIZE = 0x100000000 / 4096; + + enum class Op : uInt8 { + adc, + add1, add2, add3, add4, add5, add6, add7, + and_, + asr1, asr2, + // b1 variants: + beq, bne, bcs, bcc, bmi, bpl, bvs, bvc, bhi, bls, bge, blt, bgt, ble, + b2, + bic, + bkpt, + // blx1 variants: + bl, blx_thumb, blx_arm, + 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, + numOps, + invalid, + }; + + inline Op decodeInstructionWord(uInt16 inst) + { + //ADC add with carry + if((inst & 0xFFC0) == 0x4140) return Op::adc; + + //ADD(1) small immediate two registers + if((inst & 0xFE00) == 0x1C00 && (inst >> 6) & 0x7) return Op::add1; + + //ADD(2) big immediate one register + if((inst & 0xF800) == 0x3000) return Op::add2; + + //ADD(3) three registers + if((inst & 0xFE00) == 0x1800) return Op::add3; + + //ADD(4) two registers one or both high no flags + if((inst & 0xFF00) == 0x4400) return Op::add4; + + //ADD(5) rd = pc plus immediate + if((inst & 0xF800) == 0xA000) return Op::add5; + + //ADD(6) rd = sp plus immediate + if((inst & 0xF800) == 0xA800) return Op::add6; + + //ADD(7) sp plus immediate + if((inst & 0xFF80) == 0xB000) return Op::add7; + + //AND + if((inst & 0xFFC0) == 0x4000) return Op::and_; + + //ASR(1) two register immediate + if((inst & 0xF800) == 0x1000) return Op::asr1; + + //ASR(2) two register + if((inst & 0xFFC0) == 0x4100) return Op::asr2; + + //B(1) conditional branch, decoded into its variants + if((inst & 0xF000) == 0xD000) + { + switch((inst >> 8) & 0xF) + { + case 0x0: //b eq z set + return Op::beq; + + case 0x1: //b ne z clear + return Op::bne; + + case 0x2: //b cs c set + return Op::bcs; + + case 0x3: //b cc c clear + return Op::bcc; + + case 0x4: //b mi n set + return Op::bmi; + + case 0x5: //b pl n clear + return Op::bpl; + + case 0x6: //b vs v set + return Op::bvs; + + case 0x7: //b vc v clear + return Op::bvc; + + case 0x8: //b hi c set z clear + return Op::bhi; + + case 0x9: //b ls c clear or z set + return Op::bls; + + case 0xA: //b ge N == V + return Op::bge; + + case 0xB: //b lt N != V + return Op::blt; + + case 0xC: //b gt Z==0 and N == V + return Op::bgt; + + case 0xD: //b le Z==1 or N != V + return Op::ble; + + default: + return Op::invalid; + } + } + + //B(2) unconditional branch + if((inst & 0xF800) == 0xE000) return Op::b2; + + //BIC + if((inst & 0xFFC0) == 0x4380) return Op::bic; + + //BKPT + if((inst & 0xFF00) == 0xBE00) return Op::bkpt; + + //BL/BLX(1) decoded into its variants + if((inst & 0xE000) == 0xE000) + { + if((inst & 0x1800) == 0x1000) return Op::bl; + else if((inst & 0x1800) == 0x1800) return Op::blx_thumb; + else if((inst & 0x1800) == 0x0800) return Op::blx_arm; + return Op::invalid; + } + + //BLX(2) + if((inst & 0xFF87) == 0x4780) return Op::blx2; + + //BX + if((inst & 0xFF87) == 0x4700) return Op::bx; + + //CMN + if((inst & 0xFFC0) == 0x42C0) return Op::cmn; + + //CMP(1) compare immediate + if((inst & 0xF800) == 0x2800) return Op::cmp1; + + //CMP(2) compare register + if((inst & 0xFFC0) == 0x4280) return Op::cmp2; + + //CMP(3) compare high register + if((inst & 0xFF00) == 0x4500) return Op::cmp3; + + //CPS + if((inst & 0xFFE8) == 0xB660) return Op::cps; + + //CPY copy high register + if((inst & 0xFFC0) == 0x4600) return Op::cpy; + + //EOR + if((inst & 0xFFC0) == 0x4040) return Op::eor; + + //LDMIA + if((inst & 0xF800) == 0xC800) return Op::ldmia; + + //LDR(1) two register immediate + if((inst & 0xF800) == 0x6800) return Op::ldr1; + + //LDR(2) three register + if((inst & 0xFE00) == 0x5800) return Op::ldr2; + + //LDR(3) + if((inst & 0xF800) == 0x4800) return Op::ldr3; + + //LDR(4) + if((inst & 0xF800) == 0x9800) return Op::ldr4; + + //LDRB(1) + if((inst & 0xF800) == 0x7800) return Op::ldrb1; + + //LDRB(2) + if((inst & 0xFE00) == 0x5C00) return Op::ldrb2; + + //LDRH(1) + if((inst & 0xF800) == 0x8800) return Op::ldrh1; + + //LDRH(2) + if((inst & 0xFE00) == 0x5A00) return Op::ldrh2; + + //LDRSB + if((inst & 0xFE00) == 0x5600) return Op::ldrsb; + + //LDRSH + if((inst & 0xFE00) == 0x5E00) return Op::ldrsh; + + //LSL(1) + if((inst & 0xF800) == 0x0000) return Op::lsl1; + + //LSL(2) two register + if((inst & 0xFFC0) == 0x4080) return Op::lsl2; + + //LSR(1) two register immediate + if((inst & 0xF800) == 0x0800) return Op::lsr1; + + //LSR(2) two register + if((inst & 0xFFC0) == 0x40C0) return Op::lsr2; + + //MOV(1) immediate + if((inst & 0xF800) == 0x2000) return Op::mov1; + + //MOV(2) two low registers + if((inst & 0xFFC0) == 0x1C00) return Op::mov2; + + //MOV(3) + if((inst & 0xFF00) == 0x4600) return Op::mov3; + + //MUL + if((inst & 0xFFC0) == 0x4340) return Op::mul; + + //MVN + if((inst & 0xFFC0) == 0x43C0) return Op::mvn; + + //NEG + if((inst & 0xFFC0) == 0x4240) return Op::neg; + + //ORR + if((inst & 0xFFC0) == 0x4300) return Op::orr; + + //POP + if((inst & 0xFE00) == 0xBC00) return Op::pop; + + //PUSH + if((inst & 0xFE00) == 0xB400) return Op::push; + + //REV + if((inst & 0xFFC0) == 0xBA00) return Op::rev; + + //REV16 + if((inst & 0xFFC0) == 0xBA40) return Op::rev16; + + //REVSH + if((inst & 0xFFC0) == 0xBAC0) return Op::revsh; + + //ROR + if((inst & 0xFFC0) == 0x41C0) return Op::ror; + + //SBC + if((inst & 0xFFC0) == 0x4180) return Op::sbc; + + //SETEND + if((inst & 0xFFF7) == 0xB650) return Op::setend; + + //STMIA + if((inst & 0xF800) == 0xC000) return Op::stmia; + + //STR(1) + if((inst & 0xF800) == 0x6000) return Op::str1; + + //STR(2) + if((inst & 0xFE00) == 0x5000) return Op::str2; + + //STR(3) + if((inst & 0xF800) == 0x9000) return Op::str3; + + //STRB(1) + if((inst & 0xF800) == 0x7000) return Op::strb1; + + //STRB(2) + if((inst & 0xFE00) == 0x5400) return Op::strb2; + + //STRH(1) + if((inst & 0xF800) == 0x8000) return Op::strh1; + + //STRH(2) + if((inst & 0xFE00) == 0x5200) return Op::strh2; + + //SUB(1) + if((inst & 0xFE00) == 0x1E00) return Op::sub1; + + //SUB(2) + if((inst & 0xF800) == 0x3800) return Op::sub2; + + //SUB(3) + if((inst & 0xFE00) == 0x1A00) return Op::sub3; + + //SUB(4) + if((inst & 0xFF80) == 0xB080) return Op::sub4; + + //SWI SoftWare Interupt + if((inst & 0xFF00) == 0xDF00) return Op::swi; + + //SXTB + if((inst & 0xFFC0) == 0xB240) return Op::sxtb; + + //SXTH + if((inst & 0xFFC0) == 0xB200) return Op::sxth; + + //TST + if((inst & 0xFFC0) == 0x4200) return Op::tst; + + //UXTB + if((inst & 0xFFC0) == 0xB2C0) return Op::uxtb; + + //UXTH Zero extend Halfword + if((inst & 0xFFC0) == 0xB280) return Op::uxth; + + return Op::invalid; + } +} + +CortexM0::CortexM0() +{ + myPageMap = make_unique(PAGEMAP_SIZE); + std::memset(myPageMap.get(), 0xff, PAGEMAP_SIZE); + + reset(); +} + +CortexM0& CortexM0::mapRegionData(uInt32 pageBase, + uInt32 pageCount, bool readOnly, uInt8* backingStore) +{ + MemoryRegion& region = + setupMapping(pageBase, pageCount, readOnly, MemoryRegionType::directData); + + region.access.accessData.backingStore = backingStore; + + return *this; +} + +CortexM0& CortexM0::mapRegionCode(uInt32 pageBase, + uInt32 pageCount, bool readOnly, uInt8* backingStore) +{ + MemoryRegion& region = + setupMapping(pageBase, pageCount, readOnly, MemoryRegionType::directCode); + + region.access.accessCode.backingStore = backingStore; + region.access.accessCode.ops = static_cast(std::malloc((pageCount * PAGE_SIZE) >> 1)); + + for (size_t i = 0; i < pageCount * PAGE_SIZE; i += 2) + region.access.accessCode.ops[i >> 1] = + decodeInstructionWord(READ16(backingStore, i)); + + return *this; +} + +CortexM0& CortexM0::mapRegionDelegate(uInt32 pageBase, uInt32 pageCount, bool readOnly, + CortexM0::BusTransactionDelegate* delegate) +{ + MemoryRegion& region = + setupMapping(pageBase, pageCount, readOnly, MemoryRegionType::delegate); + + region.access.delegate = delegate; + + return *this; +} + +CortexM0& CortexM0::mapDefault(CortexM0::BusTransactionDelegate* delegate) +{ + myDefaultDelegate = delegate; + + return *this; +} + +CortexM0& CortexM0::reset() +{ + reg_norm.fill(0); + znFlags = cFlag = vFlag = 0; + + return *this; +} + +CortexM0& CortexM0::setRegister(uInt8 regno, uInt32 value) +{ + write_register(regno, value); + + return *this; +} + +uInt8 CortexM0::decodeInstructionWord(uInt16 instructionWord) +{ + return static_cast(::decodeInstructionWord(instructionWord)); +} + +CortexM0::MemoryRegion& CortexM0::setupMapping(uInt32 pageBase, uInt32 pageCount, + bool readOnly, CortexM0::MemoryRegionType type) +{ + if (myNextRegionIndex == 0xff) throw runtime_error("no free memory region"); + const uInt8 regionIndex = myNextRegionIndex++; + + MemoryRegion& region = myRegions[regionIndex]; + + region.type = type; + region.base = pageBase * PAGE_SIZE; + region.size = pageCount * PAGE_SIZE; + region.readOnly = readOnly; + + for (uInt32 page = pageBase; page < pageBase + pageCount; page++) + myPageMap[page] = regionIndex; + + return region; +} + +CortexM0::BusTransactionResult CortexM0::read32(uInt32 address, uInt32& value) +{ + MemoryRegion& region = myRegions[myPageMap[address / PAGE_SIZE]]; + + switch (region.type) { + case MemoryRegionType::delegate: + return region.access.delegate->read32(address, value); + + case MemoryRegionType::directCode: + value = READ32(region.access.accessCode.backingStore, address - region.base); + return BusTransactionResult::ok; + + case MemoryRegionType::directData: + value = READ32(region.access.accessData.backingStore, address - region.base); + return BusTransactionResult::ok; + + default: + return myDefaultDelegate ? + myDefaultDelegate->read32(address, value) : BusTransactionResult::fail; + } +} + +CortexM0::BusTransactionResult CortexM0::read16(uInt32 address, uInt16& value) +{ + MemoryRegion& region = myRegions[myPageMap[address / PAGE_SIZE]]; + + switch (region.type) { + case MemoryRegionType::delegate: + return region.access.delegate->read16(address, value); + + case MemoryRegionType::directCode: + value = READ16(region.access.accessCode.backingStore, address - region.base); + return BusTransactionResult::ok; + + case MemoryRegionType::directData: + value = READ16(region.access.accessData.backingStore, address - region.base); + return BusTransactionResult::ok; + + default: + return myDefaultDelegate ? + myDefaultDelegate->read16(address, value) : BusTransactionResult::fail; + } +} + +CortexM0::BusTransactionResult CortexM0::write32(uInt32 address, uInt32 value) +{ + MemoryRegion& region = myRegions[myPageMap[address / PAGE_SIZE]]; + + switch (region.type) { + case MemoryRegionType::delegate: + return region.access.delegate->write32(address, value); + + case MemoryRegionType::directCode: + WRITE32(region.access.accessCode.backingStore, address - region.base, value); + return BusTransactionResult::ok; + + case MemoryRegionType::directData: + WRITE32(region.access.accessData.backingStore, address - region.base, value); + return BusTransactionResult::ok; + + default: + return myDefaultDelegate ? + myDefaultDelegate->write32(address, value) : BusTransactionResult::fail; + } +} + +CortexM0::BusTransactionResult CortexM0::write16(uInt32 address, uInt16 value) +{ + MemoryRegion& region = myRegions[myPageMap[address / PAGE_SIZE]]; + + switch (region.type) { + case MemoryRegionType::delegate: + return region.access.delegate->write16(address, value); + + case MemoryRegionType::directCode: { + const uInt32 offset = address - region.base; + + WRITE16(region.access.accessCode.backingStore, offset, value); + region.access.accessCode.ops[offset >> 1] = decodeInstructionWord(value); + + return BusTransactionResult::ok; + } + + case MemoryRegionType::directData: + WRITE16(region.access.accessData.backingStore, address - region.base, value); + return BusTransactionResult::ok; + + default: + return myDefaultDelegate ? + myDefaultDelegate->write16(address, value) : BusTransactionResult::fail; + } +} + +CortexM0::BusTransactionResult CortexM0::fetch16(uInt32 address, uInt16& value, uInt8& op) +{ + MemoryRegion& region = myRegions[myPageMap[address / PAGE_SIZE]]; + + switch (region.type) { + case MemoryRegionType::delegate: + return region.access.delegate->fetch16(address, value, op); + + case MemoryRegionType::directCode: { + const uInt32 offset = address - region.base; + + value = READ16(region.access.accessCode.backingStore, offset); + op = region.access.accessCode.ops[offset >> 1]; + + return BusTransactionResult::ok; + } + + case MemoryRegionType::directData: + value = READ16(region.access.accessCode.backingStore, address - region.base); + op = decodeInstructionWord(value); + + return BusTransactionResult::ok; + + default: + return myDefaultDelegate ? + myDefaultDelegate->fetch16(address, value, op) : BusTransactionResult::fail; + } +} + +void CortexM0::do_cvflag(uInt32 a, uInt32 b, uInt32 c) +{ + uInt32 rc = (a & 0x7FFFFFFF) + (b & 0x7FFFFFFF) + c; //carry in + rc >>= 31; //carry in in lsbit + a >>= 31; + b >>= 31; + uInt32 rd = (rc & 1) + (a & 1) + (b & 1); //carry out + rd >>= 1; //carry out in lsbit + + vFlag = (rc ^ rd) & 1; //if carry in != carry out then signed overflow + + rc += a + b; //carry out + cFlag = rc & 2; +} diff --git a/src/emucore/CortexM0.hxx b/src/emucore/CortexM0.hxx new file mode 100644 index 000000000..bea4891d1 --- /dev/null +++ b/src/emucore/CortexM0.hxx @@ -0,0 +1,152 @@ +//============================================================================ +// +// 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-2024 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 code is based on the "Thumbulator" by David Welch (dwelch@dwelch.com) +// Code is public domain and used with the author's consent +//============================================================================ + +#ifndef CORTEX_M0 +#define CORTEX_M0 + +#include "bspf.hxx" + +class CortexM0 +{ + public: + enum class BusTransactionResult : uInt8 { + ok, + stopAndRollback, + stop, + fail + }; + + class BusTransactionDelegate { + public: + virtual ~BusTransactionDelegate() = default; + + virtual BusTransactionResult read32(uInt32 address, uInt32& value) = 0; + virtual BusTransactionResult read16(uInt32 address, uInt16& value) = 0; + + virtual BusTransactionResult write32(uInt32 address, uInt32 value) = 0; + virtual BusTransactionResult write16(uInt32 address, uInt16 value) = 0; + + virtual BusTransactionResult fetch16(uInt32 address, uInt16& value, uInt8& op) = 0; + }; + + static constexpr uInt32 PAGE_SIZE = 4096; + + public: + CortexM0(); + + CortexM0& mapRegionData(uInt32 pageBase, uInt32 pageCount, + bool readOnly, uInt8* backingStore); + + CortexM0& mapRegionCode(uInt32 pageBase, uInt32 pageCount, + bool readOnly, uInt8* backingStore); + + CortexM0& mapRegionDelegate(uInt32 pageBase, uInt32 pageCount, + bool readOnly, BusTransactionDelegate* delegate); + + CortexM0& mapDefault(BusTransactionDelegate* delegate); + + CortexM0& reset(); + CortexM0& setRegister(uInt8 regno, uInt32 value); + + static uInt8 decodeInstructionWord(uInt16 instructionWord); + + BusTransactionResult run(uInt32 maxCycles, uInt32& cycles); + + private: + + enum class MemoryRegionType : uInt8 { + directData, + directCode, + delegate, + unmapped + }; + + struct MemoryRegionAccessData { + uInt8* backingStore; + }; + + struct MemoryRegionAccessCode { + uInt8* backingStore; + uInt8* ops; + }; + + struct MemoryRegion { + ~MemoryRegion() { + if (type == MemoryRegionType::directCode) + std::free(access.accessCode.ops); + } + + MemoryRegionType type{MemoryRegionType::unmapped}; + + uInt32 base; + uInt32 size; + bool readOnly; + + union { + MemoryRegionAccessData accessData; + MemoryRegionAccessCode accessCode; + BusTransactionDelegate* delegate; + } access; + }; + + private: + MemoryRegion& setupMapping(uInt32 pageBase, uInt32 pageCount, + bool readOnly, MemoryRegionType type); + + BusTransactionResult read32(uInt32 address, uInt32& value); + BusTransactionResult read16(uInt32 address, uInt16& value); + + BusTransactionResult write32(uInt32 address, uInt32 value); + BusTransactionResult write16(uInt32 address, uInt16 value); + + BusTransactionResult fetch16(uInt32 address, uInt16& value, uInt8& op); + + void do_cvflag(uInt32 a, uInt32 b, uInt32 c); + + int execute(); + + private: + std::array reg_norm; // normal execution mode, do not have a thread mode + uInt32 znFlags{0}; + uInt32 cFlag{0}; + uInt32 vFlag{0}; + + std::array myRegions; + unique_ptr myPageMap; + uInt8 myNextRegionIndex{0}; + BusTransactionDelegate* myDefaultDelegate{nullptr}; + + static constexpr uInt32 + CPSR_N = 1u << 31, + CPSR_Z = 1u << 30, + CPSR_C = 1u << 29, + CPSR_V = 1u << 28; + + private: + // Following constructors and assignment operators not supported + CortexM0(const CortexM0&) = delete; + CortexM0(CortexM0&&) = delete; + CortexM0& operator=(const CortexM0&) = delete; + CortexM0& operator=(CortexM0&&) = delete; +}; + +#endif // CORTEX_M0 diff --git a/src/emucore/module.mk b/src/emucore/module.mk index d356d09e1..56129e886 100644 --- a/src/emucore/module.mk +++ b/src/emucore/module.mk @@ -62,6 +62,7 @@ MODULE_OBJS := \ src/emucore/Console.o \ src/emucore/Control.o \ src/emucore/ControllerDetector.o \ + src/emucore/CortexM0.o \ src/emucore/DispatchResult.o \ src/emucore/Driving.o \ src/emucore/EventHandler.o \ diff --git a/src/os/windows/Stella.vcxproj b/src/os/windows/Stella.vcxproj index b26a30983..bccef1544 100755 --- a/src/os/windows/Stella.vcxproj +++ b/src/os/windows/Stella.vcxproj @@ -695,6 +695,7 @@ + @@ -1670,6 +1671,7 @@ + diff --git a/src/os/windows/Stella.vcxproj.filters b/src/os/windows/Stella.vcxproj.filters index bfb6759fd..33f81f4e5 100644 --- a/src/os/windows/Stella.vcxproj.filters +++ b/src/os/windows/Stella.vcxproj.filters @@ -1242,6 +1242,9 @@ Source Files\emucore + + Source Files\emucore + Source Files\debugger\gui @@ -2528,6 +2531,9 @@ Header Files\emucore + + Header Files\emucore + Header Files\debugger\gui