From 7f547db4ef4572537ff31564e0ed0ffdd48611b7 Mon Sep 17 00:00:00 2001 From: George Wright Date: Wed, 24 Jun 2026 17:49:59 -0700 Subject: [PATCH] formatting: add .clang-format, and run clang-format on all source files --- .clang-format | 321 ++++++ WindCore/arm710.cpp | 2208 +++++++++++++++++++----------------- WindCore/arm710.h | 570 +++++----- WindCore/clps7111.cpp | 1292 +++++++++++---------- WindCore/clps7111.h | 116 +- WindCore/clps7111_defs.h | 142 ++- WindCore/clps7600.cpp | 239 ++-- WindCore/clps7600.h | 44 +- WindCore/common.h | 253 +++-- WindCore/decoder-arm.c | 760 +++++++------ WindCore/decoder-inlines.h | 14 +- WindCore/decoder.c | 810 ++++++------- WindCore/decoder.h | 323 +++--- WindCore/emitter-arm.h | 627 +++++----- WindCore/emitter-inlines.h | 25 +- WindCore/emubase.h | 238 ++-- WindCore/etna.cpp | 282 ++--- WindCore/etna.h | 32 +- WindCore/hardware.h | 332 +++--- WindCore/isa-inlines.h | 20 +- WindCore/wind_defs.h | 163 ++- WindCore/windermere.cpp | 1488 +++++++++++++----------- WindCore/windermere.h | 121 +- WindQt/main.cpp | 106 +- WindQt/mainwindow.cpp | 413 ++++--- WindQt/mainwindow.h | 67 +- WindQt/pdascreenwindow.cpp | 410 ++++--- WindQt/pdascreenwindow.h | 27 +- WindWasm/main.cpp | 278 +++-- 29 files changed, 6279 insertions(+), 5442 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..f145697 --- /dev/null +++ b/.clang-format @@ -0,0 +1,321 @@ +--- +Language: Cpp +AlignAfterOpenBracket: true +AccessModifierOffset: -2 +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: true + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveShortCaseStatements: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCaseArrows: false + AlignCaseColons: false +AlignConsecutiveTableGenBreakingDAGArgColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveTableGenCondOperatorColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveTableGenDefinitionColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: + AlignPPAndNotPP: true + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowBreakBeforeNoexceptSpecifier: Never +AllowBreakBeforeQtProperty: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseExpressionOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: false +AllowShortCompoundRequirementOnASingleLine: true +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AllowShortNamespacesOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AttributeMacros: + - __capability +BinPackArguments: true +BinPackLongBracedList: true +BinPackParameters: BinPack +BitFieldColonSpacing: Both +BracedInitializerIndentWidth: -1 +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAdjacentStringLiterals: true +BreakAfterAttributes: Leave +BreakAfterJavaFieldAnnotations: false +BreakAfterOpenBracketBracedList: false +BreakAfterOpenBracketFunction: false +BreakAfterOpenBracketIf: false +BreakAfterOpenBracketLoop: false +BreakAfterOpenBracketSwitch: false +BreakAfterReturnType: None +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeCloseBracketBracedList: false +BreakBeforeCloseBracketFunction: false +BreakBeforeCloseBracketIf: false +BreakBeforeCloseBracketLoop: false +BreakBeforeCloseBracketSwitch: false +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Attach +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTemplateCloser: false +BreakBeforeTernaryOperators: true +BreakBinaryOperations: Never +BreakConstructorInitializers: BeforeColon +BreakFunctionDefinitionParameters: false +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +BreakTemplateDeclarations: MultiLine +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: AlignFirstComment +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +EnumTrailingComma: Leave +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: false +IndentExportBlock: true +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: false +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigitsInsert: 0 + BinaryMaxDigitsRemove: 0 + Decimal: 0 + DecimalMinDigitsInsert: 0 + DecimalMaxDigitsRemove: 0 + Hex: 0 + HexMinDigitsInsert: 0 + HexMaxDigitsRemove: 0 + BinaryMinDigits: 0 + DecimalMinDigits: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLines: + AtEndOfFile: false + AtStartOfBlock: true + AtStartOfFile: true +KeepFormFeed: false +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MainIncludeChar: Quote +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +NumericLiteralCase: + ExponentLetter: Leave + HexDigit: Leave + Prefix: Leave + Suffix: Leave +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +OneLineFormatOffRegex: '' +PackConstructorInitializers: BinPack +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakBeforeMemberAccess: 150 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakScopeResolution: 500 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Left +PPIndentWidth: -1 +QualifierAlignment: Leave +ReferenceAlignment: Pointer +ReflowComments: Always +RemoveBracesLLVM: false +RemoveEmptyLinesInUnwrappedLines: false +RemoveParentheses: Leave +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SkipMacroDefinitionBody: false +SortIncludes: + Enabled: true + IgnoreCase: false + IgnoreExtension: false +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterOperatorKeyword: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeJsonColon: false +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterNot: false + AfterOverloadedOperator: false + AfterPlacementOperator: true + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBraces: Never +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInContainerLiterals: true +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParens: Never +SpacesInParensOptions: + ExceptDoubleParentheses: false + InCStyleCasts: false + InConditionalStatements: false + InEmptyParentheses: false + Other: false +SpacesInSquareBrackets: false +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TableGenBreakInsideDAGArg: DontBreak +TabWidth: 8 +UseTab: Never +VerilogBreakBetweenInstancePorts: true +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +WrapNamespaceBodyWithEmptyLines: Leave +... + diff --git a/WindCore/arm710.cpp b/WindCore/arm710.cpp index 1496186..4cbe1e1 100644 --- a/WindCore/arm710.cpp +++ b/WindCore/arm710.cpp @@ -2,1218 +2,1294 @@ #include "common.h" // this will need changing if this code ever compiles on big-endian procs -inline uint32_t read32LE(uint8_t *p) { - return *((uint32_t *)p); -} -inline void write32LE(uint8_t *p, uint32_t v) { - *((uint32_t *)p) = v; -} - +inline uint32_t read32LE(uint8_t* p) { return *((uint32_t*)p); } +inline void write32LE(uint8_t* p, uint32_t v) { *((uint32_t*)p) = v; } void ARM710::switchBank(BankIndex newBank) { - if (newBank != bank) { - // R13 and R14 need saving/loading for all banks - allModesBankedRegisters[bank][0] = GPRs[13]; - allModesBankedRegisters[bank][1] = GPRs[14]; - GPRs[13] = allModesBankedRegisters[newBank][0]; - GPRs[14] = allModesBankedRegisters[newBank][1]; - - // R8 to R12 are only banked in FIQ mode - auto oldBankR8to12 = (bank == FiqBank) ? 1 : 0; - auto newBankR8to12 = (newBank == FiqBank) ? 1 : 0; - if (oldBankR8to12 != newBankR8to12) { - // swap these sets around - for (int i = 0; i < 5; i++) - fiqBankedRegisters[oldBankR8to12][i] = GPRs[8 + i]; - for (int i = 0; i < 5; i++) - GPRs[8 + i] = fiqBankedRegisters[newBankR8to12][i]; - } - - bank = newBank; - } + if (newBank != bank) { + // R13 and R14 need saving/loading for all banks + allModesBankedRegisters[bank][0] = GPRs[13]; + allModesBankedRegisters[bank][1] = GPRs[14]; + GPRs[13] = allModesBankedRegisters[newBank][0]; + GPRs[14] = allModesBankedRegisters[newBank][1]; + + // R8 to R12 are only banked in FIQ mode + auto oldBankR8to12 = (bank == FiqBank) ? 1 : 0; + auto newBankR8to12 = (newBank == FiqBank) ? 1 : 0; + if (oldBankR8to12 != newBankR8to12) { + // swap these sets around + for (int i = 0; i < 5; i++) + fiqBankedRegisters[oldBankR8to12][i] = GPRs[8 + i]; + for (int i = 0; i < 5; i++) + GPRs[8 + i] = fiqBankedRegisters[newBankR8to12][i]; + } + + bank = newBank; + } } - void ARM710::switchMode(Mode newMode) { - auto oldMode = currentMode(); - if (newMode != oldMode) { -// log("Switching mode! %x", newMode); - switchBank(modeToBank[newMode & 0xF]); - - CPSR &= ~CPSR_ModeMask; - CPSR |= newMode; - } + auto oldMode = currentMode(); + if (newMode != oldMode) { + // log("Switching mode! %x", newMode); + switchBank(modeToBank[newMode & 0xF]); + + CPSR &= ~CPSR_ModeMask; + CPSR |= newMode; + } } void ARM710::raiseException(Mode mode, uint32_t savedPC, uint32_t newPC) { - auto bankIndex = modeToBank[mode & 0xF]; -// log("Raising exception mode %x, saving PC %08x, CPSR %08x", mode, savedPC, CPSR); - SPSRs[bankIndex] = CPSR; + auto bankIndex = modeToBank[mode & 0xF]; + // log("Raising exception mode %x, saving PC %08x, CPSR %08x", mode, + // savedPC, CPSR); + SPSRs[bankIndex] = CPSR; - switchMode(mode); + switchMode(mode); - prefetchCount = 0; - GPRs[14] = savedPC; - GPRs[15] = newPC; + prefetchCount = 0; + GPRs[14] = savedPC; + GPRs[15] = newPC; } void ARM710::requestFIQ() { - raiseException(FIQ32, getRealPC() + 4, 0x1C); - CPSR |= CPSR_FIQDisable; - CPSR |= CPSR_IRQDisable; + raiseException(FIQ32, getRealPC() + 4, 0x1C); + CPSR |= CPSR_FIQDisable; + CPSR |= CPSR_IRQDisable; } void ARM710::requestIRQ() { -// log("Requesting IRQ: Last exec = %08x, setting LR = %08x", lastPcExecuted(), getRealPC() + 4); - raiseException(IRQ32, getRealPC() + 4, 0x18); - CPSR |= CPSR_IRQDisable; + // log("Requesting IRQ: Last exec = %08x, setting LR = %08x", + // lastPcExecuted(), getRealPC() + 4); + raiseException(IRQ32, getRealPC() + 4, 0x18); + CPSR |= CPSR_IRQDisable; } void ARM710::reset() { #ifdef ARM710T_CACHE - clearCache(); + clearCache(); #endif - raiseException(Supervisor32, 0, 0); + raiseException(Supervisor32, 0, 0); } - - uint32_t ARM710::tick() { - // pop an instruction off the end of the pipeline - bool haveInsn = false; - uint32_t insn; - MMUFault insnFault; - if (prefetchCount == 2) { - haveInsn = true; - insn = prefetch[1]; - insnFault = prefetchFaults[1]; - } - - // move the instruction we fetched last tick once along - if (prefetchCount >= 1) { - prefetch[1] = prefetch[0]; - prefetchFaults[1] = prefetchFaults[0]; - } - - // fetch a new instruction - auto newInsn = readVirtual(GPRs[15], V32); - GPRs[15] += 4; - prefetch[0] = newInsn.first.value_or(0); - prefetchFaults[0] = newInsn.second; - if (prefetchCount < 2) - prefetchCount++; - - // now deal with the one we popped - uint32_t clocks = 1; - if (haveInsn) { - pcHistory[pcHistoryIndex] = {GPRs[15] - 0xC, insn}; - pcHistoryIndex = (pcHistoryIndex + 1) % PcHistoryCount; - if (insnFault != NoFault) { - // Raise a prefetch error - // These do not set FSR or FAR - log("prefetch error! %08x", insnFault >> MMUFaultAddressShift); - logPcHistory(); - raiseException(Abort32, GPRs[15] - 8, 0xC); - } else { - clocks += executeInstruction(insn); - } - } - - if (faultTriggeredThisCycle) { - // data abort time! - faultTriggeredThisCycle = false; - raiseException(Abort32, GPRs[15] - 4, 0x10); - } - - return clocks; + // pop an instruction off the end of the pipeline + bool haveInsn = false; + uint32_t insn; + MMUFault insnFault; + if (prefetchCount == 2) { + haveInsn = true; + insn = prefetch[1]; + insnFault = prefetchFaults[1]; + } + + // move the instruction we fetched last tick once along + if (prefetchCount >= 1) { + prefetch[1] = prefetch[0]; + prefetchFaults[1] = prefetchFaults[0]; + } + + // fetch a new instruction + auto newInsn = readVirtual(GPRs[15], V32); + GPRs[15] += 4; + prefetch[0] = newInsn.first.value_or(0); + prefetchFaults[0] = newInsn.second; + if (prefetchCount < 2) + prefetchCount++; + + // now deal with the one we popped + uint32_t clocks = 1; + if (haveInsn) { + pcHistory[pcHistoryIndex] = {GPRs[15] - 0xC, insn}; + pcHistoryIndex = (pcHistoryIndex + 1) % PcHistoryCount; + if (insnFault != NoFault) { + // Raise a prefetch error + // These do not set FSR or FAR + log("prefetch error! %08x", insnFault >> MMUFaultAddressShift); + logPcHistory(); + raiseException(Abort32, GPRs[15] - 8, 0xC); + } else { + clocks += executeInstruction(insn); + } + } + + if (faultTriggeredThisCycle) { + // data abort time! + faultTriggeredThisCycle = false; + raiseException(Abort32, GPRs[15] - 4, 0x10); + } + + return clocks; } - static inline uint32_t extract(uint32_t value, uint32_t hiBit, uint32_t loBit) { - return (value >> loBit) & ((1 << (hiBit - loBit + 1)) - 1); -// return (value >> (32 - offset - length)) & ((1 << length) - 1); + return (value >> loBit) & ((1 << (hiBit - loBit + 1)) - 1); + // return (value >> (32 - offset - length)) & ((1 << length) - 1); } static inline bool extract1(uint32_t value, uint32_t bit) { - return (value >> bit) & 1; + return (value >> bit) & 1; } - uint32_t ARM710::executeInstruction(uint32_t i) { - uint32_t cycles = 1; -// log("executing insn %08x @ %08x", i, GPRs[15] - 0xC); - - // a big old dispatch thing here - // but first, conditions! - if (!checkCondition(extract(i, 31, 28))) - return cycles; - - if ((i & 0x0F000000) == 0x0F000000) - raiseException(Supervisor32, GPRs[15] - 8, 0x08); - else if ((i & 0x0F000F10) == 0x0E000F10) - cycles += execCP15RegisterTransfer(extract(i,23,21), extract1(i,20), extract(i,19,16), extract(i,15,12), extract(i,7,5), extract(i,3,0)); - else if ((i & 0x0E000000) == 0x0A000000) - cycles += execBranch(extract1(i,24), extract(i,23,0)); - else if ((i & 0x0E000000) == 0x08000000) - cycles += execBlockDataTransfer(extract(i,24,20), extract(i,19,16), extract(i,15,0)); - else if ((i & 0x0C000000) == 0x04000000) - cycles += execSingleDataTransfer(extract(i,25,20), extract(i,19,16), extract(i,15,12), extract(i,11,0)); - else if ((i & 0x0FB00FF0) == 0x01000090) - cycles += execSingleDataSwap(extract1(i,22), extract(i,19,16), extract(i,15,12), extract(i,3,0)); - else if ((i & 0x0F8000F0) == 0x00000090) - cycles += execMultiply(extract(i,21,20), extract(i,19,16), extract(i,15,12), extract(i,11,8), extract(i,3,0)); - else if ((i & 0x0F8000F0) == 0x00800090 && isTVersion) - cycles += execMultiplyLong(extract(i,22,20), extract(i,19,16), extract(i,15,12), extract(i,11,8), extract(i,3,0)); - else if ((i & 0x0E000090) == 0x00000090) { - cycles += execSingleHalfWordDataTransfer(extract(i, 24, 20), extract(i, 19, 16), extract(i, 15, 12), extract(i, 11, 8), extract(i, 6, 5), extract(i, 3, 0)); - } else if ((i & 0x0C000000) == 0x00000000) - cycles += execDataProcessing(extract1(i,25), extract(i,24,21), extract1(i,20), extract(i,19,16), extract(i,15,12), extract(i,11,0)); - else - raiseException(Undefined32, GPRs[15] - 8, 0x04); - - return cycles; + uint32_t cycles = 1; + // log("executing insn %08x @ %08x", i, GPRs[15] - 0xC); + + // a big old dispatch thing here + // but first, conditions! + if (!checkCondition(extract(i, 31, 28))) + return cycles; + + if ((i & 0x0F000000) == 0x0F000000) + raiseException(Supervisor32, GPRs[15] - 8, 0x08); + else if ((i & 0x0F000F10) == 0x0E000F10) + cycles += execCP15RegisterTransfer(extract(i, 23, 21), extract1(i, 20), + extract(i, 19, 16), extract(i, 15, 12), + extract(i, 7, 5), extract(i, 3, 0)); + else if ((i & 0x0E000000) == 0x0A000000) + cycles += execBranch(extract1(i, 24), extract(i, 23, 0)); + else if ((i & 0x0E000000) == 0x08000000) + cycles += execBlockDataTransfer(extract(i, 24, 20), extract(i, 19, 16), + extract(i, 15, 0)); + else if ((i & 0x0C000000) == 0x04000000) + cycles += execSingleDataTransfer(extract(i, 25, 20), extract(i, 19, 16), + extract(i, 15, 12), extract(i, 11, 0)); + else if ((i & 0x0FB00FF0) == 0x01000090) + cycles += execSingleDataSwap(extract1(i, 22), extract(i, 19, 16), + extract(i, 15, 12), extract(i, 3, 0)); + else if ((i & 0x0F8000F0) == 0x00000090) + cycles += + execMultiply(extract(i, 21, 20), extract(i, 19, 16), extract(i, 15, 12), + extract(i, 11, 8), extract(i, 3, 0)); + else if ((i & 0x0F8000F0) == 0x00800090 && isTVersion) + cycles += execMultiplyLong(extract(i, 22, 20), extract(i, 19, 16), + extract(i, 15, 12), extract(i, 11, 8), + extract(i, 3, 0)); + else if ((i & 0x0E000090) == 0x00000090) { + cycles += execSingleHalfWordDataTransfer( + extract(i, 24, 20), extract(i, 19, 16), extract(i, 15, 12), + extract(i, 11, 8), extract(i, 6, 5), extract(i, 3, 0)); + } else if ((i & 0x0C000000) == 0x00000000) + cycles += execDataProcessing(extract1(i, 25), extract(i, 24, 21), + extract1(i, 20), extract(i, 19, 16), + extract(i, 15, 12), extract(i, 11, 0)); + else + raiseException(Undefined32, GPRs[15] - 8, 0x04); + + return cycles; } -uint32_t ARM710::execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t Rn, uint32_t Rd, uint32_t Operand2) -{ - uint32_t cycles = 0; // TODO increment me semi-accurately - bool shifterCarryOutput; - - // compute our Op1 (may be unnecessary but that's ok) - uint32_t op1 = GPRs[Rn]; - - // compute our Op2 - uint32_t op2; - if (!I) { - // REGISTER - uint32_t Rm = extract(Operand2, 3, 0); - op2 = GPRs[Rm]; - - uint8_t shiftBy; - - // this is the real painful one, honestly - if (extract(Operand2, 4, 4)) { - // Shift by Register - uint32_t Rs = extract(Operand2, 11, 8); - shiftBy = GPRs[Rs] & 0xFF; - } else { - // Shift by Immediate - shiftBy = extract(Operand2, 11, 7); - - if (Rn == 15) // if PC is fetched... - op1 -= 4; // compensate for prefetching - if (Rm == 15) - op2 -= 4; - } - - if (extract(Operand2, 4, 4) && (shiftBy == 0)) { - // register shift by 0 never does anything - shifterCarryOutput = flagC(); - } else { - switch (extract(Operand2, 6, 5)) { - case 0: // Logical Left (LSL) - if (shiftBy == 0) { - shifterCarryOutput = flagC(); - // no change to op2! - } else if (shiftBy <= 31) { - shifterCarryOutput = extract1(op2, 31 - shiftBy); - op2 <<= shiftBy; - } else if (shiftBy == 32) { - shifterCarryOutput = extract1(op2, 0); - op2 = 0; - } else /*if (shiftBy >= 33)*/ { - shifterCarryOutput = false; - op2 = 0; - } - break; - case 1: // Logical Right (LSR) - if (shiftBy == 0 || shiftBy == 32) { - shifterCarryOutput = extract1(op2, 31); - op2 = 0; - } else if (shiftBy <= 31) { - shifterCarryOutput = extract1(op2, shiftBy - 1); - op2 >>= shiftBy; - } else /*if (shiftBy >= 33)*/ { - shifterCarryOutput = false; - op2 = 0; - } - break; - case 2: // Arithmetic Right (ASR) - if (shiftBy == 0 || shiftBy >= 32) { - shifterCarryOutput = extract1(op2, 31); - op2 = (int32_t)op2 >> 31; - } else /*if (shiftBy <= 31)*/ { - shifterCarryOutput = extract1(op2, shiftBy - 1); - op2 = (int32_t)op2 >> shiftBy; - } - break; - case 3: // Rotate Right (ROR) - if (shiftBy == 0) { // treated as RRX - shifterCarryOutput = op2 & 1; - op2 >>= 1; - op2 |= flagC() ? 0x80000000 : 0; - } else { - shiftBy %= 32; - if (shiftBy == 0) { // like 32 - shifterCarryOutput = extract1(op2, 31); - // no change to op2 - } else { - shifterCarryOutput = extract1(op2, shiftBy - 1); - op2 = ROR(op2, shiftBy); - } - } - break; - } - } - } else { - // IMMEDIATE - if (Rn == 15) // if PC is fetched... - op1 -= 4; // compensate for prefetching - - uint32_t Rotate = extract(Operand2, 11, 8); - uint32_t Imm = extract(Operand2, 7, 0); - op2 = ROR(Imm, Rotate * 2); - shifterCarryOutput = flagC(); // correct? unsure... - } - - // we have our operands, what next - uint64_t result = 0; - uint32_t flags = 0; - -#define LOGICAL_OP(v) \ - result = v; \ - flags |= (result & 0xFFFFFFFF) ? 0 : CPSR_Z; \ - flags |= (result & 0x80000000) ? CPSR_N : 0; \ - flags |= shifterCarryOutput ? CPSR_C : 0; \ - flags |= (CPSR & CPSR_V); - -#define ADD_OP(a, b, c) \ - result = (uint64_t)(a) + (uint64_t)(b) + (uint64_t)(c); \ - flags |= (result & 0xFFFFFFFF) ? 0 : CPSR_Z; \ - flags |= (result & 0x80000000) ? CPSR_N : 0; \ - flags |= (result & 0x100000000) ? CPSR_C : 0; \ - flags |= ((((a) & 0x80000000) == ((b) & 0x80000000)) && (((a) & 0x80000000) != (result & 0x80000000))) ? CPSR_V : 0; +uint32_t ARM710::execDataProcessing(bool I, uint32_t Opcode, bool S, + uint32_t Rn, uint32_t Rd, + uint32_t Operand2) { + uint32_t cycles = 0; // TODO increment me semi-accurately + bool shifterCarryOutput; + + // compute our Op1 (may be unnecessary but that's ok) + uint32_t op1 = GPRs[Rn]; + + // compute our Op2 + uint32_t op2; + if (!I) { + // REGISTER + uint32_t Rm = extract(Operand2, 3, 0); + op2 = GPRs[Rm]; + + uint8_t shiftBy; + + // this is the real painful one, honestly + if (extract(Operand2, 4, 4)) { + // Shift by Register + uint32_t Rs = extract(Operand2, 11, 8); + shiftBy = GPRs[Rs] & 0xFF; + } else { + // Shift by Immediate + shiftBy = extract(Operand2, 11, 7); + + if (Rn == 15) // if PC is fetched... + op1 -= 4; // compensate for prefetching + if (Rm == 15) + op2 -= 4; + } + + if (extract(Operand2, 4, 4) && (shiftBy == 0)) { + // register shift by 0 never does anything + shifterCarryOutput = flagC(); + } else { + switch (extract(Operand2, 6, 5)) { + case 0: // Logical Left (LSL) + if (shiftBy == 0) { + shifterCarryOutput = flagC(); + // no change to op2! + } else if (shiftBy <= 31) { + shifterCarryOutput = extract1(op2, 31 - shiftBy); + op2 <<= shiftBy; + } else if (shiftBy == 32) { + shifterCarryOutput = extract1(op2, 0); + op2 = 0; + } else /*if (shiftBy >= 33)*/ { + shifterCarryOutput = false; + op2 = 0; + } + break; + case 1: // Logical Right (LSR) + if (shiftBy == 0 || shiftBy == 32) { + shifterCarryOutput = extract1(op2, 31); + op2 = 0; + } else if (shiftBy <= 31) { + shifterCarryOutput = extract1(op2, shiftBy - 1); + op2 >>= shiftBy; + } else /*if (shiftBy >= 33)*/ { + shifterCarryOutput = false; + op2 = 0; + } + break; + case 2: // Arithmetic Right (ASR) + if (shiftBy == 0 || shiftBy >= 32) { + shifterCarryOutput = extract1(op2, 31); + op2 = (int32_t)op2 >> 31; + } else /*if (shiftBy <= 31)*/ { + shifterCarryOutput = extract1(op2, shiftBy - 1); + op2 = (int32_t)op2 >> shiftBy; + } + break; + case 3: // Rotate Right (ROR) + if (shiftBy == 0) { // treated as RRX + shifterCarryOutput = op2 & 1; + op2 >>= 1; + op2 |= flagC() ? 0x80000000 : 0; + } else { + shiftBy %= 32; + if (shiftBy == 0) { // like 32 + shifterCarryOutput = extract1(op2, 31); + // no change to op2 + } else { + shifterCarryOutput = extract1(op2, shiftBy - 1); + op2 = ROR(op2, shiftBy); + } + } + break; + } + } + } else { + // IMMEDIATE + if (Rn == 15) // if PC is fetched... + op1 -= 4; // compensate for prefetching + + uint32_t Rotate = extract(Operand2, 11, 8); + uint32_t Imm = extract(Operand2, 7, 0); + op2 = ROR(Imm, Rotate * 2); + shifterCarryOutput = flagC(); // correct? unsure... + } + + // we have our operands, what next + uint64_t result = 0; + uint32_t flags = 0; + +#define LOGICAL_OP(v) \ + result = v; \ + flags |= (result & 0xFFFFFFFF) ? 0 : CPSR_Z; \ + flags |= (result & 0x80000000) ? CPSR_N : 0; \ + flags |= shifterCarryOutput ? CPSR_C : 0; \ + flags |= (CPSR & CPSR_V); + +#define ADD_OP(a, b, c) \ + result = (uint64_t)(a) + (uint64_t)(b) + (uint64_t)(c); \ + flags |= (result & 0xFFFFFFFF) ? 0 : CPSR_Z; \ + flags |= (result & 0x80000000) ? CPSR_N : 0; \ + flags |= (result & 0x100000000) ? CPSR_C : 0; \ + flags |= ((((a) & 0x80000000) == ((b) & 0x80000000)) && \ + (((a) & 0x80000000) != (result & 0x80000000))) \ + ? CPSR_V \ + : 0; #define SUB_OP(a, b, c) ADD_OP(a, ~b, c) - - switch (Opcode) { - case 0: LOGICAL_OP(op1 & op2); break; // AND - case 1: LOGICAL_OP(op1 ^ op2); break; // EOR - case 2: SUB_OP(op1, op2, 1); break; // SUB - case 3: SUB_OP(op2, op1, 1); break; // RSB - case 4: ADD_OP(op1, op2, 0); break; // ADD - case 5: ADD_OP(op1, op2, flagC()); break; // ADC - case 6: SUB_OP(op1, op2, flagC()); break; // SBC - case 7: SUB_OP(op2, op1, flagC()); break; // RSC - case 8: LOGICAL_OP(op1 & op2); break; // TST - case 9: LOGICAL_OP(op1 ^ op2); break; // TEQ - case 0xA: SUB_OP(op1, op2, 1); break; // CMP - case 0xB: ADD_OP(op1, op2, 0); break; // CMN - case 0xC: LOGICAL_OP(op1 | op2); break; // ORR - case 0xD: LOGICAL_OP(op2); break; // MOV - case 0xE: LOGICAL_OP(op1 & ~op2); break; // BIC - case 0xF: LOGICAL_OP(~op2); break; // MVN - } - - if (Opcode >= 8 && Opcode <= 0xB) { - // Output-less opcodes: special behaviour - if (S) { - CPSR = (CPSR & ~CPSR_FlagMask) | flags; -// log("CPSR setflags=%08x results in CPSR=%08x", flags, CPSR); - } else if (Opcode == 8) { - // MRS, CPSR -> Reg - GPRs[Rd] = CPSR; -// log("r%d <- CPSR(%08x)", Rd, GPRs[Rd]); - } else if (Opcode == 9) { - // MSR, Reg -> CPSR - bool canChangeMode = extract1(Rn, 0); - if (canChangeMode && isPrivileged()) { - auto newCPSR = GPRs[extract(Operand2, 3, 0)]; - switchMode(modeFromCPSR(newCPSR)); - CPSR = newCPSR; -// log("CPSR change privileged: %08x", CPSR); - } else { - // for the flag-only version, immediates are allowed - // so we just re-use what was calculated earlier... - auto newFlag = I ? op2 : GPRs[extract(Operand2, 3, 0)]; - CPSR &= ~CPSR_FlagMask; - CPSR |= (newFlag & CPSR_FlagMask); -// log("CPSR change unprivileged: new=%08x result=%08x", newFlag, CPSR); - } - } else if (Opcode == 0xA) { - // MRS, SPSR -> Reg - if (isPrivileged()) { - GPRs[Rd] = SPSRs[currentBank()]; -// log("r%d <- SPSR(%08x)", Rd, GPRs[Rd]); - } - } else /*if (Opcode == 0xB)*/ { - bool canChangeMode = extract1(Rn, 0); - if (isPrivileged()) { - if (canChangeMode) { - SPSRs[currentBank()] = GPRs[extract(Operand2, 3, 0)]; -// log("SPSR change privileged: %08x", SPSRs[currentBank()]); - } else { - // same hat - auto newFlag = I ? op2 : GPRs[extract(Operand2, 3, 0)]; - SPSRs[currentBank()] &= ~CPSR_FlagMask; - SPSRs[currentBank()] |= (newFlag & CPSR_FlagMask); -// log("SPSR change unprivileged: new=%08x result=%08x", newFlag, SPSRs[currentBank()]); - } - } - } - } else { - GPRs[Rd] = result & 0xFFFFFFFF; - - if (Rd == 15) { - // Writing to PC - // Special things occur here! - GPRs[Rd] &= ~3; // TODO is this really necessary?? - prefetchCount = 0; - if (S && isPrivileged()) { - // We SHOULD be privileged - // (Raise an error otherwise...?) - auto saved = SPSRs[currentBank()]; - switchMode(modeFromCPSR(saved)); - CPSR = saved; -// log("dataproc restore CPSR: %08x", saved); - } - } else if (S) { - CPSR = (CPSR & ~CPSR_FlagMask) | flags; -// log("dataproc flag change: flags=%08x CPSR=%08x", flags, CPSR); - } - } - - return cycles; + switch (Opcode) { + case 0: + LOGICAL_OP(op1 & op2); + break; // AND + case 1: + LOGICAL_OP(op1 ^ op2); + break; // EOR + case 2: + SUB_OP(op1, op2, 1); + break; // SUB + case 3: + SUB_OP(op2, op1, 1); + break; // RSB + case 4: + ADD_OP(op1, op2, 0); + break; // ADD + case 5: + ADD_OP(op1, op2, flagC()); + break; // ADC + case 6: + SUB_OP(op1, op2, flagC()); + break; // SBC + case 7: + SUB_OP(op2, op1, flagC()); + break; // RSC + case 8: + LOGICAL_OP(op1 & op2); + break; // TST + case 9: + LOGICAL_OP(op1 ^ op2); + break; // TEQ + case 0xA: + SUB_OP(op1, op2, 1); + break; // CMP + case 0xB: + ADD_OP(op1, op2, 0); + break; // CMN + case 0xC: + LOGICAL_OP(op1 | op2); + break; // ORR + case 0xD: + LOGICAL_OP(op2); + break; // MOV + case 0xE: + LOGICAL_OP(op1 & ~op2); + break; // BIC + case 0xF: + LOGICAL_OP(~op2); + break; // MVN + } + + if (Opcode >= 8 && Opcode <= 0xB) { + // Output-less opcodes: special behaviour + if (S) { + CPSR = (CPSR & ~CPSR_FlagMask) | flags; + // log("CPSR setflags=%08x results in CPSR=%08x", + // flags, CPSR); + } else if (Opcode == 8) { + // MRS, CPSR -> Reg + GPRs[Rd] = CPSR; + // log("r%d <- CPSR(%08x)", Rd, GPRs[Rd]); + } else if (Opcode == 9) { + // MSR, Reg -> CPSR + bool canChangeMode = extract1(Rn, 0); + if (canChangeMode && isPrivileged()) { + auto newCPSR = GPRs[extract(Operand2, 3, 0)]; + switchMode(modeFromCPSR(newCPSR)); + CPSR = newCPSR; + // log("CPSR change privileged: %08x", + // CPSR); + } else { + // for the flag-only version, immediates are allowed + // so we just re-use what was calculated earlier... + auto newFlag = I ? op2 : GPRs[extract(Operand2, 3, 0)]; + CPSR &= ~CPSR_FlagMask; + CPSR |= (newFlag & CPSR_FlagMask); + // log("CPSR change unprivileged: new=%08x + // result=%08x", newFlag, CPSR); + } + } else if (Opcode == 0xA) { + // MRS, SPSR -> Reg + if (isPrivileged()) { + GPRs[Rd] = SPSRs[currentBank()]; + // log("r%d <- SPSR(%08x)", Rd, GPRs[Rd]); + } + } else /*if (Opcode == 0xB)*/ { + bool canChangeMode = extract1(Rn, 0); + if (isPrivileged()) { + if (canChangeMode) { + SPSRs[currentBank()] = GPRs[extract(Operand2, 3, 0)]; + // log("SPSR change privileged: + //%08x", SPSRs[currentBank()]); + } else { + // same hat + auto newFlag = I ? op2 : GPRs[extract(Operand2, 3, 0)]; + SPSRs[currentBank()] &= ~CPSR_FlagMask; + SPSRs[currentBank()] |= (newFlag & CPSR_FlagMask); + // log("SPSR change unprivileged: + // new=%08x result=%08x", newFlag, SPSRs[currentBank()]); + } + } + } + } else { + GPRs[Rd] = result & 0xFFFFFFFF; + + if (Rd == 15) { + // Writing to PC + // Special things occur here! + GPRs[Rd] &= ~3; // TODO is this really necessary?? + prefetchCount = 0; + if (S && isPrivileged()) { + // We SHOULD be privileged + // (Raise an error otherwise...?) + auto saved = SPSRs[currentBank()]; + switchMode(modeFromCPSR(saved)); + CPSR = saved; + // log("dataproc restore CPSR: %08x", + // saved); + } + } else if (S) { + CPSR = (CPSR & ~CPSR_FlagMask) | flags; + // log("dataproc flag change: flags=%08x + // CPSR=%08x", flags, CPSR); + } + } + + return cycles; } -uint32_t ARM710::execMultiply(uint32_t AS, uint32_t Rd, uint32_t Rn, uint32_t Rs, uint32_t Rm) -{ - // no need for R15 fuckery - // datasheet says it's not allowed here - if (AS & 2) - GPRs[Rd] = GPRs[Rm] * GPRs[Rs] + GPRs[Rn]; - else - GPRs[Rd] = GPRs[Rm] * GPRs[Rs]; - - if (AS & 1) { - CPSR &= ~(CPSR_N | CPSR_Z); - CPSR |= GPRs[Rd] ? 0 : CPSR_Z; - CPSR |= (GPRs[Rd] & 0x80000000) ? CPSR_N : 0; - } - - return 0; +uint32_t ARM710::execMultiply(uint32_t AS, uint32_t Rd, uint32_t Rn, + uint32_t Rs, uint32_t Rm) { + // no need for R15 fuckery + // datasheet says it's not allowed here + if (AS & 2) + GPRs[Rd] = GPRs[Rm] * GPRs[Rs] + GPRs[Rn]; + else + GPRs[Rd] = GPRs[Rm] * GPRs[Rs]; + + if (AS & 1) { + CPSR &= ~(CPSR_N | CPSR_Z); + CPSR |= GPRs[Rd] ? 0 : CPSR_Z; + CPSR |= (GPRs[Rd] & 0x80000000) ? CPSR_N : 0; + } + + return 0; } // ARM710T only! -uint32_t ARM710::execMultiplyLong(uint32_t UAS, uint32_t RdHi, uint32_t RdLo, uint32_t Rs, uint32_t Rm) -{ - // no need for R15 fuckery - // datasheet says it's not allowed here - uint64_t result; - if (UAS & 4) // unsigned - result = (uint64_t)GPRs[Rm] * (uint64_t)GPRs[Rs]; - else // signed - result = (uint64_t)((int64_t)GPRs[Rm] * (int64_t)GPRs[Rs]); - - if (UAS & 2) { - // accumulate - uint64_t addend = (uint64_t)GPRs[RdLo] | ((uint64_t)GPRs[RdHi] << 32); - result += addend; - } - - if (UAS & 1) { - CPSR &= ~(CPSR_N | CPSR_Z); - CPSR |= result ? 0 : CPSR_Z; - CPSR |= (result & 0x8000000000000000) ? CPSR_N : 0; - } - - GPRs[RdLo] = result & 0xFFFFFFFF; - GPRs[RdHi] = result >> 32; - - return 0; +uint32_t ARM710::execMultiplyLong(uint32_t UAS, uint32_t RdHi, uint32_t RdLo, + uint32_t Rs, uint32_t Rm) { + // no need for R15 fuckery + // datasheet says it's not allowed here + uint64_t result; + if (UAS & 4) // unsigned + result = (uint64_t)GPRs[Rm] * (uint64_t)GPRs[Rs]; + else // signed + result = (uint64_t)((int64_t)GPRs[Rm] * (int64_t)GPRs[Rs]); + + if (UAS & 2) { + // accumulate + uint64_t addend = (uint64_t)GPRs[RdLo] | ((uint64_t)GPRs[RdHi] << 32); + result += addend; + } + + if (UAS & 1) { + CPSR &= ~(CPSR_N | CPSR_Z); + CPSR |= result ? 0 : CPSR_Z; + CPSR |= (result & 0x8000000000000000) ? CPSR_N : 0; + } + + GPRs[RdLo] = result & 0xFFFFFFFF; + GPRs[RdHi] = result >> 32; + + return 0; } -uint32_t ARM710::execSingleDataSwap(bool B, uint32_t Rn, uint32_t Rd, uint32_t Rm) -{ - auto valueSize = B ? V8 : V32; - auto readResult = readVirtual(GPRs[Rn], valueSize); - auto fault = readResult.second; +uint32_t ARM710::execSingleDataSwap(bool B, uint32_t Rn, uint32_t Rd, + uint32_t Rm) { + auto valueSize = B ? V8 : V32; + auto readResult = readVirtual(GPRs[Rn], valueSize); + auto fault = readResult.second; - if (fault == NoFault) { - fault = writeVirtual(GPRs[Rm], GPRs[Rn], valueSize); - if (fault == NoFault) - GPRs[Rd] = readResult.first.value(); - } + if (fault == NoFault) { + fault = writeVirtual(GPRs[Rm], GPRs[Rn], valueSize); + if (fault == NoFault) + GPRs[Rd] = readResult.first.value(); + } - if (fault != NoFault) - reportFault(fault); + if (fault != NoFault) + reportFault(fault); - return 1; + return 1; } -uint32_t ARM710::execSingleDataTransfer(uint32_t IPUBWL, uint32_t Rn, uint32_t Rd, uint32_t offset) -{ - bool load = extract1(IPUBWL, 0); - bool writeback = extract1(IPUBWL, 1); - auto valueSize = extract1(IPUBWL, 2) ? V8 : V32; - bool up = extract1(IPUBWL, 3); - bool preIndex = extract1(IPUBWL, 4); - bool immediate = !extract1(IPUBWL, 5); - - // calculate the offset - uint32_t calcOffset; - if (!immediate) { - // REGISTER - uint32_t Rm = extract(offset, 3, 0); - calcOffset = GPRs[Rm]; - - uint8_t shiftBy = extract(offset, 11, 7); - - switch (extract(offset, 6, 5)) { - case 0: // Logical Left (LSL) - if (shiftBy > 0) - calcOffset <<= shiftBy; - break; - case 1: // Logical Right (LSR) - if (shiftBy == 0) - calcOffset = 0; - else - calcOffset >>= shiftBy; - break; - case 2: // Arithmetic Right (ASR) - if (shiftBy == 0) - calcOffset = (int32_t)calcOffset >> 31; - else - calcOffset = (int32_t)calcOffset >> shiftBy; - break; - case 3: // Rotate Right (ROR) - if (shiftBy == 0) { // treated as RRX - calcOffset >>= 1; - calcOffset |= flagC() ? 0x80000000 : 0; - } else - calcOffset = ROR(calcOffset, shiftBy); - break; - } - } else { - // IMMEDIATE - // No rotation or anything here - calcOffset = offset; - } - - uint32_t base = GPRs[Rn]; - if (Rn == 15) base -= 4; // prefetch adjustment - uint32_t modifiedBase = up ? (base + calcOffset) : (base - calcOffset); - uint32_t transferAddr = preIndex ? modifiedBase : base; - - bool changeModes = !preIndex && writeback && isPrivileged(); - auto saveMode = currentMode(); - - MMUFault fault; - - if (load) { - if (changeModes) switchMode(User32); - auto readResult = readVirtual(transferAddr, valueSize); - if (changeModes) switchMode(saveMode); - if (readResult.first.has_value()) { - GPRs[Rd] = readResult.first.value(); - if (Rd == 15) prefetchCount = 0; - } - fault = readResult.second; - } else { - uint32_t value = GPRs[Rd]; - if (changeModes) switchMode(User32); - fault = writeVirtual(value, transferAddr, valueSize); - if (changeModes) switchMode(saveMode); - } - - if ((preIndex && writeback) || !preIndex) - GPRs[Rn] = modifiedBase; - - if (fault != NoFault) - reportFault(fault); - - return 2; +uint32_t ARM710::execSingleDataTransfer(uint32_t IPUBWL, uint32_t Rn, + uint32_t Rd, uint32_t offset) { + bool load = extract1(IPUBWL, 0); + bool writeback = extract1(IPUBWL, 1); + auto valueSize = extract1(IPUBWL, 2) ? V8 : V32; + bool up = extract1(IPUBWL, 3); + bool preIndex = extract1(IPUBWL, 4); + bool immediate = !extract1(IPUBWL, 5); + + // calculate the offset + uint32_t calcOffset; + if (!immediate) { + // REGISTER + uint32_t Rm = extract(offset, 3, 0); + calcOffset = GPRs[Rm]; + + uint8_t shiftBy = extract(offset, 11, 7); + + switch (extract(offset, 6, 5)) { + case 0: // Logical Left (LSL) + if (shiftBy > 0) + calcOffset <<= shiftBy; + break; + case 1: // Logical Right (LSR) + if (shiftBy == 0) + calcOffset = 0; + else + calcOffset >>= shiftBy; + break; + case 2: // Arithmetic Right (ASR) + if (shiftBy == 0) + calcOffset = (int32_t)calcOffset >> 31; + else + calcOffset = (int32_t)calcOffset >> shiftBy; + break; + case 3: // Rotate Right (ROR) + if (shiftBy == 0) { // treated as RRX + calcOffset >>= 1; + calcOffset |= flagC() ? 0x80000000 : 0; + } else + calcOffset = ROR(calcOffset, shiftBy); + break; + } + } else { + // IMMEDIATE + // No rotation or anything here + calcOffset = offset; + } + + uint32_t base = GPRs[Rn]; + if (Rn == 15) + base -= 4; // prefetch adjustment + uint32_t modifiedBase = up ? (base + calcOffset) : (base - calcOffset); + uint32_t transferAddr = preIndex ? modifiedBase : base; + + bool changeModes = !preIndex && writeback && isPrivileged(); + auto saveMode = currentMode(); + + MMUFault fault; + + if (load) { + if (changeModes) + switchMode(User32); + auto readResult = readVirtual(transferAddr, valueSize); + if (changeModes) + switchMode(saveMode); + if (readResult.first.has_value()) { + GPRs[Rd] = readResult.first.value(); + if (Rd == 15) + prefetchCount = 0; + } + fault = readResult.second; + } else { + uint32_t value = GPRs[Rd]; + if (changeModes) + switchMode(User32); + fault = writeVirtual(value, transferAddr, valueSize); + if (changeModes) + switchMode(saveMode); + } + + if ((preIndex && writeback) || !preIndex) + GPRs[Rn] = modifiedBase; + + if (fault != NoFault) + reportFault(fault); + + return 2; } -uint32_t ARM710::execSingleHalfWordDataTransfer(uint32_t PUIWL, uint32_t Rn, uint32_t Rd, uint32_t addrMode1, uint32_t SH, uint32_t addrMode2) -{ - bool load = extract1(PUIWL, 0); - bool writeback = extract1(PUIWL, 1); - bool immediate = extract1(PUIWL, 2); - bool up = extract1(PUIWL, 3); - bool preIndex = extract1(PUIWL, 4); - - uint32_t LSH = ((PUIWL << 2) | SH) & 0x7; - ValueSize valueSize; - bool isSigned; - - switch (LSH) { - case 0x1: - valueSize = V16; - isSigned = false; - break; - case 0x5: - valueSize = V16; - isSigned = false; - break; - case 0x6: - valueSize = V8; - isSigned = true; - break; - case 0x7: - valueSize = V16; - isSigned = true; - break; - default: - // Invalid instruction on ARMv4 as it doesn't support double word ldr/str - return 2; - } - - // calculate the offset - uint32_t calcOffset; - if (!immediate) { - // addrMode1 should be zero (SBZ) - // addrMode2 is Rm - calcOffset = GPRs[addrMode2]; - } else { - // IMMEDIATE - // No rotation or anything here - // addrMode1 is the high 4 bits - // addrMode2 is the low 4 bits - calcOffset = (addrMode1 << 4) | addrMode2; - } - - uint32_t base = GPRs[Rn]; - if (Rn == 15) base -= 4; // prefetch adjustment - uint32_t modifiedBase = up ? (base + calcOffset) : (base - calcOffset); - uint32_t transferAddr = preIndex ? modifiedBase : base; - - bool changeModes = !preIndex && writeback && isPrivileged(); - auto saveMode = currentMode(); - - MMUFault fault; - - if (load) { - if (changeModes) switchMode(User32); - auto readResult = readVirtual(transferAddr, valueSize); - if (changeModes) switchMode(saveMode); - if (readResult.first.has_value()) { - GPRs[Rd] = readResult.first.value(); - if (Rd == 15) prefetchCount = 0; - } - fault = readResult.second; - } else { - uint32_t value = GPRs[Rd]; - if (changeModes) switchMode(User32); - fault = writeVirtual(value, transferAddr, valueSize); - if (changeModes) switchMode(saveMode); - } - - if ((preIndex && writeback) || !preIndex) - GPRs[Rn] = modifiedBase; - - if (fault != NoFault) - reportFault(fault); - - return 2; +uint32_t ARM710::execSingleHalfWordDataTransfer(uint32_t PUIWL, uint32_t Rn, + uint32_t Rd, uint32_t addrMode1, + uint32_t SH, + uint32_t addrMode2) { + bool load = extract1(PUIWL, 0); + bool writeback = extract1(PUIWL, 1); + bool immediate = extract1(PUIWL, 2); + bool up = extract1(PUIWL, 3); + bool preIndex = extract1(PUIWL, 4); + + uint32_t LSH = ((PUIWL << 2) | SH) & 0x7; + ValueSize valueSize; + bool isSigned; + + switch (LSH) { + case 0x1: + valueSize = V16; + isSigned = false; + break; + case 0x5: + valueSize = V16; + isSigned = false; + break; + case 0x6: + valueSize = V8; + isSigned = true; + break; + case 0x7: + valueSize = V16; + isSigned = true; + break; + default: + // Invalid instruction on ARMv4 as it doesn't support double word ldr/str + return 2; + } + + // calculate the offset + uint32_t calcOffset; + if (!immediate) { + // addrMode1 should be zero (SBZ) + // addrMode2 is Rm + calcOffset = GPRs[addrMode2]; + } else { + // IMMEDIATE + // No rotation or anything here + // addrMode1 is the high 4 bits + // addrMode2 is the low 4 bits + calcOffset = (addrMode1 << 4) | addrMode2; + } + + uint32_t base = GPRs[Rn]; + if (Rn == 15) + base -= 4; // prefetch adjustment + uint32_t modifiedBase = up ? (base + calcOffset) : (base - calcOffset); + uint32_t transferAddr = preIndex ? modifiedBase : base; + + bool changeModes = !preIndex && writeback && isPrivileged(); + auto saveMode = currentMode(); + + MMUFault fault; + + if (load) { + if (changeModes) + switchMode(User32); + auto readResult = readVirtual(transferAddr, valueSize); + if (changeModes) + switchMode(saveMode); + if (readResult.first.has_value()) { + GPRs[Rd] = readResult.first.value(); + if (Rd == 15) + prefetchCount = 0; + } + fault = readResult.second; + } else { + uint32_t value = GPRs[Rd]; + if (changeModes) + switchMode(User32); + fault = writeVirtual(value, transferAddr, valueSize); + if (changeModes) + switchMode(saveMode); + } + + if ((preIndex && writeback) || !preIndex) + GPRs[Rn] = modifiedBase; + + if (fault != NoFault) + reportFault(fault); + + return 2; } -uint32_t ARM710::execBlockDataTransfer(uint32_t PUSWL, uint32_t Rn, uint32_t registerList) -{ - bool load = extract1(PUSWL, 0); - bool store = !load; - bool writeback = extract1(PUSWL, 1); - bool psrForceUser = extract1(PUSWL, 2); - bool up = extract1(PUSWL, 3); - bool preIndex = extract1(PUSWL, 4); - - MMUFault fault = NoFault; - uint32_t base = GPRs[Rn] & ~3; - uint32_t blockSize = popcount32(registerList) * 4; - - uint32_t lowAddr, updatedBase; - if (up) { - updatedBase = base + blockSize; - lowAddr = base + (preIndex ? 4 : 0); - } else { - updatedBase = base - blockSize; - lowAddr = updatedBase + (preIndex ? 0 : 4); - } - - auto saveBank = bank; - if (psrForceUser && (store || !(registerList & 0x8000))) - switchBank(MainBank); - - bool doneWriteback = false; - if (load && writeback) { - doneWriteback = true; - GPRs[Rn] = updatedBase; - } - - uint32_t addr = lowAddr; - for (int i = 0; i < 16; i++) { - if (registerList & (1 << i)) { - // work on this one - if (load) { - // handling for LDM faults may be kinda iffy... - // wording on datasheet is a bit unclear - auto readResult = readVirtual(addr, V32); - if (readResult.first.has_value()) - GPRs[i] = readResult.first.value(); - if (readResult.second != NoFault) { - fault = readResult.second; - break; - } - } else { - auto newFault = writeVirtual(GPRs[i], addr, V32); - if (newFault != NoFault) - fault = newFault; - } - - addr += 4; - - if (writeback && !doneWriteback) { - doneWriteback = true; - GPRs[Rn] = updatedBase; - } - } - } - - // datasheet specifies that base register must be - // restored if an error occurs during LDM - if (load && fault != NoFault) - GPRs[Rn] = writeback ? updatedBase : base; - - if (psrForceUser && (store || !(registerList & 0x8000))) - switchBank(saveBank); - - if (load && (registerList & 0x8000)) { - prefetchCount = 0; - if (psrForceUser && isPrivileged() && fault == NoFault) { - auto saved = SPSRs[currentBank()]; - switchMode(modeFromCPSR(saved)); - CPSR = saved; -// log("reloading saved SPSR: %08x", saved); - } - } - - if (fault != NoFault) - reportFault(fault); - - return 0; // fixme +uint32_t ARM710::execBlockDataTransfer(uint32_t PUSWL, uint32_t Rn, + uint32_t registerList) { + bool load = extract1(PUSWL, 0); + bool store = !load; + bool writeback = extract1(PUSWL, 1); + bool psrForceUser = extract1(PUSWL, 2); + bool up = extract1(PUSWL, 3); + bool preIndex = extract1(PUSWL, 4); + + MMUFault fault = NoFault; + uint32_t base = GPRs[Rn] & ~3; + uint32_t blockSize = popcount32(registerList) * 4; + + uint32_t lowAddr, updatedBase; + if (up) { + updatedBase = base + blockSize; + lowAddr = base + (preIndex ? 4 : 0); + } else { + updatedBase = base - blockSize; + lowAddr = updatedBase + (preIndex ? 0 : 4); + } + + auto saveBank = bank; + if (psrForceUser && (store || !(registerList & 0x8000))) + switchBank(MainBank); + + bool doneWriteback = false; + if (load && writeback) { + doneWriteback = true; + GPRs[Rn] = updatedBase; + } + + uint32_t addr = lowAddr; + for (int i = 0; i < 16; i++) { + if (registerList & (1 << i)) { + // work on this one + if (load) { + // handling for LDM faults may be kinda iffy... + // wording on datasheet is a bit unclear + auto readResult = readVirtual(addr, V32); + if (readResult.first.has_value()) + GPRs[i] = readResult.first.value(); + if (readResult.second != NoFault) { + fault = readResult.second; + break; + } + } else { + auto newFault = writeVirtual(GPRs[i], addr, V32); + if (newFault != NoFault) + fault = newFault; + } + + addr += 4; + + if (writeback && !doneWriteback) { + doneWriteback = true; + GPRs[Rn] = updatedBase; + } + } + } + + // datasheet specifies that base register must be + // restored if an error occurs during LDM + if (load && fault != NoFault) + GPRs[Rn] = writeback ? updatedBase : base; + + if (psrForceUser && (store || !(registerList & 0x8000))) + switchBank(saveBank); + + if (load && (registerList & 0x8000)) { + prefetchCount = 0; + if (psrForceUser && isPrivileged() && fault == NoFault) { + auto saved = SPSRs[currentBank()]; + switchMode(modeFromCPSR(saved)); + CPSR = saved; + // log("reloading saved SPSR: %08x", saved); + } + } + + if (fault != NoFault) + reportFault(fault); + + return 0; // fixme } -uint32_t ARM710::execBranch(bool L, uint32_t offset) -{ - if (L) - GPRs[14] = GPRs[15] - 8; +uint32_t ARM710::execBranch(bool L, uint32_t offset) { + if (L) + GPRs[14] = GPRs[15] - 8; - // start with 24 bits, shift left 2, sign extend to 32 - int32_t sextOffset = (int32_t)(offset << 8) >> 6; + // start with 24 bits, shift left 2, sign extend to 32 + int32_t sextOffset = (int32_t)(offset << 8) >> 6; - prefetchCount = 0; - GPRs[15] -= 4; // account for our prefetch being +4 too much - GPRs[15] += sextOffset; - return 0; + prefetchCount = 0; + GPRs[15] -= 4; // account for our prefetch being +4 too much + GPRs[15] += sextOffset; + return 0; } -uint32_t ARM710::execCP15RegisterTransfer(uint32_t CPOpc, bool L, uint32_t CRn, uint32_t Rd, uint32_t CP, uint32_t CRm) -{ - (void)CP; - (void)CRm; - - if (!isPrivileged()) - return 0; - - if (L) { - // read a value - uint32_t what = 0; - - switch (CRn) { - case 0: what = cp15_id; break; - case 3: what = cp15_domainAccessControl; break; - case 5: what = cp15_faultStatus; break; - case 6: what = cp15_faultAddress; break; - } - - if (Rd == 15) - CPSR = (CPSR & ~CPSR_FlagMask) | (what & CPSR_FlagMask); - else - GPRs[Rd] = what; - } else { - // store a value - uint32_t what = GPRs[Rd]; - - switch (CRn) { - case 1: cp15_control = what; log("setting cp15_control to %08x", what); break; - case 2: cp15_translationTableBase = what; break; - case 3: cp15_domainAccessControl = what; break; - case 5: - if (isTVersion) - cp15_faultStatus = what; +uint32_t ARM710::execCP15RegisterTransfer(uint32_t CPOpc, bool L, uint32_t CRn, + uint32_t Rd, uint32_t CP, + uint32_t CRm) { + (void)CP; + (void)CRm; + + if (!isPrivileged()) + return 0; + + if (L) { + // read a value + uint32_t what = 0; + + switch (CRn) { + case 0: + what = cp15_id; + break; + case 3: + what = cp15_domainAccessControl; + break; + case 5: + what = cp15_faultStatus; + break; + case 6: + what = cp15_faultAddress; + break; + } + + if (Rd == 15) + CPSR = (CPSR & ~CPSR_FlagMask) | (what & CPSR_FlagMask); + else + GPRs[Rd] = what; + } else { + // store a value + uint32_t what = GPRs[Rd]; + + switch (CRn) { + case 1: + cp15_control = what; + log("setting cp15_control to %08x", what); + break; + case 2: + cp15_translationTableBase = what; + break; + case 3: + cp15_domainAccessControl = what; + break; + case 5: + if (isTVersion) + cp15_faultStatus = what; #ifdef ARM710T_TLB - else - flushTlb(); + else + flushTlb(); #endif - break; - case 6: - if (isTVersion) - cp15_faultAddress = what; + break; + case 6: + if (isTVersion) + cp15_faultAddress = what; #ifdef ARM710T_TLB - else - flushTlb(what); - break; + else + flushTlb(what); + break; #endif - case 7: + case 7: #ifdef ARM710T_CACHE - clearCache(); - log("cache cleared"); + clearCache(); + log("cache cleared"); #endif - break; - case 8: { + break; + case 8: { #ifdef ARM710T_TLB - if (isTVersion) { - if (CPOpc == 1) - flushTlb(what); - else - flushTlb(); - } + if (isTVersion) { + if (CPOpc == 1) + flushTlb(what); + else + flushTlb(); + } #endif - break; - } - } - } + break; + } + } + } - return 0; + return 0; } - - #ifdef ARM710T_CACHE void ARM710T::clearCache() { - for (uint32_t i = 0; i < CacheSets; i++) { - for (uint32_t j = 0; j < CacheBlocksPerSet; j++) { - cacheBlockTags[i][j] = 0; - } - } + for (uint32_t i = 0; i < CacheSets; i++) { + for (uint32_t j = 0; j < CacheBlocksPerSet; j++) { + cacheBlockTags[i][j] = 0; + } + } } -uint8_t *ARM710T::findCacheLine(uint32_t virtAddr) { - uint32_t set = virtAddr & CacheAddressSetMask; - uint32_t tag = virtAddr & CacheAddressTagMask; - set >>= CacheAddressSetShift; +uint8_t* ARM710T::findCacheLine(uint32_t virtAddr) { + uint32_t set = virtAddr & CacheAddressSetMask; + uint32_t tag = virtAddr & CacheAddressTagMask; + set >>= CacheAddressSetShift; - for (uint32_t i = 0; i < CacheBlocksPerSet; i++) { - if (cacheBlockTags[set][i] & CacheBlockEnabled) { - if ((cacheBlockTags[set][i] & ~CacheBlockEnabled) == tag) - return &cacheBlocks[set][i][0]; - } - } + for (uint32_t i = 0; i < CacheBlocksPerSet; i++) { + if (cacheBlockTags[set][i] & CacheBlockEnabled) { + if ((cacheBlockTags[set][i] & ~CacheBlockEnabled) == tag) + return &cacheBlocks[set][i][0]; + } + } - return nullptr; + return nullptr; } -pair ARM710T::addCacheLineAndRead(uint32_t physAddr, uint32_t virtAddr, ValueSize valueSize, int domain, bool isPage) { - uint32_t set = virtAddr & CacheAddressSetMask; - uint32_t tag = virtAddr & CacheAddressTagMask; - set >>= CacheAddressSetShift; - - // "it will be randomly placed in a cache bank" - // - the ARM710a data sheet, 6-2 (p90) - uint32_t i = rand() % CacheBlocksPerSet; - uint8_t *block = &cacheBlocks[set][i][0]; - MaybeU32 result; - MMUFault fault = NoFault; - - for (uint32_t j = 0; j < CacheBlockSize; j += 4) { - auto word = readPhysical((physAddr & ~CacheAddressLineMask) + j, V32); - if (word.has_value()) { - write32LE(&block[j], word.value()); - if (valueSize == V8 && j == (virtAddr & CacheAddressLineMask & ~3)) - result = (word.value() >> ((virtAddr & 3) * 8)) & 0xFF; - else if (valueSize == V32 && j == (virtAddr & CacheAddressLineMask)) - result = word.value(); - } else { - // read error, great - // TODO: should probably prioritise specific kinds of faults over others - fault = encodeFaultSorP(SorPLinefetchError, isPage, domain, virtAddr & ~CacheAddressLineMask); - break; - } - } - - // the cache block is only stored if it's complete - if (fault == NoFault) - cacheBlockTags[set][i] = tag | CacheBlockEnabled; - - return make_pair(result, fault); +pair +ARM710T::addCacheLineAndRead(uint32_t physAddr, uint32_t virtAddr, + ValueSize valueSize, int domain, bool isPage) { + uint32_t set = virtAddr & CacheAddressSetMask; + uint32_t tag = virtAddr & CacheAddressTagMask; + set >>= CacheAddressSetShift; + + // "it will be randomly placed in a cache bank" + // - the ARM710a data sheet, 6-2 (p90) + uint32_t i = rand() % CacheBlocksPerSet; + uint8_t* block = &cacheBlocks[set][i][0]; + MaybeU32 result; + MMUFault fault = NoFault; + + for (uint32_t j = 0; j < CacheBlockSize; j += 4) { + auto word = readPhysical((physAddr & ~CacheAddressLineMask) + j, V32); + if (word.has_value()) { + write32LE(&block[j], word.value()); + if (valueSize == V8 && j == (virtAddr & CacheAddressLineMask & ~3)) + result = (word.value() >> ((virtAddr & 3) * 8)) & 0xFF; + else if (valueSize == V32 && j == (virtAddr & CacheAddressLineMask)) + result = word.value(); + } else { + // read error, great + // TODO: should probably prioritise specific kinds of faults over others + fault = encodeFaultSorP(SorPLinefetchError, isPage, domain, + virtAddr & ~CacheAddressLineMask); + break; + } + } + + // the cache block is only stored if it's complete + if (fault == NoFault) + cacheBlockTags[set][i] = tag | CacheBlockEnabled; + + return make_pair(result, fault); } MaybeU32 ARM710T::readCached(uint32_t virtAddr, ValueSize valueSize) { - uint8_t *line = findCacheLine(virtAddr); - if (line) { - if (valueSize == V8) - return line[virtAddr & CacheAddressLineMask]; - else /*if (valueSize == V32)*/ - return read32LE(&line[virtAddr & CacheAddressLineMask]); - } - return {}; + uint8_t* line = findCacheLine(virtAddr); + if (line) { + if (valueSize == V8) + return line[virtAddr & CacheAddressLineMask]; + else /*if (valueSize == V32)*/ + return read32LE(&line[virtAddr & CacheAddressLineMask]); + } + return {}; } - -bool ARM710T::writeCached(uint32_t value, uint32_t virtAddr, ValueSize valueSize) { - uint8_t *line = findCacheLine(virtAddr); - if (line) { - if (valueSize == V8) - line[virtAddr & CacheAddressLineMask] = value & 0xFF; - else /*if (valueSize == V32)*/ - write32LE(&line[virtAddr & CacheAddressLineMask], value); - return true; - } - return false; +bool ARM710T::writeCached(uint32_t value, uint32_t virtAddr, + ValueSize valueSize) { + uint8_t* line = findCacheLine(virtAddr); + if (line) { + if (valueSize == V8) + line[virtAddr & CacheAddressLineMask] = value & 0xFF; + else /*if (valueSize == V32)*/ + write32LE(&line[virtAddr & CacheAddressLineMask], value); + return true; + } + return false; } #endif - -uint32_t ARM710::physAddrFromTlbEntry(TlbEntry *tlbEntry, uint32_t virtAddr) { - if ((tlbEntry->lv2Entry & 3) == 2) { - // Smøl page - return (tlbEntry->lv2Entry & 0xFFFFF000) | (virtAddr & 0xFFF); - } else if ((tlbEntry->lv2Entry & 3) == 1) { - // Lørge page - return (tlbEntry->lv2Entry & 0xFFFF0000) | (virtAddr & 0xFFFF); - } else { - // Section - return (tlbEntry->lv1Entry & 0xFFF00000) | (virtAddr & 0xFFFFF); - } +uint32_t ARM710::physAddrFromTlbEntry(TlbEntry* tlbEntry, uint32_t virtAddr) { + if ((tlbEntry->lv2Entry & 3) == 2) { + // Smøl page + return (tlbEntry->lv2Entry & 0xFFFFF000) | (virtAddr & 0xFFF); + } else if ((tlbEntry->lv2Entry & 3) == 1) { + // Lørge page + return (tlbEntry->lv2Entry & 0xFFFF0000) | (virtAddr & 0xFFFF); + } else { + // Section + return (tlbEntry->lv1Entry & 0xFFF00000) | (virtAddr & 0xFFFFF); + } } - MaybeU32 ARM710::virtToPhys(uint32_t virtAddr) { - if (!isMMUEnabled()) - return virtAddr; - - TlbEntry tempEntry; - auto translated = translateAddressUsingTlb(virtAddr, &tempEntry); - if (holds_alternative(translated)) { - auto tlbEntry = get(translated); - return physAddrFromTlbEntry(tlbEntry, virtAddr); - } else { - return MaybeU32(); - } + if (!isMMUEnabled()) + return virtAddr; + + TlbEntry tempEntry; + auto translated = translateAddressUsingTlb(virtAddr, &tempEntry); + if (holds_alternative(translated)) { + auto tlbEntry = get(translated); + return physAddrFromTlbEntry(tlbEntry, virtAddr); + } else { + return MaybeU32(); + } } - MaybeU32 ARM710::readVirtualDebug(uint32_t virtAddr, ValueSize valueSize) { - if (auto v = virtToPhys(virtAddr); v.has_value()) - return readPhysical(v.value(), valueSize); - else - return {}; + if (auto v = virtToPhys(virtAddr); v.has_value()) + return readPhysical(v.value(), valueSize); + else + return {}; } +pair ARM710::readVirtual(uint32_t virtAddr, + ValueSize valueSize) { + if (isAlignmentFaultEnabled() && valueSize == V32 && virtAddr & 3) + return make_pair(MaybeU32(), encodeFault(AlignmentFault, 0, virtAddr)); -pair ARM710::readVirtual(uint32_t virtAddr, ValueSize valueSize) { - if (isAlignmentFaultEnabled() && valueSize == V32 && virtAddr & 3) - return make_pair(MaybeU32(), encodeFault(AlignmentFault, 0, virtAddr)); - - // fast path: cache + // fast path: cache #ifdef ARM710T_CACHE - if (auto v = readCached(virtAddr, valueSize); v.has_value()) - return make_pair(v.value(), NoFault); + if (auto v = readCached(virtAddr, valueSize); v.has_value()) + return make_pair(v.value(), NoFault); #endif - if (!isMMUEnabled()) { - // things are very simple without a MMU - if (auto v = readPhysical(virtAddr, valueSize); v.has_value()) - return make_pair(v.value(), NoFault); - else - return make_pair(MaybeU32(), encodeFault(NonMMUError, 0, virtAddr)); - } + if (!isMMUEnabled()) { + // things are very simple without a MMU + if (auto v = readPhysical(virtAddr, valueSize); v.has_value()) + return make_pair(v.value(), NoFault); + else + return make_pair(MaybeU32(), encodeFault(NonMMUError, 0, virtAddr)); + } - auto translated = translateAddressUsingTlb(virtAddr); - if (holds_alternative(translated)) - return make_pair(MaybeU32(), get(translated)); + auto translated = translateAddressUsingTlb(virtAddr); + if (holds_alternative(translated)) + return make_pair(MaybeU32(), get(translated)); - // resolve this boy - auto tlbEntry = get(translated); + // resolve this boy + auto tlbEntry = get(translated); - if (auto f = checkAccessPermissions(tlbEntry, virtAddr, false); f != NoFault) - return make_pair(MaybeU32(), f); + if (auto f = checkAccessPermissions(tlbEntry, virtAddr, false); f != NoFault) + return make_pair(MaybeU32(), f); - int domain = (tlbEntry->lv1Entry >> 5) & 0xF; - bool isPage = (tlbEntry->lv2Entry != 0); + int domain = (tlbEntry->lv1Entry >> 5) & 0xF; + bool isPage = (tlbEntry->lv2Entry != 0); - uint32_t physAddr = physAddrFromTlbEntry(tlbEntry, virtAddr); + uint32_t physAddr = physAddrFromTlbEntry(tlbEntry, virtAddr); #ifdef ARM710T_CACHE - bool cacheable = tlbEntry->lv2Entry ? (tlbEntry->lv2Entry & 8) : (tlbEntry->lv1Entry & 8); - if (cacheable && isCacheEnabled()) - return addCacheLineAndRead(physAddr, virtAddr, valueSize, domain, isPage); - else + bool cacheable = + tlbEntry->lv2Entry ? (tlbEntry->lv2Entry & 8) : (tlbEntry->lv1Entry & 8); + if (cacheable && isCacheEnabled()) + return addCacheLineAndRead(physAddr, virtAddr, valueSize, domain, isPage); + else #endif - if (auto result = readPhysical(physAddr, valueSize); result.has_value()) - return make_pair(result, NoFault); - else - return make_pair(result, encodeFaultSorP(SorPOtherBusError, isPage, domain, virtAddr)); + if (auto result = readPhysical(physAddr, valueSize); result.has_value()) + return make_pair(result, NoFault); + else + return make_pair( + result, encodeFaultSorP(SorPOtherBusError, isPage, domain, virtAddr)); } -ARM710::MMUFault ARM710::writeVirtual(uint32_t value, uint32_t virtAddr, ValueSize valueSize) { - if (isAlignmentFaultEnabled() && valueSize == V32 && virtAddr & 3) - return encodeFault(AlignmentFault, 0, virtAddr); +ARM710::MMUFault ARM710::writeVirtual(uint32_t value, uint32_t virtAddr, + ValueSize valueSize) { + if (isAlignmentFaultEnabled() && valueSize == V32 && virtAddr & 3) + return encodeFault(AlignmentFault, 0, virtAddr); - if (!isMMUEnabled()) { - // direct virtual -> physical mapping, sans MMU - if (!writePhysical(value, virtAddr, valueSize)) - return encodeFault(NonMMUError, 0, virtAddr); - } else { - auto translated = translateAddressUsingTlb(virtAddr); - if (holds_alternative(translated)) - return get(translated); + if (!isMMUEnabled()) { + // direct virtual -> physical mapping, sans MMU + if (!writePhysical(value, virtAddr, valueSize)) + return encodeFault(NonMMUError, 0, virtAddr); + } else { + auto translated = translateAddressUsingTlb(virtAddr); + if (holds_alternative(translated)) + return get(translated); - // resolve this boy - auto tlbEntry = get(translated); + // resolve this boy + auto tlbEntry = get(translated); - if (auto f = checkAccessPermissions(tlbEntry, virtAddr, true); f != NoFault) - return f; + if (auto f = checkAccessPermissions(tlbEntry, virtAddr, true); f != NoFault) + return f; - uint32_t physAddr = physAddrFromTlbEntry(tlbEntry, virtAddr); - int domain = (tlbEntry->lv1Entry >> 5) & 0xF; - bool isPage = (tlbEntry->lv2Entry != 0); + uint32_t physAddr = physAddrFromTlbEntry(tlbEntry, virtAddr); + int domain = (tlbEntry->lv1Entry >> 5) & 0xF; + bool isPage = (tlbEntry->lv2Entry != 0); - if (!writePhysical(value, physAddr, valueSize)) - return encodeFaultSorP(SorPOtherBusError, isPage, domain, virtAddr); - } + if (!writePhysical(value, physAddr, valueSize)) + return encodeFaultSorP(SorPOtherBusError, isPage, domain, virtAddr); + } - // commit to cache if all was good + // commit to cache if all was good #ifdef ARM710T_CACHE - writeCached(value, virtAddr, valueSize); + writeCached(value, virtAddr, valueSize); #endif - return NoFault; + return NoFault; } - - // TLB #ifdef ARM710T_TLB void ARM710::flushTlb() { - for (TlbEntry &e : tlb) - e = {0, 0, 0, 0}; + for (TlbEntry& e : tlb) + e = {0, 0, 0, 0}; } void ARM710::flushTlb(uint32_t virtAddr) { - for (TlbEntry &e : tlb) { - if (e.addrMask && (virtAddr & e.addrMask) == e.addr) { - e = {0, 0, 0, 0}; - break; - } - } + for (TlbEntry& e : tlb) { + if (e.addrMask && (virtAddr & e.addrMask) == e.addr) { + e = {0, 0, 0, 0}; + break; + } + } } #endif -ARM710::TlbEntry *ARM710::_allocateTlbEntry(uint32_t addrMask, uint32_t addr) { +ARM710::TlbEntry* ARM710::_allocateTlbEntry(uint32_t addrMask, uint32_t addr) { #ifdef ARM710T_TLB - TlbEntry *entry = &tlb[nextTlbIndex]; - nextTlbIndex = (nextTlbIndex + 1) % TlbSize; + TlbEntry* entry = &tlb[nextTlbIndex]; + nextTlbIndex = (nextTlbIndex + 1) % TlbSize; #else - TlbEntry *entry = &singleTlbEntry; + TlbEntry* entry = &singleTlbEntry; #endif - entry->addrMask = addrMask; - entry->addr = addr & addrMask; - return entry; + entry->addrMask = addrMask; + entry->addr = addr & addrMask; + return entry; } -variant ARM710::translateAddressUsingTlb(uint32_t virtAddr, TlbEntry *useMe) { +variant +ARM710::translateAddressUsingTlb(uint32_t virtAddr, TlbEntry* useMe) { #ifdef ARM710T_TLB - // first things first, do we have a matching entry in the TLB? - for (TlbEntry &e : tlb) { - if (e.addrMask && (virtAddr & e.addrMask) == e.addr) - return &e; - } + // first things first, do we have a matching entry in the TLB? + for (TlbEntry& e : tlb) { + if (e.addrMask && (virtAddr & e.addrMask) == e.addr) + return &e; + } #endif - // no, so do a page table walk - TlbEntry *entry; - uint32_t tableIndex = virtAddr >> 20; - - // fetch the Level 1 entry - auto lv1EntryOpt = readPhysical(cp15_translationTableBase | (tableIndex << 2), V32); - if (!lv1EntryOpt.has_value()) - return Lv1TranslationError; - auto lv1Entry = lv1EntryOpt.value(); - int domain = (lv1Entry >> 5) & 0xF; - - switch (lv1Entry & 3) { - case 0: - case 3: - // invalid! - return encodeFault(SectionTranslationFault, domain, virtAddr); - case 2: - // a Section entry is straightforward - // we just throw that immediately into the TLB - entry = useMe ? useMe : _allocateTlbEntry(0xFFF00000, virtAddr); - entry->lv1Entry = lv1Entry; - entry->lv2Entry = 0; - return entry; - case 1: - // a Page requires a Level 2 read - uint32_t pageTableAddr = lv1Entry & 0xFFFFFC00; - uint32_t lv2TableIndex = (virtAddr >> 12) & 0xFF; - - auto lv2EntryOpt = readPhysical(pageTableAddr | (lv2TableIndex << 2), V32); - if (!lv2EntryOpt.has_value()) - return encodeFault(Lv2TranslationError, domain, virtAddr); - auto lv2Entry = lv2EntryOpt.value(); - - switch (lv2Entry & 3) { - case 0: - case 3: - // invalid! - return encodeFault(PageTranslationFault, domain, virtAddr); - case 1: - // Large 64kb page - entry = useMe ? useMe : _allocateTlbEntry(0xFFFF0000, virtAddr); - entry->lv1Entry = lv1Entry; - entry->lv2Entry = lv2Entry; - return entry; - case 2: - // Small 4kb page - entry = useMe ? useMe : _allocateTlbEntry(0xFFFFF000, virtAddr); - entry->lv1Entry = lv1Entry; - entry->lv2Entry = lv2Entry; - return entry; - } - } - - // we should never get here as the switch covers 0, 1, 2, 3 - // but this satisfies a compiler warning - return SectionTranslationFault; + // no, so do a page table walk + TlbEntry* entry; + uint32_t tableIndex = virtAddr >> 20; + + // fetch the Level 1 entry + auto lv1EntryOpt = + readPhysical(cp15_translationTableBase | (tableIndex << 2), V32); + if (!lv1EntryOpt.has_value()) + return Lv1TranslationError; + auto lv1Entry = lv1EntryOpt.value(); + int domain = (lv1Entry >> 5) & 0xF; + + switch (lv1Entry & 3) { + case 0: + case 3: + // invalid! + return encodeFault(SectionTranslationFault, domain, virtAddr); + case 2: + // a Section entry is straightforward + // we just throw that immediately into the TLB + entry = useMe ? useMe : _allocateTlbEntry(0xFFF00000, virtAddr); + entry->lv1Entry = lv1Entry; + entry->lv2Entry = 0; + return entry; + case 1: + // a Page requires a Level 2 read + uint32_t pageTableAddr = lv1Entry & 0xFFFFFC00; + uint32_t lv2TableIndex = (virtAddr >> 12) & 0xFF; + + auto lv2EntryOpt = readPhysical(pageTableAddr | (lv2TableIndex << 2), V32); + if (!lv2EntryOpt.has_value()) + return encodeFault(Lv2TranslationError, domain, virtAddr); + auto lv2Entry = lv2EntryOpt.value(); + + switch (lv2Entry & 3) { + case 0: + case 3: + // invalid! + return encodeFault(PageTranslationFault, domain, virtAddr); + case 1: + // Large 64kb page + entry = useMe ? useMe : _allocateTlbEntry(0xFFFF0000, virtAddr); + entry->lv1Entry = lv1Entry; + entry->lv2Entry = lv2Entry; + return entry; + case 2: + // Small 4kb page + entry = useMe ? useMe : _allocateTlbEntry(0xFFFFF000, virtAddr); + entry->lv1Entry = lv1Entry; + entry->lv2Entry = lv2Entry; + return entry; + } + } + + // we should never get here as the switch covers 0, 1, 2, 3 + // but this satisfies a compiler warning + return SectionTranslationFault; } - - -ARM710::MMUFault ARM710::checkAccessPermissions(ARM710::TlbEntry *entry, uint32_t virtAddr, bool isWrite) const { - int domain; - int accessPerms; - bool isPage; - - // extract info from the entries - domain = (entry->lv1Entry >> 5) & 0xF; - if (entry->lv2Entry) { - // Page - accessPerms = (entry->lv2Entry >> 4) & 0xFF; - - int permIndex; - if ((entry->lv2Entry & 3) == 1) // Large 64kb - permIndex = (virtAddr >> 14) & 3; - else // Small 4kb - permIndex = (virtAddr >> 10) & 3; - - accessPerms >>= (permIndex * 2); - accessPerms &= 3; - isPage = true; - } else { - // Section - accessPerms = (entry->lv1Entry >> 10) & 3; - isPage = false; - } - - // now, do our checks - int primaryAccessControls = (cp15_domainAccessControl >> (domain * 2)) & 3; - - // Manager: always allowed - if (primaryAccessControls == 3) - return NoFault; - - // Client: enforce checks! - if (primaryAccessControls == 1) { -#define OK_IF_TRUE(b) return ((b) ? NoFault : encodeFaultSorP(SorPPermissionFault, isPage, domain, virtAddr)) - bool System = cp15_control & 0x100; - bool ROM = cp15_control & 0x200; - - if (accessPerms == 0) { - if (!System && !ROM) { - // 00/0/0: Any access generates a permission fault - OK_IF_TRUE(false); - } else if (System && !ROM) { - // 00/1/0: Supervisor read only permitted - OK_IF_TRUE(!isWrite && isPrivileged()); - } else if (!System && ROM) { - // 00/0/1: Any write generates a permission fault - OK_IF_TRUE(!isWrite); - } else /*if (System && ROM)*/ { - // Reserved - OK_IF_TRUE(false); - } - } else if (accessPerms == 1) { - // 01/x/x: Access allowed only in Supervisor mode - OK_IF_TRUE(isPrivileged()); - } else if (accessPerms == 2) { - // 10/x/x: Writes in User mode cause permission fault - OK_IF_TRUE(!isWrite || isPrivileged()); - } else /*if (accessPerms == 3)*/ { - // 11/x/x: All access types permitted in both modes - OK_IF_TRUE(true); - } +ARM710::MMUFault ARM710::checkAccessPermissions(ARM710::TlbEntry* entry, + uint32_t virtAddr, + bool isWrite) const { + int domain; + int accessPerms; + bool isPage; + + // extract info from the entries + domain = (entry->lv1Entry >> 5) & 0xF; + if (entry->lv2Entry) { + // Page + accessPerms = (entry->lv2Entry >> 4) & 0xFF; + + int permIndex; + if ((entry->lv2Entry & 3) == 1) // Large 64kb + permIndex = (virtAddr >> 14) & 3; + else // Small 4kb + permIndex = (virtAddr >> 10) & 3; + + accessPerms >>= (permIndex * 2); + accessPerms &= 3; + isPage = true; + } else { + // Section + accessPerms = (entry->lv1Entry >> 10) & 3; + isPage = false; + } + + // now, do our checks + int primaryAccessControls = (cp15_domainAccessControl >> (domain * 2)) & 3; + + // Manager: always allowed + if (primaryAccessControls == 3) + return NoFault; + + // Client: enforce checks! + if (primaryAccessControls == 1) { +#define OK_IF_TRUE(b) \ + return ( \ + (b) ? NoFault \ + : encodeFaultSorP(SorPPermissionFault, isPage, domain, virtAddr)) + bool System = cp15_control & 0x100; + bool ROM = cp15_control & 0x200; + + if (accessPerms == 0) { + if (!System && !ROM) { + // 00/0/0: Any access generates a permission fault + OK_IF_TRUE(false); + } else if (System && !ROM) { + // 00/1/0: Supervisor read only permitted + OK_IF_TRUE(!isWrite && isPrivileged()); + } else if (!System && ROM) { + // 00/0/1: Any write generates a permission fault + OK_IF_TRUE(!isWrite); + } else /*if (System && ROM)*/ { + // Reserved + OK_IF_TRUE(false); + } + } else if (accessPerms == 1) { + // 01/x/x: Access allowed only in Supervisor mode + OK_IF_TRUE(isPrivileged()); + } else if (accessPerms == 2) { + // 10/x/x: Writes in User mode cause permission fault + OK_IF_TRUE(!isWrite || isPrivileged()); + } else /*if (accessPerms == 3)*/ { + // 11/x/x: All access types permitted in both modes + OK_IF_TRUE(true); + } #undef OK_IF_TRUE - } + } - // No Access or Reserved: never allowed (Domain Fault) - return encodeFaultSorP(SorPDomainFault, isPage, domain, virtAddr); + // No Access or Reserved: never allowed (Domain Fault) + return encodeFaultSorP(SorPDomainFault, isPage, domain, virtAddr); } - void ARM710::reportFault(MMUFault fault) { - if (fault != NoFault) { - if ((fault & 0xF) != NonMMUError) { - cp15_faultStatus = fault & (MMUFaultTypeMask | MMUFaultDomainMask); - cp15_faultAddress = fault >> MMUFaultAddressShift; - } - - static const char *faultTypes[] = { - "NoFault", - "AlignmentFault", - "???", - "NonMMUError", - "SectionLinefetchError", - "SectionTranslationFault", - "PageLinefetchError", - "PageTranslationFault", - "SectionOtherBusError", - "SectionDomainFault", - "PageOtherBusError", - "PageDomainFault", - "Lv1TranslationError", - "SectionPermissionFault", - "Lv2TranslationError", - "PagePermissionFault" - }; - log("⚠️ Fault type=%s domain=%d address=%08x pc=%08x lr=%08x", - faultTypes[fault & MMUFaultTypeMask], - (fault & MMUFaultDomainMask) >> MMUFaultDomainShift, - fault >> MMUFaultAddressShift, - GPRs[15], GPRs[14]); - - // this signals a branch to DataAbort after the - // instruction is done executing - faultTriggeredThisCycle = true; - } + if (fault != NoFault) { + if ((fault & 0xF) != NonMMUError) { + cp15_faultStatus = fault & (MMUFaultTypeMask | MMUFaultDomainMask); + cp15_faultAddress = fault >> MMUFaultAddressShift; + } + + static const char* faultTypes[] = {"NoFault", + "AlignmentFault", + "???", + "NonMMUError", + "SectionLinefetchError", + "SectionTranslationFault", + "PageLinefetchError", + "PageTranslationFault", + "SectionOtherBusError", + "SectionDomainFault", + "PageOtherBusError", + "PageDomainFault", + "Lv1TranslationError", + "SectionPermissionFault", + "Lv2TranslationError", + "PagePermissionFault"}; + log("⚠️ Fault type=%s domain=%d address=%08x pc=%08x lr=%08x", + faultTypes[fault & MMUFaultTypeMask], + (fault & MMUFaultDomainMask) >> MMUFaultDomainShift, + fault >> MMUFaultAddressShift, GPRs[15], GPRs[14]); + + // this signals a branch to DataAbort after the + // instruction is done executing + faultTriggeredThisCycle = true; + } } +void ARM710::log(const char* format, ...) { + if (logger) { + char buffer[1024]; -void ARM710::log(const char *format, ...) { - if (logger) { - char buffer[1024]; - - va_list vaList; - va_start(vaList, format); - vsnprintf(buffer, sizeof(buffer), format, vaList); - va_end(vaList); + va_list vaList; + va_start(vaList, format); + vsnprintf(buffer, sizeof(buffer), format, vaList); + va_end(vaList); - logger(buffer); - } + logger(buffer); + } } void ARM710::logPcHistory() { - for (int i = 0; i < PcHistoryCount; i++) { - pcHistoryIndex = (pcHistoryIndex + 1) % PcHistoryCount; - log("%03d: %08x %08x", i, pcHistory[pcHistoryIndex].addr, pcHistory[pcHistoryIndex].insn); - } + for (int i = 0; i < PcHistoryCount; i++) { + pcHistoryIndex = (pcHistoryIndex + 1) % PcHistoryCount; + log("%03d: %08x %08x", i, pcHistory[pcHistoryIndex].addr, + pcHistory[pcHistoryIndex].insn); + } } diff --git a/WindCore/arm710.h b/WindCore/arm710.h index f0fa139..6430e1c 100644 --- a/WindCore/arm710.h +++ b/WindCore/arm710.h @@ -1,7 +1,7 @@ #pragma once #include -#include #include +#include #include using namespace std; @@ -18,288 +18,326 @@ using namespace std; // TLB is 64 entries // Speedhacks: -//#define ARM710T_CACHE -//#define ARM710T_TLB +// #define ARM710T_CACHE +// #define ARM710T_TLB typedef optional MaybeU32; -class ARM710 -{ +class ARM710 { public: - enum ValueSize { V8 = 0, V16 = 1, V32 = 2 }; - - enum MMUFault : uint64_t { - // ref: datasheet 9-13 (p111) - NoFault = 0, - AlignmentFault = 1, - // the ARM gods say there is to be no fault 2 or 3 - SectionLinefetchError = 4, - SectionTranslationFault = 5, - PageLinefetchError = 6, - PageTranslationFault = 7, - SectionOtherBusError = 8, - SectionDomainFault = 9, - PageOtherBusError = 0xA, - PageDomainFault = 0xB, - Lv1TranslationError = 0xC, - SectionPermissionFault = 0xD, - Lv2TranslationError = 0xE, - PagePermissionFault = 0xF, - - // not actually in the ARM datasheet - // so we are reusing it for nefarious purposes - NonMMUError = 3, - - MMUFaultTypeMask = 0xF, - MMUFaultDomainMask = 0xF0, - MMUFaultDomainShift = 4, - MMUFaultAddressMask = 0xFFFFFFFF00000000, - MMUFaultAddressShift = 32 - }; - - - - ARM710(bool _isTVersion) { - isTVersion = _isTVersion; - cp15_id = _isTVersion ? 0x41807100 : 0x41047100; - clearAllValues(); - } - virtual ~ARM710() { } - - void clearAllValues() { - bank = MainBank; - CPSR = 0; - for (int i = 0; i < 16; i++) GPRs[i] = 0; - for (int i = 0; i < 5; i++) { - fiqBankedRegisters[0][i] = 0; - fiqBankedRegisters[1][i] = 0; - SPSRs[i] = 0; - } - for (int i = 0; i < 6; i++) { - allModesBankedRegisters[i][0] = 0; - allModesBankedRegisters[i][1] = 0; - } - - cp15_control = 0; - cp15_translationTableBase = 0; - cp15_domainAccessControl = 0; - cp15_faultStatus = 0; - cp15_faultAddress = 0; - prefetchCount = 0; + enum ValueSize { V8 = 0, V16 = 1, V32 = 2 }; + + enum MMUFault : uint64_t { + // ref: datasheet 9-13 (p111) + NoFault = 0, + AlignmentFault = 1, + // the ARM gods say there is to be no fault 2 or 3 + SectionLinefetchError = 4, + SectionTranslationFault = 5, + PageLinefetchError = 6, + PageTranslationFault = 7, + SectionOtherBusError = 8, + SectionDomainFault = 9, + PageOtherBusError = 0xA, + PageDomainFault = 0xB, + Lv1TranslationError = 0xC, + SectionPermissionFault = 0xD, + Lv2TranslationError = 0xE, + PagePermissionFault = 0xF, + + // not actually in the ARM datasheet + // so we are reusing it for nefarious purposes + NonMMUError = 3, + + MMUFaultTypeMask = 0xF, + MMUFaultDomainMask = 0xF0, + MMUFaultDomainShift = 4, + MMUFaultAddressMask = 0xFFFFFFFF00000000, + MMUFaultAddressShift = 32 + }; + + ARM710(bool _isTVersion) { + isTVersion = _isTVersion; + cp15_id = _isTVersion ? 0x41807100 : 0x41047100; + clearAllValues(); + } + virtual ~ARM710() {} + + void clearAllValues() { + bank = MainBank; + CPSR = 0; + for (int i = 0; i < 16; i++) + GPRs[i] = 0; + for (int i = 0; i < 5; i++) { + fiqBankedRegisters[0][i] = 0; + fiqBankedRegisters[1][i] = 0; + SPSRs[i] = 0; + } + for (int i = 0; i < 6; i++) { + allModesBankedRegisters[i][0] = 0; + allModesBankedRegisters[i][1] = 0; + } + + cp15_control = 0; + cp15_translationTableBase = 0; + cp15_domainAccessControl = 0; + cp15_faultStatus = 0; + cp15_faultAddress = 0; + prefetchCount = 0; #ifdef ARM710T_CACHE - clearCache(); + clearCache(); #endif #ifdef ARM710T_TLB - flushTlb(); + flushTlb(); #endif - } - - void setProcessorID(uint32_t v) { cp15_id = v; } - bool canAcceptFIQ() const { return !(CPSR & CPSR_FIQDisable); } - bool canAcceptIRQ() const { return !(CPSR & CPSR_IRQDisable); } - void requestFIQ(); // pull nFIQ low - void requestIRQ(); // pull nIRQ low - void reset(); // pull nRESET low - - bool instructionReady() const { return (prefetchCount == 2); } - uint32_t tick(); // run the chip for at least 1 clock cycle - - MaybeU32 readVirtualDebug(uint32_t virtAddr, ValueSize valueSize); - MaybeU32 virtToPhys(uint32_t virtAddr); - - pair readVirtual(uint32_t virtAddr, ValueSize valueSize); - virtual MaybeU32 readPhysical(uint32_t physAddr, ValueSize valueSize) = 0; - MMUFault writeVirtual(uint32_t value, uint32_t virtAddr, ARM710::ValueSize valueSize); - virtual bool writePhysical(uint32_t value, uint32_t physAddr, ARM710::ValueSize valueSize) = 0; - - uint32_t getGPR(int index) const { return GPRs[index]; } - uint32_t getCPSR() const { return CPSR; } - uint32_t getRealPC() const { - return GPRs[15] - (4 * prefetchCount); - } - - void setLogger(std::function newLogger) { logger = newLogger; } - uint32_t lastPcExecuted() const { return pcHistory[(pcHistoryIndex - 1) % PcHistoryCount].addr; } + } + + void setProcessorID(uint32_t v) { cp15_id = v; } + bool canAcceptFIQ() const { return !(CPSR & CPSR_FIQDisable); } + bool canAcceptIRQ() const { return !(CPSR & CPSR_IRQDisable); } + void requestFIQ(); // pull nFIQ low + void requestIRQ(); // pull nIRQ low + void reset(); // pull nRESET low + + bool instructionReady() const { return (prefetchCount == 2); } + uint32_t tick(); // run the chip for at least 1 clock cycle + + MaybeU32 readVirtualDebug(uint32_t virtAddr, ValueSize valueSize); + MaybeU32 virtToPhys(uint32_t virtAddr); + + pair readVirtual(uint32_t virtAddr, ValueSize valueSize); + virtual MaybeU32 readPhysical(uint32_t physAddr, ValueSize valueSize) = 0; + MMUFault writeVirtual(uint32_t value, uint32_t virtAddr, + ARM710::ValueSize valueSize); + virtual bool writePhysical(uint32_t value, uint32_t physAddr, + ARM710::ValueSize valueSize) = 0; + + uint32_t getGPR(int index) const { return GPRs[index]; } + uint32_t getCPSR() const { return CPSR; } + uint32_t getRealPC() const { return GPRs[15] - (4 * prefetchCount); } + + void setLogger(std::function newLogger) { + logger = newLogger; + } + uint32_t lastPcExecuted() const { + return pcHistory[(pcHistoryIndex - 1) % PcHistoryCount].addr; + } + public: - void log(const char *format, ...); - void logPcHistory(); + void log(const char* format, ...); + void logPcHistory(); + private: - std::function logger; - - enum { PcHistoryCount = 10 }; - struct { uint32_t addr, insn; } pcHistory[PcHistoryCount]; - uint32_t pcHistoryIndex = 0; - - enum { Nop = 0xE1A00000 }; - - enum Mode : uint8_t { - User32 = 0x10, - FIQ32 = 0x11, - IRQ32 = 0x12, - Supervisor32 = 0x13, - Abort32 = 0x17, - Undefined32 = 0x1B - }; - - enum BankIndex : uint8_t { - FiqBank, - IrqBank, - SvcBank, - AbtBank, - UndBank, - MainBank - }; - - constexpr static const BankIndex modeToBank[16] = { - MainBank, FiqBank, IrqBank, SvcBank, - MainBank, MainBank, MainBank, AbtBank, - MainBank, MainBank, MainBank, UndBank, - MainBank, MainBank, MainBank, MainBank - }; - - enum : uint32_t { - CPSR_ModeMask = 0x0000001F, - CPSR_FIQDisable = 0x00000040, - CPSR_IRQDisable = 0x00000080, - CPSR_V = 0x10000000, - CPSR_C = 0x20000000, - CPSR_Z = 0x40000000, - CPSR_N = 0x80000000, - CPSR_FlagMask = 0xF0000000 - }; - - // active state - BankIndex bank; - uint32_t CPSR; - uint32_t GPRs[16]; - - // saved state - uint32_t fiqBankedRegisters[2][5]; // R8..R12 inclusive - uint32_t allModesBankedRegisters[6][2]; // R13, R14 - uint32_t SPSRs[5]; - - // coprocessor 15 - uint32_t cp15_id; // 0: read-only - uint32_t cp15_control; // 1: write-only - uint32_t cp15_translationTableBase; // 2: write-only - uint32_t cp15_domainAccessControl; // 3: write-only - uint8_t cp15_faultStatus; // 5: read-only (writing has unrelated effects) - uint32_t cp15_faultAddress; // 6: read-only (writing has unrelated effects) - - bool isTVersion; - - bool flagV() const { return CPSR & CPSR_V; } - bool flagC() const { return CPSR & CPSR_C; } - bool flagZ() const { return CPSR & CPSR_Z; } - bool flagN() const { return CPSR & CPSR_N; } - bool checkCondition(int cond) const { - switch (cond) { - /*EQ*/ case 0: return flagZ(); - /*NE*/ case 1: return !flagZ(); - /*CS*/ case 2: return flagC(); - /*CC*/ case 3: return !flagC(); - /*MI*/ case 4: return flagN(); - /*PL*/ case 5: return !flagN(); - /*VS*/ case 6: return flagV(); - /*VC*/ case 7: return !flagV(); - /*HI*/ case 8: return flagC() && !flagZ(); - /*LS*/ case 9: return !flagC() || flagZ(); - /*GE*/ case 0xA: return flagN() == flagV(); - /*LT*/ case 0xB: return flagN() != flagV(); - /*GT*/ case 0xC: return !flagZ() && (flagN() == flagV()); - /*LE*/ case 0xD: return flagZ() || (flagN() != flagV()); - /*AL*/ case 0xE: return true; - /*NV*/ /*case 0xF:*/ - default: return false; - } - } - - static Mode modeFromCPSR(uint32_t v) { return (Mode)(v & CPSR_ModeMask); } - Mode currentMode() const { return modeFromCPSR(CPSR); } - BankIndex currentBank() const { return modeToBank[(Mode)(CPSR & 0xF)]; } - bool isPrivileged() const { return (CPSR & 0x1F) > User32; } - bool isMMUEnabled() const { return (cp15_control & 1); } - bool isAlignmentFaultEnabled() const { return (cp15_control & 2); } - bool isCacheEnabled() const { return (cp15_control & 4); } - bool isWriteBufferEnabled() const { return (cp15_control & 8); } - - void switchMode(Mode mode); - void switchBank(BankIndex bank); - void raiseException(Mode mode, uint32_t savedPC, uint32_t newPC); - - // MMU/TLB - enum MMUFaultSorP : uint64_t { - SorPLinefetchError = 4, - SorPTranslationFault = 5, - SorPOtherBusError = 8, - SorPDomainFault = 9, - SorPPermissionFault = 0xD, - }; - - MMUFault encodeFault(MMUFault fault, int domain, uint32_t virtAddr) const { - return (MMUFault)(fault | (domain << 4) | ((uint64_t)virtAddr << 32)); - } - MMUFault encodeFaultSorP(MMUFaultSorP baseFault, bool isPage, int domain, uint32_t virtAddr) const { - return (MMUFault)(baseFault | (isPage ? 2 : 0) | (domain << 4) | ((uint64_t)virtAddr << 32)); - } - - struct TlbEntry { uint32_t addrMask, addr, lv1Entry, lv2Entry; }; + std::function logger; + + enum { PcHistoryCount = 10 }; + struct { + uint32_t addr, insn; + } pcHistory[PcHistoryCount]; + uint32_t pcHistoryIndex = 0; + + enum { Nop = 0xE1A00000 }; + + enum Mode : uint8_t { + User32 = 0x10, + FIQ32 = 0x11, + IRQ32 = 0x12, + Supervisor32 = 0x13, + Abort32 = 0x17, + Undefined32 = 0x1B + }; + + enum BankIndex : uint8_t { + FiqBank, + IrqBank, + SvcBank, + AbtBank, + UndBank, + MainBank + }; + + constexpr static const BankIndex modeToBank[16] = { + MainBank, FiqBank, IrqBank, SvcBank, MainBank, MainBank, + MainBank, AbtBank, MainBank, MainBank, MainBank, UndBank, + MainBank, MainBank, MainBank, MainBank}; + + enum : uint32_t { + CPSR_ModeMask = 0x0000001F, + CPSR_FIQDisable = 0x00000040, + CPSR_IRQDisable = 0x00000080, + CPSR_V = 0x10000000, + CPSR_C = 0x20000000, + CPSR_Z = 0x40000000, + CPSR_N = 0x80000000, + CPSR_FlagMask = 0xF0000000 + }; + + // active state + BankIndex bank; + uint32_t CPSR; + uint32_t GPRs[16]; + + // saved state + uint32_t fiqBankedRegisters[2][5]; // R8..R12 inclusive + uint32_t allModesBankedRegisters[6][2]; // R13, R14 + uint32_t SPSRs[5]; + + // coprocessor 15 + uint32_t cp15_id; // 0: read-only + uint32_t cp15_control; // 1: write-only + uint32_t cp15_translationTableBase; // 2: write-only + uint32_t cp15_domainAccessControl; // 3: write-only + uint8_t cp15_faultStatus; // 5: read-only (writing has unrelated effects) + uint32_t cp15_faultAddress; // 6: read-only (writing has unrelated effects) + + bool isTVersion; + + bool flagV() const { return CPSR & CPSR_V; } + bool flagC() const { return CPSR & CPSR_C; } + bool flagZ() const { return CPSR & CPSR_Z; } + bool flagN() const { return CPSR & CPSR_N; } + bool checkCondition(int cond) const { + switch (cond) { + /*EQ*/ case 0: + return flagZ(); + /*NE*/ case 1: + return !flagZ(); + /*CS*/ case 2: + return flagC(); + /*CC*/ case 3: + return !flagC(); + /*MI*/ case 4: + return flagN(); + /*PL*/ case 5: + return !flagN(); + /*VS*/ case 6: + return flagV(); + /*VC*/ case 7: + return !flagV(); + /*HI*/ case 8: + return flagC() && !flagZ(); + /*LS*/ case 9: + return !flagC() || flagZ(); + /*GE*/ case 0xA: + return flagN() == flagV(); + /*LT*/ case 0xB: + return flagN() != flagV(); + /*GT*/ case 0xC: + return !flagZ() && (flagN() == flagV()); + /*LE*/ case 0xD: + return flagZ() || (flagN() != flagV()); + /*AL*/ case 0xE: + return true; + /*NV*/ /*case 0xF:*/ + default: + return false; + } + } + + static Mode modeFromCPSR(uint32_t v) { return (Mode)(v & CPSR_ModeMask); } + Mode currentMode() const { return modeFromCPSR(CPSR); } + BankIndex currentBank() const { return modeToBank[(Mode)(CPSR & 0xF)]; } + bool isPrivileged() const { return (CPSR & 0x1F) > User32; } + bool isMMUEnabled() const { return (cp15_control & 1); } + bool isAlignmentFaultEnabled() const { return (cp15_control & 2); } + bool isCacheEnabled() const { return (cp15_control & 4); } + bool isWriteBufferEnabled() const { return (cp15_control & 8); } + + void switchMode(Mode mode); + void switchBank(BankIndex bank); + void raiseException(Mode mode, uint32_t savedPC, uint32_t newPC); + + // MMU/TLB + enum MMUFaultSorP : uint64_t { + SorPLinefetchError = 4, + SorPTranslationFault = 5, + SorPOtherBusError = 8, + SorPDomainFault = 9, + SorPPermissionFault = 0xD, + }; + + MMUFault encodeFault(MMUFault fault, int domain, uint32_t virtAddr) const { + return (MMUFault)(fault | (domain << 4) | ((uint64_t)virtAddr << 32)); + } + MMUFault encodeFaultSorP(MMUFaultSorP baseFault, bool isPage, int domain, + uint32_t virtAddr) const { + return (MMUFault)(baseFault | (isPage ? 2 : 0) | (domain << 4) | + ((uint64_t)virtAddr << 32)); + } + + struct TlbEntry { + uint32_t addrMask, addr, lv1Entry, lv2Entry; + }; #ifdef ARM710T_TLB - enum { TlbSize = 64 }; - TlbEntry tlb[TlbSize]; - int nextTlbIndex = 0; + enum { TlbSize = 64 }; + TlbEntry tlb[TlbSize]; + int nextTlbIndex = 0; - void flushTlb(); - void flushTlb(uint32_t virtAddr); + void flushTlb(); + void flushTlb(uint32_t virtAddr); #else - TlbEntry singleTlbEntry; -#endif + TlbEntry singleTlbEntry; +#endif - TlbEntry *_allocateTlbEntry(uint32_t addrMask, uint32_t addr); - variant translateAddressUsingTlb(uint32_t virtAddr, TlbEntry *useMe=nullptr); - static uint32_t physAddrFromTlbEntry(TlbEntry *tlbEntry, uint32_t virtAddr); - MMUFault checkAccessPermissions(TlbEntry *entry, uint32_t virtAddr, bool isWrite) const; + TlbEntry* _allocateTlbEntry(uint32_t addrMask, uint32_t addr); + variant + translateAddressUsingTlb(uint32_t virtAddr, TlbEntry* useMe = nullptr); + static uint32_t physAddrFromTlbEntry(TlbEntry* tlbEntry, uint32_t virtAddr); + MMUFault checkAccessPermissions(TlbEntry* entry, uint32_t virtAddr, + bool isWrite) const; - bool faultTriggeredThisCycle = false; - void reportFault(MMUFault fault); + bool faultTriggeredThisCycle = false; + void reportFault(MMUFault fault); - // Instruction/Data Cache + // Instruction/Data Cache #ifdef ARM710T_CACHE - enum { - CacheSets = 4, - CacheBlocksPerSet = 128, - CacheBlockSize = 0x10, - - CacheAddressLineMask = 0x0000000F, - CacheAddressSetMask = 0x00000030, CacheAddressSetShift = 4, - CacheAddressTagMask = 0xFFFFFFC0, - - CacheBlockEnabled = 1 - }; - uint32_t cacheBlockTags[CacheSets][CacheBlocksPerSet]; - uint8_t cacheBlocks[CacheSets][CacheBlocksPerSet][CacheBlockSize]; - - void clearCache(); - uint8_t *findCacheLine(uint32_t virtAddr); - pair addCacheLineAndRead(uint32_t physAddr, uint32_t virtAddr, ValueSize valueSize, int domain, bool isPage); - MaybeU32 readCached(uint32_t virtAddr, ValueSize valueSize); - bool writeCached(uint32_t value, uint32_t virtAddr, ValueSize valueSize); + enum { + CacheSets = 4, + CacheBlocksPerSet = 128, + CacheBlockSize = 0x10, + + CacheAddressLineMask = 0x0000000F, + CacheAddressSetMask = 0x00000030, + CacheAddressSetShift = 4, + CacheAddressTagMask = 0xFFFFFFC0, + + CacheBlockEnabled = 1 + }; + uint32_t cacheBlockTags[CacheSets][CacheBlocksPerSet]; + uint8_t cacheBlocks[CacheSets][CacheBlocksPerSet][CacheBlockSize]; + + void clearCache(); + uint8_t* findCacheLine(uint32_t virtAddr); + pair addCacheLineAndRead(uint32_t physAddr, + uint32_t virtAddr, + ValueSize valueSize, int domain, + bool isPage); + MaybeU32 readCached(uint32_t virtAddr, ValueSize valueSize); + bool writeCached(uint32_t value, uint32_t virtAddr, ValueSize valueSize); #endif - // Instruction Loop - int prefetchCount; - uint32_t prefetch[2]; - MMUFault prefetchFaults[2]; - - uint32_t executeInstruction(uint32_t insn); - - uint32_t execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t Rn, uint32_t Rd, uint32_t Operand2); - uint32_t execMultiply(uint32_t AS, uint32_t Rd, uint32_t Rn, uint32_t Rs, uint32_t Rm); - uint32_t execMultiplyLong(uint32_t UAS, uint32_t RdHi, uint32_t RdLo, uint32_t Rs, uint32_t Rm); - uint32_t execSingleDataSwap(bool B, uint32_t Rn, uint32_t Rd, uint32_t Rm); - uint32_t execSingleDataTransfer(uint32_t IPUBWL, uint32_t Rn, uint32_t Rd, uint32_t offset); - uint32_t execSingleHalfWordDataTransfer(uint32_t PUIWL, uint32_t Rn, uint32_t Rd, uint32_t addrMode1, uint32_t SH, uint32_t addrMode2); - uint32_t execBlockDataTransfer(uint32_t PUSWL, uint32_t Rn, uint32_t registerList); - uint32_t execBranch(bool L, uint32_t offset); - uint32_t execCP15RegisterTransfer(uint32_t CPOpc, bool L, uint32_t CRn, uint32_t Rd, uint32_t CP, uint32_t CRm); + // Instruction Loop + int prefetchCount; + uint32_t prefetch[2]; + MMUFault prefetchFaults[2]; + + uint32_t executeInstruction(uint32_t insn); + + uint32_t execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t Rn, + uint32_t Rd, uint32_t Operand2); + uint32_t execMultiply(uint32_t AS, uint32_t Rd, uint32_t Rn, uint32_t Rs, + uint32_t Rm); + uint32_t execMultiplyLong(uint32_t UAS, uint32_t RdHi, uint32_t RdLo, + uint32_t Rs, uint32_t Rm); + uint32_t execSingleDataSwap(bool B, uint32_t Rn, uint32_t Rd, uint32_t Rm); + uint32_t execSingleDataTransfer(uint32_t IPUBWL, uint32_t Rn, uint32_t Rd, + uint32_t offset); + uint32_t execSingleHalfWordDataTransfer(uint32_t PUIWL, uint32_t Rn, + uint32_t Rd, uint32_t addrMode1, + uint32_t SH, uint32_t addrMode2); + uint32_t execBlockDataTransfer(uint32_t PUSWL, uint32_t Rn, + uint32_t registerList); + uint32_t execBranch(bool L, uint32_t offset); + uint32_t execCP15RegisterTransfer(uint32_t CPOpc, bool L, uint32_t CRn, + uint32_t Rd, uint32_t CP, uint32_t CRm); }; diff --git a/WindCore/clps7111.cpp b/WindCore/clps7111.cpp index 618e546..0f5087a 100644 --- a/WindCore/clps7111.cpp +++ b/WindCore/clps7111.cpp @@ -1,646 +1,768 @@ #include "clps7111.h" #include "clps7111_defs.h" +#include "common.h" #include "hardware.h" #include -#include "common.h" - namespace CLPS7111 { -Emulator::Emulator() : EmuBase(false), pcCardController(this) { -} - - -uint32_t Emulator::getRTC() { - return time(nullptr) - 946684800; -} - +Emulator::Emulator() : EmuBase(false), pcCardController(this) {} +uint32_t Emulator::getRTC() { return time(nullptr) - 946684800; } uint32_t Emulator::readReg8(uint32_t reg) { - if (reg == PADR) { - return ((portValues >> 24) & 0x80) | (readKeyboard() & 0x7F); - } else if (reg == PBDR) { - return ((portValues >> 16) & 0x0F) | ((keyboardExtra ^ 0xF) << 4); - } else if (reg == PDDR) { - return (portValues >> 8) & 0xFF; - } else if (reg == PEDR) { - return portValues & 0xFF; - } else if (reg == PADDR) { - return (portDirections >> 24) & 0xFF; - } else if (reg == PBDDR) { - return (portDirections >> 16) & 0xFF; - } else if (reg == PDDDR) { - return (portDirections >> 8) & 0xFF; - } else if (reg == PEDDR) { - return portDirections & 0xFF; - } else { - log("RegRead8 unknown:: pc=%08x lr=%08x reg=%03x", getRealPC(), getGPR(14), reg); - return 0xFF; - } + if (reg == PADR) { + return ((portValues >> 24) & 0x80) | (readKeyboard() & 0x7F); + } else if (reg == PBDR) { + return ((portValues >> 16) & 0x0F) | ((keyboardExtra ^ 0xF) << 4); + } else if (reg == PDDR) { + return (portValues >> 8) & 0xFF; + } else if (reg == PEDR) { + return portValues & 0xFF; + } else if (reg == PADDR) { + return (portDirections >> 24) & 0xFF; + } else if (reg == PBDDR) { + return (portDirections >> 16) & 0xFF; + } else if (reg == PDDDR) { + return (portDirections >> 8) & 0xFF; + } else if (reg == PEDDR) { + return portDirections & 0xFF; + } else { + log("RegRead8 unknown:: pc=%08x lr=%08x reg=%03x", getRealPC(), getGPR(14), + reg); + return 0xFF; + } } uint32_t Emulator::readReg32(uint32_t reg) { - if (reg == SYSCON1) { - uint32_t flg = 0; - if (tc1.config & Timer::PERIODIC) flg |= 0x10; - if (tc1.config & Timer::MODE_512KHZ) flg |= 0x20; - if (tc2.config & Timer::PERIODIC) flg |= 0x40; - if (tc2.config & Timer::MODE_512KHZ) flg |= 0x80; - flg |= (kScan & 0xF); - return flg; - } else if (reg == SYSFLG1) { - uint32_t flg = sysFlg1; - flg |= 2; // external power present - flg |= (rtcDiv << 16); - // maybe set more stuff? - return flg; - } else if (reg == INTSR1) { - return pendingInterrupts & 0xFFFF; - } else if (reg == INTMR1) { - return interruptMask & 0xFFFF; - } else if (reg == LCDCON) { - return lcdControl; - } else if (reg == TC1D) { - return tc1.value; - } else if (reg == TC2D) { - return tc2.value; - } else if (reg == RTCDR) { - return rtc; - } else if (reg == SYNCIO) { - switch (lastSyncioRequest & 0xFF) { - case 0xC1: // DigitiserX - return (touchX * 8) + 305; - case 0x81: // DigitiserY - return (touchY * 13.53) + 680; - case 0x91: // MainBattery - return 3000; - case 0xD1: // BackupBattery - return 3100; - case 0xA1: // Reference - return 1000; - } - log("SYNCIO read unknown:: req=%08x", lastSyncioRequest); - return 0xFFFFFFFF; - } else if (reg == PALLSW) { - return lcdPalette & 0xFFFFFFFF; - } else if (reg == PALMSW) { - return lcdPalette >> 32; - } else if (reg == SYSCON2) { - return 0; - } else if (reg == SYSFLG2) { - return 0; - } else if (reg == INTSR2) { - return pendingInterrupts >> 16; - } else if (reg == INTMR2) { - return interruptMask >> 16; - } else { - log("RegRead32 unknown:: pc=%08x lr=%08x reg=%03x", getRealPC(), getGPR(14), reg); - return 0xFFFFFFFF; - } + if (reg == SYSCON1) { + uint32_t flg = 0; + if (tc1.config & Timer::PERIODIC) + flg |= 0x10; + if (tc1.config & Timer::MODE_512KHZ) + flg |= 0x20; + if (tc2.config & Timer::PERIODIC) + flg |= 0x40; + if (tc2.config & Timer::MODE_512KHZ) + flg |= 0x80; + flg |= (kScan & 0xF); + return flg; + } else if (reg == SYSFLG1) { + uint32_t flg = sysFlg1; + flg |= 2; // external power present + flg |= (rtcDiv << 16); + // maybe set more stuff? + return flg; + } else if (reg == INTSR1) { + return pendingInterrupts & 0xFFFF; + } else if (reg == INTMR1) { + return interruptMask & 0xFFFF; + } else if (reg == LCDCON) { + return lcdControl; + } else if (reg == TC1D) { + return tc1.value; + } else if (reg == TC2D) { + return tc2.value; + } else if (reg == RTCDR) { + return rtc; + } else if (reg == SYNCIO) { + switch (lastSyncioRequest & 0xFF) { + case 0xC1: // DigitiserX + return (touchX * 8) + 305; + case 0x81: // DigitiserY + return (touchY * 13.53) + 680; + case 0x91: // MainBattery + return 3000; + case 0xD1: // BackupBattery + return 3100; + case 0xA1: // Reference + return 1000; + } + log("SYNCIO read unknown:: req=%08x", lastSyncioRequest); + return 0xFFFFFFFF; + } else if (reg == PALLSW) { + return lcdPalette & 0xFFFFFFFF; + } else if (reg == PALMSW) { + return lcdPalette >> 32; + } else if (reg == SYSCON2) { + return 0; + } else if (reg == SYSFLG2) { + return 0; + } else if (reg == INTSR2) { + return pendingInterrupts >> 16; + } else if (reg == INTMR2) { + return interruptMask >> 16; + } else { + log("RegRead32 unknown:: pc=%08x lr=%08x reg=%03x", getRealPC(), getGPR(14), + reg); + return 0xFFFFFFFF; + } } void Emulator::writeReg8(uint32_t reg, uint8_t value) { - if (reg == PADR) { - uint32_t oldPorts = portValues; - portValues &= 0x00FFFFFF; - portValues |= (uint32_t)value << 24; - diffPorts(oldPorts, portValues); - } else if (reg == PBDR) { - uint32_t oldPorts = portValues; - portValues &= 0xFF00FFFF; - portValues |= (uint32_t)value << 16; -// if ((portValues & 0x10000) && !(oldPorts & 0x10000)) -// etna.setPromBit0High(); -// else if (!(portValues & 0x10000) && (oldPorts & 0x10000)) -// etna.setPromBit0Low(); -// if ((portValues & 0x20000) && !(oldPorts & 0x20000)) -// etna.setPromBit1High(); - diffPorts(oldPorts, portValues); - } else if (reg == PDDR) { - uint32_t oldPorts = portValues; - portValues &= 0xFFFF00FF; - portValues |= (uint32_t)value << 8; - diffPorts(oldPorts, portValues); - } else if (reg == PEDR) { - uint32_t oldPorts = portValues; - portValues &= 0xFFFFFF00; - portValues |= (uint32_t)value; - diffPorts(oldPorts, portValues); - } else if (reg == PADDR) { - portDirections &= 0x00FFFFFF; - portDirections |= (uint32_t)value << 24; - } else if (reg == PBDDR) { - portDirections &= 0xFF00FFFF; - portDirections |= (uint32_t)value << 16; - } else if (reg == PDDDR) { - portDirections &= 0xFFFF00FF; - portDirections |= (uint32_t)value << 8; - } else if (reg == PEDDR) { - portDirections &= 0xFFFFFF00; - portDirections |= (uint32_t)value; - } else if (reg == FRBADDR) { - log("LCD: address write %08x", value << 28); - lcdAddress = value << 28; - } else { - log("RegWrite8 unknown:: pc=%08x reg=%03x value=%02x", getRealPC(), reg, value); - } + if (reg == PADR) { + uint32_t oldPorts = portValues; + portValues &= 0x00FFFFFF; + portValues |= (uint32_t)value << 24; + diffPorts(oldPorts, portValues); + } else if (reg == PBDR) { + uint32_t oldPorts = portValues; + portValues &= 0xFF00FFFF; + portValues |= (uint32_t)value << 16; + // if ((portValues & 0x10000) && !(oldPorts & 0x10000)) + // etna.setPromBit0High(); + // else if (!(portValues & 0x10000) && (oldPorts & 0x10000)) + // etna.setPromBit0Low(); + // if ((portValues & 0x20000) && !(oldPorts & 0x20000)) + // etna.setPromBit1High(); + diffPorts(oldPorts, portValues); + } else if (reg == PDDR) { + uint32_t oldPorts = portValues; + portValues &= 0xFFFF00FF; + portValues |= (uint32_t)value << 8; + diffPorts(oldPorts, portValues); + } else if (reg == PEDR) { + uint32_t oldPorts = portValues; + portValues &= 0xFFFFFF00; + portValues |= (uint32_t)value; + diffPorts(oldPorts, portValues); + } else if (reg == PADDR) { + portDirections &= 0x00FFFFFF; + portDirections |= (uint32_t)value << 24; + } else if (reg == PBDDR) { + portDirections &= 0xFF00FFFF; + portDirections |= (uint32_t)value << 16; + } else if (reg == PDDDR) { + portDirections &= 0xFFFF00FF; + portDirections |= (uint32_t)value << 8; + } else if (reg == PEDDR) { + portDirections &= 0xFFFFFF00; + portDirections |= (uint32_t)value; + } else if (reg == FRBADDR) { + log("LCD: address write %08x", value << 28); + lcdAddress = value << 28; + } else { + log("RegWrite8 unknown:: pc=%08x reg=%03x value=%02x", getRealPC(), reg, + value); + } } void Emulator::writeReg32(uint32_t reg, uint32_t value) { - if (reg == SYSCON1) { - kScan = value & 0xF; - uint8_t tc1cfg = Timer::ENABLED; // always on with PS-7111! - if (value & 0x10) tc1cfg |= Timer::PERIODIC; - if (value & 0x20) tc1cfg |= Timer::MODE_512KHZ; - uint8_t tc2cfg = Timer::ENABLED; - if (value & 0x40) tc2cfg |= Timer::PERIODIC; - if (value & 0x80) tc2cfg |= Timer::MODE_512KHZ; - tc1.setConfig(tc1cfg); - tc2.setConfig(tc2cfg); - } else if (reg == INTMR1) { - interruptMask &= 0xFFFF0000;; - interruptMask |= (value & 0xFFFF); - } else if (reg == LCDCON) { - log("LCD: ctl write %08x", value); - lcdControl = value; - } else if (reg == TC1D) { - tc1.load(value); - } else if (reg == TC2D) { - tc2.load(value); - } else if (reg == RTCDR) { - rtc = value; - } else if (reg == SYNCIO) { - lastSyncioRequest = value & 0xFFFF; - } else if (reg == PALLSW) { - lcdPalette &= 0xFFFFFFFF00000000; - lcdPalette |= value; - } else if (reg == PALMSW) { - lcdPalette &= 0x00000000FFFFFFFF; - lcdPalette |= (uint64_t)value << 32; - } else if (reg == HALT) { - halted = true; - // BLEOI = 0x410, - // MCEOI = 0x414, - } else if (reg == TEOI) { - pendingInterrupts &= ~(1 << TINT); - // TEOI = 0x418, - // STFCLR = 0x41C, - // E2EOI = 0x420, - } else if (reg == TC1EOI) { - pendingInterrupts &= ~(1 << TC1OI); - } else if (reg == TC2EOI) { - pendingInterrupts &= ~(1 << TC2OI); - } else if (reg == SYSCON2) { - log("SysCon2 write: %08x", value); - } else if (reg == INTMR2) { - interruptMask &= 0xFFFF; - interruptMask |= (value << 16); - } else if (reg == KBDEOI) { - pendingInterrupts &= ~(1 << KBDINT); - } else { - log("RegWrite32 unknown:: pc=%08x reg=%03x value=%08x", getRealPC(), reg, value); - } + if (reg == SYSCON1) { + kScan = value & 0xF; + uint8_t tc1cfg = Timer::ENABLED; // always on with PS-7111! + if (value & 0x10) + tc1cfg |= Timer::PERIODIC; + if (value & 0x20) + tc1cfg |= Timer::MODE_512KHZ; + uint8_t tc2cfg = Timer::ENABLED; + if (value & 0x40) + tc2cfg |= Timer::PERIODIC; + if (value & 0x80) + tc2cfg |= Timer::MODE_512KHZ; + tc1.setConfig(tc1cfg); + tc2.setConfig(tc2cfg); + } else if (reg == INTMR1) { + interruptMask &= 0xFFFF0000; + ; + interruptMask |= (value & 0xFFFF); + } else if (reg == LCDCON) { + log("LCD: ctl write %08x", value); + lcdControl = value; + } else if (reg == TC1D) { + tc1.load(value); + } else if (reg == TC2D) { + tc2.load(value); + } else if (reg == RTCDR) { + rtc = value; + } else if (reg == SYNCIO) { + lastSyncioRequest = value & 0xFFFF; + } else if (reg == PALLSW) { + lcdPalette &= 0xFFFFFFFF00000000; + lcdPalette |= value; + } else if (reg == PALMSW) { + lcdPalette &= 0x00000000FFFFFFFF; + lcdPalette |= (uint64_t)value << 32; + } else if (reg == HALT) { + halted = true; + // BLEOI = 0x410, + // MCEOI = 0x414, + } else if (reg == TEOI) { + pendingInterrupts &= ~(1 << TINT); + // TEOI = 0x418, + // STFCLR = 0x41C, + // E2EOI = 0x420, + } else if (reg == TC1EOI) { + pendingInterrupts &= ~(1 << TC1OI); + } else if (reg == TC2EOI) { + pendingInterrupts &= ~(1 << TC2OI); + } else if (reg == SYSCON2) { + log("SysCon2 write: %08x", value); + } else if (reg == INTMR2) { + interruptMask &= 0xFFFF; + interruptMask |= (value << 16); + } else if (reg == KBDEOI) { + pendingInterrupts &= ~(1 << KBDINT); + } else { + log("RegWrite32 unknown:: pc=%08x reg=%03x value=%08x", getRealPC(), reg, + value); + } } MaybeU32 Emulator::readPhysical(uint32_t physAddr, ValueSize valueSize) { - uint8_t region = (physAddr >> 28); - if (valueSize == V8) { - if (region == 0) - return ROM[physAddr & 0xFFFFFF]; - else if (region == 1) - return ROM2[physAddr & 0x3FFFF]; - else if (region == 4) - return pcCardController.read(physAddr & 0xFFFFFFF, V8); - else if (region == 8 && physAddr <= 0x80001FFF) - return readReg8(physAddr & 0x1FFF); - else if (region == 0xC) - return MemoryBlockC0[physAddr & MemoryBlockMask]; - else if (region > 0xC) - return 0xFF; // just throw accesses to unmapped RAM away - } else { - uint32_t result; - if (region == 0) - LOAD_32LE(result, physAddr & 0xFFFFFF, ROM); - else if (region == 1) - LOAD_32LE(result, physAddr & 0x3FFFF, ROM2); - else if (region == 4) - result = pcCardController.read(physAddr & 0xFFFFFFF, V32); - else if (region == 8 && physAddr <= 0x80001FFF) - result = readReg32(physAddr & 0x1FFF); - else if (region == 0xC) - LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockC0); - else if (region > 0xC) - return 0xFFFFFFFF; // just throw accesses to unmapped RAM away - else - return {}; - return result; - } - - return {}; + uint8_t region = (physAddr >> 28); + if (valueSize == V8) { + if (region == 0) + return ROM[physAddr & 0xFFFFFF]; + else if (region == 1) + return ROM2[physAddr & 0x3FFFF]; + else if (region == 4) + return pcCardController.read(physAddr & 0xFFFFFFF, V8); + else if (region == 8 && physAddr <= 0x80001FFF) + return readReg8(physAddr & 0x1FFF); + else if (region == 0xC) + return MemoryBlockC0[physAddr & MemoryBlockMask]; + else if (region > 0xC) + return 0xFF; // just throw accesses to unmapped RAM away + } else { + uint32_t result; + if (region == 0) + LOAD_32LE(result, physAddr & 0xFFFFFF, ROM); + else if (region == 1) + LOAD_32LE(result, physAddr & 0x3FFFF, ROM2); + else if (region == 4) + result = pcCardController.read(physAddr & 0xFFFFFFF, V32); + else if (region == 8 && physAddr <= 0x80001FFF) + result = readReg32(physAddr & 0x1FFF); + else if (region == 0xC) + LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockC0); + else if (region > 0xC) + return 0xFFFFFFFF; // just throw accesses to unmapped RAM away + else + return {}; + return result; + } + + return {}; } -bool Emulator::writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) { - uint8_t region = (physAddr >> 28); - if (valueSize == V8) { - if (region == 0xC) - MemoryBlockC0[physAddr & MemoryBlockMask] = (uint8_t)value; - else if (region > 0xC) - return true; // just throw accesses to unmapped RAM away - else if (region == 4) - pcCardController.write(value, physAddr & 0xFFFFFFF, V8); - else if (region == 8 && physAddr <= 0x80001FFF) - writeReg8(physAddr & 0x1FFF, value); - else - return false; - } else { - if (region == 0xC) - STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockC0); - else if (region > 0xC) - return true; // just throw accesses to unmapped RAM away - else if (region == 4) - pcCardController.write(value, physAddr & 0xFFFFFFF, V32); - else if (region == 8 && physAddr <= 0x80001FFF) - writeReg32(physAddr & 0x1FFF, value); - else - return false; - } - return true; +bool Emulator::writePhysical(uint32_t value, uint32_t physAddr, + ValueSize valueSize) { + uint8_t region = (physAddr >> 28); + if (valueSize == V8) { + if (region == 0xC) + MemoryBlockC0[physAddr & MemoryBlockMask] = (uint8_t)value; + else if (region > 0xC) + return true; // just throw accesses to unmapped RAM away + else if (region == 4) + pcCardController.write(value, physAddr & 0xFFFFFFF, V8); + else if (region == 8 && physAddr <= 0x80001FFF) + writeReg8(physAddr & 0x1FFF, value); + else + return false; + } else { + if (region == 0xC) + STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockC0); + else if (region > 0xC) + return true; // just throw accesses to unmapped RAM away + else if (region == 4) + pcCardController.write(value, physAddr & 0xFFFFFFF, V32); + else if (region == 8 && physAddr <= 0x80001FFF) + writeReg32(physAddr & 0x1FFF, value); + else + return false; + } + return true; } - - void Emulator::configure() { - if (configured) return; - configured = true; + if (configured) + return; + configured = true; - srand(1000); + srand(1000); - memset(&tc1, 0, sizeof(tc1)); - memset(&tc2, 0, sizeof(tc1)); - tc1.clockSpeed = CLOCK_SPEED; - tc2.clockSpeed = CLOCK_SPEED; + memset(&tc1, 0, sizeof(tc1)); + memset(&tc2, 0, sizeof(tc1)); + tc1.clockSpeed = CLOCK_SPEED; + tc2.clockSpeed = CLOCK_SPEED; - nextTickAt = TICK_INTERVAL; - tc1.nextTickAt = tc1.tickInterval(); - tc2.nextTickAt = tc2.tickInterval(); - rtc = getRTC(); + nextTickAt = TICK_INTERVAL; + tc1.nextTickAt = tc1.tickInterval(); + tc2.nextTickAt = tc2.tickInterval(); + rtc = getRTC(); - reset(); + reset(); } -uint8_t *Emulator::getROMBuffer() { - return ROM; -} -size_t Emulator::getROMSize() { - return sizeof(ROM); -} -void Emulator::loadROM(uint8_t *buffer, size_t size) { - memcpy(ROM, buffer, min(size, sizeof(ROM))); +uint8_t* Emulator::getROMBuffer() { return ROM; } +size_t Emulator::getROMSize() { return sizeof(ROM); } +void Emulator::loadROM(uint8_t* buffer, size_t size) { + memcpy(ROM, buffer, min(size, sizeof(ROM))); } void Emulator::executeUntil(int64_t cycles) { - if (!configured) - configure(); - - while (!asleep && passedCycles < cycles) { - if (passedCycles >= nextTickAt) { - // increment RTCDIV - if (rtcDiv == 0x3F) { - rtc++; - rtcDiv = 0; - } else { - rtcDiv++; - } - - nextTickAt += TICK_INTERVAL; - pendingInterrupts |= (1<= 0x80000000 && new_pc <= 0x90000000) { - log("BAD PC %08x!!", new_pc); - logPcHistory(); - return; - } - } - } + if (!configured) + configure(); + + while (!asleep && passedCycles < cycles) { + if (passedCycles >= nextTickAt) { + // increment RTCDIV + if (rtcDiv == 0x3F) { + rtc++; + rtcDiv = 0; + } else { + rtcDiv++; + } + + nextTickAt += TICK_INTERVAL; + pendingInterrupts |= (1 << TINT); + } + if (tc1.tick(passedCycles)) + pendingInterrupts |= (1 << TC1OI); + if (tc2.tick(passedCycles)) + pendingInterrupts |= (1 << TC2OI); + + if ((pendingInterrupts & interruptMask & FIQ_INTERRUPTS) != 0 && + canAcceptFIQ()) { + requestFIQ(); + halted = false; + } + if ((pendingInterrupts & interruptMask & IRQ_INTERRUPTS) != 0 && + canAcceptIRQ()) { + requestIRQ(); + halted = false; + } + + // what's running? + if (halted) { + // keep the clock moving + passedCycles++; + } else { + if (auto v = virtToPhys(getGPR(15) - 0xC); + v.has_value() && instructionReady()) + debugPC(v.value()); + passedCycles += tick(); + + uint32_t new_pc = getGPR(15) - 0xC; + if (_breakpoints.find(new_pc) != _breakpoints.end()) { + log("⚠️ Breakpoint triggered at %08x!", new_pc); + return; + } + if (new_pc >= 0x80000000 && new_pc <= 0x90000000) { + log("BAD PC %08x!!", new_pc); + logPcHistory(); + return; + } + } + } } - -const char *Emulator::identifyObjectCon(uint32_t ptr) { - if (ptr == readVirtualDebug(0x80000880, V32).value()) return "process"; - if (ptr == readVirtualDebug(0x80000884, V32).value()) return "thread"; - if (ptr == readVirtualDebug(0x80000888, V32).value()) return "chunk"; -// if (ptr == readVirtualDebug(0x8000088C, V32).value()) return "semaphore"; -// if (ptr == readVirtualDebug(0x80000890, V32).value()) return "mutex"; - if (ptr == readVirtualDebug(0x80000894, V32).value()) return "logicaldevice"; - if (ptr == readVirtualDebug(0x80000898, V32).value()) return "physicaldevice"; - if (ptr == readVirtualDebug(0x8000089C, V32).value()) return "channel"; - if (ptr == readVirtualDebug(0x800008A0, V32).value()) return "server"; -// if (ptr == readVirtualDebug(0x800008A4, V32).value()) return "unk8A4"; // name always null - if (ptr == readVirtualDebug(0x800008AC, V32).value()) return "library"; -// if (ptr == readVirtualDebug(0x800008B0, V32).value()) return "unk8B0"; // name always null -// if (ptr == readVirtualDebug(0x800008B4, V32).value()) return "unk8B4"; // name always null - return nullptr; +const char* Emulator::identifyObjectCon(uint32_t ptr) { + if (ptr == readVirtualDebug(0x80000880, V32).value()) + return "process"; + if (ptr == readVirtualDebug(0x80000884, V32).value()) + return "thread"; + if (ptr == readVirtualDebug(0x80000888, V32).value()) + return "chunk"; + // if (ptr == readVirtualDebug(0x8000088C, V32).value()) return + //"semaphore"; if (ptr == readVirtualDebug(0x80000890, V32).value()) + //return "mutex"; + if (ptr == readVirtualDebug(0x80000894, V32).value()) + return "logicaldevice"; + if (ptr == readVirtualDebug(0x80000898, V32).value()) + return "physicaldevice"; + if (ptr == readVirtualDebug(0x8000089C, V32).value()) + return "channel"; + if (ptr == readVirtualDebug(0x800008A0, V32).value()) + return "server"; + // if (ptr == readVirtualDebug(0x800008A4, V32).value()) return "unk8A4"; + //// name always null + if (ptr == readVirtualDebug(0x800008AC, V32).value()) + return "library"; + // if (ptr == readVirtualDebug(0x800008B0, V32).value()) return "unk8B0"; + //// name always null if (ptr == readVirtualDebug(0x800008B4, + ///V32).value()) + // return "unk8B4"; // name always null + return nullptr; } -void Emulator::fetchStr(uint32_t str, char *buf) { - if (str == 0) { - strcpy(buf, ""); - return; - } - int size = readVirtualDebug(str, V32).value(); - for (int i = 0; i < size; i++) { - buf[i] = readVirtualDebug(str + 4 + i, V8).value(); - } - buf[size] = 0; +void Emulator::fetchStr(uint32_t str, char* buf) { + if (str == 0) { + strcpy(buf, ""); + return; + } + int size = readVirtualDebug(str, V32).value(); + for (int i = 0; i < size; i++) { + buf[i] = readVirtualDebug(str + 4 + i, V8).value(); + } + buf[size] = 0; } -void Emulator::fetchName(uint32_t obj, char *buf) { - fetchStr(readVirtualDebug(obj + 0x10, V32).value(), buf); +void Emulator::fetchName(uint32_t obj, char* buf) { + fetchStr(readVirtualDebug(obj + 0x10, V32).value(), buf); } -void Emulator::fetchProcessFilename(uint32_t obj, char *buf) { - fetchStr(readVirtualDebug(obj + 0x3C, V32).value(), buf); +void Emulator::fetchProcessFilename(uint32_t obj, char* buf) { + fetchStr(readVirtualDebug(obj + 0x3C, V32).value(), buf); } void Emulator::debugPC(uint32_t pc) { - char objName[1000]; - if (pc == 0x32304) { - // CObjectCon::AddL() - uint32_t container = getGPR(0); - uint32_t obj = getGPR(1); - const char *wut = identifyObjectCon(container); - if (wut) { - fetchName(obj, objName); - if (strcmp(wut, "process") == 0) { - char procName[1000]; - fetchProcessFilename(obj, procName); - log("OBJS: added %s at %08x <%s> <%s>", wut, obj, objName, procName); - } else { - log("OBJS: added %s at %08x <%s>", wut, obj, objName); - } - } - } - - if (pc == 0x634) { - uint32_t virtAddr = getGPR(0); - uint32_t physAddr = getGPR(1); - uint32_t btIndex = getGPR(2); - uint32_t regionSize = getGPR(3); - log("KERNEL MMU SECTION: v:%08x p:%08x size:%08x idx:%02x", - virtAddr, physAddr, regionSize, btIndex); - } - if (pc == 0x66C) { - uint32_t virtAddr = getGPR(0); - uint32_t physAddr = getGPR(1); - uint32_t btIndex = getGPR(2); - uint32_t regionSize = getGPR(3); - uint32_t pageTableA = getGPR(4); - uint32_t pageTableB = getGPR(5); - log("KERNEL MMU PAGES: v:%08x p:%08x size:%08x idx:%02x tableA:%08x tableB:%08x", - virtAddr, physAddr, regionSize, btIndex, pageTableA, pageTableB); - } - if (pc == 0x15070) { - uint32_t virtAddr = getGPR(0); - uint32_t physAddr = getGPR(1); - uint32_t regionSize = getGPR(2); - uint32_t a = getGPR(3); - log("DPlatChunkHw MAPPING: v:%08x p:%08x size:%08x arg:%08x", - virtAddr, physAddr, regionSize, a); - } - - if (pc == 0x16198) { - uint32_t rawEvent = getGPR(0); - uint32_t evtType = readVirtualDebug(rawEvent, V32).value_or(0); - uint32_t evtTick = readVirtualDebug(rawEvent + 4, V32).value_or(0); - uint32_t evtParamA = readVirtualDebug(rawEvent + 8, V32).value_or(0); - uint32_t evtParamB = readVirtualDebug(rawEvent + 0xC, V32).value_or(0); - const char *n = "???"; - switch (evtType) { - case 0: n = "ENone"; break; - case 1: n = "EPointerMove"; break; - case 2: n = "EPointerSwitchOn"; break; - case 3: n = "EKeyDown"; break; - case 4: n = "EKeyUp"; break; - case 5: n = "ERedraw"; break; - case 6: n = "ESwitchOn"; break; - case 7: n = "EActive"; break; - case 8: n = "EInactive"; break; - case 9: n = "EUpdateModifiers"; break; - case 10: n = "EButton1Down"; break; - case 11: n = "EButton1Up"; break; - case 12: n = "EButton2Down"; break; - case 13: n = "EButton2Up"; break; - case 14: n = "EButton3Down"; break; - case 15: n = "EButton3Up"; break; - case 16: n = "ESwitchOff"; break; - } - log("EVENT %s: tick=%d params=%08x,%08x", n, evtTick, evtParamA, evtParamB); - } + char objName[1000]; + if (pc == 0x32304) { + // CObjectCon::AddL() + uint32_t container = getGPR(0); + uint32_t obj = getGPR(1); + const char* wut = identifyObjectCon(container); + if (wut) { + fetchName(obj, objName); + if (strcmp(wut, "process") == 0) { + char procName[1000]; + fetchProcessFilename(obj, procName); + log("OBJS: added %s at %08x <%s> <%s>", wut, obj, objName, procName); + } else { + log("OBJS: added %s at %08x <%s>", wut, obj, objName); + } + } + } + + if (pc == 0x634) { + uint32_t virtAddr = getGPR(0); + uint32_t physAddr = getGPR(1); + uint32_t btIndex = getGPR(2); + uint32_t regionSize = getGPR(3); + log("KERNEL MMU SECTION: v:%08x p:%08x size:%08x idx:%02x", virtAddr, + physAddr, regionSize, btIndex); + } + if (pc == 0x66C) { + uint32_t virtAddr = getGPR(0); + uint32_t physAddr = getGPR(1); + uint32_t btIndex = getGPR(2); + uint32_t regionSize = getGPR(3); + uint32_t pageTableA = getGPR(4); + uint32_t pageTableB = getGPR(5); + log("KERNEL MMU PAGES: v:%08x p:%08x size:%08x idx:%02x tableA:%08x " + "tableB:%08x", + virtAddr, physAddr, regionSize, btIndex, pageTableA, pageTableB); + } + if (pc == 0x15070) { + uint32_t virtAddr = getGPR(0); + uint32_t physAddr = getGPR(1); + uint32_t regionSize = getGPR(2); + uint32_t a = getGPR(3); + log("DPlatChunkHw MAPPING: v:%08x p:%08x size:%08x arg:%08x", virtAddr, + physAddr, regionSize, a); + } + + if (pc == 0x16198) { + uint32_t rawEvent = getGPR(0); + uint32_t evtType = readVirtualDebug(rawEvent, V32).value_or(0); + uint32_t evtTick = readVirtualDebug(rawEvent + 4, V32).value_or(0); + uint32_t evtParamA = readVirtualDebug(rawEvent + 8, V32).value_or(0); + uint32_t evtParamB = readVirtualDebug(rawEvent + 0xC, V32).value_or(0); + const char* n = "???"; + switch (evtType) { + case 0: + n = "ENone"; + break; + case 1: + n = "EPointerMove"; + break; + case 2: + n = "EPointerSwitchOn"; + break; + case 3: + n = "EKeyDown"; + break; + case 4: + n = "EKeyUp"; + break; + case 5: + n = "ERedraw"; + break; + case 6: + n = "ESwitchOn"; + break; + case 7: + n = "EActive"; + break; + case 8: + n = "EInactive"; + break; + case 9: + n = "EUpdateModifiers"; + break; + case 10: + n = "EButton1Down"; + break; + case 11: + n = "EButton1Up"; + break; + case 12: + n = "EButton2Down"; + break; + case 13: + n = "EButton2Up"; + break; + case 14: + n = "EButton3Down"; + break; + case 15: + n = "EButton3Up"; + break; + case 16: + n = "ESwitchOff"; + break; + } + log("EVENT %s: tick=%d params=%08x,%08x", n, evtTick, evtParamA, evtParamB); + } } - -const char *Emulator::getDeviceName() const { return "Osaris"; } -int Emulator::getDigitiserWidth() const { return 440; } +const char* Emulator::getDeviceName() const { return "Osaris"; } +int Emulator::getDigitiserWidth() const { return 440; } int Emulator::getDigitiserHeight() const { return 200; } -int Emulator::getLCDOffsetX() const { return 60; } -int Emulator::getLCDOffsetY() const { return 0; } -int Emulator::getLCDWidth() const { return 320; } -int Emulator::getLCDHeight() const { return 200; } - -void Emulator::readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) const { - if (lcdAddress == 0xC0000000) { - int width = 320, height = 200; - int bpp = 1; - if (lcdControl & 0x40000000) bpp = 2; - if (lcdControl & 0x80000000) bpp = 4; - int ppb = 8 / bpp; - - // build our image out - int lineWidth = (width * bpp) / 8; - for (int y = 0; y < height; y++) { - int lineOffs = lineWidth * y; - for (int x = 0; x < width; x++) { - uint8_t byte = MemoryBlockC0[lineOffs + (x / ppb)]; - int shift = (x & (ppb - 1)) * bpp; - int mask = (1 << bpp) - 1; - int palIdx = (byte >> shift) & mask; - int palValue; - if (bpp == 1) - palValue = palIdx * 255; - else - palValue = (lcdPalette >> (palIdx * 4)) & 0xF; - - palValue |= (palValue << 4); - if (is32BitOutput) { - lines[y][x*4] = palValue ^ 0xFF; - lines[y][x*4+1] = palValue ^ 0xFF; - lines[y][x*4+2] = palValue ^ 0xFF; - } else { - lines[y][x] = palValue ^ 0xFF; - } - } - } - } +int Emulator::getLCDOffsetX() const { return 60; } +int Emulator::getLCDOffsetY() const { return 0; } +int Emulator::getLCDWidth() const { return 320; } +int Emulator::getLCDHeight() const { return 200; } + +void Emulator::readLCDIntoBuffer(uint8_t** lines, bool is32BitOutput) const { + if (lcdAddress == 0xC0000000) { + int width = 320, height = 200; + int bpp = 1; + if (lcdControl & 0x40000000) + bpp = 2; + if (lcdControl & 0x80000000) + bpp = 4; + int ppb = 8 / bpp; + + // build our image out + int lineWidth = (width * bpp) / 8; + for (int y = 0; y < height; y++) { + int lineOffs = lineWidth * y; + for (int x = 0; x < width; x++) { + uint8_t byte = MemoryBlockC0[lineOffs + (x / ppb)]; + int shift = (x & (ppb - 1)) * bpp; + int mask = (1 << bpp) - 1; + int palIdx = (byte >> shift) & mask; + int palValue; + if (bpp == 1) + palValue = palIdx * 255; + else + palValue = (lcdPalette >> (palIdx * 4)) & 0xF; + + palValue |= (palValue << 4); + if (is32BitOutput) { + lines[y][x * 4] = palValue ^ 0xFF; + lines[y][x * 4 + 1] = palValue ^ 0xFF; + lines[y][x * 4 + 2] = palValue ^ 0xFF; + } else { + lines[y][x] = palValue ^ 0xFF; + } + } + } + } } - - void Emulator::diffPorts(uint32_t oldval, uint32_t newval) { - uint32_t changes = oldval ^ newval; - if (changes & 1) log("PRT E0: %d", newval&1); - if (changes & 2) log("PRT E1: %d", newval&2); - if (changes & 4) log("PRT E2: %d", newval&4); - if (changes & 0x100) log("PRT D0: %d", newval&0x100); - if (changes & 0x200) log("PRT D1: %d", newval&0x200); - if (changes & 0x400) log("PRT D2: %d", newval&0x400); - if (changes & 0x800) log("PRT D3: %d", newval&0x800); - if (changes & 0x1000) log("PRT D4: %d", newval&0x1000); - if (changes & 0x2000) log("PRT D5: %d", newval&0x2000); - if (changes & 0x4000) log("PRT D6: %d", newval&0x4000); - if (changes & 0x8000) log("PRT D7: %d", newval&0x8000); - if (changes & 0x10000) log("PRT B0: %d", newval&0x10000); - if (changes & 0x20000) log("PRT B1: %d", newval&0x20000); - if (changes & 0x40000) log("PRT B2: %d", newval&0x40000); - if (changes & 0x80000) log("PRT B3: %d", newval&0x80000); - if (changes & 0x100000) log("PRT B4: %d", newval&0x100000); - if (changes & 0x200000) log("PRT B5: %d", newval&0x200000); - if (changes & 0x400000) log("PRT B6: %d", newval&0x400000); - if (changes & 0x800000) log("PRT B7: %d", newval&0x800000); + uint32_t changes = oldval ^ newval; + if (changes & 1) + log("PRT E0: %d", newval & 1); + if (changes & 2) + log("PRT E1: %d", newval & 2); + if (changes & 4) + log("PRT E2: %d", newval & 4); + if (changes & 0x100) + log("PRT D0: %d", newval & 0x100); + if (changes & 0x200) + log("PRT D1: %d", newval & 0x200); + if (changes & 0x400) + log("PRT D2: %d", newval & 0x400); + if (changes & 0x800) + log("PRT D3: %d", newval & 0x800); + if (changes & 0x1000) + log("PRT D4: %d", newval & 0x1000); + if (changes & 0x2000) + log("PRT D5: %d", newval & 0x2000); + if (changes & 0x4000) + log("PRT D6: %d", newval & 0x4000); + if (changes & 0x8000) + log("PRT D7: %d", newval & 0x8000); + if (changes & 0x10000) + log("PRT B0: %d", newval & 0x10000); + if (changes & 0x20000) + log("PRT B1: %d", newval & 0x20000); + if (changes & 0x40000) + log("PRT B2: %d", newval & 0x40000); + if (changes & 0x80000) + log("PRT B3: %d", newval & 0x80000); + if (changes & 0x100000) + log("PRT B4: %d", newval & 0x100000); + if (changes & 0x200000) + log("PRT B5: %d", newval & 0x200000); + if (changes & 0x400000) + log("PRT B6: %d", newval & 0x400000); + if (changes & 0x800000) + log("PRT B7: %d", newval & 0x800000); } - uint32_t Emulator::readKeyboard() const { - if (kScan & 8) { - // Select one keyboard - if ((kScan & 7) < 7) - return keyboardColumns[kScan & 7]; - else - return 0; - } else if (kScan == 0) { - // Report all columns combined - uint8_t val = 0; - for (int i = 0; i < 7; i++) - val |= keyboardColumns[i]; - return val; - } else { - return 0; - } + if (kScan & 8) { + // Select one keyboard + if ((kScan & 7) < 7) + return keyboardColumns[kScan & 7]; + else + return 0; + } else if (kScan == 0) { + // Report all columns combined + uint8_t val = 0; + for (int i = 0; i < 7; i++) + val |= keyboardColumns[i]; + return val; + } else { + return 0; + } } void Emulator::setKeyboardKey(EpocKey key, bool value) { - int idx = -1; -#define KEY(column, bit) idx = (column << 8) | (1 << bit); break - - switch ((int)key) { - case '1': KEY(0, 0); - case '2': KEY(1, 0); - case '3': KEY(2, 0); - case '4': KEY(3, 0); - case '5': KEY(4, 0); - case '6': KEY(5, 0); - case '7': KEY(6, 0); - - case '8': KEY(0, 1); - case '9': KEY(1, 1); - case '0': KEY(2, 1); - case 'P': KEY(3, 1); - case EStdKeySingleQuote: KEY(4, 1); - case EStdKeyEnter: KEY(5, 1); - case EStdKeyBackspace: KEY(6, 1); - - case EStdKeyEscape: KEY(0, 2); - case 'Q': KEY(1, 2); - case 'W': KEY(2, 2); - case 'E': KEY(3, 2); - case 'R': KEY(4, 2); - case 'T': KEY(5, 2); - case 'Y': KEY(6, 2); - - case 'U': KEY(0, 3); - case 'J': KEY(1, 3); - case 'I': KEY(2, 3); - case 'K': KEY(3, 3); - case 'O': KEY(4, 3); - case 'L': KEY(5, 3); - case EStdKeyUpArrow: KEY(6, 3); - - case EStdKeyTab: KEY(0, 4); - case 'A': KEY(1, 4); - case 'S': KEY(2, 4); - case 'D': KEY(3, 4); - case 'F': KEY(4, 4); - case 'G': KEY(5, 4); - case 'H': KEY(6, 4); - - case EStdKeySpace: KEY(0, 5); - case EStdKeyComma: KEY(1, 5); - case 'M': KEY(2, 5); - case EStdKeyFullStop: KEY(3, 5); - case EStdKeyLeftArrow: KEY(4, 5); - case EStdKeyDownArrow: KEY(5, 5); - case EStdKeyRightArrow: KEY(6, 5); - - case 'Z': KEY(0, 6); - case 'X': KEY(1, 6); - case EStdKeyMenu: KEY(2, 6); - case 'C': KEY(3, 6); - case 'V': KEY(4, 6); - case 'B': KEY(5, 6); - case 'N': KEY(6, 6); - - case EStdKeyLeftShift: KEY(8, 0); - case EStdKeyRightShift: KEY(8, 1); - case EStdKeyLeftCtrl: KEY(8, 2); - case EStdKeyLeftFunc: KEY(8, 3); - } - - if (idx >= 0x800) { - if (value) - keyboardExtra |= (idx & 0xFF); - else - keyboardExtra &= ~(idx & 0xFF); - } else if (idx >= 0) { - if (value) - keyboardColumns[idx >> 8] |= (idx & 0xFF); - else - keyboardColumns[idx >> 8] &= ~(idx & 0xFF); - } + int idx = -1; +#define KEY(column, bit) \ + idx = (column << 8) | (1 << bit); \ + break + + switch ((int)key) { + case '1': + KEY(0, 0); + case '2': + KEY(1, 0); + case '3': + KEY(2, 0); + case '4': + KEY(3, 0); + case '5': + KEY(4, 0); + case '6': + KEY(5, 0); + case '7': + KEY(6, 0); + + case '8': + KEY(0, 1); + case '9': + KEY(1, 1); + case '0': + KEY(2, 1); + case 'P': + KEY(3, 1); + case EStdKeySingleQuote: + KEY(4, 1); + case EStdKeyEnter: + KEY(5, 1); + case EStdKeyBackspace: + KEY(6, 1); + + case EStdKeyEscape: + KEY(0, 2); + case 'Q': + KEY(1, 2); + case 'W': + KEY(2, 2); + case 'E': + KEY(3, 2); + case 'R': + KEY(4, 2); + case 'T': + KEY(5, 2); + case 'Y': + KEY(6, 2); + + case 'U': + KEY(0, 3); + case 'J': + KEY(1, 3); + case 'I': + KEY(2, 3); + case 'K': + KEY(3, 3); + case 'O': + KEY(4, 3); + case 'L': + KEY(5, 3); + case EStdKeyUpArrow: + KEY(6, 3); + + case EStdKeyTab: + KEY(0, 4); + case 'A': + KEY(1, 4); + case 'S': + KEY(2, 4); + case 'D': + KEY(3, 4); + case 'F': + KEY(4, 4); + case 'G': + KEY(5, 4); + case 'H': + KEY(6, 4); + + case EStdKeySpace: + KEY(0, 5); + case EStdKeyComma: + KEY(1, 5); + case 'M': + KEY(2, 5); + case EStdKeyFullStop: + KEY(3, 5); + case EStdKeyLeftArrow: + KEY(4, 5); + case EStdKeyDownArrow: + KEY(5, 5); + case EStdKeyRightArrow: + KEY(6, 5); + + case 'Z': + KEY(0, 6); + case 'X': + KEY(1, 6); + case EStdKeyMenu: + KEY(2, 6); + case 'C': + KEY(3, 6); + case 'V': + KEY(4, 6); + case 'B': + KEY(5, 6); + case 'N': + KEY(6, 6); + + case EStdKeyLeftShift: + KEY(8, 0); + case EStdKeyRightShift: + KEY(8, 1); + case EStdKeyLeftCtrl: + KEY(8, 2); + case EStdKeyLeftFunc: + KEY(8, 3); + } + + if (idx >= 0x800) { + if (value) + keyboardExtra |= (idx & 0xFF); + else + keyboardExtra &= ~(idx & 0xFF); + } else if (idx >= 0) { + if (value) + keyboardColumns[idx >> 8] |= (idx & 0xFF); + else + keyboardColumns[idx >> 8] &= ~(idx & 0xFF); + } } - void Emulator::updateTouchInput(int32_t x, int32_t y, bool down) { - pendingInterrupts &= ~(1 << EINT2); - if (down) - pendingInterrupts |= (1 << EINT2); - log("Touch: x=%d y=%d down=%s", x, y, down ? "yes" : "no"); - touchX = x; - touchY = y; + pendingInterrupts &= ~(1 << EINT2); + if (down) + pendingInterrupts |= (1 << EINT2); + log("Touch: x=%d y=%d down=%s", x, y, down ? "yes" : "no"); + touchX = x; + touchY = y; } -} +} // namespace CLPS7111 diff --git a/WindCore/clps7111.h b/WindCore/clps7111.h index 47dae14..ccb5b51 100644 --- a/WindCore/clps7111.h +++ b/WindCore/clps7111.h @@ -1,80 +1,80 @@ #pragma once -#include "emubase.h" #include "clps7111_defs.h" #include "clps7600.h" -#include "hardware.h" +#include "emubase.h" #include "etna.h" +#include "hardware.h" namespace CLPS7111 { class Emulator : public EmuBase { public: - uint8_t ROM[0x800000]; - uint8_t ROM2[0x40000]; - uint8_t MemoryBlockC0[0x400000]; - enum { MemoryBlockMask = 0x3FFFFF }; + uint8_t ROM[0x800000]; + uint8_t ROM2[0x40000]; + uint8_t MemoryBlockC0[0x400000]; + enum { MemoryBlockMask = 0x3FFFFF }; private: - uint16_t pendingInterrupts = 0; - uint16_t interruptMask = 0; - uint32_t portValues = 0; - uint32_t portDirections = 0; - uint32_t sysFlg1 = 0x20008000; // constant CL-PS7111 flag and cold start flag - uint32_t lcdControl = 0; - uint32_t lcdAddress = 0xC0000000; - uint32_t rtc = 0; - uint32_t rtcDiv = 0; - uint64_t lcdPalette = 0; - uint16_t lastSyncioRequest = 0; - - uint32_t kScan = 0; - uint8_t keyboardColumns[7] = {0,0,0,0,0,0,0}; - uint8_t keyboardExtra = 0; - int32_t touchX = 0, touchY = 0; + uint16_t pendingInterrupts = 0; + uint16_t interruptMask = 0; + uint32_t portValues = 0; + uint32_t portDirections = 0; + uint32_t sysFlg1 = 0x20008000; // constant CL-PS7111 flag and cold start flag + uint32_t lcdControl = 0; + uint32_t lcdAddress = 0xC0000000; + uint32_t rtc = 0; + uint32_t rtcDiv = 0; + uint64_t lcdPalette = 0; + uint16_t lastSyncioRequest = 0; - Timer tc1, tc2; - CLPS7600 pcCardController; - bool halted = false, asleep = false; + uint32_t kScan = 0; + uint8_t keyboardColumns[7] = {0, 0, 0, 0, 0, 0, 0}; + uint8_t keyboardExtra = 0; + int32_t touchX = 0, touchY = 0; + Timer tc1, tc2; + CLPS7600 pcCardController; + bool halted = false, asleep = false; - uint32_t getRTC(); + uint32_t getRTC(); - uint32_t readReg8(uint32_t reg); - uint32_t readReg32(uint32_t reg); - void writeReg8(uint32_t reg, uint8_t value); - void writeReg32(uint32_t reg, uint32_t value); + uint32_t readReg8(uint32_t reg); + uint32_t readReg32(uint32_t reg); + void writeReg8(uint32_t reg, uint8_t value); + void writeReg32(uint32_t reg, uint32_t value); public: - MaybeU32 readPhysical(uint32_t physAddr, ValueSize valueSize) override; - bool writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) override; + MaybeU32 readPhysical(uint32_t physAddr, ValueSize valueSize) override; + bool writePhysical(uint32_t value, uint32_t physAddr, + ValueSize valueSize) override; private: - bool configured = false; - void configure(); + bool configured = false; + void configure(); - const char *identifyObjectCon(uint32_t ptr); - void fetchStr(uint32_t str, char *buf); - void fetchName(uint32_t obj, char *buf); - void fetchProcessFilename(uint32_t obj, char *buf); - void debugPC(uint32_t pc); - void diffPorts(uint32_t oldval, uint32_t newval); - uint32_t readKeyboard() const; + const char* identifyObjectCon(uint32_t ptr); + void fetchStr(uint32_t str, char* buf); + void fetchName(uint32_t obj, char* buf); + void fetchProcessFilename(uint32_t obj, char* buf); + void debugPC(uint32_t pc); + void diffPorts(uint32_t oldval, uint32_t newval); + uint32_t readKeyboard() const; public: - Emulator(); - uint8_t *getROMBuffer() override; - size_t getROMSize() override; - void loadROM(uint8_t *buffer, size_t size) override; - void executeUntil(int64_t cycles) override; - int32_t getClockSpeed() const override { return CLOCK_SPEED; } - const char *getDeviceName() const override; - int getDigitiserWidth() const override; - int getDigitiserHeight() const override; - int getLCDOffsetX() const override; - int getLCDOffsetY() const override; - int getLCDWidth() const override; - int getLCDHeight() const override; - void readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) const override; - void setKeyboardKey(EpocKey key, bool value) override; - void updateTouchInput(int32_t x, int32_t y, bool down) override; + Emulator(); + uint8_t* getROMBuffer() override; + size_t getROMSize() override; + void loadROM(uint8_t* buffer, size_t size) override; + void executeUntil(int64_t cycles) override; + int32_t getClockSpeed() const override { return CLOCK_SPEED; } + const char* getDeviceName() const override; + int getDigitiserWidth() const override; + int getDigitiserHeight() const override; + int getLCDOffsetX() const override; + int getLCDOffsetY() const override; + int getLCDWidth() const override; + int getLCDHeight() const override; + void readLCDIntoBuffer(uint8_t** lines, bool is32BitOutput) const override; + void setKeyboardKey(EpocKey key, bool value) override; + void updateTouchInput(int32_t x, int32_t y, bool down) override; }; -} +} // namespace CLPS7111 diff --git a/WindCore/clps7111_defs.h b/WindCore/clps7111_defs.h index af02b65..a49d74f 100644 --- a/WindCore/clps7111_defs.h +++ b/WindCore/clps7111_defs.h @@ -2,82 +2,78 @@ #include namespace CLPS7111 { -enum { - CLOCK_SPEED = 0x4800*1000, - TICK_INTERVAL = CLOCK_SPEED / 64 -}; +enum { CLOCK_SPEED = 0x4800 * 1000, TICK_INTERVAL = CLOCK_SPEED / 64 }; enum Interrupt { - EXTFIQ = 0, // FiqExternal - BLINT = 1, // FiqBatLow - WEINT = 2, // FiqWatchDog - MCINT = 3, // FiqMediaChg - CSINT = 4, // IrqCodec - EINT1 = 5, // IrqExt1 - EINT2 = 6, // IrqExt2 - EINT3 = 7, // IrqExt3 - TC1OI = 8, // IrqTimer1 - TC2OI = 9, // IrqTimer2 - RTCMI = 10, // IrqRtcMatch - TINT = 11, // IrqTick - UTXINT = 12, // IrqUartTx? - URXINT1 = 13, // IrqUartRx? - UMSINT = 14, // IrqUartModem? - SSEOTI = 15, // IrqSpi - KBDINT = 16, // IrqKeyPress? - UTXINT2 = 28, // IrqSpi2Tx? - URXINT2 = 29, // IrqSpi2Rx? - FIQ_INTERRUPTS = 0x000F, - IRQ_INTERRUPTS = 0xFFF0 + EXTFIQ = 0, // FiqExternal + BLINT = 1, // FiqBatLow + WEINT = 2, // FiqWatchDog + MCINT = 3, // FiqMediaChg + CSINT = 4, // IrqCodec + EINT1 = 5, // IrqExt1 + EINT2 = 6, // IrqExt2 + EINT3 = 7, // IrqExt3 + TC1OI = 8, // IrqTimer1 + TC2OI = 9, // IrqTimer2 + RTCMI = 10, // IrqRtcMatch + TINT = 11, // IrqTick + UTXINT = 12, // IrqUartTx? + URXINT1 = 13, // IrqUartRx? + UMSINT = 14, // IrqUartModem? + SSEOTI = 15, // IrqSpi + KBDINT = 16, // IrqKeyPress? + UTXINT2 = 28, // IrqSpi2Tx? + URXINT2 = 29, // IrqSpi2Rx? + FIQ_INTERRUPTS = 0x000F, + IRQ_INTERRUPTS = 0xFFF0 }; enum Register { - PADR = 0, - PBDR = 1, - PDDR = 3, - PADDR = 0x40, - PBDDR = 0x41, - PDDDR = 0x43, - PEDR = 0x80, - PEDDR = 0xC0, - SYSCON1 = 0x100, - SYSFLG1 = 0x140, - MEMCFG1 = 0x180, - MEMCFG2 = 0x1C0, - DRFPR = 0x200, - INTSR1 = 0x240, - INTMR1 = 0x280, - LCDCON = 0x2C0, - TC1D = 0x300, - TC2D = 0x340, - RTCDR = 0x380, - RTCMR = 0x3C0, - PMPCON = 0x400, - CODR = 0x440, - UARTDR1 = 0x480, - UBRLCR1 = 0x4C0, - SYNCIO = 0x500, - PALLSW = 0x540, - PALMSW = 0x580, - STFCLR = 0x5C0, - BLEOI = 0x600, - MCEOI = 0x640, - TEOI = 0x680, - TC1EOI = 0x6C0, - TC2EOI = 0x700, - RTCEOI = 0x740, - UMSEOI = 0x780, - COEOI = 0x7C0, - HALT = 0x800, - STDBY = 0x840, - FRBADDR = 0x1000, - SYSCON2 = 0x1100, - SYSFLG2 = 0x1140, - INTSR2 = 0x1240, - INTMR2 = 0x1280, - UARTDR2 = 0x1480, - UBRLCR2 = 0x14C0, - KBDEOI = 0x1700 + PADR = 0, + PBDR = 1, + PDDR = 3, + PADDR = 0x40, + PBDDR = 0x41, + PDDDR = 0x43, + PEDR = 0x80, + PEDDR = 0xC0, + SYSCON1 = 0x100, + SYSFLG1 = 0x140, + MEMCFG1 = 0x180, + MEMCFG2 = 0x1C0, + DRFPR = 0x200, + INTSR1 = 0x240, + INTMR1 = 0x280, + LCDCON = 0x2C0, + TC1D = 0x300, + TC2D = 0x340, + RTCDR = 0x380, + RTCMR = 0x3C0, + PMPCON = 0x400, + CODR = 0x440, + UARTDR1 = 0x480, + UBRLCR1 = 0x4C0, + SYNCIO = 0x500, + PALLSW = 0x540, + PALMSW = 0x580, + STFCLR = 0x5C0, + BLEOI = 0x600, + MCEOI = 0x640, + TEOI = 0x680, + TC1EOI = 0x6C0, + TC2EOI = 0x700, + RTCEOI = 0x740, + UMSEOI = 0x780, + COEOI = 0x7C0, + HALT = 0x800, + STDBY = 0x840, + FRBADDR = 0x1000, + SYSCON2 = 0x1100, + SYSFLG2 = 0x1140, + INTSR2 = 0x1240, + INTMR2 = 0x1280, + UARTDR2 = 0x1480, + UBRLCR2 = 0x14C0, + KBDEOI = 0x1700 }; -} - +} // namespace CLPS7111 diff --git a/WindCore/clps7600.cpp b/WindCore/clps7600.cpp index 3b2d36a..98b7d98 100644 --- a/WindCore/clps7600.cpp +++ b/WindCore/clps7600.cpp @@ -1,133 +1,136 @@ #include "clps7600.h" #include "arm710.h" -CLPS7600::CLPS7600(ARM710 *_cpu) -{ - cpu = _cpu; -} +CLPS7600::CLPS7600(ARM710* _cpu) { cpu = _cpu; } enum { - PCM_BVD1 = 1, - PCM_BVD2 = 2, - PCM_CD1 = 4, - PCM_CD2 = 8, - PCM_VS1 = 0x10, - PCM_VS2 = 0x20, - PDREQ_L = 0x40, - PCTL = 0x100, - PCM_WP = 0x200, - PCM_RDY = 0x400, - FIFOTHLD = 0x800, - IDLE = 0x1000, - WR_FAIL = 0x2000, - RD_FAIL = 0x4000, - RESERVED = 0x8000 + PCM_BVD1 = 1, + PCM_BVD2 = 2, + PCM_CD1 = 4, + PCM_CD2 = 8, + PCM_VS1 = 0x10, + PCM_VS2 = 0x20, + PDREQ_L = 0x40, + PCTL = 0x100, + PCM_WP = 0x200, + PCM_RDY = 0x400, + FIFOTHLD = 0x800, + IDLE = 0x1000, + WR_FAIL = 0x2000, + RD_FAIL = 0x4000, + RESERVED = 0x8000 }; uint32_t CLPS7600::getInputLevel() const { - uint32_t v = 0; + uint32_t v = 0; - if (isMemoryMode()) - v |= PCM_RDY; // we are ALWAYS ready + if (isMemoryMode()) + v |= PCM_RDY; // we are ALWAYS ready - return v; + return v; } -uint32_t CLPS7600::read(uint32_t addr, ARM710::ValueSize valueSize) -{ - cpu->log("CLPS7600 read: addr=%07x size=%d pc=%08x lr=%08x", addr, (valueSize == ARM710::V32) ? 32 : 8, cpu->getRealPC(), cpu->getGPR(14)); - if (valueSize == ARM710::V32) { - switch (addr) { - case 0xC000000: // Interrupt Status - return interruptStatus; - case 0xC000400: // Interrupt Mask - return interruptMask; - case 0xC001C00: // Interrupt Input Level - return getInputLevel(); - case 0xC002000: // System Interface Configuration - return systemInterfaceConfig; - case 0xC002400: // Card Interface Configuration - return cardInterfaceConfig; - case 0xC002800: // Power Management - return powerManagement; - case 0xC002C00: // Card Power Control - return cardPowerControl; - case 0xC003000: // Card Interface Timing 0A - return cardInterfaceTiming0A; - case 0xC003400: // Card Interface Timing 0B - return cardInterfaceTiming0B; - case 0xC003800: // Card Interface Timing 1A - return cardInterfaceTiming1A; - case 0xC003C00: // Card Interface Timing 1B - return cardInterfaceTiming1B; - case 0xC004000: // DMA Control - return dmaControl; - case 0xC004400: // Device Information - return deviceInformation; - default: - cpu->log("CLPS7600 unknown register read: addr=%07x pc=%08x lr=%08x", addr, cpu->getRealPC(), cpu->getGPR(14)); - return 0xFFFFFFFF; - } - } - cpu->log("unknown!!"); - return 0xFF; +uint32_t CLPS7600::read(uint32_t addr, ARM710::ValueSize valueSize) { + cpu->log("CLPS7600 read: addr=%07x size=%d pc=%08x lr=%08x", addr, + (valueSize == ARM710::V32) ? 32 : 8, cpu->getRealPC(), + cpu->getGPR(14)); + if (valueSize == ARM710::V32) { + switch (addr) { + case 0xC000000: // Interrupt Status + return interruptStatus; + case 0xC000400: // Interrupt Mask + return interruptMask; + case 0xC001C00: // Interrupt Input Level + return getInputLevel(); + case 0xC002000: // System Interface Configuration + return systemInterfaceConfig; + case 0xC002400: // Card Interface Configuration + return cardInterfaceConfig; + case 0xC002800: // Power Management + return powerManagement; + case 0xC002C00: // Card Power Control + return cardPowerControl; + case 0xC003000: // Card Interface Timing 0A + return cardInterfaceTiming0A; + case 0xC003400: // Card Interface Timing 0B + return cardInterfaceTiming0B; + case 0xC003800: // Card Interface Timing 1A + return cardInterfaceTiming1A; + case 0xC003C00: // Card Interface Timing 1B + return cardInterfaceTiming1B; + case 0xC004000: // DMA Control + return dmaControl; + case 0xC004400: // Device Information + return deviceInformation; + default: + cpu->log("CLPS7600 unknown register read: addr=%07x pc=%08x lr=%08x", + addr, cpu->getRealPC(), cpu->getGPR(14)); + return 0xFFFFFFFF; + } + } + cpu->log("unknown!!"); + return 0xFF; } -void CLPS7600::write(uint32_t value, uint32_t addr, ARM710::ValueSize valueSize) -{ - cpu->log("CLPS7600 write: addr=%07x size=%d value=%08x pc=%08x lr=%08x", addr, (valueSize == ARM710::V32) ? 32 : 8, value, cpu->getRealPC(), cpu->getGPR(14)); - if (valueSize == ARM710::V32) { - switch (addr) { - case 0xC000400: // Interrupt Mask - interruptMask = value; - break; - case 0xC000800: // Interrupt Clear - break; - case 0xC000C00: // Interrupt Output Select - break; - case 0xC001000: // Interrupt Reserved Register 1 - break; - case 0xC001400: // Interrupt Reserved Register 2 - break; - case 0xC001800: // Interrupt Reserved Register 3 - break; - case 0xC002000: // System Interface Configuration - systemInterfaceConfig = value; - break; - case 0xC002400: // Card Interface Configuration - cardInterfaceConfig = value; - cpu->log("PC card enabled: %s", (value & 0x400) ? "yes" : "no"); - cpu->log("PC card write protect: %s", (value & 0x200) ? "yes" : "no"); - cpu->log("PC card mode: %s", (value & 0x100) ? "i/o" : "memory"); - break; - case 0xC002800: // Power Management - powerManagement = value; - break; - case 0xC002C00: // Card Power Control - cardPowerControl = value; - break; - case 0xC003000: // Card Interface Timing 0A - cardInterfaceTiming0A = value; - break; - case 0xC003400: // Card Interface Timing 0B - cardInterfaceTiming0B = value; - break; - case 0xC003800: // Card Interface Timing 1A - cardInterfaceTiming1A = value; - break; - case 0xC003C00: // Card Interface Timing 1B - cardInterfaceTiming1B = value; - break; - case 0xC004000: // DMA Control - dmaControl = value; - break; - case 0xC004400: // Device Information - deviceInformation = value; - break; - default: - cpu->log("CLPS7600 unknown register write: addr=%07x value=%08x pc=%08x lr=%08x", addr, value, cpu->getRealPC(), cpu->getGPR(14)); - } - } else { - cpu->log("unknown write!!"); - } +void CLPS7600::write(uint32_t value, uint32_t addr, + ARM710::ValueSize valueSize) { + cpu->log("CLPS7600 write: addr=%07x size=%d value=%08x pc=%08x lr=%08x", addr, + (valueSize == ARM710::V32) ? 32 : 8, value, cpu->getRealPC(), + cpu->getGPR(14)); + if (valueSize == ARM710::V32) { + switch (addr) { + case 0xC000400: // Interrupt Mask + interruptMask = value; + break; + case 0xC000800: // Interrupt Clear + break; + case 0xC000C00: // Interrupt Output Select + break; + case 0xC001000: // Interrupt Reserved Register 1 + break; + case 0xC001400: // Interrupt Reserved Register 2 + break; + case 0xC001800: // Interrupt Reserved Register 3 + break; + case 0xC002000: // System Interface Configuration + systemInterfaceConfig = value; + break; + case 0xC002400: // Card Interface Configuration + cardInterfaceConfig = value; + cpu->log("PC card enabled: %s", (value & 0x400) ? "yes" : "no"); + cpu->log("PC card write protect: %s", (value & 0x200) ? "yes" : "no"); + cpu->log("PC card mode: %s", (value & 0x100) ? "i/o" : "memory"); + break; + case 0xC002800: // Power Management + powerManagement = value; + break; + case 0xC002C00: // Card Power Control + cardPowerControl = value; + break; + case 0xC003000: // Card Interface Timing 0A + cardInterfaceTiming0A = value; + break; + case 0xC003400: // Card Interface Timing 0B + cardInterfaceTiming0B = value; + break; + case 0xC003800: // Card Interface Timing 1A + cardInterfaceTiming1A = value; + break; + case 0xC003C00: // Card Interface Timing 1B + cardInterfaceTiming1B = value; + break; + case 0xC004000: // DMA Control + dmaControl = value; + break; + case 0xC004400: // Device Information + deviceInformation = value; + break; + default: + cpu->log("CLPS7600 unknown register write: addr=%07x value=%08x pc=%08x " + "lr=%08x", + addr, value, cpu->getRealPC(), cpu->getGPR(14)); + } + } else { + cpu->log("unknown write!!"); + } } diff --git a/WindCore/clps7600.h b/WindCore/clps7600.h index e9fe2a9..6e766a8 100644 --- a/WindCore/clps7600.h +++ b/WindCore/clps7600.h @@ -1,33 +1,31 @@ #pragma once -#include #include "arm710.h" +#include -class CLPS7600 -{ +class CLPS7600 { private: - ARM710 *cpu; + ARM710* cpu; - uint32_t interruptStatus = 0; - uint32_t interruptMask = 0; - uint32_t systemInterfaceConfig = 0x1F8; - uint32_t cardInterfaceConfig = 0; - uint32_t powerManagement = 0; - uint32_t cardPowerControl = 0; - uint32_t cardInterfaceTiming0A = 0x1F00; - uint32_t cardInterfaceTiming0B = 0; - uint32_t cardInterfaceTiming1A = 0x1F00; - uint32_t cardInterfaceTiming1B = 0; - uint32_t dmaControl = 0; - uint32_t deviceInformation = 0x40; + uint32_t interruptStatus = 0; + uint32_t interruptMask = 0; + uint32_t systemInterfaceConfig = 0x1F8; + uint32_t cardInterfaceConfig = 0; + uint32_t powerManagement = 0; + uint32_t cardPowerControl = 0; + uint32_t cardInterfaceTiming0A = 0x1F00; + uint32_t cardInterfaceTiming0B = 0; + uint32_t cardInterfaceTiming1A = 0x1F00; + uint32_t cardInterfaceTiming1B = 0; + uint32_t dmaControl = 0; + uint32_t deviceInformation = 0x40; - bool isIOMode() const { return (cardInterfaceConfig & 0x100); } - bool isMemoryMode() const { return !(cardInterfaceConfig & 0x100); } - uint32_t getInputLevel() const; + bool isIOMode() const { return (cardInterfaceConfig & 0x100); } + bool isMemoryMode() const { return !(cardInterfaceConfig & 0x100); } + uint32_t getInputLevel() const; public: - CLPS7600(ARM710 *_cpu); + CLPS7600(ARM710* _cpu); - uint32_t read(uint32_t addr, ARM710::ValueSize valueSize); - void write(uint32_t value, uint32_t addr, ARM710::ValueSize valueSize); + uint32_t read(uint32_t addr, ARM710::ValueSize valueSize); + void write(uint32_t value, uint32_t addr, ARM710::ValueSize valueSize); }; - diff --git a/WindCore/common.h b/WindCore/common.h index 0b0e6d9..90cb63b 100644 --- a/WindCore/common.h +++ b/WindCore/common.h @@ -50,14 +50,14 @@ typedef intptr_t ssize_t; #define snprintf _snprintf #define strdup _strdup #define lseek _lseek -#define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) +#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) #elif defined(__wii__) #include typedef intptr_t ssize_t; #else #include -#include #include +#include #endif #ifdef PSP2 @@ -66,7 +66,7 @@ typedef intptr_t ssize_t; #endif #ifndef SSIZE_MAX -#define SSIZE_MAX ((ssize_t) (SIZE_MAX >> 1)) +#define SSIZE_MAX ((ssize_t)(SIZE_MAX >> 1)) #endif #ifndef UNUSED @@ -77,14 +77,17 @@ typedef intptr_t ssize_t; #define M_PI 3.141592654f #endif -#if !defined(_MSC_VER) && (defined(__llvm__) || (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) +#if !defined(_MSC_VER) && (defined(__llvm__) || (__GNUC__ > 4) || \ + (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) #define ATOMIC_STORE(DST, SRC) __atomic_store_n(&DST, SRC, __ATOMIC_RELEASE) #define ATOMIC_LOAD(DST, SRC) DST = __atomic_load_n(&SRC, __ATOMIC_ACQUIRE) #define ATOMIC_ADD(DST, OP) __atomic_add_fetch(&DST, OP, __ATOMIC_RELEASE) #define ATOMIC_SUB(DST, OP) __atomic_sub_fetch(&DST, OP, __ATOMIC_RELEASE) #define ATOMIC_OR(DST, OP) __atomic_or_fetch(&DST, OP, __ATOMIC_RELEASE) #define ATOMIC_AND(DST, OP) __atomic_and_fetch(&DST, OP, __ATOMIC_RELEASE) -#define ATOMIC_CMPXCHG(DST, EXPECTED, SRC) __atomic_compare_exchange_n(&DST, &EXPECTED, SRC, true,__ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE) +#define ATOMIC_CMPXCHG(DST, EXPECTED, SRC) \ + __atomic_compare_exchange_n(&DST, &EXPECTED, SRC, true, __ATOMIC_ACQ_REL, \ + __ATOMIC_ACQUIRE) #define ATOMIC_STORE_PTR(DST, SRC) ATOMIC_STORE(DST, SRC) #define ATOMIC_LOAD_PTR(DST, SRC) ATOMIC_LOAD(DST, SRC) #elif defined _MSC_VER @@ -94,9 +97,11 @@ typedef intptr_t ssize_t; #define ATOMIC_SUB(DST, OP) InterlockedAddRelease(&DST, -OP) #define ATOMIC_OR(DST, OP) InterlockedOrRelease(&DST, OP) #define ATOMIC_AND(DST, OP) InterlockedAndRelease(&DST, OP) -#define ATOMIC_CMPXCHG(DST, EXPECTED, SRC) (InterlockedCompareExchange(&DST, SRC, EXPECTED) == EXPECTED) +#define ATOMIC_CMPXCHG(DST, EXPECTED, SRC) \ + (InterlockedCompareExchange(&DST, SRC, EXPECTED) == EXPECTED) #define ATOMIC_STORE_PTR(DST, SRC) InterlockedExchangePointer(&DST, SRC) -#define ATOMIC_LOAD_PTR(DST, SRC) DST = InterlockedCompareExchangePointer(&SRC, 0, 0) +#define ATOMIC_LOAD_PTR(DST, SRC) \ + DST = InterlockedCompareExchangePointer(&SRC, 0, 0) #else // TODO #define ATOMIC_STORE(DST, SRC) DST = SRC @@ -105,7 +110,8 @@ typedef intptr_t ssize_t; #define ATOMIC_SUB(DST, OP) DST -= OP #define ATOMIC_OR(DST, OP) DST |= OP #define ATOMIC_AND(DST, OP) DST &= OP -#define ATOMIC_CMPXCHG(DST, EXPECTED, OP) ((DST == EXPECTED) ? ((DST = OP), true) : false) +#define ATOMIC_CMPXCHG(DST, EXPECTED, OP) \ + ((DST == EXPECTED) ? ((DST = OP), true) : false) #define ATOMIC_STORE_PTR(DST, SRC) ATOMIC_STORE(DST, SRC) #define ATOMIC_LOAD_PTR(DST, SRC) ATOMIC_LOAD(DST, SRC) #endif @@ -122,107 +128,140 @@ typedef intptr_t ssize_t; #endif #if defined __BIG_ENDIAN__ -#define LOAD_32BE(DEST, ADDR, ARR) DEST = *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) +#define LOAD_32BE(DEST, ADDR, ARR) \ + DEST = *(uint32_t*)((uintptr_t)(ARR) + (size_t)(ADDR)) #if defined(__PPC__) || defined(__POWERPC__) -#define LOAD_32LE(DEST, ADDR, ARR) { \ - uint32_t _addr = (ADDR); \ - const void* _ptr = (ARR); \ - __asm__("lwbrx %0, %1, %2" : "=r"(DEST) : "b"(_ptr), "r"(_addr)); \ -} +#define LOAD_32LE(DEST, ADDR, ARR) \ + { \ + uint32_t _addr = (ADDR); \ + const void* _ptr = (ARR); \ + __asm__("lwbrx %0, %1, %2" : "=r"(DEST) : "b"(_ptr), "r"(_addr)); \ + } -#define LOAD_16LE(DEST, ADDR, ARR) { \ - uint32_t _addr = (ADDR); \ - const void* _ptr = (ARR); \ - __asm__("lhbrx %0, %1, %2" : "=r"(DEST) : "b"(_ptr), "r"(_addr)); \ -} +#define LOAD_16LE(DEST, ADDR, ARR) \ + { \ + uint32_t _addr = (ADDR); \ + const void* _ptr = (ARR); \ + __asm__("lhbrx %0, %1, %2" : "=r"(DEST) : "b"(_ptr), "r"(_addr)); \ + } -#define STORE_32LE(SRC, ADDR, ARR) { \ - uint32_t _addr = (ADDR); \ - void* _ptr = (ARR); \ - __asm__("stwbrx %0, %1, %2" : : "r"(SRC), "b"(_ptr), "r"(_addr) : "memory"); \ -} +#define STORE_32LE(SRC, ADDR, ARR) \ + { \ + uint32_t _addr = (ADDR); \ + void* _ptr = (ARR); \ + __asm__("stwbrx %0, %1, %2" \ + : \ + : "r"(SRC), "b"(_ptr), "r"(_addr) \ + : "memory"); \ + } -#define STORE_16LE(SRC, ADDR, ARR) { \ - uint32_t _addr = (ADDR); \ - void* _ptr = (ARR); \ - __asm__("sthbrx %0, %1, %2" : : "r"(SRC), "b"(_ptr), "r"(_addr) : "memory"); \ -} +#define STORE_16LE(SRC, ADDR, ARR) \ + { \ + uint32_t _addr = (ADDR); \ + void* _ptr = (ARR); \ + __asm__("sthbrx %0, %1, %2" \ + : \ + : "r"(SRC), "b"(_ptr), "r"(_addr) \ + : "memory"); \ + } -#define LOAD_64LE(DEST, ADDR, ARR) { \ - uint32_t _addr = (ADDR); \ - union { \ - struct { \ - uint32_t hi; \ - uint32_t lo; \ - }; \ - uint64_t b64; \ - } bswap; \ - const void* _ptr = (ARR); \ - __asm__( \ - "lwbrx %0, %2, %3 \n" \ - "lwbrx %1, %2, %4 \n" \ - : "=&r"(bswap.lo), "=&r"(bswap.hi) : "b"(_ptr), "r"(_addr), "r"(_addr + 4)) ; \ - DEST = bswap.b64; \ -} +#define LOAD_64LE(DEST, ADDR, ARR) \ + { \ + uint32_t _addr = (ADDR); \ + union { \ + struct { \ + uint32_t hi; \ + uint32_t lo; \ + }; \ + uint64_t b64; \ + } bswap; \ + const void* _ptr = (ARR); \ + __asm__("lwbrx %0, %2, %3 \n" \ + "lwbrx %1, %2, %4 \n" \ + : "=&r"(bswap.lo), "=&r"(bswap.hi) \ + : "b"(_ptr), "r"(_addr), "r"(_addr + 4)); \ + DEST = bswap.b64; \ + } -#define STORE_64LE(SRC, ADDR, ARR) { \ - uint32_t _addr = (ADDR); \ - union { \ - struct { \ - uint32_t hi; \ - uint32_t lo; \ - }; \ - uint64_t b64; \ - } bswap = { .b64 = SRC }; \ - const void* _ptr = (ARR); \ - __asm__( \ - "stwbrx %0, %2, %3 \n" \ - "stwbrx %1, %2, %4 \n" \ - : : "r"(bswap.hi), "r"(bswap.lo), "b"(_ptr), "r"(_addr), "r"(_addr + 4) : "memory"); \ -} +#define STORE_64LE(SRC, ADDR, ARR) \ + { \ + uint32_t _addr = (ADDR); \ + union { \ + struct { \ + uint32_t hi; \ + uint32_t lo; \ + }; \ + uint64_t b64; \ + } bswap = {.b64 = SRC}; \ + const void* _ptr = (ARR); \ + __asm__("stwbrx %0, %2, %3 \n" \ + "stwbrx %1, %2, %4 \n" \ + : \ + : "r"(bswap.hi), "r"(bswap.lo), "b"(_ptr), "r"(_addr), \ + "r"(_addr + 4) \ + : "memory"); \ + } -#elif defined(__llvm__) || (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) -#define LOAD_64LE(DEST, ADDR, ARR) DEST = __builtin_bswap64(((uint64_t*) ARR)[(ADDR) >> 3]) -#define LOAD_32LE(DEST, ADDR, ARR) DEST = __builtin_bswap32(((uint32_t*) ARR)[(ADDR) >> 2]) -#define LOAD_16LE(DEST, ADDR, ARR) DEST = __builtin_bswap16(((uint16_t*) ARR)[(ADDR) >> 1]) -#define STORE_64LE(SRC, ADDR, ARR) ((uint64_t*) ARR)[(ADDR) >> 3] = __builtin_bswap64(SRC) -#define STORE_32LE(SRC, ADDR, ARR) ((uint32_t*) ARR)[(ADDR) >> 2] = __builtin_bswap32(SRC) -#define STORE_16LE(SRC, ADDR, ARR) ((uint16_t*) ARR)[(ADDR) >> 1] = __builtin_bswap16(SRC) +#elif defined(__llvm__) || (__GNUC__ > 4) || \ + (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) +#define LOAD_64LE(DEST, ADDR, ARR) \ + DEST = __builtin_bswap64(((uint64_t*)ARR)[(ADDR) >> 3]) +#define LOAD_32LE(DEST, ADDR, ARR) \ + DEST = __builtin_bswap32(((uint32_t*)ARR)[(ADDR) >> 2]) +#define LOAD_16LE(DEST, ADDR, ARR) \ + DEST = __builtin_bswap16(((uint16_t*)ARR)[(ADDR) >> 1]) +#define STORE_64LE(SRC, ADDR, ARR) \ + ((uint64_t*)ARR)[(ADDR) >> 3] = __builtin_bswap64(SRC) +#define STORE_32LE(SRC, ADDR, ARR) \ + ((uint32_t*)ARR)[(ADDR) >> 2] = __builtin_bswap32(SRC) +#define STORE_16LE(SRC, ADDR, ARR) \ + ((uint16_t*)ARR)[(ADDR) >> 1] = __builtin_bswap16(SRC) #else #error Big endian build not supported on this platform. #endif #else -#define LOAD_64LE(DEST, ADDR, ARR) DEST = *(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) -#define LOAD_32LE(DEST, ADDR, ARR) DEST = *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) -#define LOAD_16LE(DEST, ADDR, ARR) DEST = *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) -#define STORE_64LE(SRC, ADDR, ARR) *(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC -#define STORE_32LE(SRC, ADDR, ARR) *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC -#define STORE_16LE(SRC, ADDR, ARR) *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC +#define LOAD_64LE(DEST, ADDR, ARR) \ + DEST = *(uint64_t*)((uintptr_t)(ARR) + (size_t)(ADDR)) +#define LOAD_32LE(DEST, ADDR, ARR) \ + DEST = *(uint32_t*)((uintptr_t)(ARR) + (size_t)(ADDR)) +#define LOAD_16LE(DEST, ADDR, ARR) \ + DEST = *(uint16_t*)((uintptr_t)(ARR) + (size_t)(ADDR)) +#define STORE_64LE(SRC, ADDR, ARR) \ + *(uint64_t*)((uintptr_t)(ARR) + (size_t)(ADDR)) = SRC +#define STORE_32LE(SRC, ADDR, ARR) \ + *(uint32_t*)((uintptr_t)(ARR) + (size_t)(ADDR)) = SRC +#define STORE_16LE(SRC, ADDR, ARR) \ + *(uint16_t*)((uintptr_t)(ARR) + (size_t)(ADDR)) = SRC #ifdef _MSC_VER -#define LOAD_32BE(DEST, ADDR, ARR) DEST = _byteswap_ulong(((uint32_t*) ARR)[(ADDR) >> 2]) +#define LOAD_32BE(DEST, ADDR, ARR) \ + DEST = _byteswap_ulong(((uint32_t*)ARR)[(ADDR) >> 2]) #else -#define LOAD_32BE(DEST, ADDR, ARR) DEST = __builtin_bswap32(((uint32_t*) ARR)[(ADDR) >> 2]) +#define LOAD_32BE(DEST, ADDR, ARR) \ + DEST = __builtin_bswap32(((uint32_t*)ARR)[(ADDR) >> 2]) #endif #endif #define MAKE_MASK(START, END) (((1 << ((END) - (START))) - 1) << (START)) #define CHECK_BITS(SRC, START, END) ((SRC) & MAKE_MASK(START, END)) -#define EXT_BITS(SRC, START, END) (((SRC) >> (START)) & ((1 << ((END) - (START))) - 1)) -#define INS_BITS(SRC, START, END, BITS) (CLEAR_BITS(SRC, START, END) | (((BITS) << (START)) & MAKE_MASK(START, END))) +#define EXT_BITS(SRC, START, END) \ + (((SRC) >> (START)) & ((1 << ((END) - (START))) - 1)) +#define INS_BITS(SRC, START, END, BITS) \ + (CLEAR_BITS(SRC, START, END) | (((BITS) << (START)) & MAKE_MASK(START, END))) #define CLEAR_BITS(SRC, START, END) ((SRC) & ~MAKE_MASK(START, END)) #define FILL_BITS(SRC, START, END) ((SRC) | MAKE_MASK(START, END)) -#define TEST_FILL_BITS(SRC, START, END, TEST) ((TEST) ? (FILL_BITS(SRC, START, END)) : (CLEAR_BITS(SRC, START, END))) +#define TEST_FILL_BITS(SRC, START, END, TEST) \ + ((TEST) ? (FILL_BITS(SRC, START, END)) : (CLEAR_BITS(SRC, START, END))) #ifdef _MSC_VER -#pragma section(".CRT$XCU",read) +#pragma section(".CRT$XCU", read) #define ATTRIBUTE_UNUSED #define ATTRIBUTE_FORMAT(X, Y, Z) #define ATTRIBUTE_NOINLINE // Adapted from https://stackoverflow.com/a/2390626 -#define _CONSTRUCTOR(FN, PRE) \ - static void FN(void); \ - __declspec(allocate(".CRT$XCU")) void (*_CONSTRUCTOR_ ## FN)(void) = FN; \ - static void FN(void) +#define _CONSTRUCTOR(FN, PRE) \ + static void FN(void); \ + __declspec(allocate(".CRT$XCU")) void (*_CONSTRUCTOR_##FN)(void) = FN; \ + static void FN(void) #ifdef _WIN64 #define CONSTRUCTOR(FN) _CONSTRUCTOR(FN, "") #else @@ -237,25 +276,26 @@ typedef intptr_t ssize_t; #define DECL_BITFIELD(NAME, TYPE) typedef TYPE NAME -#define DECL_BITS(TYPE, FIELD, START, SIZE) \ - ATTRIBUTE_UNUSED static inline TYPE TYPE ## Is ## FIELD (TYPE src) { \ - return CHECK_BITS(src, (START), (START) + (SIZE)); \ - } \ - ATTRIBUTE_UNUSED static inline TYPE TYPE ## Get ## FIELD (TYPE src) { \ - return EXT_BITS(src, (START), (START) + (SIZE)); \ - } \ - ATTRIBUTE_UNUSED static inline TYPE TYPE ## Clear ## FIELD (TYPE src) { \ - return CLEAR_BITS(src, (START), (START) + (SIZE)); \ - } \ - ATTRIBUTE_UNUSED static inline TYPE TYPE ## Fill ## FIELD (TYPE src) { \ - return FILL_BITS(src, (START), (START) + (SIZE)); \ - } \ - ATTRIBUTE_UNUSED static inline TYPE TYPE ## Set ## FIELD (TYPE src, TYPE bits) { \ - return INS_BITS(src, (START), (START) + (SIZE), bits); \ - } \ - ATTRIBUTE_UNUSED static inline TYPE TYPE ## TestFill ## FIELD (TYPE src, bool test) { \ - return TEST_FILL_BITS(src, (START), (START) + (SIZE), test); \ - } +#define DECL_BITS(TYPE, FIELD, START, SIZE) \ + ATTRIBUTE_UNUSED static inline TYPE TYPE##Is##FIELD(TYPE src) { \ + return CHECK_BITS(src, (START), (START) + (SIZE)); \ + } \ + ATTRIBUTE_UNUSED static inline TYPE TYPE##Get##FIELD(TYPE src) { \ + return EXT_BITS(src, (START), (START) + (SIZE)); \ + } \ + ATTRIBUTE_UNUSED static inline TYPE TYPE##Clear##FIELD(TYPE src) { \ + return CLEAR_BITS(src, (START), (START) + (SIZE)); \ + } \ + ATTRIBUTE_UNUSED static inline TYPE TYPE##Fill##FIELD(TYPE src) { \ + return FILL_BITS(src, (START), (START) + (SIZE)); \ + } \ + ATTRIBUTE_UNUSED static inline TYPE TYPE##Set##FIELD(TYPE src, TYPE bits) { \ + return INS_BITS(src, (START), (START) + (SIZE), bits); \ + } \ + ATTRIBUTE_UNUSED static inline TYPE TYPE##TestFill##FIELD(TYPE src, \ + bool test) { \ + return TEST_FILL_BITS(src, (START), (START) + (SIZE), test); \ + } #define DECL_BIT(TYPE, FIELD, BIT) DECL_BITS(TYPE, FIELD, BIT, 1) @@ -267,12 +307,13 @@ typedef intptr_t ssize_t; #define UNLIKELY(X) (!!(X)) #endif -#define ROR(I, ROTATE) ((((uint32_t) (I)) >> ROTATE) | ((uint32_t) (I) << ((-ROTATE) & 31))) +#define ROR(I, ROTATE) \ + ((((uint32_t)(I)) >> ROTATE) | ((uint32_t)(I) << ((-ROTATE) & 31))) static inline uint32_t popcount32(unsigned bits) { - bits = bits - ((bits >> 1) & 0x55555555); - bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333); - return (((bits + (bits >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; + bits = bits - ((bits >> 1) & 0x55555555); + bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333); + return (((bits + (bits >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; } CXX_GUARD_END diff --git a/WindCore/decoder-arm.c b/WindCore/decoder-arm.c index afbb03d..6df4e73 100644 --- a/WindCore/decoder-arm.c +++ b/WindCore/decoder-arm.c @@ -9,278 +9,311 @@ #include "emitter-arm.h" #include "isa-inlines.h" -#define ADDR_MODE_1_SHIFT(OP) \ - info->op3.reg = opcode & 0x0000000F; \ - info->op3.shifterOp = ARM_SHIFT_ ## OP; \ - info->operandFormat |= ARM_OPERAND_REGISTER_3; \ - if (opcode & 0x00000010) { \ - info->op3.shifterReg = (opcode >> 8) & 0xF; \ - ++info->iCycles; \ - info->operandFormat |= ARM_OPERAND_SHIFT_REGISTER_3; \ - } else { \ - info->op3.shifterImm = (opcode >> 7) & 0x1F; \ - info->operandFormat |= ARM_OPERAND_SHIFT_IMMEDIATE_3; \ - } - -#define ADDR_MODE_1_LSL \ - ADDR_MODE_1_SHIFT(LSL) \ - if (!info->op3.shifterImm) { \ - info->operandFormat &= ~ARM_OPERAND_SHIFT_IMMEDIATE_3; \ - info->op3.shifterOp = ARM_SHIFT_NONE; \ - } +#define ADDR_MODE_1_SHIFT(OP) \ + info->op3.reg = opcode & 0x0000000F; \ + info->op3.shifterOp = ARM_SHIFT_##OP; \ + info->operandFormat |= ARM_OPERAND_REGISTER_3; \ + if (opcode & 0x00000010) { \ + info->op3.shifterReg = (opcode >> 8) & 0xF; \ + ++info->iCycles; \ + info->operandFormat |= ARM_OPERAND_SHIFT_REGISTER_3; \ + } else { \ + info->op3.shifterImm = (opcode >> 7) & 0x1F; \ + info->operandFormat |= ARM_OPERAND_SHIFT_IMMEDIATE_3; \ + } + +#define ADDR_MODE_1_LSL \ + ADDR_MODE_1_SHIFT(LSL) \ + if (!info->op3.shifterImm) { \ + info->operandFormat &= ~ARM_OPERAND_SHIFT_IMMEDIATE_3; \ + info->op3.shifterOp = ARM_SHIFT_NONE; \ + } #define ADDR_MODE_1_LSR ADDR_MODE_1_SHIFT(LSR) #define ADDR_MODE_1_ASR ADDR_MODE_1_SHIFT(ASR) -#define ADDR_MODE_1_ROR \ - ADDR_MODE_1_SHIFT(ROR) \ - if (!info->op3.shifterImm) { \ - info->op3.shifterOp = ARM_SHIFT_RRX; \ - } - -#define ADDR_MODE_1_IMM \ - int rotate = (opcode & 0x00000F00) >> 7; \ - int immediate = opcode & 0x000000FF; \ - info->op3.immediate = ROR(immediate, rotate); \ - info->operandFormat |= ARM_OPERAND_IMMEDIATE_3; - -#define ADDR_MODE_2_SHIFT(OP) \ - info->memory.format |= ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_SHIFTED_OFFSET; \ - info->memory.offset.shifterOp = ARM_SHIFT_ ## OP; \ - info->memory.offset.shifterImm = (opcode >> 7) & 0x1F; \ - info->memory.offset.reg = opcode & 0x0000000F; - -#define ADDR_MODE_2_LSL \ - ADDR_MODE_2_SHIFT(LSL) \ - if (!info->memory.offset.shifterImm) { \ - info->memory.format &= ~ARM_MEMORY_SHIFTED_OFFSET; \ - info->memory.offset.shifterOp = ARM_SHIFT_NONE; \ - } - -#define ADDR_MODE_2_LSR ADDR_MODE_2_SHIFT(LSR) \ - if (!info->memory.offset.shifterImm) { \ - info->memory.offset.shifterImm = 32; \ - } - -#define ADDR_MODE_2_ASR ADDR_MODE_2_SHIFT(ASR) \ - if (!info->memory.offset.shifterImm) { \ - info->memory.offset.shifterImm = 32; \ - } - -#define ADDR_MODE_2_ROR \ - ADDR_MODE_2_SHIFT(ROR) \ - if (!info->memory.offset.shifterImm) { \ - info->memory.offset.shifterOp = ARM_SHIFT_RRX; \ - } - -#define ADDR_MODE_2_IMM \ - info->memory.format |= ARM_MEMORY_IMMEDIATE_OFFSET; \ - info->memory.offset.immediate = opcode & 0x00000FFF; - -#define ADDR_MODE_3_REG \ - info->memory.format |= ARM_MEMORY_REGISTER_OFFSET; \ - info->memory.offset.reg = opcode & 0x0000000F; - -#define ADDR_MODE_3_IMM \ - info->memory.format |= ARM_MEMORY_IMMEDIATE_OFFSET; \ - info->memory.offset.immediate = (opcode & 0x0000000F) | ((opcode & 0x00000F00) >> 4); - -#define DEFINE_DECODER_ARM(NAME, MNEMONIC, BODY) \ - static void _ARMDecode ## NAME (uint32_t opcode, struct ARMInstructionInfo* info) { \ - UNUSED(opcode); \ - info->mnemonic = ARM_MN_ ## MNEMONIC; \ - BODY; \ - } - -#define DEFINE_ALU_DECODER_EX_ARM(NAME, MNEMONIC, S, SHIFTER, OTHER_AFFECTED, SKIPPED) \ - DEFINE_DECODER_ARM(NAME, MNEMONIC, \ - info->op1.reg = (opcode >> 12) & 0xF; \ - info->op2.reg = (opcode >> 16) & 0xF; \ - info->operandFormat = ARM_OPERAND_REGISTER_1 | \ - OTHER_AFFECTED | \ - ARM_OPERAND_REGISTER_2; \ - info->affectsCPSR = S; \ - SHIFTER; \ - if (SKIPPED == 1) { \ - info->op1 = info->op2; \ - info->op2 = info->op3; \ - info->operandFormat >>= 8; \ - } else if (SKIPPED == 2) { \ - info->op2 = info->op3; \ - info->operandFormat |= info->operandFormat >> 8; \ - info->operandFormat &= ~ARM_OPERAND_3; \ - } \ - if (info->op1.reg == ARM_PC) { \ - info->branchType = ARM_BRANCH_INDIRECT; \ - }) - -#define DEFINE_ALU_DECODER_ARM(NAME, SKIPPED) \ - DEFINE_ALU_DECODER_EX_ARM(NAME ## _LSL, NAME, 0, ADDR_MODE_1_LSL, ARM_OPERAND_AFFECTED_1, SKIPPED) \ - DEFINE_ALU_DECODER_EX_ARM(NAME ## S_LSL, NAME, 1, ADDR_MODE_1_LSL, ARM_OPERAND_AFFECTED_1, SKIPPED) \ - DEFINE_ALU_DECODER_EX_ARM(NAME ## _LSR, NAME, 0, ADDR_MODE_1_LSR, ARM_OPERAND_AFFECTED_1, SKIPPED) \ - DEFINE_ALU_DECODER_EX_ARM(NAME ## S_LSR, NAME, 1, ADDR_MODE_1_LSR, ARM_OPERAND_AFFECTED_1, SKIPPED) \ - DEFINE_ALU_DECODER_EX_ARM(NAME ## _ASR, NAME, 0, ADDR_MODE_1_ASR, ARM_OPERAND_AFFECTED_1, SKIPPED) \ - DEFINE_ALU_DECODER_EX_ARM(NAME ## S_ASR, NAME, 1, ADDR_MODE_1_ASR, ARM_OPERAND_AFFECTED_1, SKIPPED) \ - DEFINE_ALU_DECODER_EX_ARM(NAME ## _ROR, NAME, 0, ADDR_MODE_1_ROR, ARM_OPERAND_AFFECTED_1, SKIPPED) \ - DEFINE_ALU_DECODER_EX_ARM(NAME ## S_ROR, NAME, 1, ADDR_MODE_1_ROR, ARM_OPERAND_AFFECTED_1, SKIPPED) \ - DEFINE_ALU_DECODER_EX_ARM(NAME ## I, NAME, 0, ADDR_MODE_1_IMM, ARM_OPERAND_AFFECTED_1, SKIPPED) \ - DEFINE_ALU_DECODER_EX_ARM(NAME ## SI, NAME, 1, ADDR_MODE_1_IMM, ARM_OPERAND_AFFECTED_1, SKIPPED) - -#define DEFINE_ALU_DECODER_S_ONLY_ARM(NAME) \ - DEFINE_ALU_DECODER_EX_ARM(NAME ## _LSL, NAME, 1, ADDR_MODE_1_LSL, ARM_OPERAND_NONE, 1) \ - DEFINE_ALU_DECODER_EX_ARM(NAME ## _LSR, NAME, 1, ADDR_MODE_1_LSR, ARM_OPERAND_NONE, 1) \ - DEFINE_ALU_DECODER_EX_ARM(NAME ## _ASR, NAME, 1, ADDR_MODE_1_ASR, ARM_OPERAND_NONE, 1) \ - DEFINE_ALU_DECODER_EX_ARM(NAME ## _ROR, NAME, 1, ADDR_MODE_1_ROR, ARM_OPERAND_NONE, 1) \ - DEFINE_ALU_DECODER_EX_ARM(NAME ## I, NAME, 1, ADDR_MODE_1_IMM, ARM_OPERAND_NONE, 1) - -#define DEFINE_MULTIPLY_DECODER_EX_ARM(NAME, MNEMONIC, S, OTHER_AFFECTED) \ - DEFINE_DECODER_ARM(NAME, MNEMONIC, \ - info->op1.reg = (opcode >> 16) & 0xF; \ - info->op2.reg = opcode & 0xF; \ - info->op3.reg = (opcode >> 8) & 0xF; \ - info->op4.reg = (opcode >> 12) & 0xF; \ - info->operandFormat = ARM_OPERAND_REGISTER_1 | \ - ARM_OPERAND_AFFECTED_1 | \ - ARM_OPERAND_REGISTER_2 | \ - ARM_OPERAND_REGISTER_3 | \ - OTHER_AFFECTED; \ - info->affectsCPSR = S; \ - if (info->op1.reg == ARM_PC) { \ - info->branchType = ARM_BRANCH_INDIRECT; \ - }) - -#define DEFINE_LONG_MULTIPLY_DECODER_EX_ARM(NAME, MNEMONIC, S) \ - DEFINE_DECODER_ARM(NAME, MNEMONIC, \ - info->op1.reg = (opcode >> 12) & 0xF; \ - info->op2.reg = (opcode >> 16) & 0xF; \ - info->op3.reg = opcode & 0xF; \ - info->op4.reg = (opcode >> 8) & 0xF; \ - info->operandFormat = ARM_OPERAND_REGISTER_1 | \ - ARM_OPERAND_AFFECTED_1 | \ - ARM_OPERAND_REGISTER_2 | \ - ARM_OPERAND_AFFECTED_2 | \ - ARM_OPERAND_REGISTER_3 | \ - ARM_OPERAND_REGISTER_4; \ - info->affectsCPSR = S; \ - if (info->op1.reg == ARM_PC) { \ - info->branchType = ARM_BRANCH_INDIRECT; \ - }) - -#define DEFINE_MULTIPLY_DECODER_ARM(NAME, OTHER_AFFECTED) \ - DEFINE_MULTIPLY_DECODER_EX_ARM(NAME, NAME, 0, OTHER_AFFECTED) \ - DEFINE_MULTIPLY_DECODER_EX_ARM(NAME ## S, NAME, 1, OTHER_AFFECTED) - -#define DEFINE_LONG_MULTIPLY_DECODER_ARM(NAME) \ - DEFINE_LONG_MULTIPLY_DECODER_EX_ARM(NAME, NAME, 0) \ - DEFINE_LONG_MULTIPLY_DECODER_EX_ARM(NAME ## S, NAME, 1) - -#define DEFINE_LOAD_STORE_DECODER_EX_ARM(NAME, MNEMONIC, ADDRESSING_MODE, ADDRESSING_DECODING, CYCLES, TYPE) \ - DEFINE_DECODER_ARM(NAME, MNEMONIC, \ - info->op1.reg = (opcode >> 12) & 0xF; \ - info->memory.baseReg = (opcode >> 16) & 0xF; \ - info->memory.width = TYPE; \ - info->operandFormat = ARM_OPERAND_REGISTER_1 | \ - ARM_OPERAND_AFFECTED_1 | /* TODO: Remove this for STR */ \ - ARM_OPERAND_MEMORY_2; \ - info->memory.format = ARM_MEMORY_REGISTER_BASE | ADDRESSING_MODE; \ - ADDRESSING_DECODING; \ - CYCLES;) - -#define DEFINE_LOAD_STORE_DECODER_SET_ARM(NAME, MNEMONIC, ADDRESSING_MODE, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_DECODER_EX_ARM(NAME, MNEMONIC, \ - ARM_MEMORY_POST_INCREMENT | \ - ARM_MEMORY_WRITEBACK | \ - ARM_MEMORY_OFFSET_SUBTRACT, \ - ADDRESSING_MODE, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_DECODER_EX_ARM(NAME ## U, MNEMONIC, \ - ARM_MEMORY_POST_INCREMENT | \ - ARM_MEMORY_WRITEBACK, \ - ADDRESSING_MODE, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_DECODER_EX_ARM(NAME ## P, MNEMONIC, \ - ARM_MEMORY_OFFSET_SUBTRACT, \ - ADDRESSING_MODE, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_DECODER_EX_ARM(NAME ## PW, MNEMONIC, \ - ARM_MEMORY_PRE_INCREMENT | \ - ARM_MEMORY_WRITEBACK | \ - ARM_MEMORY_OFFSET_SUBTRACT, \ - ADDRESSING_MODE, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_DECODER_EX_ARM(NAME ## PU, MNEMONIC, \ - 0, \ - ADDRESSING_MODE, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_DECODER_EX_ARM(NAME ## PUW, MNEMONIC, \ - ARM_MEMORY_WRITEBACK, \ - ADDRESSING_MODE, CYCLES, TYPE) - -#define DEFINE_LOAD_STORE_MODE_2_DECODER_ARM(NAME, MNEMONIC, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_DECODER_SET_ARM(NAME ## _LSL_, MNEMONIC, ADDR_MODE_2_LSL, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_DECODER_SET_ARM(NAME ## _LSR_, MNEMONIC, ADDR_MODE_2_LSR, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_DECODER_SET_ARM(NAME ## _ASR_, MNEMONIC, ADDR_MODE_2_ASR, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_DECODER_SET_ARM(NAME ## _ROR_, MNEMONIC, ADDR_MODE_2_ROR, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_DECODER_SET_ARM(NAME ## I, MNEMONIC, ADDR_MODE_2_IMM, CYCLES, TYPE) - -#define DEFINE_LOAD_STORE_MODE_3_DECODER_ARM(NAME, MNEMONIC, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_DECODER_SET_ARM(NAME, MNEMONIC, ADDR_MODE_3_REG, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_DECODER_SET_ARM(NAME ## I, MNEMONIC, ADDR_MODE_3_IMM, CYCLES, TYPE) - -#define DEFINE_LOAD_STORE_T_DECODER_SET_ARM(NAME, MNEMONIC, ADDRESSING_MODE, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_DECODER_EX_ARM(NAME, MNEMONIC, \ - ARM_MEMORY_POST_INCREMENT | \ - ARM_MEMORY_WRITEBACK | \ - ARM_MEMORY_OFFSET_SUBTRACT, \ - ADDRESSING_MODE, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_DECODER_EX_ARM(NAME ## U, MNEMONIC, \ - ARM_MEMORY_POST_INCREMENT | \ - ARM_MEMORY_WRITEBACK, \ - ADDRESSING_MODE, CYCLES, TYPE) - -#define DEFINE_LOAD_STORE_T_DECODER_ARM(NAME, MNEMONIC, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_T_DECODER_SET_ARM(NAME ## _LSL_, MNEMONIC, ADDR_MODE_2_LSL, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_T_DECODER_SET_ARM(NAME ## _LSR_, MNEMONIC, ADDR_MODE_2_LSR, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_T_DECODER_SET_ARM(NAME ## _ASR_, MNEMONIC, ADDR_MODE_2_ASR, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_T_DECODER_SET_ARM(NAME ## _ROR_, MNEMONIC, ADDR_MODE_2_ROR, CYCLES, TYPE) \ - DEFINE_LOAD_STORE_T_DECODER_SET_ARM(NAME ## I, MNEMONIC, ADDR_MODE_2_IMM, CYCLES, TYPE) - -#define DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME, MNEMONIC, DIRECTION, WRITEBACK) \ - DEFINE_DECODER_ARM(NAME, MNEMONIC, \ - info->memory.baseReg = (opcode >> 16) & 0xF; \ - info->op1.immediate = opcode & 0x0000FFFF; \ - if (info->op1.immediate & (1 << ARM_PC)) { \ - info->branchType = ARM_BRANCH_INDIRECT; \ - } \ - info->operandFormat = ARM_OPERAND_MEMORY_1; \ - info->memory.format = ARM_MEMORY_REGISTER_BASE | \ - WRITEBACK | \ - ARM_MEMORY_ ## DIRECTION;) - - -#define DEFINE_LOAD_STORE_MULTIPLE_DECODER_ARM(NAME) \ - DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME ## DA, NAME, DECREMENT_AFTER, 0) \ - DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME ## DAW, NAME, DECREMENT_AFTER, ARM_MEMORY_WRITEBACK) \ - DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME ## DB, NAME, DECREMENT_BEFORE, 0) \ - DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME ## DBW, NAME, DECREMENT_BEFORE, ARM_MEMORY_WRITEBACK) \ - DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME ## IA, NAME, INCREMENT_AFTER, 0) \ - DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME ## IAW, NAME, INCREMENT_AFTER, ARM_MEMORY_WRITEBACK) \ - DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME ## IB, NAME, INCREMENT_BEFORE, 0) \ - DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME ## IBW, NAME, INCREMENT_BEFORE, ARM_MEMORY_WRITEBACK) \ - DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME ## SDA, NAME, DECREMENT_AFTER, ARM_MEMORY_SPSR_SWAP) \ - DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME ## SDAW, NAME, DECREMENT_AFTER, ARM_MEMORY_WRITEBACK | ARM_MEMORY_SPSR_SWAP) \ - DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME ## SDB, NAME, DECREMENT_BEFORE, ARM_MEMORY_SPSR_SWAP) \ - DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME ## SDBW, NAME, DECREMENT_BEFORE, ARM_MEMORY_WRITEBACK | ARM_MEMORY_SPSR_SWAP) \ - DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME ## SIA, NAME, INCREMENT_AFTER, ARM_MEMORY_SPSR_SWAP) \ - DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME ## SIAW, NAME, INCREMENT_AFTER, ARM_MEMORY_WRITEBACK | ARM_MEMORY_SPSR_SWAP) \ - DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME ## SIB, NAME, INCREMENT_BEFORE, ARM_MEMORY_SPSR_SWAP) \ - DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME ## SIBW, NAME, INCREMENT_BEFORE, ARM_MEMORY_WRITEBACK | ARM_MEMORY_SPSR_SWAP) - -#define DEFINE_SWP_DECODER_ARM(NAME, TYPE) \ - DEFINE_DECODER_ARM(NAME, SWP, \ - info->memory.baseReg = (opcode >> 16) & 0xF; \ - info->op1.reg = (opcode >> 12) & 0xF; \ - info->op2.reg = opcode & 0xF; \ - info->operandFormat = ARM_OPERAND_REGISTER_1 | \ - ARM_OPERAND_AFFECTED_1 | \ - ARM_OPERAND_REGISTER_2 | \ - ARM_OPERAND_MEMORY_3; \ - info->memory.format = ARM_MEMORY_REGISTER_BASE; \ - info->memory.width = TYPE;) +#define ADDR_MODE_1_ROR \ + ADDR_MODE_1_SHIFT(ROR) \ + if (!info->op3.shifterImm) { \ + info->op3.shifterOp = ARM_SHIFT_RRX; \ + } + +#define ADDR_MODE_1_IMM \ + int rotate = (opcode & 0x00000F00) >> 7; \ + int immediate = opcode & 0x000000FF; \ + info->op3.immediate = ROR(immediate, rotate); \ + info->operandFormat |= ARM_OPERAND_IMMEDIATE_3; + +#define ADDR_MODE_2_SHIFT(OP) \ + info->memory.format |= \ + ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_SHIFTED_OFFSET; \ + info->memory.offset.shifterOp = ARM_SHIFT_##OP; \ + info->memory.offset.shifterImm = (opcode >> 7) & 0x1F; \ + info->memory.offset.reg = opcode & 0x0000000F; + +#define ADDR_MODE_2_LSL \ + ADDR_MODE_2_SHIFT(LSL) \ + if (!info->memory.offset.shifterImm) { \ + info->memory.format &= ~ARM_MEMORY_SHIFTED_OFFSET; \ + info->memory.offset.shifterOp = ARM_SHIFT_NONE; \ + } + +#define ADDR_MODE_2_LSR \ + ADDR_MODE_2_SHIFT(LSR) \ + if (!info->memory.offset.shifterImm) { \ + info->memory.offset.shifterImm = 32; \ + } + +#define ADDR_MODE_2_ASR \ + ADDR_MODE_2_SHIFT(ASR) \ + if (!info->memory.offset.shifterImm) { \ + info->memory.offset.shifterImm = 32; \ + } + +#define ADDR_MODE_2_ROR \ + ADDR_MODE_2_SHIFT(ROR) \ + if (!info->memory.offset.shifterImm) { \ + info->memory.offset.shifterOp = ARM_SHIFT_RRX; \ + } + +#define ADDR_MODE_2_IMM \ + info->memory.format |= ARM_MEMORY_IMMEDIATE_OFFSET; \ + info->memory.offset.immediate = opcode & 0x00000FFF; + +#define ADDR_MODE_3_REG \ + info->memory.format |= ARM_MEMORY_REGISTER_OFFSET; \ + info->memory.offset.reg = opcode & 0x0000000F; + +#define ADDR_MODE_3_IMM \ + info->memory.format |= ARM_MEMORY_IMMEDIATE_OFFSET; \ + info->memory.offset.immediate = \ + (opcode & 0x0000000F) | ((opcode & 0x00000F00) >> 4); + +#define DEFINE_DECODER_ARM(NAME, MNEMONIC, BODY) \ + static void _ARMDecode##NAME(uint32_t opcode, \ + struct ARMInstructionInfo* info) { \ + UNUSED(opcode); \ + info->mnemonic = ARM_MN_##MNEMONIC; \ + BODY; \ + } + +#define DEFINE_ALU_DECODER_EX_ARM(NAME, MNEMONIC, S, SHIFTER, OTHER_AFFECTED, \ + SKIPPED) \ + DEFINE_DECODER_ARM( \ + NAME, MNEMONIC, info->op1.reg = (opcode >> 12) & 0xF; \ + info->op2.reg = (opcode >> 16) & 0xF; \ + info->operandFormat = \ + ARM_OPERAND_REGISTER_1 | OTHER_AFFECTED | ARM_OPERAND_REGISTER_2; \ + info->affectsCPSR = S; SHIFTER; if (SKIPPED == 1) { \ + info->op1 = info->op2; \ + info->op2 = info->op3; \ + info->operandFormat >>= 8; \ + } else if (SKIPPED == 2) { \ + info->op2 = info->op3; \ + info->operandFormat |= info->operandFormat >> 8; \ + info->operandFormat &= ~ARM_OPERAND_3; \ + } if (info->op1.reg == ARM_PC) { \ + info->branchType = ARM_BRANCH_INDIRECT; \ + }) + +#define DEFINE_ALU_DECODER_ARM(NAME, SKIPPED) \ + DEFINE_ALU_DECODER_EX_ARM(NAME##_LSL, NAME, 0, ADDR_MODE_1_LSL, \ + ARM_OPERAND_AFFECTED_1, SKIPPED) \ + DEFINE_ALU_DECODER_EX_ARM(NAME##S_LSL, NAME, 1, ADDR_MODE_1_LSL, \ + ARM_OPERAND_AFFECTED_1, SKIPPED) \ + DEFINE_ALU_DECODER_EX_ARM(NAME##_LSR, NAME, 0, ADDR_MODE_1_LSR, \ + ARM_OPERAND_AFFECTED_1, SKIPPED) \ + DEFINE_ALU_DECODER_EX_ARM(NAME##S_LSR, NAME, 1, ADDR_MODE_1_LSR, \ + ARM_OPERAND_AFFECTED_1, SKIPPED) \ + DEFINE_ALU_DECODER_EX_ARM(NAME##_ASR, NAME, 0, ADDR_MODE_1_ASR, \ + ARM_OPERAND_AFFECTED_1, SKIPPED) \ + DEFINE_ALU_DECODER_EX_ARM(NAME##S_ASR, NAME, 1, ADDR_MODE_1_ASR, \ + ARM_OPERAND_AFFECTED_1, SKIPPED) \ + DEFINE_ALU_DECODER_EX_ARM(NAME##_ROR, NAME, 0, ADDR_MODE_1_ROR, \ + ARM_OPERAND_AFFECTED_1, SKIPPED) \ + DEFINE_ALU_DECODER_EX_ARM(NAME##S_ROR, NAME, 1, ADDR_MODE_1_ROR, \ + ARM_OPERAND_AFFECTED_1, SKIPPED) \ + DEFINE_ALU_DECODER_EX_ARM(NAME##I, NAME, 0, ADDR_MODE_1_IMM, \ + ARM_OPERAND_AFFECTED_1, SKIPPED) \ + DEFINE_ALU_DECODER_EX_ARM(NAME##SI, NAME, 1, ADDR_MODE_1_IMM, \ + ARM_OPERAND_AFFECTED_1, SKIPPED) + +#define DEFINE_ALU_DECODER_S_ONLY_ARM(NAME) \ + DEFINE_ALU_DECODER_EX_ARM(NAME##_LSL, NAME, 1, ADDR_MODE_1_LSL, \ + ARM_OPERAND_NONE, 1) \ + DEFINE_ALU_DECODER_EX_ARM(NAME##_LSR, NAME, 1, ADDR_MODE_1_LSR, \ + ARM_OPERAND_NONE, 1) \ + DEFINE_ALU_DECODER_EX_ARM(NAME##_ASR, NAME, 1, ADDR_MODE_1_ASR, \ + ARM_OPERAND_NONE, 1) \ + DEFINE_ALU_DECODER_EX_ARM(NAME##_ROR, NAME, 1, ADDR_MODE_1_ROR, \ + ARM_OPERAND_NONE, 1) \ + DEFINE_ALU_DECODER_EX_ARM(NAME##I, NAME, 1, ADDR_MODE_1_IMM, \ + ARM_OPERAND_NONE, 1) + +#define DEFINE_MULTIPLY_DECODER_EX_ARM(NAME, MNEMONIC, S, OTHER_AFFECTED) \ + DEFINE_DECODER_ARM( \ + NAME, MNEMONIC, info->op1.reg = (opcode >> 16) & 0xF; \ + info->op2.reg = opcode & 0xF; info->op3.reg = (opcode >> 8) & 0xF; \ + info->op4.reg = (opcode >> 12) & 0xF; \ + info->operandFormat = ARM_OPERAND_REGISTER_1 | ARM_OPERAND_AFFECTED_1 | \ + ARM_OPERAND_REGISTER_2 | ARM_OPERAND_REGISTER_3 | \ + OTHER_AFFECTED; \ + info->affectsCPSR = S; if (info->op1.reg == ARM_PC) { \ + info->branchType = ARM_BRANCH_INDIRECT; \ + }) + +#define DEFINE_LONG_MULTIPLY_DECODER_EX_ARM(NAME, MNEMONIC, S) \ + DEFINE_DECODER_ARM( \ + NAME, MNEMONIC, info->op1.reg = (opcode >> 12) & 0xF; \ + info->op2.reg = (opcode >> 16) & 0xF; info->op3.reg = opcode & 0xF; \ + info->op4.reg = (opcode >> 8) & 0xF; \ + info->operandFormat = ARM_OPERAND_REGISTER_1 | ARM_OPERAND_AFFECTED_1 | \ + ARM_OPERAND_REGISTER_2 | ARM_OPERAND_AFFECTED_2 | \ + ARM_OPERAND_REGISTER_3 | ARM_OPERAND_REGISTER_4; \ + info->affectsCPSR = S; if (info->op1.reg == ARM_PC) { \ + info->branchType = ARM_BRANCH_INDIRECT; \ + }) + +#define DEFINE_MULTIPLY_DECODER_ARM(NAME, OTHER_AFFECTED) \ + DEFINE_MULTIPLY_DECODER_EX_ARM(NAME, NAME, 0, OTHER_AFFECTED) \ + DEFINE_MULTIPLY_DECODER_EX_ARM(NAME##S, NAME, 1, OTHER_AFFECTED) + +#define DEFINE_LONG_MULTIPLY_DECODER_ARM(NAME) \ + DEFINE_LONG_MULTIPLY_DECODER_EX_ARM(NAME, NAME, 0) \ + DEFINE_LONG_MULTIPLY_DECODER_EX_ARM(NAME##S, NAME, 1) + +#define DEFINE_LOAD_STORE_DECODER_EX_ARM(NAME, MNEMONIC, ADDRESSING_MODE, \ + ADDRESSING_DECODING, CYCLES, TYPE) \ + DEFINE_DECODER_ARM( \ + NAME, MNEMONIC, info->op1.reg = (opcode >> 12) & 0xF; \ + info->memory.baseReg = (opcode >> 16) & 0xF; info->memory.width = TYPE; \ + info->operandFormat = \ + ARM_OPERAND_REGISTER_1 | \ + ARM_OPERAND_AFFECTED_1 | /* TODO: Remove this for STR */ \ + ARM_OPERAND_MEMORY_2; \ + info->memory.format = ARM_MEMORY_REGISTER_BASE | ADDRESSING_MODE; \ + ADDRESSING_DECODING; CYCLES;) + +#define DEFINE_LOAD_STORE_DECODER_SET_ARM(NAME, MNEMONIC, ADDRESSING_MODE, \ + CYCLES, TYPE) \ + DEFINE_LOAD_STORE_DECODER_EX_ARM(NAME, MNEMONIC, \ + ARM_MEMORY_POST_INCREMENT | \ + ARM_MEMORY_WRITEBACK | \ + ARM_MEMORY_OFFSET_SUBTRACT, \ + ADDRESSING_MODE, CYCLES, TYPE) \ + DEFINE_LOAD_STORE_DECODER_EX_ARM( \ + NAME##U, MNEMONIC, ARM_MEMORY_POST_INCREMENT | ARM_MEMORY_WRITEBACK, \ + ADDRESSING_MODE, CYCLES, TYPE) \ + DEFINE_LOAD_STORE_DECODER_EX_ARM(NAME##P, MNEMONIC, \ + ARM_MEMORY_OFFSET_SUBTRACT, \ + ADDRESSING_MODE, CYCLES, TYPE) \ + DEFINE_LOAD_STORE_DECODER_EX_ARM(NAME##PW, MNEMONIC, \ + ARM_MEMORY_PRE_INCREMENT | \ + ARM_MEMORY_WRITEBACK | \ + ARM_MEMORY_OFFSET_SUBTRACT, \ + ADDRESSING_MODE, CYCLES, TYPE) \ + DEFINE_LOAD_STORE_DECODER_EX_ARM(NAME##PU, MNEMONIC, 0, ADDRESSING_MODE, \ + CYCLES, TYPE) \ + DEFINE_LOAD_STORE_DECODER_EX_ARM(NAME##PUW, MNEMONIC, ARM_MEMORY_WRITEBACK, \ + ADDRESSING_MODE, CYCLES, TYPE) + +#define DEFINE_LOAD_STORE_MODE_2_DECODER_ARM(NAME, MNEMONIC, CYCLES, TYPE) \ + DEFINE_LOAD_STORE_DECODER_SET_ARM(NAME##_LSL_, MNEMONIC, ADDR_MODE_2_LSL, \ + CYCLES, TYPE) \ + DEFINE_LOAD_STORE_DECODER_SET_ARM(NAME##_LSR_, MNEMONIC, ADDR_MODE_2_LSR, \ + CYCLES, TYPE) \ + DEFINE_LOAD_STORE_DECODER_SET_ARM(NAME##_ASR_, MNEMONIC, ADDR_MODE_2_ASR, \ + CYCLES, TYPE) \ + DEFINE_LOAD_STORE_DECODER_SET_ARM(NAME##_ROR_, MNEMONIC, ADDR_MODE_2_ROR, \ + CYCLES, TYPE) \ + DEFINE_LOAD_STORE_DECODER_SET_ARM(NAME##I, MNEMONIC, ADDR_MODE_2_IMM, \ + CYCLES, TYPE) + +#define DEFINE_LOAD_STORE_MODE_3_DECODER_ARM(NAME, MNEMONIC, CYCLES, TYPE) \ + DEFINE_LOAD_STORE_DECODER_SET_ARM(NAME, MNEMONIC, ADDR_MODE_3_REG, CYCLES, \ + TYPE) \ + DEFINE_LOAD_STORE_DECODER_SET_ARM(NAME##I, MNEMONIC, ADDR_MODE_3_IMM, \ + CYCLES, TYPE) + +#define DEFINE_LOAD_STORE_T_DECODER_SET_ARM(NAME, MNEMONIC, ADDRESSING_MODE, \ + CYCLES, TYPE) \ + DEFINE_LOAD_STORE_DECODER_EX_ARM(NAME, MNEMONIC, \ + ARM_MEMORY_POST_INCREMENT | \ + ARM_MEMORY_WRITEBACK | \ + ARM_MEMORY_OFFSET_SUBTRACT, \ + ADDRESSING_MODE, CYCLES, TYPE) \ + DEFINE_LOAD_STORE_DECODER_EX_ARM( \ + NAME##U, MNEMONIC, ARM_MEMORY_POST_INCREMENT | ARM_MEMORY_WRITEBACK, \ + ADDRESSING_MODE, CYCLES, TYPE) + +#define DEFINE_LOAD_STORE_T_DECODER_ARM(NAME, MNEMONIC, CYCLES, TYPE) \ + DEFINE_LOAD_STORE_T_DECODER_SET_ARM(NAME##_LSL_, MNEMONIC, ADDR_MODE_2_LSL, \ + CYCLES, TYPE) \ + DEFINE_LOAD_STORE_T_DECODER_SET_ARM(NAME##_LSR_, MNEMONIC, ADDR_MODE_2_LSR, \ + CYCLES, TYPE) \ + DEFINE_LOAD_STORE_T_DECODER_SET_ARM(NAME##_ASR_, MNEMONIC, ADDR_MODE_2_ASR, \ + CYCLES, TYPE) \ + DEFINE_LOAD_STORE_T_DECODER_SET_ARM(NAME##_ROR_, MNEMONIC, ADDR_MODE_2_ROR, \ + CYCLES, TYPE) \ + DEFINE_LOAD_STORE_T_DECODER_SET_ARM(NAME##I, MNEMONIC, ADDR_MODE_2_IMM, \ + CYCLES, TYPE) + +#define DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME, MNEMONIC, DIRECTION, \ + WRITEBACK) \ + DEFINE_DECODER_ARM( \ + NAME, MNEMONIC, info->memory.baseReg = (opcode >> 16) & 0xF; \ + info->op1.immediate = opcode & 0x0000FFFF; \ + if (info->op1.immediate & (1 << ARM_PC)) { \ + info->branchType = ARM_BRANCH_INDIRECT; \ + } info->operandFormat = ARM_OPERAND_MEMORY_1; \ + info->memory.format = \ + ARM_MEMORY_REGISTER_BASE | WRITEBACK | ARM_MEMORY_##DIRECTION;) + +#define DEFINE_LOAD_STORE_MULTIPLE_DECODER_ARM(NAME) \ + DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME##DA, NAME, DECREMENT_AFTER, \ + 0) \ + DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME##DAW, NAME, DECREMENT_AFTER, \ + ARM_MEMORY_WRITEBACK) \ + DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME##DB, NAME, DECREMENT_BEFORE, \ + 0) \ + DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME##DBW, NAME, DECREMENT_BEFORE, \ + ARM_MEMORY_WRITEBACK) \ + DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME##IA, NAME, INCREMENT_AFTER, \ + 0) \ + DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME##IAW, NAME, INCREMENT_AFTER, \ + ARM_MEMORY_WRITEBACK) \ + DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME##IB, NAME, INCREMENT_BEFORE, \ + 0) \ + DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME##IBW, NAME, INCREMENT_BEFORE, \ + ARM_MEMORY_WRITEBACK) \ + DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME##SDA, NAME, DECREMENT_AFTER, \ + ARM_MEMORY_SPSR_SWAP) \ + DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME##SDAW, NAME, DECREMENT_AFTER, \ + ARM_MEMORY_WRITEBACK | \ + ARM_MEMORY_SPSR_SWAP) \ + DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME##SDB, NAME, DECREMENT_BEFORE, \ + ARM_MEMORY_SPSR_SWAP) \ + DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM( \ + NAME##SDBW, NAME, DECREMENT_BEFORE, \ + ARM_MEMORY_WRITEBACK | ARM_MEMORY_SPSR_SWAP) \ + DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME##SIA, NAME, INCREMENT_AFTER, \ + ARM_MEMORY_SPSR_SWAP) \ + DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME##SIAW, NAME, INCREMENT_AFTER, \ + ARM_MEMORY_WRITEBACK | \ + ARM_MEMORY_SPSR_SWAP) \ + DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME##SIB, NAME, INCREMENT_BEFORE, \ + ARM_MEMORY_SPSR_SWAP) \ + DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM( \ + NAME##SIBW, NAME, INCREMENT_BEFORE, \ + ARM_MEMORY_WRITEBACK | ARM_MEMORY_SPSR_SWAP) + +#define DEFINE_SWP_DECODER_ARM(NAME, TYPE) \ + DEFINE_DECODER_ARM( \ + NAME, SWP, info->memory.baseReg = (opcode >> 16) & 0xF; \ + info->op1.reg = (opcode >> 12) & 0xF; info->op2.reg = opcode & 0xF; \ + info->operandFormat = ARM_OPERAND_REGISTER_1 | ARM_OPERAND_AFFECTED_1 | \ + ARM_OPERAND_REGISTER_2 | ARM_OPERAND_MEMORY_3; \ + info->memory.format = ARM_MEMORY_REGISTER_BASE; \ + info->memory.width = TYPE;) DEFINE_ALU_DECODER_ARM(ADD, 0) DEFINE_ALU_DECODER_ARM(ADC, 0) @@ -312,17 +345,25 @@ DEFINE_LONG_MULTIPLY_DECODER_ARM(UMULL) DEFINE_LOAD_STORE_MODE_2_DECODER_ARM(LDR, LDR, LOAD_CYCLES, ARM_ACCESS_WORD) DEFINE_LOAD_STORE_MODE_2_DECODER_ARM(LDRB, LDR, LOAD_CYCLES, ARM_ACCESS_BYTE) -DEFINE_LOAD_STORE_MODE_3_DECODER_ARM(LDRH, LDR, LOAD_CYCLES, ARM_ACCESS_HALFWORD) -DEFINE_LOAD_STORE_MODE_3_DECODER_ARM(LDRSB, LDR, LOAD_CYCLES, ARM_ACCESS_SIGNED_BYTE) -DEFINE_LOAD_STORE_MODE_3_DECODER_ARM(LDRSH, LDR, LOAD_CYCLES, ARM_ACCESS_SIGNED_HALFWORD) +DEFINE_LOAD_STORE_MODE_3_DECODER_ARM(LDRH, LDR, LOAD_CYCLES, + ARM_ACCESS_HALFWORD) +DEFINE_LOAD_STORE_MODE_3_DECODER_ARM(LDRSB, LDR, LOAD_CYCLES, + ARM_ACCESS_SIGNED_BYTE) +DEFINE_LOAD_STORE_MODE_3_DECODER_ARM(LDRSH, LDR, LOAD_CYCLES, + ARM_ACCESS_SIGNED_HALFWORD) DEFINE_LOAD_STORE_MODE_2_DECODER_ARM(STR, STR, STORE_CYCLES, ARM_ACCESS_WORD) DEFINE_LOAD_STORE_MODE_2_DECODER_ARM(STRB, STR, STORE_CYCLES, ARM_ACCESS_BYTE) -DEFINE_LOAD_STORE_MODE_3_DECODER_ARM(STRH, STR, STORE_CYCLES, ARM_ACCESS_HALFWORD) - -DEFINE_LOAD_STORE_T_DECODER_ARM(LDRBT, LDR, LOAD_CYCLES, ARM_ACCESS_TRANSLATED_BYTE) -DEFINE_LOAD_STORE_T_DECODER_ARM(LDRT, LDR, LOAD_CYCLES, ARM_ACCESS_TRANSLATED_WORD) -DEFINE_LOAD_STORE_T_DECODER_ARM(STRBT, STR, STORE_CYCLES, ARM_ACCESS_TRANSLATED_BYTE) -DEFINE_LOAD_STORE_T_DECODER_ARM(STRT, STR, STORE_CYCLES, ARM_ACCESS_TRANSLATED_WORD) +DEFINE_LOAD_STORE_MODE_3_DECODER_ARM(STRH, STR, STORE_CYCLES, + ARM_ACCESS_HALFWORD) + +DEFINE_LOAD_STORE_T_DECODER_ARM(LDRBT, LDR, LOAD_CYCLES, + ARM_ACCESS_TRANSLATED_BYTE) +DEFINE_LOAD_STORE_T_DECODER_ARM(LDRT, LDR, LOAD_CYCLES, + ARM_ACCESS_TRANSLATED_WORD) +DEFINE_LOAD_STORE_T_DECODER_ARM(STRBT, STR, STORE_CYCLES, + ARM_ACCESS_TRANSLATED_BYTE) +DEFINE_LOAD_STORE_T_DECODER_ARM(STRT, STR, STORE_CYCLES, + ARM_ACCESS_TRANSLATED_WORD) DEFINE_LOAD_STORE_MULTIPLE_DECODER_ARM(LDM) DEFINE_LOAD_STORE_MULTIPLE_DECODER_ARM(STM) @@ -334,22 +375,19 @@ DEFINE_SWP_DECODER_ARM(SWPB, ARM_ACCESS_BYTE) // Begin branch definitions -DEFINE_DECODER_ARM(B, B, - int32_t offset = opcode << 8; - info->op1.immediate = offset >> 6; - info->operandFormat = ARM_OPERAND_IMMEDIATE_1; - info->branchType = ARM_BRANCH;) +DEFINE_DECODER_ARM(B, B, int32_t offset = opcode << 8; + info->op1.immediate = offset >> 6; + info->operandFormat = ARM_OPERAND_IMMEDIATE_1; + info->branchType = ARM_BRANCH;) -DEFINE_DECODER_ARM(BL, BL, - int32_t offset = opcode << 8; - info->op1.immediate = offset >> 6; - info->operandFormat = ARM_OPERAND_IMMEDIATE_1; - info->branchType = ARM_BRANCH_LINKED;) +DEFINE_DECODER_ARM(BL, BL, int32_t offset = opcode << 8; + info->op1.immediate = offset >> 6; + info->operandFormat = ARM_OPERAND_IMMEDIATE_1; + info->branchType = ARM_BRANCH_LINKED;) -DEFINE_DECODER_ARM(BX, BX, - info->op1.reg = opcode & 0x0000000F; - info->operandFormat = ARM_OPERAND_REGISTER_1; - info->branchType = ARM_BRANCH_INDIRECT;) +DEFINE_DECODER_ARM(BX, BX, info->op1.reg = opcode & 0x0000000F; + info->operandFormat = ARM_OPERAND_REGISTER_1; + info->branchType = ARM_BRANCH_INDIRECT;) // End branch definitions @@ -363,85 +401,75 @@ DEFINE_DECODER_ARM(MRC, ILL, info->operandFormat = ARM_OPERAND_NONE;) // Begin miscellaneous definitions -DEFINE_DECODER_ARM(BKPT, BKPT, - info->operandFormat = ARM_OPERAND_NONE; - info->traps = 1;) // Not strictly in ARMv4T, but here for convenience +DEFINE_DECODER_ARM( + BKPT, BKPT, + info->operandFormat = ARM_OPERAND_NONE; + info->traps = 1;) // Not strictly in ARMv4T, but here for convenience DEFINE_DECODER_ARM(ILL, ILL, - info->operandFormat = ARM_OPERAND_NONE; - info->traps = 1;) // Illegal opcode - -DEFINE_DECODER_ARM(MSR, MSR, - info->affectsCPSR = 1; - info->op1.reg = ARM_CPSR; - info->op1.psrBits = (opcode >> 16) & ARM_PSR_MASK; - info->op2.reg = opcode & 0x0000000F; - info->operandFormat = ARM_OPERAND_REGISTER_1 | - ARM_OPERAND_AFFECTED_1 | - ARM_OPERAND_REGISTER_2;) - -DEFINE_DECODER_ARM(MSRR, MSR, - info->op1.reg = ARM_SPSR; - info->op1.psrBits = (opcode >> 16) & ARM_PSR_MASK; - info->op2.reg = opcode & 0x0000000F; - info->operandFormat = ARM_OPERAND_REGISTER_1 | - ARM_OPERAND_AFFECTED_1 | - ARM_OPERAND_REGISTER_2;) - -DEFINE_DECODER_ARM(MRS, MRS, - info->affectsCPSR = 1; - info->op1.reg = (opcode >> 12) & 0xF; - info->op2.reg = ARM_CPSR; - info->op2.psrBits = 0; - info->operandFormat = ARM_OPERAND_REGISTER_1 | - ARM_OPERAND_AFFECTED_1 | - ARM_OPERAND_REGISTER_2;) - -DEFINE_DECODER_ARM(MRSR, MRS, - info->op1.reg = (opcode >> 12) & 0xF; - info->op2.reg = ARM_SPSR; - info->op2.psrBits = 0; - info->operandFormat = ARM_OPERAND_REGISTER_1 | - ARM_OPERAND_AFFECTED_1 | - ARM_OPERAND_REGISTER_2;) - -DEFINE_DECODER_ARM(MSRI, MSR, - int rotate = (opcode & 0x00000F00) >> 7; - int32_t operand = ROR(opcode & 0x000000FF, rotate); - info->affectsCPSR = 1; - info->op1.reg = ARM_CPSR; - info->op1.psrBits = (opcode >> 16) & ARM_PSR_MASK; - info->op2.immediate = operand; - info->operandFormat = ARM_OPERAND_REGISTER_1 | - ARM_OPERAND_AFFECTED_1 | - ARM_OPERAND_IMMEDIATE_2;) - -DEFINE_DECODER_ARM(MSRRI, MSR, - int rotate = (opcode & 0x00000F00) >> 7; - int32_t operand = ROR(opcode & 0x000000FF, rotate); - info->op1.reg = ARM_SPSR; - info->op1.psrBits = (opcode >> 16) & ARM_PSR_MASK; - info->op2.immediate = operand; - info->operandFormat = ARM_OPERAND_REGISTER_1 | - ARM_OPERAND_AFFECTED_1 | - ARM_OPERAND_IMMEDIATE_2;) - -DEFINE_DECODER_ARM(SWI, SWI, - info->op1.immediate = opcode & 0xFFFFFF; - info->operandFormat = ARM_OPERAND_IMMEDIATE_1; - info->traps = 1;) + info->operandFormat = ARM_OPERAND_NONE; + info->traps = 1;) // Illegal opcode + +DEFINE_DECODER_ARM(MSR, MSR, info->affectsCPSR = 1; info->op1.reg = ARM_CPSR; + info->op1.psrBits = (opcode >> 16) & ARM_PSR_MASK; + info->op2.reg = opcode & 0x0000000F; + info->operandFormat = ARM_OPERAND_REGISTER_1 | + ARM_OPERAND_AFFECTED_1 | + ARM_OPERAND_REGISTER_2;) + +DEFINE_DECODER_ARM(MSRR, MSR, info->op1.reg = ARM_SPSR; + info->op1.psrBits = (opcode >> 16) & ARM_PSR_MASK; + info->op2.reg = opcode & 0x0000000F; + info->operandFormat = ARM_OPERAND_REGISTER_1 | + ARM_OPERAND_AFFECTED_1 | + ARM_OPERAND_REGISTER_2;) + +DEFINE_DECODER_ARM(MRS, MRS, info->affectsCPSR = 1; + info->op1.reg = (opcode >> 12) & 0xF; + info->op2.reg = ARM_CPSR; info->op2.psrBits = 0; + info->operandFormat = ARM_OPERAND_REGISTER_1 | + ARM_OPERAND_AFFECTED_1 | + ARM_OPERAND_REGISTER_2;) + +DEFINE_DECODER_ARM(MRSR, MRS, info->op1.reg = (opcode >> 12) & 0xF; + info->op2.reg = ARM_SPSR; info->op2.psrBits = 0; + info->operandFormat = ARM_OPERAND_REGISTER_1 | + ARM_OPERAND_AFFECTED_1 | + ARM_OPERAND_REGISTER_2;) + +DEFINE_DECODER_ARM(MSRI, MSR, int rotate = (opcode & 0x00000F00) >> 7; + int32_t operand = ROR(opcode & 0x000000FF, rotate); + info->affectsCPSR = 1; info->op1.reg = ARM_CPSR; + info->op1.psrBits = (opcode >> 16) & ARM_PSR_MASK; + info->op2.immediate = operand; + info->operandFormat = ARM_OPERAND_REGISTER_1 | + ARM_OPERAND_AFFECTED_1 | + ARM_OPERAND_IMMEDIATE_2;) + +DEFINE_DECODER_ARM(MSRRI, MSR, int rotate = (opcode & 0x00000F00) >> 7; + int32_t operand = ROR(opcode & 0x000000FF, rotate); + info->op1.reg = ARM_SPSR; + info->op1.psrBits = (opcode >> 16) & ARM_PSR_MASK; + info->op2.immediate = operand; + info->operandFormat = ARM_OPERAND_REGISTER_1 | + ARM_OPERAND_AFFECTED_1 | + ARM_OPERAND_IMMEDIATE_2;) + +DEFINE_DECODER_ARM(SWI, SWI, info->op1.immediate = opcode & 0xFFFFFF; + info->operandFormat = ARM_OPERAND_IMMEDIATE_1; + info->traps = 1;) typedef void (*ARMDecoder)(uint32_t opcode, struct ARMInstructionInfo* info); static const ARMDecoder _armDecoderTable[0x1000] = { - DECLARE_ARM_EMITTER_BLOCK(_ARMDecode) -}; + DECLARE_ARM_EMITTER_BLOCK(_ARMDecode)}; void ARMDecodeARM(uint32_t opcode, struct ARMInstructionInfo* info) { - memset(info, 0, sizeof(*info)); - info->opcode = opcode; - info->branchType = ARM_BRANCH_NONE; - info->condition = opcode >> 28; - info->sInstructionCycles = 1; - ARMDecoder decoder = _armDecoderTable[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)]; - decoder(opcode, info); + memset(info, 0, sizeof(*info)); + info->opcode = opcode; + info->branchType = ARM_BRANCH_NONE; + info->condition = opcode >> 28; + info->sInstructionCycles = 1; + ARMDecoder decoder = + _armDecoderTable[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)]; + decoder(opcode, info); } diff --git a/WindCore/decoder-inlines.h b/WindCore/decoder-inlines.h index 4dd80a0..31092e2 100644 --- a/WindCore/decoder-inlines.h +++ b/WindCore/decoder-inlines.h @@ -11,13 +11,13 @@ #include #include -#define LOAD_CYCLES \ - info->iCycles = 1; \ - info->nDataCycles = 1; +#define LOAD_CYCLES \ + info->iCycles = 1; \ + info->nDataCycles = 1; -#define STORE_CYCLES \ - info->sInstructionCycles = 0; \ - info->nInstructionCycles = 1; \ - info->nDataCycles = 1; +#define STORE_CYCLES \ + info->sInstructionCycles = 0; \ + info->nInstructionCycles = 1; \ + info->nDataCycles = 1; #endif diff --git a/WindCore/decoder.c b/WindCore/decoder.c index 9e8545c..2feb1c1 100644 --- a/WindCore/decoder.c +++ b/WindCore/decoder.c @@ -7,473 +7,409 @@ #include "decoder-inlines.h" -#define ADVANCE(AMOUNT) \ - if (AMOUNT >= blen) { \ - buffer[blen - 1] = '\0'; \ - return total; \ - } \ - total += AMOUNT; \ - buffer += AMOUNT; \ - blen -= AMOUNT; +#define ADVANCE(AMOUNT) \ + if (AMOUNT >= blen) { \ + buffer[blen - 1] = '\0'; \ + return total; \ + } \ + total += AMOUNT; \ + buffer += AMOUNT; \ + blen -= AMOUNT; static int _decodeRegister(int reg, char* buffer, int blen); static int _decodeRegisterList(int list, char* buffer, int blen); static int _decodePSR(int bits, char* buffer, int blen); -static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen); -static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen); -static int _decodeShift(union ARMOperand operand, bool reg, char* buffer, int blen); +static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, + int blen); +static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, + int blen); +static int _decodeShift(union ARMOperand operand, bool reg, char* buffer, + int blen); -static const char* _armConditions[] = { - "eq", - "ne", - "cs", - "cc", - "mi", - "pl", - "vs", - "vc", - "hi", - "ls", - "ge", - "lt", - "gt", - "le", - "al", - "nv" -}; +static const char* _armConditions[] = {"eq", "ne", "cs", "cc", "mi", "pl", + "vs", "vc", "hi", "ls", "ge", "lt", + "gt", "le", "al", "nv"}; static int _decodeRegister(int reg, char* buffer, int blen) { - switch (reg) { - case ARM_SP: - strncpy(buffer, "sp", blen - 1); - return 2; - case ARM_LR: - strncpy(buffer, "lr", blen - 1); - return 2; - case ARM_PC: - strncpy(buffer, "pc", blen - 1); - return 2; - case ARM_CPSR: - strncpy(buffer, "cpsr", blen - 1); - return 4; - case ARM_SPSR: - strncpy(buffer, "spsr", blen - 1); - return 4; - default: - return snprintf(buffer, blen - 1, "r%i", reg); - } + switch (reg) { + case ARM_SP: + strncpy(buffer, "sp", blen - 1); + return 2; + case ARM_LR: + strncpy(buffer, "lr", blen - 1); + return 2; + case ARM_PC: + strncpy(buffer, "pc", blen - 1); + return 2; + case ARM_CPSR: + strncpy(buffer, "cpsr", blen - 1); + return 4; + case ARM_SPSR: + strncpy(buffer, "spsr", blen - 1); + return 4; + default: + return snprintf(buffer, blen - 1, "r%i", reg); + } } static int _decodeRegisterList(int list, char* buffer, int blen) { - if (blen <= 0) { - return 0; - } - int total = 0; - strncpy(buffer, "{", blen - 1); - ADVANCE(1); - int i; - int start = -1; - int end = -1; - int written; - for (i = 0; i <= ARM_PC; ++i) { - if (list & 1) { - if (start < 0) { - start = i; - end = i; - } else if (end + 1 == i) { - end = i; - } else { - if (end > start) { - written = _decodeRegister(start, buffer, blen); - ADVANCE(written); - strncpy(buffer, "-", blen - 1); - ADVANCE(1); - } - written = _decodeRegister(end, buffer, blen); - ADVANCE(written); - strncpy(buffer, ",", blen - 1); - ADVANCE(1); - start = i; - end = i; - } - } - list >>= 1; - } - if (start >= 0) { - if (end > start) { - written = _decodeRegister(start, buffer, blen); - ADVANCE(written); - strncpy(buffer, "-", blen - 1); - ADVANCE(1); - } - written = _decodeRegister(end, buffer, blen); - ADVANCE(written); - } - strncpy(buffer, "}", blen - 1); - ADVANCE(1); - return total; + if (blen <= 0) { + return 0; + } + int total = 0; + strncpy(buffer, "{", blen - 1); + ADVANCE(1); + int i; + int start = -1; + int end = -1; + int written; + for (i = 0; i <= ARM_PC; ++i) { + if (list & 1) { + if (start < 0) { + start = i; + end = i; + } else if (end + 1 == i) { + end = i; + } else { + if (end > start) { + written = _decodeRegister(start, buffer, blen); + ADVANCE(written); + strncpy(buffer, "-", blen - 1); + ADVANCE(1); + } + written = _decodeRegister(end, buffer, blen); + ADVANCE(written); + strncpy(buffer, ",", blen - 1); + ADVANCE(1); + start = i; + end = i; + } + } + list >>= 1; + } + if (start >= 0) { + if (end > start) { + written = _decodeRegister(start, buffer, blen); + ADVANCE(written); + strncpy(buffer, "-", blen - 1); + ADVANCE(1); + } + written = _decodeRegister(end, buffer, blen); + ADVANCE(written); + } + strncpy(buffer, "}", blen - 1); + ADVANCE(1); + return total; } static int _decodePSR(int psrBits, char* buffer, int blen) { - if (!psrBits) { - return 0; - } - int total = 0; - strncpy(buffer, "_", blen - 1); - ADVANCE(1); - if (psrBits & ARM_PSR_C) { - strncpy(buffer, "c", blen - 1); - ADVANCE(1); - } - if (psrBits & ARM_PSR_X) { - strncpy(buffer, "x", blen - 1); - ADVANCE(1); - } - if (psrBits & ARM_PSR_S) { - strncpy(buffer, "s", blen - 1); - ADVANCE(1); - } - if (psrBits & ARM_PSR_F) { - strncpy(buffer, "f", blen - 1); - ADVANCE(1); - } - return total; + if (!psrBits) { + return 0; + } + int total = 0; + strncpy(buffer, "_", blen - 1); + ADVANCE(1); + if (psrBits & ARM_PSR_C) { + strncpy(buffer, "c", blen - 1); + ADVANCE(1); + } + if (psrBits & ARM_PSR_X) { + strncpy(buffer, "x", blen - 1); + ADVANCE(1); + } + if (psrBits & ARM_PSR_S) { + strncpy(buffer, "s", blen - 1); + ADVANCE(1); + } + if (psrBits & ARM_PSR_F) { + strncpy(buffer, "f", blen - 1); + ADVANCE(1); + } + return total; } -static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen) { - return snprintf(buffer, blen - 1, "$%08X", address + pc); +static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, + int blen) { + return snprintf(buffer, blen - 1, "$%08X", address + pc); } -static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen) { - if (blen <= 1) { - return 0; - } - int total = 0; - strncpy(buffer, "[", blen - 1); - ADVANCE(1); - int written; - if (memory.format & ARM_MEMORY_REGISTER_BASE) { - if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) { - written = _decodePCRelative(memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -memory.offset.immediate : memory.offset.immediate, pc & 0xFFFFFFFC, buffer, blen); - ADVANCE(written); - } else { - written = _decodeRegister(memory.baseReg, buffer, blen); - ADVANCE(written); - if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) { - strncpy(buffer, ", ", blen - 1); - ADVANCE(2); - } - } - } - if (memory.format & ARM_MEMORY_POST_INCREMENT) { - strncpy(buffer, "], ", blen - 1); - ADVANCE(3); - } - if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) { - if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) { - written = snprintf(buffer, blen - 1, "#-%i", memory.offset.immediate); - ADVANCE(written); - } else { - written = snprintf(buffer, blen - 1, "#%i", memory.offset.immediate); - ADVANCE(written); - } - } else if (memory.format & ARM_MEMORY_REGISTER_OFFSET) { - if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) { - strncpy(buffer, "-", blen - 1); - ADVANCE(1); - } - written = _decodeRegister(memory.offset.reg, buffer, blen); - ADVANCE(written); - } - if (memory.format & ARM_MEMORY_SHIFTED_OFFSET) { - written = _decodeShift(memory.offset, false, buffer, blen); - ADVANCE(written); - } +static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, + int blen) { + if (blen <= 1) { + return 0; + } + int total = 0; + strncpy(buffer, "[", blen - 1); + ADVANCE(1); + int written; + if (memory.format & ARM_MEMORY_REGISTER_BASE) { + if (memory.baseReg == ARM_PC && + memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) { + written = _decodePCRelative(memory.format & ARM_MEMORY_OFFSET_SUBTRACT + ? -memory.offset.immediate + : memory.offset.immediate, + pc & 0xFFFFFFFC, buffer, blen); + ADVANCE(written); + } else { + written = _decodeRegister(memory.baseReg, buffer, blen); + ADVANCE(written); + if (memory.format & + (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && + !(memory.format & ARM_MEMORY_POST_INCREMENT)) { + strncpy(buffer, ", ", blen - 1); + ADVANCE(2); + } + } + } + if (memory.format & ARM_MEMORY_POST_INCREMENT) { + strncpy(buffer, "], ", blen - 1); + ADVANCE(3); + } + if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) { + if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) { + written = snprintf(buffer, blen - 1, "#-%i", memory.offset.immediate); + ADVANCE(written); + } else { + written = snprintf(buffer, blen - 1, "#%i", memory.offset.immediate); + ADVANCE(written); + } + } else if (memory.format & ARM_MEMORY_REGISTER_OFFSET) { + if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) { + strncpy(buffer, "-", blen - 1); + ADVANCE(1); + } + written = _decodeRegister(memory.offset.reg, buffer, blen); + ADVANCE(written); + } + if (memory.format & ARM_MEMORY_SHIFTED_OFFSET) { + written = _decodeShift(memory.offset, false, buffer, blen); + ADVANCE(written); + } - if (!(memory.format & ARM_MEMORY_POST_INCREMENT)) { - strncpy(buffer, "]", blen - 1); - ADVANCE(1); - } - if ((memory.format & (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) == (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) { - strncpy(buffer, "!", blen - 1); - ADVANCE(1); - } - return total; + if (!(memory.format & ARM_MEMORY_POST_INCREMENT)) { + strncpy(buffer, "]", blen - 1); + ADVANCE(1); + } + if ((memory.format & (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) == + (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) { + strncpy(buffer, "!", blen - 1); + ADVANCE(1); + } + return total; } static int _decodeShift(union ARMOperand op, bool reg, char* buffer, int blen) { - if (blen <= 1) { - return 0; - } - int total = 0; - strncpy(buffer, ", ", blen - 1); - ADVANCE(2); - int written; - switch (op.shifterOp) { - case ARM_SHIFT_LSL: - strncpy(buffer, "lsl ", blen - 1); - ADVANCE(4); - break; - case ARM_SHIFT_LSR: - strncpy(buffer, "lsr ", blen - 1); - ADVANCE(4); - break; - case ARM_SHIFT_ASR: - strncpy(buffer, "asr ", blen - 1); - ADVANCE(4); - break; - case ARM_SHIFT_ROR: - strncpy(buffer, "ror ", blen - 1); - ADVANCE(4); - break; - case ARM_SHIFT_RRX: - strncpy(buffer, "rrx", blen - 1); - ADVANCE(3); - return total; - } - if (!reg) { - written = snprintf(buffer, blen - 1, "#%i", op.shifterImm); - } else { - written = _decodeRegister(op.shifterReg, buffer, blen); - } - ADVANCE(written); - return total; + if (blen <= 1) { + return 0; + } + int total = 0; + strncpy(buffer, ", ", blen - 1); + ADVANCE(2); + int written; + switch (op.shifterOp) { + case ARM_SHIFT_LSL: + strncpy(buffer, "lsl ", blen - 1); + ADVANCE(4); + break; + case ARM_SHIFT_LSR: + strncpy(buffer, "lsr ", blen - 1); + ADVANCE(4); + break; + case ARM_SHIFT_ASR: + strncpy(buffer, "asr ", blen - 1); + ADVANCE(4); + break; + case ARM_SHIFT_ROR: + strncpy(buffer, "ror ", blen - 1); + ADVANCE(4); + break; + case ARM_SHIFT_RRX: + strncpy(buffer, "rrx", blen - 1); + ADVANCE(3); + return total; + } + if (!reg) { + written = snprintf(buffer, blen - 1, "#%i", op.shifterImm); + } else { + written = _decodeRegister(op.shifterReg, buffer, blen); + } + ADVANCE(written); + return total; } static const char* _armMnemonicStrings[] = { - "ill", - "adc", - "add", - "and", - "asr", - "b", - "bic", - "bkpt", - "bl", - "bx", - "cmn", - "cmp", - "eor", - "ldm", - "ldr", - "lsl", - "lsr", - "mla", - "mov", - "mrs", - "msr", - "mul", - "mvn", - "neg", - "orr", - "ror", - "rsb", - "rsc", - "sbc", - "smlal", - "smull", - "stm", - "str", - "sub", - "swi", - "swp", - "teq", - "tst", - "umlal", - "umull", + "ill", "adc", "add", "and", "asr", "b", "bic", "bkpt", "bl", "bx", + "cmn", "cmp", "eor", "ldm", "ldr", "lsl", "lsr", "mla", "mov", "mrs", + "msr", "mul", "mvn", "neg", "orr", "ror", "rsb", "rsc", "sbc", "smlal", + "smull", "stm", "str", "sub", "swi", "swp", "teq", "tst", "umlal", "umull", - "ill" -}; + "ill"}; -static const char* _armDirectionStrings[] = { - "da", - "ia", - "db", - "ib" -}; +static const char* _armDirectionStrings[] = {"da", "ia", "db", "ib"}; static const char* _armAccessTypeStrings[] = { - "", - "b", - "h", - "", - "", - "", - "", - "", + "", "b", "h", "", "", "", "", "", - "", - "sb", - "sh", - "", - "", - "", - "", - "", + "", "sb", "sh", "", "", "", "", "", - "", - "bt", - "", - "", - "t", - "", - "", - "" -}; + "", "bt", "", "", "t", "", "", ""}; -int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen) { - const char* mnemonic = _armMnemonicStrings[info->mnemonic]; - int written; - int total = 0; - const char* cond = ""; - if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) { - cond = _armConditions[info->condition]; - } - const char* flags = ""; - switch (info->mnemonic) { - case ARM_MN_LDM: - case ARM_MN_STM: - flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)]; - break; - case ARM_MN_LDR: - case ARM_MN_STR: - case ARM_MN_SWP: - flags = _armAccessTypeStrings[info->memory.width]; - break; - case ARM_MN_ADD: - case ARM_MN_ADC: - case ARM_MN_AND: - case ARM_MN_BIC: - case ARM_MN_EOR: - case ARM_MN_MOV: - case ARM_MN_MVN: - case ARM_MN_ORR: - case ARM_MN_RSB: - case ARM_MN_RSC: - case ARM_MN_SBC: - case ARM_MN_SUB: - if (info->affectsCPSR) { - flags = "s"; - } - break; - default: - break; - } - written = snprintf(buffer, blen - 1, "%s%s%s ", mnemonic, cond, flags); - ADVANCE(written); +int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, + int blen) { + const char* mnemonic = _armMnemonicStrings[info->mnemonic]; + int written; + int total = 0; + const char* cond = ""; + if (info->condition != ARM_CONDITION_AL && + info->condition < ARM_CONDITION_NV) { + cond = _armConditions[info->condition]; + } + const char* flags = ""; + switch (info->mnemonic) { + case ARM_MN_LDM: + case ARM_MN_STM: + flags = + _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)]; + break; + case ARM_MN_LDR: + case ARM_MN_STR: + case ARM_MN_SWP: + flags = _armAccessTypeStrings[info->memory.width]; + break; + case ARM_MN_ADD: + case ARM_MN_ADC: + case ARM_MN_AND: + case ARM_MN_BIC: + case ARM_MN_EOR: + case ARM_MN_MOV: + case ARM_MN_MVN: + case ARM_MN_ORR: + case ARM_MN_RSB: + case ARM_MN_RSC: + case ARM_MN_SBC: + case ARM_MN_SUB: + if (info->affectsCPSR) { + flags = "s"; + } + break; + default: + break; + } + written = snprintf(buffer, blen - 1, "%s%s%s ", mnemonic, cond, flags); + ADVANCE(written); - switch (info->mnemonic) { - case ARM_MN_LDM: - case ARM_MN_STM: - written = _decodeRegister(info->memory.baseReg, buffer, blen); - ADVANCE(written); - if (info->memory.format & ARM_MEMORY_WRITEBACK) { - strncpy(buffer, "!", blen - 1); - ADVANCE(1); - } - strncpy(buffer, ", ", blen - 1); - ADVANCE(2); - written = _decodeRegisterList(info->op1.immediate, buffer, blen); - ADVANCE(written); - if (info->memory.format & ARM_MEMORY_SPSR_SWAP) { - strncpy(buffer, "^", blen - 1); - ADVANCE(1); - } - break; - case ARM_MN_B: - case ARM_MN_BL: - if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) { - written = _decodePCRelative(info->op1.immediate, pc, buffer, blen); - ADVANCE(written); - } - break; - default: - if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) { - written = snprintf(buffer, blen - 1, "#%i", info->op1.immediate); - ADVANCE(written); - } else if (info->operandFormat & ARM_OPERAND_MEMORY_1) { - written = _decodeMemory(info->memory, pc, buffer, blen); - ADVANCE(written); - } else if (info->operandFormat & ARM_OPERAND_REGISTER_1) { - written = _decodeRegister(info->op1.reg, buffer, blen); - ADVANCE(written); - if (info->op1.reg > ARM_PC) { - written = _decodePSR(info->op1.psrBits, buffer, blen); - ADVANCE(written); - } - } - if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_1) { - written = _decodeShift(info->op1, true, buffer, blen); - ADVANCE(written); - } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_1) { - written = _decodeShift(info->op1, false, buffer, blen); - ADVANCE(written); - } - if (info->operandFormat & ARM_OPERAND_2) { - strncpy(buffer, ", ", blen); - ADVANCE(2); - } - if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) { - written = snprintf(buffer, blen - 1, "#%i", info->op2.immediate); - ADVANCE(written); - } else if (info->operandFormat & ARM_OPERAND_MEMORY_2) { - written = _decodeMemory(info->memory, pc, buffer, blen); - ADVANCE(written); - } else if (info->operandFormat & ARM_OPERAND_REGISTER_2) { - written = _decodeRegister(info->op2.reg, buffer, blen); - ADVANCE(written); - } - if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_2) { - written = _decodeShift(info->op2, true, buffer, blen); - ADVANCE(written); - } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_2) { - written = _decodeShift(info->op2, false, buffer, blen); - ADVANCE(written); - } - if (info->operandFormat & ARM_OPERAND_3) { - strncpy(buffer, ", ", blen - 1); - ADVANCE(2); - } - if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) { - written = snprintf(buffer, blen - 1, "#%i", info->op3.immediate); - ADVANCE(written); - } else if (info->operandFormat & ARM_OPERAND_MEMORY_3) { - written = _decodeMemory(info->memory, pc, buffer, blen); - ADVANCE(written); - } else if (info->operandFormat & ARM_OPERAND_REGISTER_3) { - written = _decodeRegister(info->op3.reg, buffer, blen); - ADVANCE(written); - } - if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_3) { - written = _decodeShift(info->op3, true, buffer, blen); - ADVANCE(written); - } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_3) { - written = _decodeShift(info->op3, false, buffer, blen); - ADVANCE(written); - } - if (info->operandFormat & ARM_OPERAND_4) { - strncpy(buffer, ", ", blen - 1); - ADVANCE(2); - } - if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) { - written = snprintf(buffer, blen - 1, "#%i", info->op4.immediate); - ADVANCE(written); - } else if (info->operandFormat & ARM_OPERAND_MEMORY_4) { - written = _decodeMemory(info->memory, pc, buffer, blen); - ADVANCE(written); - } else if (info->operandFormat & ARM_OPERAND_REGISTER_4) { - written = _decodeRegister(info->op4.reg, buffer, blen); - ADVANCE(written); - } - if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_4) { - written = _decodeShift(info->op4, true, buffer, blen); - ADVANCE(written); - } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_4) { - written = _decodeShift(info->op4, false, buffer, blen); - ADVANCE(written); - } - break; - } - buffer[blen - 1] = '\0'; - return total; + switch (info->mnemonic) { + case ARM_MN_LDM: + case ARM_MN_STM: + written = _decodeRegister(info->memory.baseReg, buffer, blen); + ADVANCE(written); + if (info->memory.format & ARM_MEMORY_WRITEBACK) { + strncpy(buffer, "!", blen - 1); + ADVANCE(1); + } + strncpy(buffer, ", ", blen - 1); + ADVANCE(2); + written = _decodeRegisterList(info->op1.immediate, buffer, blen); + ADVANCE(written); + if (info->memory.format & ARM_MEMORY_SPSR_SWAP) { + strncpy(buffer, "^", blen - 1); + ADVANCE(1); + } + break; + case ARM_MN_B: + case ARM_MN_BL: + if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) { + written = _decodePCRelative(info->op1.immediate, pc, buffer, blen); + ADVANCE(written); + } + break; + default: + if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) { + written = snprintf(buffer, blen - 1, "#%i", info->op1.immediate); + ADVANCE(written); + } else if (info->operandFormat & ARM_OPERAND_MEMORY_1) { + written = _decodeMemory(info->memory, pc, buffer, blen); + ADVANCE(written); + } else if (info->operandFormat & ARM_OPERAND_REGISTER_1) { + written = _decodeRegister(info->op1.reg, buffer, blen); + ADVANCE(written); + if (info->op1.reg > ARM_PC) { + written = _decodePSR(info->op1.psrBits, buffer, blen); + ADVANCE(written); + } + } + if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_1) { + written = _decodeShift(info->op1, true, buffer, blen); + ADVANCE(written); + } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_1) { + written = _decodeShift(info->op1, false, buffer, blen); + ADVANCE(written); + } + if (info->operandFormat & ARM_OPERAND_2) { + strncpy(buffer, ", ", blen); + ADVANCE(2); + } + if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) { + written = snprintf(buffer, blen - 1, "#%i", info->op2.immediate); + ADVANCE(written); + } else if (info->operandFormat & ARM_OPERAND_MEMORY_2) { + written = _decodeMemory(info->memory, pc, buffer, blen); + ADVANCE(written); + } else if (info->operandFormat & ARM_OPERAND_REGISTER_2) { + written = _decodeRegister(info->op2.reg, buffer, blen); + ADVANCE(written); + } + if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_2) { + written = _decodeShift(info->op2, true, buffer, blen); + ADVANCE(written); + } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_2) { + written = _decodeShift(info->op2, false, buffer, blen); + ADVANCE(written); + } + if (info->operandFormat & ARM_OPERAND_3) { + strncpy(buffer, ", ", blen - 1); + ADVANCE(2); + } + if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) { + written = snprintf(buffer, blen - 1, "#%i", info->op3.immediate); + ADVANCE(written); + } else if (info->operandFormat & ARM_OPERAND_MEMORY_3) { + written = _decodeMemory(info->memory, pc, buffer, blen); + ADVANCE(written); + } else if (info->operandFormat & ARM_OPERAND_REGISTER_3) { + written = _decodeRegister(info->op3.reg, buffer, blen); + ADVANCE(written); + } + if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_3) { + written = _decodeShift(info->op3, true, buffer, blen); + ADVANCE(written); + } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_3) { + written = _decodeShift(info->op3, false, buffer, blen); + ADVANCE(written); + } + if (info->operandFormat & ARM_OPERAND_4) { + strncpy(buffer, ", ", blen - 1); + ADVANCE(2); + } + if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) { + written = snprintf(buffer, blen - 1, "#%i", info->op4.immediate); + ADVANCE(written); + } else if (info->operandFormat & ARM_OPERAND_MEMORY_4) { + written = _decodeMemory(info->memory, pc, buffer, blen); + ADVANCE(written); + } else if (info->operandFormat & ARM_OPERAND_REGISTER_4) { + written = _decodeRegister(info->op4.reg, buffer, blen); + ADVANCE(written); + } + if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_4) { + written = _decodeShift(info->op4, true, buffer, blen); + ADVANCE(written); + } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_4) { + written = _decodeShift(info->op4, false, buffer, blen); + ADVANCE(written); + } + break; + } + buffer[blen - 1] = '\0'; + return total; } diff --git a/WindCore/decoder.h b/WindCore/decoder.h index 31515e1..38c1974 100644 --- a/WindCore/decoder.h +++ b/WindCore/decoder.h @@ -16,54 +16,56 @@ CXX_GUARD_START // Bit 3: the destination of this operand is affected by this opcode // Bit 4: this operand is shifted by a register // Bit 5: this operand is shifted by an immediate -#define ARM_OPERAND_NONE 0x00000000 -#define ARM_OPERAND_REGISTER_1 0x00000001 -#define ARM_OPERAND_IMMEDIATE_1 0x00000002 -#define ARM_OPERAND_MEMORY_1 0x00000004 -#define ARM_OPERAND_AFFECTED_1 0x00000008 -#define ARM_OPERAND_SHIFT_REGISTER_1 0x00000010 -#define ARM_OPERAND_SHIFT_IMMEDIATE_1 0x00000020 -#define ARM_OPERAND_1 0x000000FF - -#define ARM_OPERAND_REGISTER_2 0x00000100 -#define ARM_OPERAND_IMMEDIATE_2 0x00000200 -#define ARM_OPERAND_MEMORY_2 0x00000400 -#define ARM_OPERAND_AFFECTED_2 0x00000800 -#define ARM_OPERAND_SHIFT_REGISTER_2 0x00001000 -#define ARM_OPERAND_SHIFT_IMMEDIATE_2 0x00002000 -#define ARM_OPERAND_2 0x0000FF00 - -#define ARM_OPERAND_REGISTER_3 0x00010000 -#define ARM_OPERAND_IMMEDIATE_3 0x00020000 -#define ARM_OPERAND_MEMORY_3 0x00040000 -#define ARM_OPERAND_AFFECTED_3 0x00080000 -#define ARM_OPERAND_SHIFT_REGISTER_3 0x00100000 -#define ARM_OPERAND_SHIFT_IMMEDIATE_3 0x00200000 -#define ARM_OPERAND_3 0x00FF0000 - -#define ARM_OPERAND_REGISTER_4 0x01000000 -#define ARM_OPERAND_IMMEDIATE_4 0x02000000 -#define ARM_OPERAND_MEMORY_4 0x04000000 -#define ARM_OPERAND_AFFECTED_4 0x08000000 -#define ARM_OPERAND_SHIFT_REGISTER_4 0x10000000 -#define ARM_OPERAND_SHIFT_IMMEDIATE_4 0x20000000 -#define ARM_OPERAND_4 0xFF000000 - -#define ARM_OPERAND_MEMORY (ARM_OPERAND_MEMORY_1 | ARM_OPERAND_MEMORY_2 | ARM_OPERAND_MEMORY_3 | ARM_OPERAND_MEMORY_4) - -#define ARM_MEMORY_REGISTER_BASE 0x0001 -#define ARM_MEMORY_IMMEDIATE_OFFSET 0x0002 -#define ARM_MEMORY_REGISTER_OFFSET 0x0004 -#define ARM_MEMORY_SHIFTED_OFFSET 0x0008 -#define ARM_MEMORY_PRE_INCREMENT 0x0010 -#define ARM_MEMORY_POST_INCREMENT 0x0020 -#define ARM_MEMORY_OFFSET_SUBTRACT 0x0040 -#define ARM_MEMORY_WRITEBACK 0x0080 -#define ARM_MEMORY_DECREMENT_AFTER 0x0000 -#define ARM_MEMORY_INCREMENT_AFTER 0x0100 -#define ARM_MEMORY_DECREMENT_BEFORE 0x0200 -#define ARM_MEMORY_INCREMENT_BEFORE 0x0300 -#define ARM_MEMORY_SPSR_SWAP 0x0400 +#define ARM_OPERAND_NONE 0x00000000 +#define ARM_OPERAND_REGISTER_1 0x00000001 +#define ARM_OPERAND_IMMEDIATE_1 0x00000002 +#define ARM_OPERAND_MEMORY_1 0x00000004 +#define ARM_OPERAND_AFFECTED_1 0x00000008 +#define ARM_OPERAND_SHIFT_REGISTER_1 0x00000010 +#define ARM_OPERAND_SHIFT_IMMEDIATE_1 0x00000020 +#define ARM_OPERAND_1 0x000000FF + +#define ARM_OPERAND_REGISTER_2 0x00000100 +#define ARM_OPERAND_IMMEDIATE_2 0x00000200 +#define ARM_OPERAND_MEMORY_2 0x00000400 +#define ARM_OPERAND_AFFECTED_2 0x00000800 +#define ARM_OPERAND_SHIFT_REGISTER_2 0x00001000 +#define ARM_OPERAND_SHIFT_IMMEDIATE_2 0x00002000 +#define ARM_OPERAND_2 0x0000FF00 + +#define ARM_OPERAND_REGISTER_3 0x00010000 +#define ARM_OPERAND_IMMEDIATE_3 0x00020000 +#define ARM_OPERAND_MEMORY_3 0x00040000 +#define ARM_OPERAND_AFFECTED_3 0x00080000 +#define ARM_OPERAND_SHIFT_REGISTER_3 0x00100000 +#define ARM_OPERAND_SHIFT_IMMEDIATE_3 0x00200000 +#define ARM_OPERAND_3 0x00FF0000 + +#define ARM_OPERAND_REGISTER_4 0x01000000 +#define ARM_OPERAND_IMMEDIATE_4 0x02000000 +#define ARM_OPERAND_MEMORY_4 0x04000000 +#define ARM_OPERAND_AFFECTED_4 0x08000000 +#define ARM_OPERAND_SHIFT_REGISTER_4 0x10000000 +#define ARM_OPERAND_SHIFT_IMMEDIATE_4 0x20000000 +#define ARM_OPERAND_4 0xFF000000 + +#define ARM_OPERAND_MEMORY \ + (ARM_OPERAND_MEMORY_1 | ARM_OPERAND_MEMORY_2 | ARM_OPERAND_MEMORY_3 | \ + ARM_OPERAND_MEMORY_4) + +#define ARM_MEMORY_REGISTER_BASE 0x0001 +#define ARM_MEMORY_IMMEDIATE_OFFSET 0x0002 +#define ARM_MEMORY_REGISTER_OFFSET 0x0004 +#define ARM_MEMORY_SHIFTED_OFFSET 0x0008 +#define ARM_MEMORY_PRE_INCREMENT 0x0010 +#define ARM_MEMORY_POST_INCREMENT 0x0020 +#define ARM_MEMORY_OFFSET_SUBTRACT 0x0040 +#define ARM_MEMORY_WRITEBACK 0x0080 +#define ARM_MEMORY_DECREMENT_AFTER 0x0000 +#define ARM_MEMORY_INCREMENT_AFTER 0x0100 +#define ARM_MEMORY_DECREMENT_BEFORE 0x0200 +#define ARM_MEMORY_INCREMENT_BEFORE 0x0300 +#define ARM_MEMORY_SPSR_SWAP 0x0400 #define ARM_PSR_C 1 #define ARM_PSR_X 2 @@ -74,146 +76,141 @@ CXX_GUARD_START #define MEMORY_FORMAT_TO_DIRECTION(F) (((F) >> 8) & 0x3) enum ARMCondition { - ARM_CONDITION_EQ = 0x0, - ARM_CONDITION_NE = 0x1, - ARM_CONDITION_CS = 0x2, - ARM_CONDITION_CC = 0x3, - ARM_CONDITION_MI = 0x4, - ARM_CONDITION_PL = 0x5, - ARM_CONDITION_VS = 0x6, - ARM_CONDITION_VC = 0x7, - ARM_CONDITION_HI = 0x8, - ARM_CONDITION_LS = 0x9, - ARM_CONDITION_GE = 0xA, - ARM_CONDITION_LT = 0xB, - ARM_CONDITION_GT = 0xC, - ARM_CONDITION_LE = 0xD, - ARM_CONDITION_AL = 0xE, - ARM_CONDITION_NV = 0xF + ARM_CONDITION_EQ = 0x0, + ARM_CONDITION_NE = 0x1, + ARM_CONDITION_CS = 0x2, + ARM_CONDITION_CC = 0x3, + ARM_CONDITION_MI = 0x4, + ARM_CONDITION_PL = 0x5, + ARM_CONDITION_VS = 0x6, + ARM_CONDITION_VC = 0x7, + ARM_CONDITION_HI = 0x8, + ARM_CONDITION_LS = 0x9, + ARM_CONDITION_GE = 0xA, + ARM_CONDITION_LT = 0xB, + ARM_CONDITION_GT = 0xC, + ARM_CONDITION_LE = 0xD, + ARM_CONDITION_AL = 0xE, + ARM_CONDITION_NV = 0xF }; enum ARMShifterOperation { - ARM_SHIFT_NONE = 0, - ARM_SHIFT_LSL, - ARM_SHIFT_LSR, - ARM_SHIFT_ASR, - ARM_SHIFT_ROR, - ARM_SHIFT_RRX + ARM_SHIFT_NONE = 0, + ARM_SHIFT_LSL, + ARM_SHIFT_LSR, + ARM_SHIFT_ASR, + ARM_SHIFT_ROR, + ARM_SHIFT_RRX }; union ARMOperand { - struct { - uint8_t reg; - uint8_t shifterOp; - union { - uint8_t shifterReg; - uint8_t shifterImm; - uint8_t psrBits; - }; - }; - int32_t immediate; + struct { + uint8_t reg; + uint8_t shifterOp; + union { + uint8_t shifterReg; + uint8_t shifterImm; + uint8_t psrBits; + }; + }; + int32_t immediate; }; enum ARMMemoryAccessType { - ARM_ACCESS_WORD = 4, - ARM_ACCESS_HALFWORD = 2, - ARM_ACCESS_SIGNED_HALFWORD = 10, - ARM_ACCESS_BYTE = 1, - ARM_ACCESS_SIGNED_BYTE = 9, - ARM_ACCESS_TRANSLATED_WORD = 20, - ARM_ACCESS_TRANSLATED_BYTE = 17 + ARM_ACCESS_WORD = 4, + ARM_ACCESS_HALFWORD = 2, + ARM_ACCESS_SIGNED_HALFWORD = 10, + ARM_ACCESS_BYTE = 1, + ARM_ACCESS_SIGNED_BYTE = 9, + ARM_ACCESS_TRANSLATED_WORD = 20, + ARM_ACCESS_TRANSLATED_BYTE = 17 }; enum ARMBranchType { - ARM_BRANCH_NONE = 0, - ARM_BRANCH = 1, - ARM_BRANCH_INDIRECT = 2, - ARM_BRANCH_LINKED = 4 + ARM_BRANCH_NONE = 0, + ARM_BRANCH = 1, + ARM_BRANCH_INDIRECT = 2, + ARM_BRANCH_LINKED = 4 }; struct ARMMemoryAccess { - uint8_t baseReg; - uint8_t width; - uint16_t format; - union ARMOperand offset; + uint8_t baseReg; + uint8_t width; + uint16_t format; + union ARMOperand offset; }; enum ARMMnemonic { - ARM_MN_ILL = 0, - ARM_MN_ADC, - ARM_MN_ADD, - ARM_MN_AND, - ARM_MN_ASR, - ARM_MN_B, - ARM_MN_BIC, - ARM_MN_BKPT, - ARM_MN_BL, - ARM_MN_BX, - ARM_MN_CMN, - ARM_MN_CMP, - ARM_MN_EOR, - ARM_MN_LDM, - ARM_MN_LDR, - ARM_MN_LSL, - ARM_MN_LSR, - ARM_MN_MLA, - ARM_MN_MOV, - ARM_MN_MRS, - ARM_MN_MSR, - ARM_MN_MUL, - ARM_MN_MVN, - ARM_MN_NEG, - ARM_MN_ORR, - ARM_MN_ROR, - ARM_MN_RSB, - ARM_MN_RSC, - ARM_MN_SBC, - ARM_MN_SMLAL, - ARM_MN_SMULL, - ARM_MN_STM, - ARM_MN_STR, - ARM_MN_SUB, - ARM_MN_SWI, - ARM_MN_SWP, - ARM_MN_TEQ, - ARM_MN_TST, - ARM_MN_UMLAL, - ARM_MN_UMULL, - - ARM_MN_MAX + ARM_MN_ILL = 0, + ARM_MN_ADC, + ARM_MN_ADD, + ARM_MN_AND, + ARM_MN_ASR, + ARM_MN_B, + ARM_MN_BIC, + ARM_MN_BKPT, + ARM_MN_BL, + ARM_MN_BX, + ARM_MN_CMN, + ARM_MN_CMP, + ARM_MN_EOR, + ARM_MN_LDM, + ARM_MN_LDR, + ARM_MN_LSL, + ARM_MN_LSR, + ARM_MN_MLA, + ARM_MN_MOV, + ARM_MN_MRS, + ARM_MN_MSR, + ARM_MN_MUL, + ARM_MN_MVN, + ARM_MN_NEG, + ARM_MN_ORR, + ARM_MN_ROR, + ARM_MN_RSB, + ARM_MN_RSC, + ARM_MN_SBC, + ARM_MN_SMLAL, + ARM_MN_SMULL, + ARM_MN_STM, + ARM_MN_STR, + ARM_MN_SUB, + ARM_MN_SWI, + ARM_MN_SWP, + ARM_MN_TEQ, + ARM_MN_TST, + ARM_MN_UMLAL, + ARM_MN_UMULL, + + ARM_MN_MAX }; -enum { - ARM_SP = 13, - ARM_LR = 14, - ARM_PC = 15, - ARM_CPSR = 16, - ARM_SPSR = 17 -}; +enum { ARM_SP = 13, ARM_LR = 14, ARM_PC = 15, ARM_CPSR = 16, ARM_SPSR = 17 }; struct ARMInstructionInfo { - uint32_t opcode; - union ARMOperand op1; - union ARMOperand op2; - union ARMOperand op3; - union ARMOperand op4; - struct ARMMemoryAccess memory; - int operandFormat; - bool traps : 1; - bool affectsCPSR : 1; - unsigned branchType : 3; - unsigned condition : 4; - unsigned mnemonic : 6; - unsigned iCycles : 3; - unsigned cCycles : 4; - unsigned sInstructionCycles : 4; - unsigned nInstructionCycles : 4; - unsigned sDataCycles : 10; - unsigned nDataCycles : 10; + uint32_t opcode; + union ARMOperand op1; + union ARMOperand op2; + union ARMOperand op3; + union ARMOperand op4; + struct ARMMemoryAccess memory; + int operandFormat; + bool traps : 1; + bool affectsCPSR : 1; + unsigned branchType : 3; + unsigned condition : 4; + unsigned mnemonic : 6; + unsigned iCycles : 3; + unsigned cCycles : 4; + unsigned sInstructionCycles : 4; + unsigned nInstructionCycles : 4; + unsigned sDataCycles : 10; + unsigned nDataCycles : 10; }; void ARMDecodeARM(uint32_t opcode, struct ARMInstructionInfo* info); -int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen); +int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, + int blen); CXX_GUARD_END diff --git a/WindCore/emitter-arm.h b/WindCore/emitter-arm.h index e99a1b7..e979228 100644 --- a/WindCore/emitter-arm.h +++ b/WindCore/emitter-arm.h @@ -8,328 +8,331 @@ #include "emitter-inlines.h" -#define DECLARE_INSTRUCTION_ARM(EMITTER, NAME) \ - EMITTER ## NAME +#define DECLARE_INSTRUCTION_ARM(EMITTER, NAME) EMITTER##NAME -#define DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ALU) \ - DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## I)), \ - DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## I)) +#define DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ALU) \ + DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, ALU##I)), \ + DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, ALU##I)) -#define DECLARE_ARM_ALU_BLOCK(EMITTER, ALU, EX1, EX2, EX3, EX4) \ - DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _LSL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _LSL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _LSR), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _LSR), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _ASR), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _ASR), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _ROR), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _ROR), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _LSL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, EX1), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _LSR), \ - DECLARE_INSTRUCTION_ARM(EMITTER, EX2), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _ASR), \ - DECLARE_INSTRUCTION_ARM(EMITTER, EX3), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _ROR), \ - DECLARE_INSTRUCTION_ARM(EMITTER, EX4) +#define DECLARE_ARM_ALU_BLOCK(EMITTER, ALU, EX1, EX2, EX3, EX4) \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU##_LSL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU##_LSL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU##_LSR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU##_LSR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU##_ASR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU##_ASR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU##_ROR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU##_ROR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU##_LSL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, EX1), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU##_LSR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, EX2), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU##_ASR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, EX3), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU##_ROR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, EX4) -#define DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, NAME, P, U, W) \ - DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## I ## P ## U ## W)), \ - DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## I ## P ## U ## W)) +#define DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, NAME, P, U, W) \ + DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME##I##P##U##W)), \ + DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME##I##P##U##W)) -#define DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, NAME, P, U, W) \ - DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## _LSL_ ## P ## U ## W), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## _LSR_ ## P ## U ## W), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## _ASR_ ## P ## U ## W), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## _ROR_ ## P ## U ## W), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## _LSL_ ## P ## U ## W), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## _LSR_ ## P ## U ## W), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## _ASR_ ## P ## U ## W), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## _ROR_ ## P ## U ## W), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL) +#define DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, NAME, P, U, W) \ + DECLARE_INSTRUCTION_ARM(EMITTER, NAME##_LSL_##P##U##W), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, NAME##_LSR_##P##U##W), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, NAME##_ASR_##P##U##W), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, NAME##_ROR_##P##U##W), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, NAME##_LSL_##P##U##W), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, NAME##_LSR_##P##U##W), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, NAME##_ASR_##P##U##W), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, NAME##_ROR_##P##U##W), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL) -#define DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, NAME, MODE, W) \ - DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## MODE ## W)), \ - DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## MODE ## W)) +#define DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, NAME, MODE, W) \ + DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME##MODE##W)), \ + DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME##MODE##W)) -#define DECLARE_ARM_BRANCH_BLOCK(EMITTER, NAME) \ - DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, NAME)) +#define DECLARE_ARM_BRANCH_BLOCK(EMITTER, NAME) \ + DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, NAME)) // TODO: Support coprocessors -#define DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, NAME, P, U, N, W) \ - DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME)), \ - DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME)) +#define DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, NAME, P, U, N, W) \ + DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME)), \ + DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME)) -#define DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, NAME1, NAME2) \ - DO_8(DO_8(DO_INTERLACE(DECLARE_INSTRUCTION_ARM(EMITTER, NAME1), DECLARE_INSTRUCTION_ARM(EMITTER, NAME2)))) +#define DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, NAME1, NAME2) \ + DO_8(DO_8(DO_INTERLACE(DECLARE_INSTRUCTION_ARM(EMITTER, NAME1), \ + DECLARE_INSTRUCTION_ARM(EMITTER, NAME2)))) -#define DECLARE_ARM_SWI_BLOCK(EMITTER) \ - DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, SWI)) +#define DECLARE_ARM_SWI_BLOCK(EMITTER) \ + DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, SWI)) -#define DECLARE_ARM_EMITTER_BLOCK(EMITTER) \ - DECLARE_ARM_ALU_BLOCK(EMITTER, AND, MUL, STRH, ILL, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, ANDS, MULS, LDRH, LDRSB, LDRSH), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, EOR, MLA, STRH, ILL, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, EORS, MLAS, LDRH, LDRSB, LDRSH), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, SUB, ILL, STRHI, ILL, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, SUBS, ILL, LDRHI, LDRSBI, LDRSHI), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, RSB, ILL, STRHI, ILL, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, RSBS, ILL, LDRHI, LDRSBI, LDRSHI), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, ADD, UMULL, STRHU, ILL, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, ADDS, UMULLS, LDRHU, LDRSBU, LDRSHU), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, ADC, UMLAL, STRHU, ILL, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, ADCS, UMLALS, LDRHU, LDRSBU, LDRSHU), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, SBC, SMULL, STRHIU, ILL, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, SBCS, SMULLS, LDRHIU, LDRSBIU, LDRSHIU), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, RSC, SMLAL, STRHIU, ILL, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, RSCS, SMLALS, LDRHIU, LDRSBIU, LDRSHIU), \ - DECLARE_INSTRUCTION_ARM(EMITTER, MRS), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, SWP), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, STRHP), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, TST, ILL, LDRHP, LDRSBP, LDRSHP), \ - DECLARE_INSTRUCTION_ARM(EMITTER, MSR), \ - DECLARE_INSTRUCTION_ARM(EMITTER, BX), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, BKPT), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, STRHPW), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, TEQ, ILL, LDRHPW, LDRSBPW, LDRSHPW), \ - DECLARE_INSTRUCTION_ARM(EMITTER, MRSR), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, SWPB), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, STRHIP), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, CMP, ILL, LDRHIP, LDRSBIP, LDRSHIP), \ - DECLARE_INSTRUCTION_ARM(EMITTER, MSRR), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, STRHIPW), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, CMN, ILL, LDRHIPW, LDRSBIPW, LDRSHIPW), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, ORR, SMLAL, STRHPU, ILL, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, ORRS, SMLALS, LDRHPU, LDRSBPU, LDRSHPU), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, MOV, SMLAL, STRHPUW, ILL, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, MOVS, SMLALS, LDRHPUW, LDRSBPUW, LDRSHPUW), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, BIC, SMLAL, STRHIPU, ILL, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, BICS, SMLALS, LDRHIPU, LDRSBIPU, LDRSHIPU), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, MVN, SMLAL, STRHIPUW, ILL, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, MVNS, SMLALS, LDRHIPUW, LDRSBIPUW, LDRSHIPUW), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, AND), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ANDS), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, EOR), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, EORS), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SUB), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SUBS), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSB), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSBS), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADD), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADDS), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADC), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADCS), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SBC), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SBCS), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSC), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSCS), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, TST), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, TST), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MSR), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, TEQ), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, CMP), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, CMP), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MSRR), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, CMN), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ORR), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ORRS), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MOV), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MOVS), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, BIC), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, BICS), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MVN), \ - DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MVNS), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, , , ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, , , ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRT, , , ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRT, , , ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, , , ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, , , ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRBT, , , ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRBT, , , ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, , U, ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, , U, ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRT, , U, ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRT, , U, ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, , U, ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, , U, ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRBT, , U, ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRBT, , U, ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, , ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, , ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, , W), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, , W), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, , ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, , ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, , W), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, , W), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, U, ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, U, ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, U, W), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, U, W), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, U, ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, U, ), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, U, W), \ - DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, U, W), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, , , ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, , , ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRT, , , ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRT, , , ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, , , ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, , , ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRBT, , , ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRBT, , , ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, , U, ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, , U, ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRT, , U, ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRT, , U, ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, , U, ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, , U, ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRBT, , U, ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRBT, , U, ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, , ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, , ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, , W), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, , W), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, , ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, , ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, , W), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, , W), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, U, ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, U, ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, U, W), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, U, W), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, U, ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, U, ), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, U, W), \ - DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, U, W), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DA, ), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DA, ), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DA, W), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DA, W), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DA, ), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DA, ), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DA, W), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DA, W), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IA, ), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IA, ), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IA, W), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IA, W), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IA, ), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IA, ), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IA, W), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IA, W), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DB, ), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DB, ), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DB, W), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DB, W), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DB, ), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DB, ), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DB, W), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DB, W), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IB, ), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IB, ), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IB, W), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IB, W), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IB, ), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IB, ), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IB, W), \ - DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IB, W), \ - DECLARE_ARM_BRANCH_BLOCK(EMITTER, B), \ - DECLARE_ARM_BRANCH_BLOCK(EMITTER, BL), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , , ), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , , ), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , , W), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , , W), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , N, ), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , N, ), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , N, W), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , N, W), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, , ), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, , ), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, , W), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, , W), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, N, ), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, N, ), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, N, W), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, N, W), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , , ), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , , ), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , , W), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , , W), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, ), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, ), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, W), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, W), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , N, ), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , N, ), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , N, W), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , N, W), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, ), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, ), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, W), \ - DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, W), \ - DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, CDP, MCR), \ - DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, CDP, MRC), \ - DECLARE_ARM_SWI_BLOCK(EMITTER) +#define DECLARE_ARM_EMITTER_BLOCK(EMITTER) \ + DECLARE_ARM_ALU_BLOCK(EMITTER, AND, MUL, STRH, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, ANDS, MULS, LDRH, LDRSB, LDRSH), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, EOR, MLA, STRH, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, EORS, MLAS, LDRH, LDRSB, LDRSH), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, SUB, ILL, STRHI, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, SUBS, ILL, LDRHI, LDRSBI, LDRSHI), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, RSB, ILL, STRHI, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, RSBS, ILL, LDRHI, LDRSBI, LDRSHI), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, ADD, UMULL, STRHU, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, ADDS, UMULLS, LDRHU, LDRSBU, LDRSHU), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, ADC, UMLAL, STRHU, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, ADCS, UMLALS, LDRHU, LDRSBU, LDRSHU), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, SBC, SMULL, STRHIU, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, SBCS, SMULLS, LDRHIU, LDRSBIU, LDRSHIU), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, RSC, SMLAL, STRHIU, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, RSCS, SMLALS, LDRHIU, LDRSBIU, LDRSHIU), \ + DECLARE_INSTRUCTION_ARM(EMITTER, MRS), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, SWP), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, STRHP), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, TST, ILL, LDRHP, LDRSBP, LDRSHP), \ + DECLARE_INSTRUCTION_ARM(EMITTER, MSR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, BX), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, BKPT), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, STRHPW), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, TEQ, ILL, LDRHPW, LDRSBPW, LDRSHPW), \ + DECLARE_INSTRUCTION_ARM(EMITTER, MRSR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, SWPB), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, STRHIP), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, CMP, ILL, LDRHIP, LDRSBIP, LDRSHIP), \ + DECLARE_INSTRUCTION_ARM(EMITTER, MSRR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, STRHIPW), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, CMN, ILL, LDRHIPW, LDRSBIPW, LDRSHIPW), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, ORR, SMLAL, STRHPU, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, ORRS, SMLALS, LDRHPU, LDRSBPU, LDRSHPU), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, MOV, SMLAL, STRHPUW, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, MOVS, SMLALS, LDRHPUW, LDRSBPUW, \ + LDRSHPUW), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, BIC, SMLAL, STRHIPU, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, BICS, SMLALS, LDRHIPU, LDRSBIPU, \ + LDRSHIPU), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, MVN, SMLAL, STRHIPUW, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, MVNS, SMLALS, LDRHIPUW, LDRSBIPUW, \ + LDRSHIPUW), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, AND), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ANDS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, EOR), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, EORS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SUB), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SUBS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSB), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSBS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADD), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADDS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADC), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADCS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SBC), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SBCS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSC), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSCS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, TST), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, TST), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MSR), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, TEQ), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, CMP), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, CMP), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MSRR), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, CMN), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ORR), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ORRS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MOV), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MOVS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, BIC), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, BICS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MVN), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MVNS), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, , , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, , , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRT, , , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRT, , , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, , , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, , , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRBT, , , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRBT, , , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, , U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, , U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRT, , U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRT, , U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, , U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, , U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRBT, , U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRBT, , U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, , W), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, , W), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, , W), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, , W), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, U, W), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, U, W), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, U, W), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, U, W), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, , , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, , , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRT, , , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRT, , , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, , , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, , , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRBT, , , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRBT, , , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, , U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, , U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRT, , U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRT, , U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, , U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, , U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRBT, , U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRBT, , U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, , W), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, , W), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, , W), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, , W), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, U, W), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, U, W), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, U, W), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, U, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DA, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DA, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DA, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DA, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DA, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DA, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DA, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DA, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IA, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IA, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IA, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IA, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IA, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IA, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IA, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IA, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DB, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DB, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DB, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DB, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DB, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DB, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DB, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DB, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IB, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IB, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IB, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IB, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IB, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IB, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IB, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IB, W), \ + DECLARE_ARM_BRANCH_BLOCK(EMITTER, B), \ + DECLARE_ARM_BRANCH_BLOCK(EMITTER, BL), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , , ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , , ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , , W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , , W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , N, W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , N, W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, , ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, , ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, , W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, , W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, N, W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, N, W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , , ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , , ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , , W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , , W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , N, W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , N, W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, W), \ + DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, CDP, MCR), \ + DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, CDP, MRC), \ + DECLARE_ARM_SWI_BLOCK(EMITTER) #endif diff --git a/WindCore/emitter-inlines.h b/WindCore/emitter-inlines.h index 38bab70..74faa98 100644 --- a/WindCore/emitter-inlines.h +++ b/WindCore/emitter-inlines.h @@ -6,27 +6,14 @@ #ifndef EMITTER_INLINES_H #define EMITTER_INLINES_H -#define DO_4(DIRECTIVE) \ - DIRECTIVE, \ - DIRECTIVE, \ - DIRECTIVE, \ - DIRECTIVE +#define DO_4(DIRECTIVE) DIRECTIVE, DIRECTIVE, DIRECTIVE, DIRECTIVE -#define DO_8(DIRECTIVE) \ - DIRECTIVE, \ - DIRECTIVE, \ - DIRECTIVE, \ - DIRECTIVE, \ - DIRECTIVE, \ - DIRECTIVE, \ - DIRECTIVE, \ - DIRECTIVE +#define DO_8(DIRECTIVE) \ + DIRECTIVE, DIRECTIVE, DIRECTIVE, DIRECTIVE, DIRECTIVE, DIRECTIVE, DIRECTIVE, \ + DIRECTIVE -#define DO_256(DIRECTIVE) \ - DO_4(DO_8(DO_8(DIRECTIVE))) +#define DO_256(DIRECTIVE) DO_4(DO_8(DO_8(DIRECTIVE))) -#define DO_INTERLACE(LEFT, RIGHT) \ - LEFT, \ - RIGHT +#define DO_INTERLACE(LEFT, RIGHT) LEFT, RIGHT #endif diff --git a/WindCore/emubase.h b/WindCore/emubase.h index ae35d9d..ceb0018 100644 --- a/WindCore/emubase.h +++ b/WindCore/emubase.h @@ -3,135 +3,133 @@ #include enum EpocKey { - EStdKeyDial = 161, - EStdKeyOff = 160, - EStdKeyHelp = 159, - EStdKeyDictaphoneRecord = 158, - EStdKeyDictaphoneStop = 157, - EStdKeyDictaphonePlay = 156, - EStdKeySliderUp = 155, - EStdKeySliderDown = 154, - EStdKeyDecContrast = 153, - EStdKeyIncContrast = 152, - EStdKeyBacklightToggle = 151, - EStdKeyBacklightOff = 150, - EStdKeyBacklightOn = 149, - EStdKeyMenu = 148, - EStdKeyNkpFullStop = 147, - EStdKeyNkp0 = 146, - EStdKeyNkp9 = 145, - EStdKeyNkp8 = 144, - EStdKeyNkp7 = 143, - EStdKeyNkp6 = 142, - EStdKeyNkp5 = 141, - EStdKeyNkp4 = 140, - EStdKeyNkp3 = 139, - EStdKeyNkp2 = 138, - EStdKeyNkp1 = 137, - EStdKeyNkpEnter = 136, - EStdKeyNkpPlus = 135, - EStdKeyNkpMinus = 134, - EStdKeyNkpAsterisk = 133, - EStdKeyNkpForwardSlash = 132, - EStdKeyEquals = 131, - EStdKeyMinus = 130, - EStdKeySquareBracketRight = 129, - EStdKeySquareBracketLeft = 128, - EStdKeyHash = 127, - EStdKeySingleQuote = 126, - EStdKeySemiColon = 125, - EStdKeyBackSlash = 124, - EStdKeyForwardSlash = 123, - EStdKeyFullStop = 122, - EStdKeyComma = 121, - EStdKeyXXX = 120, - EStdKeyF24 = 119, - EStdKeyF23 = 118, - EStdKeyF22 = 117, - EStdKeyF21 = 116, - EStdKeyF20 = 115, - EStdKeyF19 = 114, - EStdKeyF18 = 113, - EStdKeyF17 = 112, - EStdKeyF16 = 111, - EStdKeyF15 = 110, - EStdKeyF14 = 109, - EStdKeyF13 = 108, - EStdKeyF12 = 107, - EStdKeyF11 = 106, - EStdKeyF10 = 105, - EStdKeyF9 = 104, - EStdKeyF8 = 103, - EStdKeyF7 = 102, - EStdKeyF6 = 101, - EStdKeyF5 = 100, - EStdKeyF4 = 99, - EStdKeyF3 = 98, - EStdKeyF2 = 97, - EStdKeyF1 = 96, - EStdKeyScrollLock = 28, - EStdKeyNumLock = 27, - EStdKeyCapsLock = 26, - EStdKeyRightFunc = 25, - EStdKeyLeftFunc = 24, - EStdKeyRightCtrl = 23, - EStdKeyLeftCtrl = 22, - EStdKeyRightAlt = 21, - EStdKeyLeftAlt = 20, - EStdKeyRightShift = 19, - EStdKeyLeftShift = 18, - EStdKeyDownArrow = 17, - EStdKeyUpArrow = 16, - EStdKeyRightArrow = 15, - EStdKeyLeftArrow = 14, - EStdKeyDelete = 13, - EStdKeyInsert = 12, - EStdKeyPageDown = 11, - EStdKeyPageUp = 10, - EStdKeyEnd = 9, - EStdKeyHome = 8, - EStdKeyPause = 7, - EStdKeyPrintScreen = 6, - EStdKeySpace = 5, - EStdKeyEscape = 4, - EStdKeyEnter = 3, - EStdKeyTab = 2, - EStdKeyBackspace = 1, - EStdKeyNull = 0 + EStdKeyDial = 161, + EStdKeyOff = 160, + EStdKeyHelp = 159, + EStdKeyDictaphoneRecord = 158, + EStdKeyDictaphoneStop = 157, + EStdKeyDictaphonePlay = 156, + EStdKeySliderUp = 155, + EStdKeySliderDown = 154, + EStdKeyDecContrast = 153, + EStdKeyIncContrast = 152, + EStdKeyBacklightToggle = 151, + EStdKeyBacklightOff = 150, + EStdKeyBacklightOn = 149, + EStdKeyMenu = 148, + EStdKeyNkpFullStop = 147, + EStdKeyNkp0 = 146, + EStdKeyNkp9 = 145, + EStdKeyNkp8 = 144, + EStdKeyNkp7 = 143, + EStdKeyNkp6 = 142, + EStdKeyNkp5 = 141, + EStdKeyNkp4 = 140, + EStdKeyNkp3 = 139, + EStdKeyNkp2 = 138, + EStdKeyNkp1 = 137, + EStdKeyNkpEnter = 136, + EStdKeyNkpPlus = 135, + EStdKeyNkpMinus = 134, + EStdKeyNkpAsterisk = 133, + EStdKeyNkpForwardSlash = 132, + EStdKeyEquals = 131, + EStdKeyMinus = 130, + EStdKeySquareBracketRight = 129, + EStdKeySquareBracketLeft = 128, + EStdKeyHash = 127, + EStdKeySingleQuote = 126, + EStdKeySemiColon = 125, + EStdKeyBackSlash = 124, + EStdKeyForwardSlash = 123, + EStdKeyFullStop = 122, + EStdKeyComma = 121, + EStdKeyXXX = 120, + EStdKeyF24 = 119, + EStdKeyF23 = 118, + EStdKeyF22 = 117, + EStdKeyF21 = 116, + EStdKeyF20 = 115, + EStdKeyF19 = 114, + EStdKeyF18 = 113, + EStdKeyF17 = 112, + EStdKeyF16 = 111, + EStdKeyF15 = 110, + EStdKeyF14 = 109, + EStdKeyF13 = 108, + EStdKeyF12 = 107, + EStdKeyF11 = 106, + EStdKeyF10 = 105, + EStdKeyF9 = 104, + EStdKeyF8 = 103, + EStdKeyF7 = 102, + EStdKeyF6 = 101, + EStdKeyF5 = 100, + EStdKeyF4 = 99, + EStdKeyF3 = 98, + EStdKeyF2 = 97, + EStdKeyF1 = 96, + EStdKeyScrollLock = 28, + EStdKeyNumLock = 27, + EStdKeyCapsLock = 26, + EStdKeyRightFunc = 25, + EStdKeyLeftFunc = 24, + EStdKeyRightCtrl = 23, + EStdKeyLeftCtrl = 22, + EStdKeyRightAlt = 21, + EStdKeyLeftAlt = 20, + EStdKeyRightShift = 19, + EStdKeyLeftShift = 18, + EStdKeyDownArrow = 17, + EStdKeyUpArrow = 16, + EStdKeyRightArrow = 15, + EStdKeyLeftArrow = 14, + EStdKeyDelete = 13, + EStdKeyInsert = 12, + EStdKeyPageDown = 11, + EStdKeyPageUp = 10, + EStdKeyEnd = 9, + EStdKeyHome = 8, + EStdKeyPause = 7, + EStdKeyPrintScreen = 6, + EStdKeySpace = 5, + EStdKeyEscape = 4, + EStdKeyEnter = 3, + EStdKeyTab = 2, + EStdKeyBackspace = 1, + EStdKeyNull = 0 }; -class EmuBase : public ARM710 -{ +class EmuBase : public ARM710 { protected: #ifndef __EMSCRIPTEN__ - std::unordered_set _breakpoints; + std::unordered_set _breakpoints; #endif - int64_t passedCycles = 0; - int64_t nextTickAt = 0; - uint8_t readKeyboard(int kScan); + int64_t passedCycles = 0; + int64_t nextTickAt = 0; + uint8_t readKeyboard(int kScan); public: - EmuBase(bool isTVersion) : ARM710(isTVersion) { } + EmuBase(bool isTVersion) : ARM710(isTVersion) {} - virtual uint8_t *getROMBuffer() = 0; - virtual size_t getROMSize() = 0; - virtual void loadROM(uint8_t *buffer, size_t size) = 0; - virtual void executeUntil(int64_t cycles) = 0; - virtual int32_t getClockSpeed() const = 0; - virtual const char *getDeviceName() const = 0; - virtual int getDigitiserWidth() const = 0; - virtual int getDigitiserHeight() const = 0; - virtual int getLCDOffsetX() const = 0; - virtual int getLCDOffsetY() const = 0; - virtual int getLCDWidth() const = 0; - virtual int getLCDHeight() const = 0; - virtual void readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) const = 0; - virtual void setKeyboardKey(EpocKey key, bool value) = 0; - virtual void updateTouchInput(int32_t x, int32_t y, bool down) = 0; + virtual uint8_t* getROMBuffer() = 0; + virtual size_t getROMSize() = 0; + virtual void loadROM(uint8_t* buffer, size_t size) = 0; + virtual void executeUntil(int64_t cycles) = 0; + virtual int32_t getClockSpeed() const = 0; + virtual const char* getDeviceName() const = 0; + virtual int getDigitiserWidth() const = 0; + virtual int getDigitiserHeight() const = 0; + virtual int getLCDOffsetX() const = 0; + virtual int getLCDOffsetY() const = 0; + virtual int getLCDWidth() const = 0; + virtual int getLCDHeight() const = 0; + virtual void readLCDIntoBuffer(uint8_t** lines, bool is32BitOutput) const = 0; + virtual void setKeyboardKey(EpocKey key, bool value) = 0; + virtual void updateTouchInput(int32_t x, int32_t y, bool down) = 0; #ifndef __EMSCRIPTEN__ - std::unordered_set &breakpoints() { return _breakpoints; } + std::unordered_set& breakpoints() { return _breakpoints; } #endif - uint64_t currentCycles() const { return passedCycles; } + uint64_t currentCycles() const { return passedCycles; } }; - diff --git a/WindCore/etna.cpp b/WindCore/etna.cpp index 1e7c75b..94c7ae7 100644 --- a/WindCore/etna.cpp +++ b/WindCore/etna.cpp @@ -4,153 +4,171 @@ #include enum EtnaReg { - regUnk0 = 0, - regUnk1 = 1, - regUartIntStatus = 2, - regUartIntMask = 3, - regUartBaudRateLo8 = 4, - regUartBaudRateHi4 = 5, - regPcCdIntStatus = 6, - regPcCdIntMask = 7, - regIntClear = 8, - regSktVarA0 = 9, - regSktVarA1 = 0xA, - regSktCtrl = 0xB, - regWake1 = 0xC, - regSktVarB0 = 0xD, - regSktVarB1 = 0xE, - regWake2 = 0xF + regUnk0 = 0, + regUnk1 = 1, + regUartIntStatus = 2, + regUartIntMask = 3, + regUartBaudRateLo8 = 4, + regUartBaudRateHi4 = 5, + regPcCdIntStatus = 6, + regPcCdIntMask = 7, + regIntClear = 8, + regSktVarA0 = 9, + regSktVarA1 = 0xA, + regSktCtrl = 0xB, + regWake1 = 0xC, + regSktVarB0 = 0xD, + regSktVarB1 = 0xE, + regWake2 = 0xF }; -static const char *nameReg(uint32_t reg) { - switch (reg) { - case regUnk0: return "unk0"; - case regUnk1: return "unk1"; - case regUartIntStatus: return "UartIntStatus"; - case regUartIntMask: return "UartIntMask"; - case regUartBaudRateLo8: return "UartBaudRateLo8"; - case regUartBaudRateHi4: return "UartBaudRateHi4"; - case regPcCdIntStatus: return "PcCdIntStatus"; - case regPcCdIntMask: return "PcCdIntMask"; - case regIntClear: return "IntClear"; - case regSktVarA0: return "SktVarA0"; - case regSktVarA1: return "SktVarA1"; - case regSktCtrl: return "SktCtrl"; - case regWake1: return "wake1"; - case regSktVarB0: return "SktVarB0"; - case regSktVarB1: return "SktVarB1"; - case regWake2: return "wake2"; - } - return nullptr; +static const char* nameReg(uint32_t reg) { + switch (reg) { + case regUnk0: + return "unk0"; + case regUnk1: + return "unk1"; + case regUartIntStatus: + return "UartIntStatus"; + case regUartIntMask: + return "UartIntMask"; + case regUartBaudRateLo8: + return "UartBaudRateLo8"; + case regUartBaudRateHi4: + return "UartBaudRateHi4"; + case regPcCdIntStatus: + return "PcCdIntStatus"; + case regPcCdIntMask: + return "PcCdIntMask"; + case regIntClear: + return "IntClear"; + case regSktVarA0: + return "SktVarA0"; + case regSktVarA1: + return "SktVarA1"; + case regSktCtrl: + return "SktCtrl"; + case regWake1: + return "wake1"; + case regSktVarB0: + return "SktVarB0"; + case regSktVarB1: + return "SktVarB1"; + case regWake2: + return "wake2"; + } + return nullptr; } - -Etna::Etna(ARM710 *owner) { - this->owner = owner; - - for (int i = 0; i < 0x80; i++) - prom[i] = 0; - - // defaults expected by the touchscreen code - prom[0xA] = 20; - prom[0xB] = 20; - prom[0xC] = 20; - prom[0xD] = 30; - - // some basic stuff to begin with - // set up the Psion's unique ID - prom[0x1B] = 0xDE; - prom[0x1A] = 0xAD; - prom[0x19] = 0xBE; - prom[0x18] = 0xEF; - - // give ourselves a neat custom device name - const char *key = "PSIONPSIONPSION"; - const char *name = "WindEmu!"; - prom[0x28] = strlen(name); - if (prom[0x28] > 15) - prom[0x28] = 15; - for (int i = 0; i < prom[0x28]; i++) - prom[0x29 + i] = name[i] ^ key[i]; - - // calculate the checksum - uint8_t chk = 0; - for (int i = 0; i < 0x7F; i++) - chk ^= prom[i]; - - // EPOC is expecting 66 - prom[0x7F] = chk ^ 66; +Etna::Etna(ARM710* owner) { + this->owner = owner; + + for (int i = 0; i < 0x80; i++) + prom[i] = 0; + + // defaults expected by the touchscreen code + prom[0xA] = 20; + prom[0xB] = 20; + prom[0xC] = 20; + prom[0xD] = 30; + + // some basic stuff to begin with + // set up the Psion's unique ID + prom[0x1B] = 0xDE; + prom[0x1A] = 0xAD; + prom[0x19] = 0xBE; + prom[0x18] = 0xEF; + + // give ourselves a neat custom device name + const char* key = "PSIONPSIONPSION"; + const char* name = "WindEmu!"; + prom[0x28] = strlen(name); + if (prom[0x28] > 15) + prom[0x28] = 15; + for (int i = 0; i < prom[0x28]; i++) + prom[0x29 + i] = name[i] ^ key[i]; + + // calculate the checksum + uint8_t chk = 0; + for (int i = 0; i < 0x7F; i++) + chk ^= prom[i]; + + // EPOC is expecting 66 + prom[0x7F] = chk ^ 66; } - -uint32_t Etna::readReg8(uint32_t reg) -{ -// if (!promReadActive) -// owner->log("ETNA readReg8: reg=%s @ pc=%08x,lr=%08x", nameReg(reg), owner->getGPR(15) - 4, owner->getGPR(14)); - switch (reg) { - case regIntClear: return 0; - case regSktVarA0: return 1; // will store some status flags - case regSktVarA1: return 0; // will store some more status flags - case regWake1: return wake1; - case regWake2: return wake2; - } - return 0xFF; +uint32_t Etna::readReg8(uint32_t reg) { + // if (!promReadActive) + // owner->log("ETNA readReg8: reg=%s @ pc=%08x,lr=%08x", + // nameReg(reg), owner->getGPR(15) - 4, owner->getGPR(14)); + switch (reg) { + case regIntClear: + return 0; + case regSktVarA0: + return 1; // will store some status flags + case regSktVarA1: + return 0; // will store some more status flags + case regWake1: + return wake1; + case regWake2: + return wake2; + } + return 0xFF; } -uint32_t Etna::readReg32(uint32_t reg) -{ - // may be able to remove this, p. sure Etna is byte addressing only - owner->log("ETNA readReg32: reg=%x", reg); - return 0xFFFFFFFF; -} - -void Etna::writeReg8(uint32_t reg, uint8_t value) -{ - if (!promReadActive) - owner->log("ETNA writeReg8: reg=%s value=%02x @ pc=%08x,lr=%08x", nameReg(reg), value, owner->getGPR(15) - 4, owner->getGPR(14)); - switch (reg) { - case regIntClear: pendingInterrupts &= ~value; break; - case regWake1: wake1 = value; break; - case regWake2: wake2 = value; break; - } +uint32_t Etna::readReg32(uint32_t reg) { + // may be able to remove this, p. sure Etna is byte addressing only + owner->log("ETNA readReg32: reg=%x", reg); + return 0xFFFFFFFF; } -void Etna::writeReg32(uint32_t reg, uint32_t value) -{ - // may be able to remove this, p. sure Etna is byte addressing only - owner->log("ETNA writeReg32: reg=%x value=%08x", reg, value); +void Etna::writeReg8(uint32_t reg, uint8_t value) { + if (!promReadActive) + owner->log("ETNA writeReg8: reg=%s value=%02x @ pc=%08x,lr=%08x", + nameReg(reg), value, owner->getGPR(15) - 4, owner->getGPR(14)); + switch (reg) { + case regIntClear: + pendingInterrupts &= ~value; + break; + case regWake1: + wake1 = value; + break; + case regWake2: + wake2 = value; + break; + } } -void Etna::setPromBit0High() -{ - // begin reading a word - promReadAddress = 0; - promReadValue = 0; - promAddressBitsReceived = 0; - promReadActive = true; +void Etna::writeReg32(uint32_t reg, uint32_t value) { + // may be able to remove this, p. sure Etna is byte addressing only + owner->log("ETNA writeReg32: reg=%x value=%08x", reg, value); } -void Etna::setPromBit0Low() -{ - promReadActive = false; +void Etna::setPromBit0High() { + // begin reading a word + promReadAddress = 0; + promReadValue = 0; + promAddressBitsReceived = 0; + promReadActive = true; } -void Etna::setPromBit1High() -{ - if (promAddressBitsReceived < 10) { - // we're still receiving the address - promReadAddress <<= 1; - promReadAddress |= ((wake1 & 4) >> 2); - if (++promAddressBitsReceived == 10) { - // we can fetch the value now - int addressInBytes = promReadAddress * 2; - addressInBytes %= sizeof(prom); - promReadValue = prom[addressInBytes] | (prom[addressInBytes + 1] << 8); - } - } else { - wake1 &= ~8; - if (promReadValue & 0x8000) - wake1 |= 8; - promReadValue <<= 1; +void Etna::setPromBit0Low() { promReadActive = false; } + +void Etna::setPromBit1High() { + if (promAddressBitsReceived < 10) { + // we're still receiving the address + promReadAddress <<= 1; + promReadAddress |= ((wake1 & 4) >> 2); + if (++promAddressBitsReceived == 10) { + // we can fetch the value now + int addressInBytes = promReadAddress * 2; + addressInBytes %= sizeof(prom); + promReadValue = prom[addressInBytes] | (prom[addressInBytes + 1] << 8); } + } else { + wake1 &= ~8; + if (promReadValue & 0x8000) + wake1 |= 8; + promReadValue <<= 1; + } } diff --git a/WindCore/etna.h b/WindCore/etna.h index ef42e89..f929fda 100644 --- a/WindCore/etna.h +++ b/WindCore/etna.h @@ -4,26 +4,26 @@ class ARM710; class Etna { - uint8_t prom[0x80] = {}; - uint16_t promReadAddress = 0, promReadValue = 0; - bool promReadActive = false; - int promAddressBitsReceived = 0; + uint8_t prom[0x80] = {}; + uint16_t promReadAddress = 0, promReadValue = 0; + bool promReadActive = false; + int promAddressBitsReceived = 0; - uint8_t pendingInterrupts = 0, interruptMask = 0; - uint8_t wake1 = 0, wake2 = 0; + uint8_t pendingInterrupts = 0, interruptMask = 0; + uint8_t wake1 = 0, wake2 = 0; - ARM710 *owner; + ARM710* owner; public: - Etna(ARM710 *owner); + Etna(ARM710* owner); - uint32_t readReg8(uint32_t reg); - uint32_t readReg32(uint32_t reg); - void writeReg8(uint32_t reg, uint8_t value); - void writeReg32(uint32_t reg, uint32_t value); + uint32_t readReg8(uint32_t reg); + uint32_t readReg32(uint32_t reg); + void writeReg8(uint32_t reg, uint8_t value); + void writeReg32(uint32_t reg, uint32_t value); - // PROM - void setPromBit0High(); // port B, bit 0 - void setPromBit0Low(); // port B, bit 0 - void setPromBit1High(); // port B, bit 1 + // PROM + void setPromBit0High(); // port B, bit 0 + void setPromBit0Low(); // port B, bit 0 + void setPromBit1High(); // port B, bit 1 }; diff --git a/WindCore/hardware.h b/WindCore/hardware.h index 02ac948..2f1ab0d 100644 --- a/WindCore/hardware.h +++ b/WindCore/hardware.h @@ -3,183 +3,179 @@ #include struct Timer { - ARM710 *cpu; + ARM710* cpu; - enum { - MODE_512KHZ = 1<<3, - PERIODIC = 1<<6, - ENABLED = 1<<7 - }; - int64_t nextTickAt; - uint8_t config; - uint32_t interval; - int32_t value; - int clockSpeed; + enum { MODE_512KHZ = 1 << 3, PERIODIC = 1 << 6, ENABLED = 1 << 7 }; + int64_t nextTickAt; + uint8_t config; + uint32_t interval; + int32_t value; + int clockSpeed; - int tickInterval() const { - return (config & MODE_512KHZ) ? (clockSpeed / 512000) : (clockSpeed / 2000); - } - void load(uint32_t lval) { - interval = lval; - value = lval; - } - void setConfig(uint8_t cval) { - nextTickAt -= tickInterval(); - config = cval; - nextTickAt += tickInterval(); - } - bool tick(int64_t cycles) { - if (cycles >= nextTickAt) { - nextTickAt += tickInterval(); + int tickInterval() const { + return (config & MODE_512KHZ) ? (clockSpeed / 512000) : (clockSpeed / 2000); + } + void load(uint32_t lval) { + interval = lval; + value = lval; + } + void setConfig(uint8_t cval) { + nextTickAt -= tickInterval(); + config = cval; + nextTickAt += tickInterval(); + } + bool tick(int64_t cycles) { + if (cycles >= nextTickAt) { + nextTickAt += tickInterval(); - if (config & ENABLED) { - --value; - if (value == 0) { - if (config & PERIODIC) - value = interval; - return true; - } - } - } - return false; - } - void dump() { - printf("enabled=%s periodic=%s interval=%d value=%d\n", - (config & ENABLED) ? "true" : "false", - (config & PERIODIC) ? "true" : "false", - interval, value - ); - } + if (config & ENABLED) { + --value; + if (value == 0) { + if (config & PERIODIC) + value = interval; + return true; + } + } + } + return false; + } + void dump() { + printf("enabled=%s periodic=%s interval=%d value=%d\n", + (config & ENABLED) ? "true" : "false", + (config & PERIODIC) ? "true" : "false", interval, value); + } }; enum UartRegs { - UART0DATA = 0x600, - UART0FCR = 0x604, - UART0LCR = 0x608, - UART0CON = 0x60C, - UART0FLG = 0x610, - UART0INT = 0x614, - UART0INTM = 0x618, - UART0INTR = 0x61C, - UART0TEST1 = 0x620, - UART0TEST2 = 0x624, - UART0TEST3 = 0x628, - UART1DATA = 0x700, - UART1FCR = 0x704, - UART1LCR = 0x708, - UART1CON = 0x70C, - UART1FLG = 0x710, - UART1INT = 0x714, - UART1INTM = 0x718, - UART1INTR = 0x71C, - UART1TEST1 = 0x720, - UART1TEST2 = 0x724, - UART1TEST3 = 0x728, + UART0DATA = 0x600, + UART0FCR = 0x604, + UART0LCR = 0x608, + UART0CON = 0x60C, + UART0FLG = 0x610, + UART0INT = 0x614, + UART0INTM = 0x618, + UART0INTR = 0x61C, + UART0TEST1 = 0x620, + UART0TEST2 = 0x624, + UART0TEST3 = 0x628, + UART1DATA = 0x700, + UART1FCR = 0x704, + UART1LCR = 0x708, + UART1CON = 0x70C, + UART1FLG = 0x710, + UART1INT = 0x714, + UART1INTM = 0x718, + UART1INTR = 0x71C, + UART1TEST1 = 0x720, + UART1TEST2 = 0x724, + UART1TEST3 = 0x728, }; struct UART { - ARM710 *cpu; + ARM710* cpu; - enum { - IntRx = 1, - IntTx = 2, - IntModemStatus = 4, - PortCtrlEnable = 1, - PortCtrlSirEnable = 2, - PortCtrlIrdaTx = 4, - FrameCtrlBreak = 1, - FrameCtrlParityEnable = 2, - FrameCtrlEvenParity = 4, - FrameCtrlExtraStopBit = 8, - FrameCtrlUFifoEn = 0x10, - FrameCtrlWrdLenMask = 0x60, - FrameCtrlWlen5 = 0, - FrameCtrlWlen6 = 0x20, - FrameCtrlWlen7 = 0x40, - FrameCtrlWlen8 = 0x60, - RecvFrameError = 0x100, - RecvParityError = 0x200, - RecvOverrunError = 0x400, - FlagClearToSend = 1, - FlagDataSetReady = 2, - FlagDataCarrierDetect = 4, - FlagBusy = 8, - FlagReceiveFifoEmpty = 0x10, - FlagTransmitFifoFull = 0x20 - }; - uint8_t portControl = 0; - uint8_t frameControl = 0; - uint8_t interrupts = 0, interruptMask = 0; + enum { + IntRx = 1, + IntTx = 2, + IntModemStatus = 4, + PortCtrlEnable = 1, + PortCtrlSirEnable = 2, + PortCtrlIrdaTx = 4, + FrameCtrlBreak = 1, + FrameCtrlParityEnable = 2, + FrameCtrlEvenParity = 4, + FrameCtrlExtraStopBit = 8, + FrameCtrlUFifoEn = 0x10, + FrameCtrlWrdLenMask = 0x60, + FrameCtrlWlen5 = 0, + FrameCtrlWlen6 = 0x20, + FrameCtrlWlen7 = 0x40, + FrameCtrlWlen8 = 0x60, + RecvFrameError = 0x100, + RecvParityError = 0x200, + RecvOverrunError = 0x400, + FlagClearToSend = 1, + FlagDataSetReady = 2, + FlagDataCarrierDetect = 4, + FlagBusy = 8, + FlagReceiveFifoEmpty = 0x10, + FlagTransmitFifoFull = 0x20 + }; + uint8_t portControl = 0; + uint8_t frameControl = 0; + uint8_t interrupts = 0, interruptMask = 0; - // UART0DATA = 0x600, byte write, long read - // UART0FCR = 0x604, long - // UART0LCR = 0x608, long - // UART0CON = 0x60C, byte - // UART0FLG = 0x610, byte - // UART0INT = 0x614, long write, byte read - // UART0INTM = 0x618, byte - // UART0INTR = 0x61C, byte - // UART0TEST1 = 0x620, - // UART0TEST2 = 0x624, - // UART0TEST3 = 0x628, - uint32_t readReg8(uint32_t reg) { - // UART0DATA - if (reg == (UART0CON & 0xFF)) { - return portControl; - } else if (reg == (UART0FLG & 0xFF)) { - // we pretend we are never busy, never have full fifo - return FlagReceiveFifoEmpty; - // UART0INT? - // UART0INTM? - // UART0INTR? - } else { - printf("unhandled 8bit uart read %x at pc=%08x lr=%08x\n", reg, cpu->getGPR(15), cpu->getGPR(14)); - return 0xFF; - } - } - uint32_t readReg32(uint32_t reg) { - // UART0DATA - if (reg == (UART0FCR & 0xFF)) { - return frameControl; - // UART0LCR - } else if (reg == (UART0FLG & 0xFF)) { - // we pretend we are never busy, never have full fifo - return FlagReceiveFifoEmpty; - } else { - printf("unhandled 32bit uart read %x at pc=%08x lr=%08x\n", reg, cpu->getGPR(15), cpu->getGPR(14)); - return 0xFFFFFFFF; - } - } - void writeReg8(uint32_t reg, uint8_t value) { - // UART0DATA - if (reg == (UART0CON & 0xFF)) { - portControl = value; - printf("portcon updated: enable=%d sirenable=%d irdatx=%d\n", value&1, value&2, value&4); - } else if (reg == (UART0INTM & 0xFF)) { - interruptMask = value; - printf("uart interruptmask updated: %d\n", value); - // UART0INTR? - } else { - printf("unhandled 8bit uart write %x value %02x at pc=%08x lr=%08x\n", reg, value, cpu->getGPR(15), cpu->getGPR(14)); - } - } - void writeReg32(uint32_t reg, uint32_t value) { - if (reg == (UART0FCR & 0xFF)) { - frameControl = value; - printf("frameControl updated: break=%d parityEn=%d evenParity=%d extraStop=%d ufifoEn=%d wrdLen=%d\n", - value&1, - value&2, - value&4, - value&8, - value&0x10, - ((value&0x60)>>5)+5); - } else if (reg == (UART0LCR & 0xFF)) { - printf("** uart writing lcr %x **\n", value); - } else if (reg == (UART0INT & 0xFF)) { - printf("uart interrupts %x -> %x\n", interrupts, value); - interrupts = value; - } else { - printf("unhandled 32bit uart write %x value %08x at pc=%08x lr=%08x\n", reg, value, cpu->getGPR(15), cpu->getGPR(14)); - } - } + // UART0DATA = 0x600, byte write, long read + // UART0FCR = 0x604, long + // UART0LCR = 0x608, long + // UART0CON = 0x60C, byte + // UART0FLG = 0x610, byte + // UART0INT = 0x614, long write, byte read + // UART0INTM = 0x618, byte + // UART0INTR = 0x61C, byte + // UART0TEST1 = 0x620, + // UART0TEST2 = 0x624, + // UART0TEST3 = 0x628, + uint32_t readReg8(uint32_t reg) { + // UART0DATA + if (reg == (UART0CON & 0xFF)) { + return portControl; + } else if (reg == (UART0FLG & 0xFF)) { + // we pretend we are never busy, never have full fifo + return FlagReceiveFifoEmpty; + // UART0INT? + // UART0INTM? + // UART0INTR? + } else { + printf("unhandled 8bit uart read %x at pc=%08x lr=%08x\n", reg, + cpu->getGPR(15), cpu->getGPR(14)); + return 0xFF; + } + } + uint32_t readReg32(uint32_t reg) { + // UART0DATA + if (reg == (UART0FCR & 0xFF)) { + return frameControl; + // UART0LCR + } else if (reg == (UART0FLG & 0xFF)) { + // we pretend we are never busy, never have full fifo + return FlagReceiveFifoEmpty; + } else { + printf("unhandled 32bit uart read %x at pc=%08x lr=%08x\n", reg, + cpu->getGPR(15), cpu->getGPR(14)); + return 0xFFFFFFFF; + } + } + void writeReg8(uint32_t reg, uint8_t value) { + // UART0DATA + if (reg == (UART0CON & 0xFF)) { + portControl = value; + printf("portcon updated: enable=%d sirenable=%d irdatx=%d\n", value & 1, + value & 2, value & 4); + } else if (reg == (UART0INTM & 0xFF)) { + interruptMask = value; + printf("uart interruptmask updated: %d\n", value); + // UART0INTR? + } else { + printf("unhandled 8bit uart write %x value %02x at pc=%08x lr=%08x\n", + reg, value, cpu->getGPR(15), cpu->getGPR(14)); + } + } + void writeReg32(uint32_t reg, uint32_t value) { + if (reg == (UART0FCR & 0xFF)) { + frameControl = value; + printf("frameControl updated: break=%d parityEn=%d evenParity=%d " + "extraStop=%d ufifoEn=%d wrdLen=%d\n", + value & 1, value & 2, value & 4, value & 8, value & 0x10, + ((value & 0x60) >> 5) + 5); + } else if (reg == (UART0LCR & 0xFF)) { + printf("** uart writing lcr %x **\n", value); + } else if (reg == (UART0INT & 0xFF)) { + printf("uart interrupts %x -> %x\n", interrupts, value); + interrupts = value; + } else { + printf("unhandled 32bit uart write %x value %08x at pc=%08x lr=%08x\n", + reg, value, cpu->getGPR(15), cpu->getGPR(14)); + } + } }; diff --git a/WindCore/isa-inlines.h b/WindCore/isa-inlines.h index d13aabe..b87896d 100644 --- a/WindCore/isa-inlines.h +++ b/WindCore/isa-inlines.h @@ -9,14 +9,18 @@ #include "macros.h" #define ARM_SIGN(I) ((I) >> 31) -#define ARM_SXT_8(I) (((int8_t) (I) << 24) >> 24) -#define ARM_SXT_16(I) (((int16_t) (I) << 16) >> 16) -#define ARM_UXT_64(I) (uint64_t)(uint32_t) (I) +#define ARM_SXT_8(I) (((int8_t)(I) << 24) >> 24) +#define ARM_SXT_16(I) (((int16_t)(I) << 16) >> 16) +#define ARM_UXT_64(I) (uint64_t)(uint32_t)(I) -#define ARM_CARRY_FROM(M, N, D) (((uint32_t) (M) >> 31) + ((uint32_t) (N) >> 31) > ((uint32_t) (D) >> 31)) -#define ARM_BORROW_FROM(M, N, D) (((uint32_t) (M)) >= ((uint32_t) (N))) -#define ARM_BORROW_FROM_CARRY(M, N, D, C) (ARM_UXT_64(M) >= (ARM_UXT_64(N)) + (uint64_t) (C)) -#define ARM_V_ADDITION(M, N, D) (!(ARM_SIGN((M) ^ (N))) && (ARM_SIGN((M) ^ (D)))) -#define ARM_V_SUBTRACTION(M, N, D) ((ARM_SIGN((M) ^ (N))) && (ARM_SIGN((M) ^ (D)))) +#define ARM_CARRY_FROM(M, N, D) \ + (((uint32_t)(M) >> 31) + ((uint32_t)(N) >> 31) > ((uint32_t)(D) >> 31)) +#define ARM_BORROW_FROM(M, N, D) (((uint32_t)(M)) >= ((uint32_t)(N))) +#define ARM_BORROW_FROM_CARRY(M, N, D, C) \ + (ARM_UXT_64(M) >= (ARM_UXT_64(N)) + (uint64_t)(C)) +#define ARM_V_ADDITION(M, N, D) \ + (!(ARM_SIGN((M) ^ (N))) && (ARM_SIGN((M) ^ (D)))) +#define ARM_V_SUBTRACTION(M, N, D) \ + ((ARM_SIGN((M) ^ (N))) && (ARM_SIGN((M) ^ (D)))) #endif diff --git a/WindCore/wind_defs.h b/WindCore/wind_defs.h index 9d74b8d..571500a 100644 --- a/WindCore/wind_defs.h +++ b/WindCore/wind_defs.h @@ -2,92 +2,89 @@ #include namespace Windermere { -enum { - CLOCK_SPEED = 0x9000*1000, - TICK_INTERVAL = CLOCK_SPEED / 64 -}; +enum { CLOCK_SPEED = 0x9000 * 1000, TICK_INTERVAL = CLOCK_SPEED / 64 }; enum Interrupt { - EXTFIQ = 0, // FiqExternal - BLINT = 1, // FiqBatLow - WEINT = 2, // FiqWatchDog - MCINT = 3, // FiqMediaChg - CSINT = 4, // IrqCodec - EINT1 = 5, // IrqExt1 - EINT2 = 6, // IrqExt2 - EINT3 = 7, // IrqExt3 - TC1OI = 8, // IrqTimer1 - TC2OI = 9, // IrqTimer2 - RTCMI = 10, // IrqRtcMatch - TINT = 11, // IrqTick - UART1 = 12, // IrqUart1 - UART2 = 13, // IrqUart1 - LCDINT = 14, // IrqLcd - SSEOTI = 15, // IrqSpi - FIQ_INTERRUPTS = 0x000F, - IRQ_INTERRUPTS = 0xFFF0 + EXTFIQ = 0, // FiqExternal + BLINT = 1, // FiqBatLow + WEINT = 2, // FiqWatchDog + MCINT = 3, // FiqMediaChg + CSINT = 4, // IrqCodec + EINT1 = 5, // IrqExt1 + EINT2 = 6, // IrqExt2 + EINT3 = 7, // IrqExt3 + TC1OI = 8, // IrqTimer1 + TC2OI = 9, // IrqTimer2 + RTCMI = 10, // IrqRtcMatch + TINT = 11, // IrqTick + UART1 = 12, // IrqUart1 + UART2 = 13, // IrqUart1 + LCDINT = 14, // IrqLcd + SSEOTI = 15, // IrqSpi + FIQ_INTERRUPTS = 0x000F, + IRQ_INTERRUPTS = 0xFFF0 }; enum Register { - MEMCFG1 = 0, - MEMCFG2 = 4, - DRAM_CFG = 0x100, - LCDCTL = 0x200, - LCDST = 0x204, - LCD_DBAR1 = 0x210, - LCDT0 = 0x220, - LCDT1 = 0x224, - LCDT2 = 0x228, - PWRSR = 0x400, - PWRCNT = 0x404, - HALT = 0x408, - STBY = 0x40C, - BLEOI = 0x410, - MCEOI = 0x414, - TEOI = 0x418, - STFCLR = 0x41C, - E2EOI = 0x420, - INTSR = 0x500, - INTRSR = 0x504, - INTENS = 0x508, - INTENC = 0x50C, - INTTEST1 = 0x514, - INTTEST2 = 0x518, - PUMPCON = 0x900, - CODR = 0xA00, - CONFG = 0xA04, - COLFG = 0xA08, - COEOI = 0xA0C, - COTEST = 0xA10, - SSCR0 = 0xB00, - SSCR1 = 0xB04, - SSDR = 0xB0C, - SSSR = 0xB14, - TC1LOAD = 0xC00, - TC1VAL = 0xC04, - TC1CTRL = 0xC08, - TC1EOI = 0xC0C, - TC2LOAD = 0xC20, - TC2VAL = 0xC24, - TC2CTRL = 0xC28, - TC2EOI = 0xC2C, - BZCONT = 0xC40, - RTCDRL = 0xD00, - RTCDRU = 0xD04, - RTCMRL = 0xD08, - RTCMRU = 0xD0C, - RTCEOI = 0xD10, - PADR = 0xE00, - PBDR = 0xE04, - PCDR = 0xE08, - PDDR = 0xE0C, - PADDR = 0xE10, - PBDDR = 0xE14, - PCDDR = 0xE18, - PDDDR = 0xE1C, - PEDR = 0xE20, - PEDDR = 0xE24, - KSCAN = 0xE28, - LCDMUX = 0xE2C + MEMCFG1 = 0, + MEMCFG2 = 4, + DRAM_CFG = 0x100, + LCDCTL = 0x200, + LCDST = 0x204, + LCD_DBAR1 = 0x210, + LCDT0 = 0x220, + LCDT1 = 0x224, + LCDT2 = 0x228, + PWRSR = 0x400, + PWRCNT = 0x404, + HALT = 0x408, + STBY = 0x40C, + BLEOI = 0x410, + MCEOI = 0x414, + TEOI = 0x418, + STFCLR = 0x41C, + E2EOI = 0x420, + INTSR = 0x500, + INTRSR = 0x504, + INTENS = 0x508, + INTENC = 0x50C, + INTTEST1 = 0x514, + INTTEST2 = 0x518, + PUMPCON = 0x900, + CODR = 0xA00, + CONFG = 0xA04, + COLFG = 0xA08, + COEOI = 0xA0C, + COTEST = 0xA10, + SSCR0 = 0xB00, + SSCR1 = 0xB04, + SSDR = 0xB0C, + SSSR = 0xB14, + TC1LOAD = 0xC00, + TC1VAL = 0xC04, + TC1CTRL = 0xC08, + TC1EOI = 0xC0C, + TC2LOAD = 0xC20, + TC2VAL = 0xC24, + TC2CTRL = 0xC28, + TC2EOI = 0xC2C, + BZCONT = 0xC40, + RTCDRL = 0xD00, + RTCDRU = 0xD04, + RTCMRL = 0xD08, + RTCMRU = 0xD0C, + RTCEOI = 0xD10, + PADR = 0xE00, + PBDR = 0xE04, + PCDR = 0xE08, + PDDR = 0xE0C, + PADDR = 0xE10, + PBDDR = 0xE14, + PCDDR = 0xE18, + PDDDR = 0xE1C, + PEDR = 0xE20, + PEDDR = 0xE24, + KSCAN = 0xE28, + LCDMUX = 0xE2C }; -} +} // namespace Windermere diff --git a/WindCore/windermere.cpp b/WindCore/windermere.cpp index 41bbe70..e8a28a0 100644 --- a/WindCore/windermere.cpp +++ b/WindCore/windermere.cpp @@ -1,756 +1,908 @@ #include "windermere.h" -#include "wind_defs.h" +#include "common.h" #include "hardware.h" +#include "wind_defs.h" #include -#include "common.h" - -//#define INCLUDE_D -//#define INCLUDE_BANK1 +// #define INCLUDE_D +// #define INCLUDE_BANK1 namespace Windermere { -Emulator::Emulator() : EmuBase(true), etna(this) { -} - - -uint32_t Emulator::getRTC() { - return time(nullptr) - 946684800; -} +Emulator::Emulator() : EmuBase(true), etna(this) {} +uint32_t Emulator::getRTC() { return time(nullptr) - 946684800; } uint32_t Emulator::readReg8(uint32_t reg) { - if ((reg & 0xF00) == 0x600) { - return uart1.readReg8(reg & 0xFF); - } else if ((reg & 0xF00) == 0x700) { - return uart2.readReg8(reg & 0xFF); - } else if (reg == TC1CTRL) { - return tc1.config; - } else if (reg == TC2CTRL) { - return tc2.config; - } else if (reg == PADR) { - return readKeyboard(); - } else if (reg == PBDR) { - return (portValues >> 16) & 0xFF; - } else if (reg == PCDR) { - return (portValues >> 8) & 0xFF; - } else if (reg == PDDR) { - return portValues & 0xFF; - } else if (reg == PADDR) { - return (portDirections >> 24) & 0xFF; - } else if (reg == PBDDR) { - return (portDirections >> 16) & 0xFF; - } else if (reg == PCDDR) { - return (portDirections >> 8) & 0xFF; - } else if (reg == PDDDR) { - return portDirections & 0xFF; - } else { -// printf("RegRead8 unknown:: pc=%08x lr=%08x reg=%03x\n", getGPR(15)-4, getGPR(14), reg); - return 0xFF; - } + if ((reg & 0xF00) == 0x600) { + return uart1.readReg8(reg & 0xFF); + } else if ((reg & 0xF00) == 0x700) { + return uart2.readReg8(reg & 0xFF); + } else if (reg == TC1CTRL) { + return tc1.config; + } else if (reg == TC2CTRL) { + return tc2.config; + } else if (reg == PADR) { + return readKeyboard(); + } else if (reg == PBDR) { + return (portValues >> 16) & 0xFF; + } else if (reg == PCDR) { + return (portValues >> 8) & 0xFF; + } else if (reg == PDDR) { + return portValues & 0xFF; + } else if (reg == PADDR) { + return (portDirections >> 24) & 0xFF; + } else if (reg == PBDDR) { + return (portDirections >> 16) & 0xFF; + } else if (reg == PCDDR) { + return (portDirections >> 8) & 0xFF; + } else if (reg == PDDDR) { + return portDirections & 0xFF; + } else { + // printf("RegRead8 unknown:: pc=%08x lr=%08x reg=%03x\n", + // getGPR(15)-4, getGPR(14), reg); + return 0xFF; + } } uint32_t Emulator::readReg32(uint32_t reg) { - if (reg == LCDCTL) { - printf("LCD control read pc=%08x lr=%08x !!!\n", getGPR(15), getGPR(14)); - return lcdControl; - } else if (reg == LCDST) { - printf("LCD state read pc=%08x lr=%08x !!!\n", getGPR(15), getGPR(14)); - return 0xFFFFFFFF; - } else if (reg == PWRSR) { -// printf("!!! PWRSR read pc=%08x lr=%08x !!!\n", getGPR(15), getGPR(14)); - return pwrsr; - } else if (reg == INTSR) { - return pendingInterrupts & interruptMask; - } else if (reg == INTRSR) { - return pendingInterrupts; - } else if (reg == INTENS) { - return interruptMask; - } else if ((reg & 0xF00) == 0x600) { - return uart1.readReg32(reg & 0xFF); - } else if ((reg & 0xF00) == 0x700) { - return uart2.readReg32(reg & 0xFF); - } else if (reg == TC1VAL) { - return tc1.value; - } else if (reg == TC2VAL) { - return tc2.value; - } else if (reg == SSDR) { - // as per 5000A7B0 in 5mx rom - uint16_t ssiValue = 0; - switch (lastSSIRequest) { - case 0xD0D3: ssiValue = (uint16_t)(50 + (touchX * 5.7)); break; - case 0x9093: ssiValue = (uint16_t)(3834 - (touchY * 13.225)); break; - case 0xA4A4: ssiValue = 3100; break; // MainBattery - case 0xE4E4: ssiValue = 3100; break; // BackupBattery - } - - uint32_t ret = 0; - if (ssiReadCounter == 4) ret = (ssiValue >> 5) & 0x7F; - if (ssiReadCounter == 5) ret = (ssiValue << 3) & 0xF8; - ssiReadCounter++; - if (ssiReadCounter == 6) ssiReadCounter = 0; - - // by hardware we should be clearing SSEOTI here, i think - // but we just leave it on to simplify things - return ret; - } else if (reg == SSSR) { - return 0; - } else if (reg == RTCDRL) { - uint16_t v = rtc & 0xFFFF; -// log("RTCDRL: %04x", v); - return v; - } else if (reg == RTCDRU) { - uint16_t v = rtc >> 16; -// log("RTCDRU: %04x", v); - return v; - } else if (reg == KSCAN) { - return kScan; - } else { -// printf("RegRead32 unknown:: pc=%08x lr=%08x reg=%03x\n", getGPR(15)-4, getGPR(14), reg); - return 0xFFFFFFFF; - } + if (reg == LCDCTL) { + printf("LCD control read pc=%08x lr=%08x !!!\n", getGPR(15), getGPR(14)); + return lcdControl; + } else if (reg == LCDST) { + printf("LCD state read pc=%08x lr=%08x !!!\n", getGPR(15), getGPR(14)); + return 0xFFFFFFFF; + } else if (reg == PWRSR) { + // printf("!!! PWRSR read pc=%08x lr=%08x !!!\n", getGPR(15), + // getGPR(14)); + return pwrsr; + } else if (reg == INTSR) { + return pendingInterrupts & interruptMask; + } else if (reg == INTRSR) { + return pendingInterrupts; + } else if (reg == INTENS) { + return interruptMask; + } else if ((reg & 0xF00) == 0x600) { + return uart1.readReg32(reg & 0xFF); + } else if ((reg & 0xF00) == 0x700) { + return uart2.readReg32(reg & 0xFF); + } else if (reg == TC1VAL) { + return tc1.value; + } else if (reg == TC2VAL) { + return tc2.value; + } else if (reg == SSDR) { + // as per 5000A7B0 in 5mx rom + uint16_t ssiValue = 0; + switch (lastSSIRequest) { + case 0xD0D3: + ssiValue = (uint16_t)(50 + (touchX * 5.7)); + break; + case 0x9093: + ssiValue = (uint16_t)(3834 - (touchY * 13.225)); + break; + case 0xA4A4: + ssiValue = 3100; + break; // MainBattery + case 0xE4E4: + ssiValue = 3100; + break; // BackupBattery + } + + uint32_t ret = 0; + if (ssiReadCounter == 4) + ret = (ssiValue >> 5) & 0x7F; + if (ssiReadCounter == 5) + ret = (ssiValue << 3) & 0xF8; + ssiReadCounter++; + if (ssiReadCounter == 6) + ssiReadCounter = 0; + + // by hardware we should be clearing SSEOTI here, i think + // but we just leave it on to simplify things + return ret; + } else if (reg == SSSR) { + return 0; + } else if (reg == RTCDRL) { + uint16_t v = rtc & 0xFFFF; + // log("RTCDRL: %04x", v); + return v; + } else if (reg == RTCDRU) { + uint16_t v = rtc >> 16; + // log("RTCDRU: %04x", v); + return v; + } else if (reg == KSCAN) { + return kScan; + } else { + // printf("RegRead32 unknown:: pc=%08x lr=%08x reg=%03x\n", + // getGPR(15)-4, getGPR(14), reg); + return 0xFFFFFFFF; + } } void Emulator::writeReg8(uint32_t reg, uint8_t value) { - if ((reg & 0xF00) == 0x600) { - uart1.writeReg8(reg & 0xFF, value); - } else if ((reg & 0xF00) == 0x700) { - uart2.writeReg8(reg & 0xFF, value); - } else if (reg == TC1CTRL) { - tc1.setConfig(value); - } else if (reg == TC2CTRL) { - tc2.setConfig(value); - } else if (reg == PADR) { - uint32_t oldPorts = portValues; - portValues &= 0x00FFFFFF; - portValues |= (uint32_t)value << 24; - diffPorts(oldPorts, portValues); - } else if (reg == PBDR) { - uint32_t oldPorts = portValues; - portValues &= 0xFF00FFFF; - portValues |= (uint32_t)value << 16; - if ((portValues & 0x10000) && !(oldPorts & 0x10000)) - etna.setPromBit0High(); - else if (!(portValues & 0x10000) && (oldPorts & 0x10000)) - etna.setPromBit0Low(); - if ((portValues & 0x20000) && !(oldPorts & 0x20000)) - etna.setPromBit1High(); - diffPorts(oldPorts, portValues); - } else if (reg == PCDR) { - uint32_t oldPorts = portValues; - portValues &= 0xFFFF00FF; - portValues |= (uint32_t)value << 8; - diffPorts(oldPorts, portValues); - } else if (reg == PDDR) { - uint32_t oldPorts = portValues; - portValues &= 0xFFFFFF00; - portValues |= (uint32_t)value; - diffPorts(oldPorts, portValues); - } else if (reg == PADDR) { - portDirections &= 0x00FFFFFF; - portDirections |= (uint32_t)value << 24; - } else if (reg == PBDDR) { - portDirections &= 0xFF00FFFF; - portDirections |= (uint32_t)value << 16; - } else if (reg == PCDDR) { - portDirections &= 0xFFFF00FF; - portDirections |= (uint32_t)value << 8; - } else if (reg == PDDDR) { - portDirections &= 0xFFFFFF00; - portDirections |= (uint32_t)value; - } else if (reg == KSCAN) { - kScan = value; - } else { -// printf("RegWrite8 unknown:: pc=%08x reg=%03x value=%02x\n", getGPR(15)-4, reg, value); - } + if ((reg & 0xF00) == 0x600) { + uart1.writeReg8(reg & 0xFF, value); + } else if ((reg & 0xF00) == 0x700) { + uart2.writeReg8(reg & 0xFF, value); + } else if (reg == TC1CTRL) { + tc1.setConfig(value); + } else if (reg == TC2CTRL) { + tc2.setConfig(value); + } else if (reg == PADR) { + uint32_t oldPorts = portValues; + portValues &= 0x00FFFFFF; + portValues |= (uint32_t)value << 24; + diffPorts(oldPorts, portValues); + } else if (reg == PBDR) { + uint32_t oldPorts = portValues; + portValues &= 0xFF00FFFF; + portValues |= (uint32_t)value << 16; + if ((portValues & 0x10000) && !(oldPorts & 0x10000)) + etna.setPromBit0High(); + else if (!(portValues & 0x10000) && (oldPorts & 0x10000)) + etna.setPromBit0Low(); + if ((portValues & 0x20000) && !(oldPorts & 0x20000)) + etna.setPromBit1High(); + diffPorts(oldPorts, portValues); + } else if (reg == PCDR) { + uint32_t oldPorts = portValues; + portValues &= 0xFFFF00FF; + portValues |= (uint32_t)value << 8; + diffPorts(oldPorts, portValues); + } else if (reg == PDDR) { + uint32_t oldPorts = portValues; + portValues &= 0xFFFFFF00; + portValues |= (uint32_t)value; + diffPorts(oldPorts, portValues); + } else if (reg == PADDR) { + portDirections &= 0x00FFFFFF; + portDirections |= (uint32_t)value << 24; + } else if (reg == PBDDR) { + portDirections &= 0xFF00FFFF; + portDirections |= (uint32_t)value << 16; + } else if (reg == PCDDR) { + portDirections &= 0xFFFF00FF; + portDirections |= (uint32_t)value << 8; + } else if (reg == PDDDR) { + portDirections &= 0xFFFFFF00; + portDirections |= (uint32_t)value; + } else if (reg == KSCAN) { + kScan = value; + } else { + // printf("RegWrite8 unknown:: pc=%08x reg=%03x value=%02x\n", + // getGPR(15)-4, reg, value); + } } void Emulator::writeReg32(uint32_t reg, uint32_t value) { - if (reg == LCDCTL) { - printf("LCD: ctl write %08x\n", value); - lcdControl = value; - } else if (reg == LCD_DBAR1) { - printf("LCD: address write %08x\n", value); - lcdAddress = value; - } else if (reg == LCDT0) { - printf("LCD: horz timing write %08x\n", value); - } else if (reg == LCDT1) { - printf("LCD: vert timing write %08x\n", value); - } else if (reg == LCDT2) { - printf("LCD: clocks write %08x\n", value); - } else if (reg == INTENS) { -// diffInterrupts(interruptMask, interruptMask | value); - interruptMask |= value; - } else if (reg == INTENC) { -// diffInterrupts(interruptMask, interruptMask &~ value); - interruptMask &= ~value; - } else if (reg == HALT) { - halted = true; - // BLEOI = 0x410, - // MCEOI = 0x414, - } else if (reg == TEOI) { - pendingInterrupts &= ~(1 << TINT); - // TEOI = 0x418, - // STFCLR = 0x41C, - // E2EOI = 0x420, - } else if ((reg & 0xF00) == 0x600) { - uart1.writeReg32(reg & 0xFF, value); - } else if ((reg & 0xF00) == 0x700) { - uart2.writeReg32(reg & 0xFF, value); - } else if (reg == SSDR) { - if (value != 0) - lastSSIRequest = (lastSSIRequest >> 8) | (value & 0xFF00); - } else if (reg == TC1LOAD) { - tc1.load(value); - } else if (reg == TC1EOI) { - pendingInterrupts &= ~(1 << TC1OI); - } else if (reg == TC2LOAD) { - tc2.load(value); - } else if (reg == TC2EOI) { - pendingInterrupts &= ~(1 << TC2OI); - } else if (reg == RTCDRL) { - rtc &= 0xFFFF0000; - rtc |= (value & 0xFFFF); - log("RTC write lower: %04x", value); - } else if (reg == RTCDRU) { - rtc &= 0x0000FFFF; - rtc |= (value & 0xFFFF) << 16; - log("RTC write upper: %04x", value); - } else { -// printf("RegWrite32 unknown:: pc=%08x reg=%03x value=%08x\n", getGPR(15)-4, reg, value); - } + if (reg == LCDCTL) { + printf("LCD: ctl write %08x\n", value); + lcdControl = value; + } else if (reg == LCD_DBAR1) { + printf("LCD: address write %08x\n", value); + lcdAddress = value; + } else if (reg == LCDT0) { + printf("LCD: horz timing write %08x\n", value); + } else if (reg == LCDT1) { + printf("LCD: vert timing write %08x\n", value); + } else if (reg == LCDT2) { + printf("LCD: clocks write %08x\n", value); + } else if (reg == INTENS) { + // diffInterrupts(interruptMask, interruptMask | value); + interruptMask |= value; + } else if (reg == INTENC) { + // diffInterrupts(interruptMask, interruptMask &~ value); + interruptMask &= ~value; + } else if (reg == HALT) { + halted = true; + // BLEOI = 0x410, + // MCEOI = 0x414, + } else if (reg == TEOI) { + pendingInterrupts &= ~(1 << TINT); + // TEOI = 0x418, + // STFCLR = 0x41C, + // E2EOI = 0x420, + } else if ((reg & 0xF00) == 0x600) { + uart1.writeReg32(reg & 0xFF, value); + } else if ((reg & 0xF00) == 0x700) { + uart2.writeReg32(reg & 0xFF, value); + } else if (reg == SSDR) { + if (value != 0) + lastSSIRequest = (lastSSIRequest >> 8) | (value & 0xFF00); + } else if (reg == TC1LOAD) { + tc1.load(value); + } else if (reg == TC1EOI) { + pendingInterrupts &= ~(1 << TC1OI); + } else if (reg == TC2LOAD) { + tc2.load(value); + } else if (reg == TC2EOI) { + pendingInterrupts &= ~(1 << TC2OI); + } else if (reg == RTCDRL) { + rtc &= 0xFFFF0000; + rtc |= (value & 0xFFFF); + log("RTC write lower: %04x", value); + } else if (reg == RTCDRU) { + rtc &= 0x0000FFFF; + rtc |= (value & 0xFFFF) << 16; + log("RTC write upper: %04x", value); + } else { + // printf("RegWrite32 unknown:: pc=%08x reg=%03x value=%08x\n", + // getGPR(15)-4, reg, value); + } } MaybeU32 Emulator::readPhysical(uint32_t physAddr, ValueSize valueSize) { - uint8_t region = (physAddr >> 24) & 0xF1; - if (valueSize == V8) { - if (region == 0) - return ROM[physAddr & 0xFFFFFF]; - else if (region == 0x10) - return ROM2[physAddr & 0x3FFFF]; - else if (region == 0x20 && physAddr <= 0x20000FFF) - return etna.readReg8(physAddr & 0xFFF); - else if (region == 0x80 && physAddr <= 0x80000FFF) - return readReg8(physAddr & 0xFFF); + uint8_t region = (physAddr >> 24) & 0xF1; + if (valueSize == V8) { + if (region == 0) + return ROM[physAddr & 0xFFFFFF]; + else if (region == 0x10) + return ROM2[physAddr & 0x3FFFF]; + else if (region == 0x20 && physAddr <= 0x20000FFF) + return etna.readReg8(physAddr & 0xFFF); + else if (region == 0x80 && physAddr <= 0x80000FFF) + return readReg8(physAddr & 0xFFF); #if defined(INCLUDE_BANK1) - else if (region == 0xC0) - return MemoryBlockC0[physAddr & MemoryBlockMask]; - else if (region == 0xC1) - return MemoryBlockC1[physAddr & MemoryBlockMask]; - else if (region == 0xD0) - return MemoryBlockD0[physAddr & MemoryBlockMask]; - else if (region == 0xD1) - return MemoryBlockD1[physAddr & MemoryBlockMask]; + else if (region == 0xC0) + return MemoryBlockC0[physAddr & MemoryBlockMask]; + else if (region == 0xC1) + return MemoryBlockC1[physAddr & MemoryBlockMask]; + else if (region == 0xD0) + return MemoryBlockD0[physAddr & MemoryBlockMask]; + else if (region == 0xD1) + return MemoryBlockD1[physAddr & MemoryBlockMask]; #elif defined(INCLUDE_D) - else if (region == 0xC0 || region == 0xC1) - return MemoryBlockC0[physAddr & MemoryBlockMask]; - else if (region == 0xD0 || region == 0xD1) - return MemoryBlockD0[physAddr & MemoryBlockMask]; + else if (region == 0xC0 || region == 0xC1) + return MemoryBlockC0[physAddr & MemoryBlockMask]; + else if (region == 0xD0 || region == 0xD1) + return MemoryBlockD0[physAddr & MemoryBlockMask]; #else - else if (region == 0xC0 || region == 0xC1 || region == 0xD0 || region == 0xD1) - return MemoryBlockC0[physAddr & MemoryBlockMask]; + else if (region == 0xC0 || region == 0xC1 || region == 0xD0 || + region == 0xD1) + return MemoryBlockC0[physAddr & MemoryBlockMask]; #endif - else if (region >= 0xC0) - return 0xFF; // just throw accesses to unmapped RAM away - } else { - uint32_t result; - if (region == 0) - LOAD_32LE(result, physAddr & 0xFFFFFF, ROM); - else if (region == 0x10) - LOAD_32LE(result, physAddr & 0x3FFFF, ROM2); - else if (region == 0x20 && physAddr <= 0x20000FFF) - result = etna.readReg32(physAddr & 0xFFF); - else if (region == 0x80 && physAddr <= 0x80000FFF) - result = readReg32(physAddr & 0xFFF); + else if (region >= 0xC0) + return 0xFF; // just throw accesses to unmapped RAM away + } else { + uint32_t result; + if (region == 0) + LOAD_32LE(result, physAddr & 0xFFFFFF, ROM); + else if (region == 0x10) + LOAD_32LE(result, physAddr & 0x3FFFF, ROM2); + else if (region == 0x20 && physAddr <= 0x20000FFF) + result = etna.readReg32(physAddr & 0xFFF); + else if (region == 0x80 && physAddr <= 0x80000FFF) + result = readReg32(physAddr & 0xFFF); #if defined(INCLUDE_BANK1) - else if (region == 0xC0) - LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockC0); - else if (region == 0xC1) - LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockC1); - else if (region == 0xD0) - LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockD0); - else if (region == 0xD1) - LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockD1); + else if (region == 0xC0) + LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockC0); + else if (region == 0xC1) + LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockC1); + else if (region == 0xD0) + LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockD0); + else if (region == 0xD1) + LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockD1); #elif defined(INCLUDE_D) - else if (region == 0xC0 || region == 0xC1) - LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockC0); - else if (region == 0xD0 || region == 0xD1) - LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockD0); + else if (region == 0xC0 || region == 0xC1) + LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockC0); + else if (region == 0xD0 || region == 0xD1) + LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockD0); #else - else if (region == 0xC0 || region == 0xC1 || region == 0xD0 || region == 0xD1) - LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockC0); + else if (region == 0xC0 || region == 0xC1 || region == 0xD0 || + region == 0xD1) + LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockC0); #endif - else if (region >= 0xC0) - return 0xFFFFFFFF; // just throw accesses to unmapped RAM away - else - return {}; - return result; - } - - return {}; + else if (region >= 0xC0) + return 0xFFFFFFFF; // just throw accesses to unmapped RAM away + else + return {}; + return result; + } + + return {}; } -bool Emulator::writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) { - uint8_t region = (physAddr >> 24) & 0xF1; - if (valueSize == V8) { +bool Emulator::writePhysical(uint32_t value, uint32_t physAddr, + ValueSize valueSize) { + uint8_t region = (physAddr >> 24) & 0xF1; + if (valueSize == V8) { #if defined(INCLUDE_BANK1) - if (region == 0xC0) - MemoryBlockC0[physAddr & MemoryBlockMask] = (uint8_t)value; - else if (region == 0xC1) - MemoryBlockC1[physAddr & MemoryBlockMask] = (uint8_t)value; - else if (region == 0xD0) - MemoryBlockD0[physAddr & MemoryBlockMask] = (uint8_t)value; - else if (region == 0xD1) - MemoryBlockD1[physAddr & MemoryBlockMask] = (uint8_t)value; + if (region == 0xC0) + MemoryBlockC0[physAddr & MemoryBlockMask] = (uint8_t)value; + else if (region == 0xC1) + MemoryBlockC1[physAddr & MemoryBlockMask] = (uint8_t)value; + else if (region == 0xD0) + MemoryBlockD0[physAddr & MemoryBlockMask] = (uint8_t)value; + else if (region == 0xD1) + MemoryBlockD1[physAddr & MemoryBlockMask] = (uint8_t)value; #elif defined(INCLUDE_D) - if (region == 0xC0 || region == 0xC1) - MemoryBlockC0[physAddr & MemoryBlockMask] = (uint8_t)value; - else if (region == 0xD0 || region == 0xD1) - MemoryBlockD0[physAddr & MemoryBlockMask] = (uint8_t)value; + if (region == 0xC0 || region == 0xC1) + MemoryBlockC0[physAddr & MemoryBlockMask] = (uint8_t)value; + else if (region == 0xD0 || region == 0xD1) + MemoryBlockD0[physAddr & MemoryBlockMask] = (uint8_t)value; #else - if (region == 0xC0 || region == 0xC1 || region == 0xD0 || region == 0xD1) - MemoryBlockC0[physAddr & MemoryBlockMask] = (uint8_t)value; + if (region == 0xC0 || region == 0xC1 || region == 0xD0 || region == 0xD1) + MemoryBlockC0[physAddr & MemoryBlockMask] = (uint8_t)value; #endif - else if (region >= 0xC0) - return true; // just throw accesses to unmapped RAM away - else if (region == 0x20 && physAddr <= 0x20000FFF) - etna.writeReg8(physAddr & 0xFFF, value); - else if (region == 0x80 && physAddr <= 0x80000FFF) - writeReg8(physAddr & 0xFFF, value); - else - return false; - } else { - uint8_t region = (physAddr >> 24) & 0xF1; + else if (region >= 0xC0) + return true; // just throw accesses to unmapped RAM away + else if (region == 0x20 && physAddr <= 0x20000FFF) + etna.writeReg8(physAddr & 0xFFF, value); + else if (region == 0x80 && physAddr <= 0x80000FFF) + writeReg8(physAddr & 0xFFF, value); + else + return false; + } else { + uint8_t region = (physAddr >> 24) & 0xF1; #if defined(INCLUDE_BANK1) - if (region == 0xC0) - STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockC0); - else if (region == 0xC1) - STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockC1); - else if (region == 0xD0) - STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockD0); - else if (region == 0xD1) - STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockD1); + if (region == 0xC0) + STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockC0); + else if (region == 0xC1) + STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockC1); + else if (region == 0xD0) + STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockD0); + else if (region == 0xD1) + STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockD1); #elif defined(INCLUDE_D) - if (region == 0xC0 || region == 0xC1) - STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockC0); - else if (region == 0xD0 || region == 0xD1) - STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockD0); + if (region == 0xC0 || region == 0xC1) + STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockC0); + else if (region == 0xD0 || region == 0xD1) + STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockD0); #else - if (region == 0xC0 || region == 0xC1 || region == 0xD0 || region == 0x01) - STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockC0); + if (region == 0xC0 || region == 0xC1 || region == 0xD0 || region == 0x01) + STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockC0); #endif - else if (region >= 0xC0) - return true; // just throw accesses to unmapped RAM away - else if (region == 0x20 && physAddr <= 0x20000FFF) - etna.writeReg32(physAddr & 0xFFF, value); - else if (region == 0x80 && physAddr <= 0x80000FFF) - writeReg32(physAddr & 0xFFF, value); - else - return false; - } - return true; + else if (region >= 0xC0) + return true; // just throw accesses to unmapped RAM away + else if (region == 0x20 && physAddr <= 0x20000FFF) + etna.writeReg32(physAddr & 0xFFF, value); + else if (region == 0x80 && physAddr <= 0x80000FFF) + writeReg32(physAddr & 0xFFF, value); + else + return false; + } + return true; } - - void Emulator::configure() { - if (configured) return; - configured = true; + if (configured) + return; + configured = true; - srand(1000); + srand(1000); - uart1.cpu = this; - uart2.cpu = this; - memset(&tc1, 0, sizeof(tc1)); - memset(&tc2, 0, sizeof(tc1)); - tc1.clockSpeed = CLOCK_SPEED; - tc2.clockSpeed = CLOCK_SPEED; + uart1.cpu = this; + uart2.cpu = this; + memset(&tc1, 0, sizeof(tc1)); + memset(&tc2, 0, sizeof(tc1)); + tc1.clockSpeed = CLOCK_SPEED; + tc2.clockSpeed = CLOCK_SPEED; - nextTickAt = TICK_INTERVAL; - tc1.nextTickAt = tc1.tickInterval(); - tc2.nextTickAt = tc2.tickInterval(); - rtc = getRTC(); + nextTickAt = TICK_INTERVAL; + tc1.nextTickAt = tc1.tickInterval(); + tc2.nextTickAt = tc2.tickInterval(); + rtc = getRTC(); - reset(); + reset(); } -uint8_t *Emulator::getROMBuffer() { - return ROM; -} -size_t Emulator::getROMSize() { - return sizeof(ROM); -} -void Emulator::loadROM(uint8_t *buffer, size_t size) { - memcpy(ROM, buffer, min(size, sizeof(ROM))); +uint8_t* Emulator::getROMBuffer() { return ROM; } +size_t Emulator::getROMSize() { return sizeof(ROM); } +void Emulator::loadROM(uint8_t* buffer, size_t size) { + memcpy(ROM, buffer, min(size, sizeof(ROM))); } void Emulator::executeUntil(int64_t cycles) { - if (!configured) - configure(); - - while (!asleep && passedCycles < cycles) { - if (passedCycles >= nextTickAt) { - // increment RTCDIV - if ((pwrsr & 0x3F) == 0x3F) { - rtc++; - pwrsr &= ~0x3F; - } else { - pwrsr++; - } - - nextTickAt += TICK_INTERVAL; - pendingInterrupts |= (1<= nextTickAt) { + // increment RTCDIV + if ((pwrsr & 0x3F) == 0x3F) { + rtc++; + pwrsr &= ~0x3F; + } else { + pwrsr++; + } + + nextTickAt += TICK_INTERVAL; + pendingInterrupts |= (1 << TINT); + } + if (tc1.tick(passedCycles)) + pendingInterrupts |= (1 << TC1OI); + if (tc2.tick(passedCycles)) + pendingInterrupts |= (1 << TC2OI); + + if ((pendingInterrupts & interruptMask & FIQ_INTERRUPTS) != 0 && + canAcceptFIQ()) { + requestFIQ(); + halted = false; + } + if ((pendingInterrupts & interruptMask & IRQ_INTERRUPTS) != 0 && + canAcceptIRQ()) { + requestIRQ(); + halted = false; + } + + // what's running? + if (halted) { + // keep the clock moving + // when does the next earliest thing happen? + // this stops us from spinning needlessly + int64_t nextEvent = nextTickAt; + if (tc1.nextTickAt < nextEvent) + nextEvent = tc1.nextTickAt; + if (tc2.nextTickAt < nextEvent) + nextEvent = tc2.nextTickAt; + if (cycles < nextEvent) + nextEvent = cycles; + passedCycles = nextEvent; + } else { + if (auto v = virtToPhys(getGPR(15) - 0xC); + v.has_value() && instructionReady()) + debugPC(v.value()); + passedCycles += tick(); #ifndef __EMSCRIPTEN__ - uint32_t new_pc = getGPR(15) - 0xC; - if (_breakpoints.find(new_pc) != _breakpoints.end()) { - log("⚠️ Breakpoint triggered at %08x!", new_pc); - return; - } + uint32_t new_pc = getGPR(15) - 0xC; + if (_breakpoints.find(new_pc) != _breakpoints.end()) { + log("⚠️ Breakpoint triggered at %08x!", new_pc); + return; + } #endif - } - } + } + } } - -const char *Emulator::identifyObjectCon(uint32_t ptr) { - if (ptr == readVirtualDebug(0x80000980, V32).value()) return "process"; - if (ptr == readVirtualDebug(0x80000984, V32).value()) return "thread"; - if (ptr == readVirtualDebug(0x80000988, V32).value()) return "chunk"; -// if (ptr == readVirtualDebug(0x8000098C, V32).value()) return "semaphore"; -// if (ptr == readVirtualDebug(0x80000990, V32).value()) return "mutex"; - if (ptr == readVirtualDebug(0x80000994, V32).value()) return "logicaldevice"; - if (ptr == readVirtualDebug(0x80000998, V32).value()) return "physicaldevice"; - if (ptr == readVirtualDebug(0x8000099C, V32).value()) return "channel"; - if (ptr == readVirtualDebug(0x800009A0, V32).value()) return "server"; -// if (ptr == readVirtualDebug(0x800009A4, V32).value()) return "unk9A4"; // name always null - if (ptr == readVirtualDebug(0x800009AC, V32).value()) return "library"; -// if (ptr == readVirtualDebug(0x800009B0, V32).value()) return "unk9B0"; // name always null -// if (ptr == readVirtualDebug(0x800009B4, V32).value()) return "unk9B4"; // name always null - return NULL; +const char* Emulator::identifyObjectCon(uint32_t ptr) { + if (ptr == readVirtualDebug(0x80000980, V32).value()) + return "process"; + if (ptr == readVirtualDebug(0x80000984, V32).value()) + return "thread"; + if (ptr == readVirtualDebug(0x80000988, V32).value()) + return "chunk"; + // if (ptr == readVirtualDebug(0x8000098C, V32).value()) return + //"semaphore"; if (ptr == readVirtualDebug(0x80000990, V32).value()) + //return "mutex"; + if (ptr == readVirtualDebug(0x80000994, V32).value()) + return "logicaldevice"; + if (ptr == readVirtualDebug(0x80000998, V32).value()) + return "physicaldevice"; + if (ptr == readVirtualDebug(0x8000099C, V32).value()) + return "channel"; + if (ptr == readVirtualDebug(0x800009A0, V32).value()) + return "server"; + // if (ptr == readVirtualDebug(0x800009A4, V32).value()) return "unk9A4"; + //// name always null + if (ptr == readVirtualDebug(0x800009AC, V32).value()) + return "library"; + // if (ptr == readVirtualDebug(0x800009B0, V32).value()) return "unk9B0"; + //// name always null if (ptr == readVirtualDebug(0x800009B4, + ///V32).value()) + // return "unk9B4"; // name always null + return NULL; } -void Emulator::fetchStr(uint32_t str, char *buf) { - if (str == 0) { - strcpy(buf, ""); - return; - } - int size = readVirtualDebug(str, V32).value(); - for (int i = 0; i < size; i++) { - buf[i] = readVirtualDebug(str + 4 + i, V8).value(); - } - buf[size] = 0; +void Emulator::fetchStr(uint32_t str, char* buf) { + if (str == 0) { + strcpy(buf, ""); + return; + } + int size = readVirtualDebug(str, V32).value(); + for (int i = 0; i < size; i++) { + buf[i] = readVirtualDebug(str + 4 + i, V8).value(); + } + buf[size] = 0; } -void Emulator::fetchName(uint32_t obj, char *buf) { - fetchStr(readVirtualDebug(obj + 0x10, V32).value(), buf); +void Emulator::fetchName(uint32_t obj, char* buf) { + fetchStr(readVirtualDebug(obj + 0x10, V32).value(), buf); } -void Emulator::fetchProcessFilename(uint32_t obj, char *buf) { - fetchStr(readVirtualDebug(obj + 0x3C, V32).value(), buf); +void Emulator::fetchProcessFilename(uint32_t obj, char* buf) { + fetchStr(readVirtualDebug(obj + 0x3C, V32).value(), buf); } void Emulator::debugPC(uint32_t pc) { - char objName[1000]; - if (pc == 0x2CBC4) { - // CObjectCon::AddL() - uint32_t container = getGPR(0); - uint32_t obj = getGPR(1); - const char *wut = identifyObjectCon(container); - if (wut) { - fetchName(obj, objName); - if (strcmp(wut, "process") == 0) { - char procName[1000]; - fetchProcessFilename(obj, procName); - log("OBJS: added %s at %08x <%s> <%s>", wut, obj, objName, procName); - } else { - log("OBJS: added %s at %08x <%s>", wut, obj, objName); - } - } - } - - if (pc == 0x6D8) { - uint32_t virtAddr = getGPR(0); - uint32_t physAddr = getGPR(1); - uint32_t btIndex = getGPR(2); - uint32_t regionSize = getGPR(3); - log("KERNEL MMU SECTION: v:%08x p:%08x size:%08x idx:%02x", - virtAddr, physAddr, regionSize, btIndex); - } - if (pc == 0x710) { - uint32_t virtAddr = getGPR(0); - uint32_t physAddr = getGPR(1); - uint32_t btIndex = getGPR(2); - uint32_t regionSize = getGPR(3); - uint32_t pageTableA = getGPR(4); - uint32_t pageTableB = getGPR(5); - log("KERNEL MMU PAGES: v:%08x p:%08x size:%08x idx:%02x tableA:%08x tableB:%08x", - virtAddr, physAddr, regionSize, btIndex, pageTableA, pageTableB); - } - - if (pc == 0x1576C) { - uint32_t rawEvent = getGPR(0); - uint32_t evtType = readVirtualDebug(rawEvent, V32).value_or(0); - uint32_t evtTick = readVirtualDebug(rawEvent + 4, V32).value_or(0); - uint32_t evtParamA = readVirtualDebug(rawEvent + 8, V32).value_or(0); - uint32_t evtParamB = readVirtualDebug(rawEvent + 0xC, V32).value_or(0); - const char *n = "???"; - switch (evtType) { - case 0: n = "ENone"; break; - case 1: n = "EPointerMove"; break; - case 2: n = "EPointerSwitchOn"; break; - case 3: n = "EKeyDown"; break; - case 4: n = "EKeyUp"; break; - case 5: n = "ERedraw"; break; - case 6: n = "ESwitchOn"; break; - case 7: n = "EActive"; break; - case 8: n = "EInactive"; break; - case 9: n = "EUpdateModifiers"; break; - case 10: n = "EButton1Down"; break; - case 11: n = "EButton1Up"; break; - case 12: n = "EButton2Down"; break; - case 13: n = "EButton2Up"; break; - case 14: n = "EButton3Down"; break; - case 15: n = "EButton3Up"; break; - case 16: n = "ESwitchOff"; break; - } - log("EVENT %s: tick=%d params=%d,%d", n, evtTick, evtParamA, evtParamB); - } + char objName[1000]; + if (pc == 0x2CBC4) { + // CObjectCon::AddL() + uint32_t container = getGPR(0); + uint32_t obj = getGPR(1); + const char* wut = identifyObjectCon(container); + if (wut) { + fetchName(obj, objName); + if (strcmp(wut, "process") == 0) { + char procName[1000]; + fetchProcessFilename(obj, procName); + log("OBJS: added %s at %08x <%s> <%s>", wut, obj, objName, procName); + } else { + log("OBJS: added %s at %08x <%s>", wut, obj, objName); + } + } + } + + if (pc == 0x6D8) { + uint32_t virtAddr = getGPR(0); + uint32_t physAddr = getGPR(1); + uint32_t btIndex = getGPR(2); + uint32_t regionSize = getGPR(3); + log("KERNEL MMU SECTION: v:%08x p:%08x size:%08x idx:%02x", virtAddr, + physAddr, regionSize, btIndex); + } + if (pc == 0x710) { + uint32_t virtAddr = getGPR(0); + uint32_t physAddr = getGPR(1); + uint32_t btIndex = getGPR(2); + uint32_t regionSize = getGPR(3); + uint32_t pageTableA = getGPR(4); + uint32_t pageTableB = getGPR(5); + log("KERNEL MMU PAGES: v:%08x p:%08x size:%08x idx:%02x tableA:%08x " + "tableB:%08x", + virtAddr, physAddr, regionSize, btIndex, pageTableA, pageTableB); + } + + if (pc == 0x1576C) { + uint32_t rawEvent = getGPR(0); + uint32_t evtType = readVirtualDebug(rawEvent, V32).value_or(0); + uint32_t evtTick = readVirtualDebug(rawEvent + 4, V32).value_or(0); + uint32_t evtParamA = readVirtualDebug(rawEvent + 8, V32).value_or(0); + uint32_t evtParamB = readVirtualDebug(rawEvent + 0xC, V32).value_or(0); + const char* n = "???"; + switch (evtType) { + case 0: + n = "ENone"; + break; + case 1: + n = "EPointerMove"; + break; + case 2: + n = "EPointerSwitchOn"; + break; + case 3: + n = "EKeyDown"; + break; + case 4: + n = "EKeyUp"; + break; + case 5: + n = "ERedraw"; + break; + case 6: + n = "ESwitchOn"; + break; + case 7: + n = "EActive"; + break; + case 8: + n = "EInactive"; + break; + case 9: + n = "EUpdateModifiers"; + break; + case 10: + n = "EButton1Down"; + break; + case 11: + n = "EButton1Up"; + break; + case 12: + n = "EButton2Down"; + break; + case 13: + n = "EButton2Up"; + break; + case 14: + n = "EButton3Down"; + break; + case 15: + n = "EButton3Up"; + break; + case 16: + n = "ESwitchOff"; + break; + } + log("EVENT %s: tick=%d params=%d,%d", n, evtTick, evtParamA, evtParamB); + } } - -const char *Emulator::getDeviceName() const { return "Series 5mx"; } -int Emulator::getDigitiserWidth() const { return 695; } +const char* Emulator::getDeviceName() const { return "Series 5mx"; } +int Emulator::getDigitiserWidth() const { return 695; } int Emulator::getDigitiserHeight() const { return 280; } -int Emulator::getLCDOffsetX() const { return 45; } -int Emulator::getLCDOffsetY() const { return 5; } -int Emulator::getLCDWidth() const { return 640; } -int Emulator::getLCDHeight() const { return 240; } +int Emulator::getLCDOffsetX() const { return 45; } +int Emulator::getLCDOffsetY() const { return 5; } +int Emulator::getLCDWidth() const { return 640; } +int Emulator::getLCDHeight() const { return 240; } // TODO move this elsewhere static bool initRgbValues = false; static uint32_t rgbValues[16]; -void Emulator::readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) const { - if (!initRgbValues) { - initRgbValues = true; - for (int i = 0; i < 16; i++) { - int r = (0x99 * i) / 15; - int g = (0xAA * i) / 15; - int b = (0x88 * i) / 15; - rgbValues[15 - i] = r | (g << 8) | (b << 16) | 0xFF000000; - } - } - - if ((lcdAddress >> 24) == 0xC0) { - const uint8_t *lcdBuf = &MemoryBlockC0[lcdAddress & MemoryBlockMask]; - int width = 640, height = 240; - - // fetch palette - int bpp = 1 << (lcdBuf[1] >> 4); - int ppb = 8 / bpp; - uint16_t palette[16]; - for (int i = 0; i < 16; i++) - palette[i] = lcdBuf[i*2] | ((lcdBuf[i*2+1] << 8) & 0xF00); - - // build our image out - int lineWidth = (width * bpp) / 8; - for (int y = 0; y < height; y++) { - int lineOffs = 0x20 + (lineWidth * y); - for (int x = 0; x < width; x++) { - uint8_t byte = lcdBuf[lineOffs + (x / ppb)]; - int shift = (x & (ppb - 1)) * bpp; - int mask = (1 << bpp) - 1; - int palIdx = (byte >> shift) & mask; - int palValue = palette[palIdx]; - - if (is32BitOutput) { - auto line = (uint32_t *)lines[y]; - line[x] = rgbValues[palValue]; - } else { - palValue |= (palValue << 4); - lines[y][x] = palValue ^ 0xFF; - } - } - } - } +void Emulator::readLCDIntoBuffer(uint8_t** lines, bool is32BitOutput) const { + if (!initRgbValues) { + initRgbValues = true; + for (int i = 0; i < 16; i++) { + int r = (0x99 * i) / 15; + int g = (0xAA * i) / 15; + int b = (0x88 * i) / 15; + rgbValues[15 - i] = r | (g << 8) | (b << 16) | 0xFF000000; + } + } + + if ((lcdAddress >> 24) == 0xC0) { + const uint8_t* lcdBuf = &MemoryBlockC0[lcdAddress & MemoryBlockMask]; + int width = 640, height = 240; + + // fetch palette + int bpp = 1 << (lcdBuf[1] >> 4); + int ppb = 8 / bpp; + uint16_t palette[16]; + for (int i = 0; i < 16; i++) + palette[i] = lcdBuf[i * 2] | ((lcdBuf[i * 2 + 1] << 8) & 0xF00); + + // build our image out + int lineWidth = (width * bpp) / 8; + for (int y = 0; y < height; y++) { + int lineOffs = 0x20 + (lineWidth * y); + for (int x = 0; x < width; x++) { + uint8_t byte = lcdBuf[lineOffs + (x / ppb)]; + int shift = (x & (ppb - 1)) * bpp; + int mask = (1 << bpp) - 1; + int palIdx = (byte >> shift) & mask; + int palValue = palette[palIdx]; + + if (is32BitOutput) { + auto line = (uint32_t*)lines[y]; + line[x] = rgbValues[palValue]; + } else { + palValue |= (palValue << 4); + lines[y][x] = palValue ^ 0xFF; + } + } + } + } } - void Emulator::diffPorts(uint32_t oldval, uint32_t newval) { - uint32_t changes = oldval ^ newval; - if (changes & 1) log("PRT codec enable: %d", newval&1); - if (changes & 2) log("PRT audio amp enable: %d", newval&2); - if (changes & 4) log("PRT lcd power: %d", newval&4); - if (changes & 8) log("PRT etna door: %d", newval&8); - if (changes & 0x10) log("PRT sled: %d", newval&0x10); - if (changes & 0x20) log("PRT pump pwr2: %d", newval&0x20); - if (changes & 0x40) log("PRT pump pwr1: %d", newval&0x40); - if (changes & 0x80) log("PRT etna err: %d", newval&0x80); - if (changes & 0x100) log("PRT rs-232 rts: %d", newval&0x100); - if (changes & 0x200) log("PRT rs-232 dtr toggle: %d", newval&0x200); - if (changes & 0x400) log("PRT disable power led: %d", newval&0x400); - if (changes & 0x800) log("PRT enable uart1: %d", newval&0x800); - if (changes & 0x1000) log("PRT lcd backlight: %d", newval&0x1000); - if (changes & 0x2000) log("PRT enable uart0: %d", newval&0x2000); - if (changes & 0x4000) log("PRT dictaphone: %d", newval&0x4000); -// PROM read process makes this super spammy in stdout -// if (changes & 0x10000) log("PRT EECS: %d", newval&0x10000); -// if (changes & 0x20000) log("PRT EECLK: %d", newval&0x20000); - if (changes & 0x40000) log("PRT contrast0: %d", newval&0x40000); - if (changes & 0x80000) log("PRT contrast1: %d", newval&0x80000); - if (changes & 0x100000) log("PRT contrast2: %d", newval&0x100000); - if (changes & 0x200000) log("PRT contrast3: %d", newval&0x200000); - if (changes & 0x400000) log("PRT case open: %d", newval&0x400000); - if (changes & 0x800000) log("PRT etna cf power: %d", newval&0x800000); + uint32_t changes = oldval ^ newval; + if (changes & 1) + log("PRT codec enable: %d", newval & 1); + if (changes & 2) + log("PRT audio amp enable: %d", newval & 2); + if (changes & 4) + log("PRT lcd power: %d", newval & 4); + if (changes & 8) + log("PRT etna door: %d", newval & 8); + if (changes & 0x10) + log("PRT sled: %d", newval & 0x10); + if (changes & 0x20) + log("PRT pump pwr2: %d", newval & 0x20); + if (changes & 0x40) + log("PRT pump pwr1: %d", newval & 0x40); + if (changes & 0x80) + log("PRT etna err: %d", newval & 0x80); + if (changes & 0x100) + log("PRT rs-232 rts: %d", newval & 0x100); + if (changes & 0x200) + log("PRT rs-232 dtr toggle: %d", newval & 0x200); + if (changes & 0x400) + log("PRT disable power led: %d", newval & 0x400); + if (changes & 0x800) + log("PRT enable uart1: %d", newval & 0x800); + if (changes & 0x1000) + log("PRT lcd backlight: %d", newval & 0x1000); + if (changes & 0x2000) + log("PRT enable uart0: %d", newval & 0x2000); + if (changes & 0x4000) + log("PRT dictaphone: %d", newval & 0x4000); + // PROM read process makes this super spammy in stdout + // if (changes & 0x10000) log("PRT EECS: %d", newval&0x10000); + // if (changes & 0x20000) log("PRT EECLK: %d", newval&0x20000); + if (changes & 0x40000) + log("PRT contrast0: %d", newval & 0x40000); + if (changes & 0x80000) + log("PRT contrast1: %d", newval & 0x80000); + if (changes & 0x100000) + log("PRT contrast2: %d", newval & 0x100000); + if (changes & 0x200000) + log("PRT contrast3: %d", newval & 0x200000); + if (changes & 0x400000) + log("PRT case open: %d", newval & 0x400000); + if (changes & 0x800000) + log("PRT etna cf power: %d", newval & 0x800000); } void Emulator::diffInterrupts(uint16_t oldval, uint16_t newval) { - uint16_t changes = oldval ^ newval; - if (changes & 1) log("INTCHG external=%d", newval & 1); - if (changes & 2) log("INTCHG lowbat=%d", newval & 2); - if (changes & 4) log("INTCHG watchdog=%d", newval & 4); - if (changes & 8) log("INTCHG mediachg=%d", newval & 8); - if (changes & 0x10) log("INTCHG codec=%d", newval & 0x10); - if (changes & 0x20) log("INTCHG ext1=%d", newval & 0x20); - if (changes & 0x40) log("INTCHG ext2=%d", newval & 0x40); - if (changes & 0x80) log("INTCHG ext3=%d", newval & 0x80); - if (changes & 0x100) log("INTCHG timer1=%d", newval & 0x100); - if (changes & 0x200) log("INTCHG timer2=%d", newval & 0x200); - if (changes & 0x400) log("INTCHG rtcmatch=%d", newval & 0x400); - if (changes & 0x800) log("INTCHG tick=%d", newval & 0x800); - if (changes & 0x1000) log("INTCHG uart1=%d", newval & 0x1000); - if (changes & 0x2000) log("INTCHG uart2=%d", newval & 0x2000); - if (changes & 0x4000) log("INTCHG lcd=%d", newval & 0x4000); - if (changes & 0x8000) log("INTCHG spi=%d", newval & 0x8000); + uint16_t changes = oldval ^ newval; + if (changes & 1) + log("INTCHG external=%d", newval & 1); + if (changes & 2) + log("INTCHG lowbat=%d", newval & 2); + if (changes & 4) + log("INTCHG watchdog=%d", newval & 4); + if (changes & 8) + log("INTCHG mediachg=%d", newval & 8); + if (changes & 0x10) + log("INTCHG codec=%d", newval & 0x10); + if (changes & 0x20) + log("INTCHG ext1=%d", newval & 0x20); + if (changes & 0x40) + log("INTCHG ext2=%d", newval & 0x40); + if (changes & 0x80) + log("INTCHG ext3=%d", newval & 0x80); + if (changes & 0x100) + log("INTCHG timer1=%d", newval & 0x100); + if (changes & 0x200) + log("INTCHG timer2=%d", newval & 0x200); + if (changes & 0x400) + log("INTCHG rtcmatch=%d", newval & 0x400); + if (changes & 0x800) + log("INTCHG tick=%d", newval & 0x800); + if (changes & 0x1000) + log("INTCHG uart1=%d", newval & 0x1000); + if (changes & 0x2000) + log("INTCHG uart2=%d", newval & 0x2000); + if (changes & 0x4000) + log("INTCHG lcd=%d", newval & 0x4000); + if (changes & 0x8000) + log("INTCHG spi=%d", newval & 0x8000); } - uint32_t Emulator::readKeyboard() { - if (kScan & 8) { - // Select one keyboard - return keyboardColumns[kScan & 7]; - } else if (kScan == 0) { - // Report all columns combined - uint8_t val = 0; - for (int i = 0; i < 8; i++) - val |= keyboardColumns[i]; - return val; - } else { - return 0; - } + if (kScan & 8) { + // Select one keyboard + return keyboardColumns[kScan & 7]; + } else if (kScan == 0) { + // Report all columns combined + uint8_t val = 0; + for (int i = 0; i < 8; i++) + val |= keyboardColumns[i]; + return val; + } else { + return 0; + } } void Emulator::setKeyboardKey(EpocKey key, bool value) { - int idx = -1; -#define KEY(column, bit) idx = (column << 8) | (1 << bit); break - - switch ((int)key) { - case EStdKeyDictaphoneRecord: KEY(0, 6); - case '1': KEY(0, 5); - case '2': KEY(0, 4); - case '3': KEY(0, 3); - case '4': KEY(0, 2); - case '5': KEY(0, 1); - case '6': KEY(0, 0); - - case EStdKeyDictaphonePlay: KEY(1, 6); - case '7': KEY(1, 5); - case '8': KEY(1, 4); - case '9': KEY(1, 3); - case '0': KEY(1, 2); - case EStdKeyBackspace: KEY(1, 1); - case EStdKeySingleQuote: KEY(1, 0); - - case EStdKeyEscape: KEY(2, 6); - case 'Q': KEY(2, 5); - case 'W': KEY(2, 4); - case 'E': KEY(2, 3); - case 'R': KEY(2, 2); - case 'T': KEY(2, 1); - case 'Y': KEY(2, 0); - - case EStdKeyMenu: KEY(3, 6); - case 'U': KEY(3, 5); - case 'I': KEY(3, 4); - case 'O': KEY(3, 3); - case 'P': KEY(3, 2); - case 'L': KEY(3, 1); - case EStdKeyEnter: KEY(3, 0); - - case EStdKeyLeftCtrl: KEY(4, 6); - case EStdKeyTab: KEY(4, 5); - case 'A': KEY(4, 4); - case 'S': KEY(4, 3); - case 'D': KEY(4, 2); - case 'F': KEY(4, 1); - case 'G': KEY(4, 0); - - case EStdKeyLeftFunc: KEY(5, 6); - case 'H': KEY(5, 5); - case 'J': KEY(5, 4); - case 'K': KEY(5, 3); - case 'M': KEY(5, 2); - case EStdKeyFullStop: KEY(5, 1); - case EStdKeyDownArrow: KEY(5, 0); - - case EStdKeyRightShift: KEY(6, 6); - case 'Z': KEY(6, 5); - case 'X': KEY(6, 4); - case 'C': KEY(6, 3); - case 'V': KEY(6, 2); - case 'B': KEY(6, 1); - case 'N': KEY(6, 0); - - case EStdKeyLeftShift: KEY(7, 6); - case EStdKeyDictaphoneStop: KEY(7, 5); - case EStdKeySpace: KEY(7, 4); - case EStdKeyUpArrow: KEY(7, 3); - case EStdKeyComma: KEY(7, 2); - case EStdKeyLeftArrow: KEY(7, 1); - case EStdKeyRightArrow: KEY(7, 0); - } - - if (idx >= 0) { - if (value) - keyboardColumns[idx >> 8] |= (idx & 0xFF); - else - keyboardColumns[idx >> 8] &= ~(idx & 0xFF); - } + int idx = -1; +#define KEY(column, bit) \ + idx = (column << 8) | (1 << bit); \ + break + + switch ((int)key) { + case EStdKeyDictaphoneRecord: + KEY(0, 6); + case '1': + KEY(0, 5); + case '2': + KEY(0, 4); + case '3': + KEY(0, 3); + case '4': + KEY(0, 2); + case '5': + KEY(0, 1); + case '6': + KEY(0, 0); + + case EStdKeyDictaphonePlay: + KEY(1, 6); + case '7': + KEY(1, 5); + case '8': + KEY(1, 4); + case '9': + KEY(1, 3); + case '0': + KEY(1, 2); + case EStdKeyBackspace: + KEY(1, 1); + case EStdKeySingleQuote: + KEY(1, 0); + + case EStdKeyEscape: + KEY(2, 6); + case 'Q': + KEY(2, 5); + case 'W': + KEY(2, 4); + case 'E': + KEY(2, 3); + case 'R': + KEY(2, 2); + case 'T': + KEY(2, 1); + case 'Y': + KEY(2, 0); + + case EStdKeyMenu: + KEY(3, 6); + case 'U': + KEY(3, 5); + case 'I': + KEY(3, 4); + case 'O': + KEY(3, 3); + case 'P': + KEY(3, 2); + case 'L': + KEY(3, 1); + case EStdKeyEnter: + KEY(3, 0); + + case EStdKeyLeftCtrl: + KEY(4, 6); + case EStdKeyTab: + KEY(4, 5); + case 'A': + KEY(4, 4); + case 'S': + KEY(4, 3); + case 'D': + KEY(4, 2); + case 'F': + KEY(4, 1); + case 'G': + KEY(4, 0); + + case EStdKeyLeftFunc: + KEY(5, 6); + case 'H': + KEY(5, 5); + case 'J': + KEY(5, 4); + case 'K': + KEY(5, 3); + case 'M': + KEY(5, 2); + case EStdKeyFullStop: + KEY(5, 1); + case EStdKeyDownArrow: + KEY(5, 0); + + case EStdKeyRightShift: + KEY(6, 6); + case 'Z': + KEY(6, 5); + case 'X': + KEY(6, 4); + case 'C': + KEY(6, 3); + case 'V': + KEY(6, 2); + case 'B': + KEY(6, 1); + case 'N': + KEY(6, 0); + + case EStdKeyLeftShift: + KEY(7, 6); + case EStdKeyDictaphoneStop: + KEY(7, 5); + case EStdKeySpace: + KEY(7, 4); + case EStdKeyUpArrow: + KEY(7, 3); + case EStdKeyComma: + KEY(7, 2); + case EStdKeyLeftArrow: + KEY(7, 1); + case EStdKeyRightArrow: + KEY(7, 0); + } + + if (idx >= 0) { + if (value) + keyboardColumns[idx >> 8] |= (idx & 0xFF); + else + keyboardColumns[idx >> 8] &= ~(idx & 0xFF); + } } void Emulator::updateTouchInput(int32_t x, int32_t y, bool down) { - pendingInterrupts &= ~(1 << EINT3); - if (down) - pendingInterrupts |= (1 << EINT3); - touchX = x; - touchY = y; + pendingInterrupts &= ~(1 << EINT3); + if (down) + pendingInterrupts |= (1 << EINT3); + touchX = x; + touchY = y; } -} +} // namespace Windermere diff --git a/WindCore/windermere.h b/WindCore/windermere.h index defe545..9878258 100644 --- a/WindCore/windermere.h +++ b/WindCore/windermere.h @@ -1,81 +1,82 @@ #pragma once #include "emubase.h" -#include "wind_defs.h" -#include "hardware.h" #include "etna.h" +#include "hardware.h" +#include "wind_defs.h" namespace Windermere { class Emulator : public EmuBase { public: - uint8_t ROM[0x1000000]; - uint8_t ROM2[0x40000]; - uint8_t MemoryBlockC0[0x800000]; - uint8_t MemoryBlockC1[0x800000]; - uint8_t MemoryBlockD0[0x800000]; - uint8_t MemoryBlockD1[0x800000]; - enum { MemoryBlockMask = 0x7FFFFF }; + uint8_t ROM[0x1000000]; + uint8_t ROM2[0x40000]; + uint8_t MemoryBlockC0[0x800000]; + uint8_t MemoryBlockC1[0x800000]; + uint8_t MemoryBlockD0[0x800000]; + uint8_t MemoryBlockD1[0x800000]; + enum { MemoryBlockMask = 0x7FFFFF }; private: - uint16_t pendingInterrupts = 0; - uint16_t interruptMask = 0; - uint32_t portValues = 0; - uint32_t portDirections = 0; - uint32_t pwrsr = 0x00002000; // cold start flag - uint32_t lcdControl = 0; - uint32_t lcdAddress = 0; - uint32_t rtc = 0; - uint16_t lastSSIRequest = 0; - int ssiReadCounter = 0; + uint16_t pendingInterrupts = 0; + uint16_t interruptMask = 0; + uint32_t portValues = 0; + uint32_t portDirections = 0; + uint32_t pwrsr = 0x00002000; // cold start flag + uint32_t lcdControl = 0; + uint32_t lcdAddress = 0; + uint32_t rtc = 0; + uint16_t lastSSIRequest = 0; + int ssiReadCounter = 0; - uint32_t kScan = 0; - uint8_t keyboardColumns[8] = {0,0,0,0,0,0,0}; - int32_t touchX = 0, touchY = 0; + uint32_t kScan = 0; + uint8_t keyboardColumns[8] = {0, 0, 0, 0, 0, 0, 0}; + int32_t touchX = 0, touchY = 0; - Timer tc1, tc2; - UART uart1, uart2; - Etna etna; - bool halted = false, asleep = false; + Timer tc1, tc2; + UART uart1, uart2; + Etna etna; + bool halted = false, asleep = false; - uint32_t getRTC(); + uint32_t getRTC(); - uint32_t readReg8(uint32_t reg); - uint32_t readReg32(uint32_t reg); - void writeReg8(uint32_t reg, uint8_t value); - void writeReg32(uint32_t reg, uint32_t value); + uint32_t readReg8(uint32_t reg); + uint32_t readReg32(uint32_t reg); + void writeReg8(uint32_t reg, uint8_t value); + void writeReg32(uint32_t reg, uint32_t value); public: - MaybeU32 readPhysical(uint32_t physAddr, ValueSize valueSize) override; - bool writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) override; + MaybeU32 readPhysical(uint32_t physAddr, ValueSize valueSize) override; + bool writePhysical(uint32_t value, uint32_t physAddr, + ValueSize valueSize) override; private: - bool configured = false; - void configure(); + bool configured = false; + void configure(); - const char *identifyObjectCon(uint32_t ptr); - void fetchStr(uint32_t str, char *buf); - void fetchName(uint32_t obj, char *buf); - void fetchProcessFilename(uint32_t obj, char *buf); - void debugPC(uint32_t pc); - void diffPorts(uint32_t oldval, uint32_t newval); - void diffInterrupts(uint16_t oldval, uint16_t newval); - uint32_t readKeyboard(); + const char* identifyObjectCon(uint32_t ptr); + void fetchStr(uint32_t str, char* buf); + void fetchName(uint32_t obj, char* buf); + void fetchProcessFilename(uint32_t obj, char* buf); + void debugPC(uint32_t pc); + void diffPorts(uint32_t oldval, uint32_t newval); + void diffInterrupts(uint16_t oldval, uint16_t newval); + uint32_t readKeyboard(); public: - Emulator(); - uint8_t *getROMBuffer() override; - size_t getROMSize() override; - void loadROM(uint8_t *buffer, size_t size) override; - void executeUntil(int64_t cycles) override; - int32_t getClockSpeed() const override { return CLOCK_SPEED; } - const char *getDeviceName() const override; - int getDigitiserWidth() const override; - int getDigitiserHeight() const override; - int getLCDOffsetX() const override; - int getLCDOffsetY() const override; - int getLCDWidth() const override; - int getLCDHeight() const override; - void readLCDIntoBuffer(uint8_t **lines, bool is32BitOutput) const override; - void setKeyboardKey(EpocKey key, bool value) override; - void updateTouchInput(int32_t x, int32_t y, bool down) override; + Emulator(); + uint8_t* getROMBuffer() override; + size_t getROMSize() override; + void loadROM(uint8_t* buffer, size_t size) override; + void executeUntil(int64_t cycles) override; + int32_t getClockSpeed() const override { return CLOCK_SPEED; } + const char* getDeviceName() const override; + int getDigitiserWidth() const override; + int getDigitiserHeight() const override; + int getLCDOffsetX() const override; + int getLCDOffsetY() const override; + int getLCDWidth() const override; + int getLCDHeight() const override; + void readLCDIntoBuffer(uint8_t** lines, bool is32BitOutput) const override; + void setKeyboardKey(EpocKey key, bool value) override; + void updateTouchInput(int32_t x, int32_t y, bool down) override; }; -} +} // namespace Windermere diff --git a/WindQt/main.cpp b/WindQt/main.cpp index 3d9b87d..d26184c 100644 --- a/WindQt/main.cpp +++ b/WindQt/main.cpp @@ -1,59 +1,59 @@ +#include "../WindCore/clps7111.h" +#include "../WindCore/windermere.h" #include "mainwindow.h" #include #include #include -#include "../WindCore/clps7111.h" -#include "../WindCore/windermere.h" -int main(int argc, char *argv[]) -{ - QApplication a(argc, argv); - auto args = a.arguments(); - - QString romFile; - if (args.length() > 1) - romFile = args.last(); - else - romFile = QFileDialog::getOpenFileName(nullptr, "Select a ROM"); - if (romFile.isNull()) return 0; - - // what do we have? - QFile f(romFile); - f.open(QFile::ReadOnly); - auto buffer = f.readAll(); - f.close(); - - if (buffer.size() < 0x400000) { - QMessageBox::critical(nullptr, "WindEmu", "Invalid ROM file!"); - return 0; - } - - EmuBase *emu = nullptr; - uint8_t *romData = (uint8_t *)buffer.data(); - - // parse this ROM to learn what hardware it's for - int variantFile = *((uint32_t *)&romData[0x80 + 0x4C]) & 0xFFFFFFF; - if (variantFile < (buffer.size() - 8)) { - int variantImg = *((uint32_t *)&romData[variantFile + 4]) & 0xFFFFFFF; - if (variantImg < (buffer.size() - 0x70)) { - int variant = *((uint32_t *)&romData[variantImg + 0x60]); - - if (variant == 0x7060001) { - // 5mx ROM - emu = new Windermere::Emulator; - } else if (variant == 0x5040001) { - // Osaris ROM - emu = new CLPS7111::Emulator; - } else { - QMessageBox::critical(nullptr, "WindEmu", "Unrecognised ROM file!"); - return 0; - } - } - } - - emu->loadROM(romData, buffer.size()); - MainWindow w(emu); - w.show(); - - return a.exec(); +int main(int argc, char* argv[]) { + QApplication a(argc, argv); + auto args = a.arguments(); + + QString romFile; + if (args.length() > 1) + romFile = args.last(); + else + romFile = QFileDialog::getOpenFileName(nullptr, "Select a ROM"); + if (romFile.isNull()) + return 0; + + // what do we have? + QFile f(romFile); + f.open(QFile::ReadOnly); + auto buffer = f.readAll(); + f.close(); + + if (buffer.size() < 0x400000) { + QMessageBox::critical(nullptr, "WindEmu", "Invalid ROM file!"); + return 0; + } + + EmuBase* emu = nullptr; + uint8_t* romData = (uint8_t*)buffer.data(); + + // parse this ROM to learn what hardware it's for + int variantFile = *((uint32_t*)&romData[0x80 + 0x4C]) & 0xFFFFFFF; + if (variantFile < (buffer.size() - 8)) { + int variantImg = *((uint32_t*)&romData[variantFile + 4]) & 0xFFFFFFF; + if (variantImg < (buffer.size() - 0x70)) { + int variant = *((uint32_t*)&romData[variantImg + 0x60]); + + if (variant == 0x7060001) { + // 5mx ROM + emu = new Windermere::Emulator; + } else if (variant == 0x5040001) { + // Osaris ROM + emu = new CLPS7111::Emulator; + } else { + QMessageBox::critical(nullptr, "WindEmu", "Unrecognised ROM file!"); + return 0; + } + } + } + + emu->loadROM(romData, buffer.size()); + MainWindow w(emu); + w.show(); + + return a.exec(); } diff --git a/WindQt/mainwindow.cpp b/WindQt/mainwindow.cpp index fafdfd9..33709f6 100644 --- a/WindQt/mainwindow.cpp +++ b/WindQt/mainwindow.cpp @@ -1,222 +1,220 @@ #include "mainwindow.h" -#include "ui_mainwindow.h" -#include #include "../WindCore/decoder.h" #include "clps7111.h" +#include "ui_mainwindow.h" +#include -MainWindow::MainWindow(EmuBase *emu, QWidget *parent) : - QMainWindow(parent), - ui(new Ui::MainWindow), - pdaScreen(emu), - emu(emu) -{ - ui->setupUi(this); - ui->logView->setMaximumBlockCount(1000); - - elapsedTimer.start(); - emu->setLogger([&](const char *str) { - QString fullStr = QStringLiteral("[%1] %2").arg(elapsedTimer.elapsed()).arg(str); - ui->logView->appendPlainText(fullStr); - }); - - timer = new QTimer(this); - timer->setInterval(1000/64); - connect(timer, SIGNAL(timeout()), SLOT(execTimer())); - - pdaScreen.show(); - - updateScreen(); -} - -MainWindow::~MainWindow() -{ - delete ui; -} - -void MainWindow::updateScreen() -{ - ui->cycleCounter->setText(QString("Cycles: %1").arg(emu->currentCycles())); - - updateMemory(); - - char flagDisplay[] = { - (emu->getCPSR() & 0x80000000) ? 'N' : '-', - (emu->getCPSR() & 0x40000000) ? 'Z' : '-', - (emu->getCPSR() & 0x20000000) ? 'C' : '-', - (emu->getCPSR() & 0x10000000) ? 'V' : '-', - 0 - }; - const char *modeName = "???"; - switch (emu->getCPSR() & 0x1F) { - case 0x10: modeName = "User"; break; - case 0x11: modeName = "FIQ"; break; - case 0x12: modeName = "IRQ"; break; - case 0x13: modeName = "Supervisor"; break; - case 0x17: modeName = "Abort"; break; - case 0x1B: modeName = "Undefined"; break; - } - - ui->regsLabel->setText( - QString("R0: %1 / R1: %2 / R2: %3 / R3: %4 / R4: %5 / R5: %6 / R6: %7 / R7: %8\nR8: %9 / R9: %10 / R10:%11 / R11:%12 / R12:%13 / SP: %14 / LR: %15 / PC: %16\n%17 / Mode: %18") - .arg(emu->getGPR(0), 8, 16) - .arg(emu->getGPR(1), 8, 16) - .arg(emu->getGPR(2), 8, 16) - .arg(emu->getGPR(3), 8, 16) - .arg(emu->getGPR(4), 8, 16) - .arg(emu->getGPR(5), 8, 16) - .arg(emu->getGPR(6), 8, 16) - .arg(emu->getGPR(7), 8, 16) - .arg(emu->getGPR(8), 8, 16) - .arg(emu->getGPR(9), 8, 16) - .arg(emu->getGPR(10), 8, 16) - .arg(emu->getGPR(11), 8, 16) - .arg(emu->getGPR(12), 8, 16) - .arg(emu->getGPR(13), 8, 16) - .arg(emu->getGPR(14), 8, 16) - .arg(emu->getGPR(15), 8, 16) - .arg(flagDisplay) - .arg(modeName) - ); - - // show a crude disassembly - const int context = 8 * 4; - uint32_t pc = emu->getGPR(15) - 8; - uint32_t minCode = pc - context; - if (minCode >= (UINT32_MAX - context)) - minCode = 0; - uint32_t maxCode = pc + context; - if (maxCode < context) - maxCode = UINT32_MAX; - - QStringList codeLines; - for (uint32_t addr = minCode; addr >= minCode && addr <= maxCode; addr += 4) { - const char *prefix = (addr == pc) ? (emu->instructionReady() ? "==>" : "...") : " "; - struct ARMInstructionInfo info; - char buffer[512]; - - auto result = emu->readVirtual(addr, ARM710::V32); - if (result.first.has_value()) { - uint32_t opcode = result.first.value(); - ARMDecodeARM(opcode, &info); - ARMDisassemble(&info, addr, buffer, sizeof(buffer)); - codeLines.append(QString("%1 %2 | %3 | %4").arg(prefix).arg(addr, 8, 16).arg(opcode, 8, 16).arg(buffer)); - } +MainWindow::MainWindow(EmuBase* emu, QWidget* parent) + : QMainWindow(parent), ui(new Ui::MainWindow), pdaScreen(emu), emu(emu) { + ui->setupUi(this); + ui->logView->setMaximumBlockCount(1000); + + elapsedTimer.start(); + emu->setLogger([&](const char* str) { + QString fullStr = + QStringLiteral("[%1] %2").arg(elapsedTimer.elapsed()).arg(str); + ui->logView->appendPlainText(fullStr); + }); + + timer = new QTimer(this); + timer->setInterval(1000 / 64); + connect(timer, SIGNAL(timeout()), SLOT(execTimer())); + + pdaScreen.show(); + + updateScreen(); +} + +MainWindow::~MainWindow() { delete ui; } + +void MainWindow::updateScreen() { + ui->cycleCounter->setText(QString("Cycles: %1").arg(emu->currentCycles())); + + updateMemory(); + + char flagDisplay[] = {(emu->getCPSR() & 0x80000000) ? 'N' : '-', + (emu->getCPSR() & 0x40000000) ? 'Z' : '-', + (emu->getCPSR() & 0x20000000) ? 'C' : '-', + (emu->getCPSR() & 0x10000000) ? 'V' : '-', 0}; + const char* modeName = "???"; + switch (emu->getCPSR() & 0x1F) { + case 0x10: + modeName = "User"; + break; + case 0x11: + modeName = "FIQ"; + break; + case 0x12: + modeName = "IRQ"; + break; + case 0x13: + modeName = "Supervisor"; + break; + case 0x17: + modeName = "Abort"; + break; + case 0x1B: + modeName = "Undefined"; + break; + } + + ui->regsLabel->setText( + QString("R0: %1 / R1: %2 / R2: %3 / R3: %4 / R4: %5 / R5: %6 / R6: %7 / " + "R7: %8\nR8: %9 / R9: %10 / R10:%11 / R11:%12 / R12:%13 / SP: " + "%14 / LR: %15 / PC: %16\n%17 / Mode: %18") + .arg(emu->getGPR(0), 8, 16) + .arg(emu->getGPR(1), 8, 16) + .arg(emu->getGPR(2), 8, 16) + .arg(emu->getGPR(3), 8, 16) + .arg(emu->getGPR(4), 8, 16) + .arg(emu->getGPR(5), 8, 16) + .arg(emu->getGPR(6), 8, 16) + .arg(emu->getGPR(7), 8, 16) + .arg(emu->getGPR(8), 8, 16) + .arg(emu->getGPR(9), 8, 16) + .arg(emu->getGPR(10), 8, 16) + .arg(emu->getGPR(11), 8, 16) + .arg(emu->getGPR(12), 8, 16) + .arg(emu->getGPR(13), 8, 16) + .arg(emu->getGPR(14), 8, 16) + .arg(emu->getGPR(15), 8, 16) + .arg(flagDisplay) + .arg(modeName)); + + // show a crude disassembly + const int context = 8 * 4; + uint32_t pc = emu->getGPR(15) - 8; + uint32_t minCode = pc - context; + if (minCode >= (UINT32_MAX - context)) + minCode = 0; + uint32_t maxCode = pc + context; + if (maxCode < context) + maxCode = UINT32_MAX; + + QStringList codeLines; + for (uint32_t addr = minCode; addr >= minCode && addr <= maxCode; addr += 4) { + const char* prefix = + (addr == pc) ? (emu->instructionReady() ? "==>" : "...") : " "; + struct ARMInstructionInfo info; + char buffer[512]; + + auto result = emu->readVirtual(addr, ARM710::V32); + if (result.first.has_value()) { + uint32_t opcode = result.first.value(); + ARMDecodeARM(opcode, &info); + ARMDisassemble(&info, addr, buffer, sizeof(buffer)); + codeLines.append(QString("%1 %2 | %3 | %4") + .arg(prefix) + .arg(addr, 8, 16) + .arg(opcode, 8, 16) + .arg(buffer)); } - ui->codeLabel->setText(codeLines.join('\n')); + } + ui->codeLabel->setText(codeLines.join('\n')); - // now, the actual screen - pdaScreen.updateScreen(); + // now, the actual screen + pdaScreen.updateScreen(); } +void MainWindow::on_startButton_clicked() { + timer->start(); + ui->startButton->setEnabled(false); + ui->stopButton->setEnabled(true); + ui->stepInsnButton->setEnabled(false); + ui->stepTickButton->setEnabled(false); +} - -void MainWindow::on_startButton_clicked() -{ - timer->start(); - ui->startButton->setEnabled(false); - ui->stopButton->setEnabled(true); - ui->stepInsnButton->setEnabled(false); - ui->stepTickButton->setEnabled(false); +void MainWindow::on_stopButton_clicked() { + timer->stop(); + ui->startButton->setEnabled(true); + ui->stopButton->setEnabled(false); + ui->stepInsnButton->setEnabled(true); + ui->stepTickButton->setEnabled(true); } -void MainWindow::on_stopButton_clicked() -{ - timer->stop(); - ui->startButton->setEnabled(true); - ui->stopButton->setEnabled(false); - ui->stepInsnButton->setEnabled(true); - ui->stepTickButton->setEnabled(true); +void MainWindow::on_stepTickButton_clicked() { + // emu->executeUntil(emu->currentCycles() + (CLOCK_SPEED * 2)); + emu->executeUntil(emu->currentCycles() + 25000000); + updateScreen(); } -void MainWindow::on_stepTickButton_clicked() -{ -// emu->executeUntil(emu->currentCycles() + (CLOCK_SPEED * 2)); - emu->executeUntil(emu->currentCycles() + 25000000); - updateScreen(); +void MainWindow::on_stepInsnButton_clicked() { + emu->executeUntil(emu->currentCycles() + 1); + updateScreen(); } -void MainWindow::on_stepInsnButton_clicked() -{ - emu->executeUntil(emu->currentCycles() + 1); +void MainWindow::execTimer() { + if (emu) { + emu->executeUntil(emu->currentCycles() + (emu->getClockSpeed() / 64)); updateScreen(); + } } -void MainWindow::execTimer() -{ - if (emu) { - emu->executeUntil(emu->currentCycles() + (emu->getClockSpeed() / 64)); - updateScreen(); - } +void MainWindow::on_addBreakButton_clicked() { + uint32_t addr = ui->breakpointAddress->text().toUInt(nullptr, 16); + emu->breakpoints().insert(addr); + updateBreakpointsList(); } -void MainWindow::on_addBreakButton_clicked() -{ - uint32_t addr = ui->breakpointAddress->text().toUInt(nullptr, 16); - emu->breakpoints().insert(addr); - updateBreakpointsList(); +void MainWindow::on_removeBreakButton_clicked() { + uint32_t addr = ui->breakpointAddress->text().toUInt(nullptr, 16); + emu->breakpoints().erase(addr); + updateBreakpointsList(); } -void MainWindow::on_removeBreakButton_clicked() -{ - uint32_t addr = ui->breakpointAddress->text().toUInt(nullptr, 16); - emu->breakpoints().erase(addr); - updateBreakpointsList(); +void MainWindow::updateBreakpointsList() { + ui->breakpointsList->clear(); + for (uint32_t addr : emu->breakpoints()) { + ui->breakpointsList->addItem(QString::number(addr, 16)); + } } -void MainWindow::updateBreakpointsList() -{ - ui->breakpointsList->clear(); - for (uint32_t addr : emu->breakpoints()) { - ui->breakpointsList->addItem(QString::number(addr, 16)); - } +void MainWindow::on_memoryViewAddress_textEdited(const QString&) { + updateMemory(); } -void MainWindow::on_memoryViewAddress_textEdited(const QString &) -{ - updateMemory(); -} +void MainWindow::updateMemory() { + uint32_t virtBase = ui->memoryViewAddress->text().toUInt(nullptr, 16) & ~0xFF; + auto physBaseOpt = emu->virtToPhys(virtBase); + auto physBase = physBaseOpt.value_or(0xFFFFFFFF); + bool ok = physBaseOpt.has_value(); + if (ok && (virtBase != physBase)) + ui->physicalAddressLabel->setText( + QStringLiteral("Physical: %1").arg(physBase, 8, 16, QLatin1Char('0'))); + + uint8_t block[0x100]; + if (ok) { + for (int i = 0; i < 0x100; i++) { + block[i] = emu->readPhysical(physBase + i, ARM710::V8).value(); + } + } + + QStringList output; + for (int row = 0; row < 16; row++) { + QString outLine; + outLine.reserve(8 + 2 + (2 * 16) + 3 + 16); + outLine.append(QStringLiteral("%1 |").arg(virtBase + (row * 16), 8, 16)); + for (int col = 0; col < 16; col++) { + if (ok) + outLine.append(QStringLiteral(" %1").arg(block[row * 16 + col], 2, 16, + QLatin1Char('0'))); + else + outLine.append(QStringLiteral(" ??")); + } + outLine.append(QStringLiteral(" | ")); + for (int col = 0; col < 16; col++) { + uint8_t byte = block[row * 16 + col]; + if (!ok) + outLine.append('?'); + else if (byte >= 0x20 && byte <= 0x7E) + outLine.append((QChar)byte); + else + outLine.append('.'); + } + output.append(outLine); + } -void MainWindow::updateMemory() -{ - uint32_t virtBase = ui->memoryViewAddress->text().toUInt(nullptr, 16) & ~0xFF; - auto physBaseOpt = emu->virtToPhys(virtBase); - auto physBase = physBaseOpt.value_or(0xFFFFFFFF); - bool ok = physBaseOpt.has_value(); - if (ok && (virtBase != physBase)) - ui->physicalAddressLabel->setText(QStringLiteral("Physical: %1").arg(physBase, 8, 16, QLatin1Char('0'))); - - uint8_t block[0x100]; - if (ok) { - for (int i = 0; i < 0x100; i++) { - block[i] = emu->readPhysical(physBase + i, ARM710::V8).value(); - } - } - - QStringList output; - for (int row = 0; row < 16; row++) { - QString outLine; - outLine.reserve(8 + 2 + (2 * 16) + 3 + 16); - outLine.append(QStringLiteral("%1 |").arg(virtBase + (row * 16), 8, 16)); - for (int col = 0; col < 16; col++) { - if (ok) - outLine.append(QStringLiteral(" %1").arg(block[row*16+col], 2, 16, QLatin1Char('0'))); - else - outLine.append(QStringLiteral(" ??")); - } - outLine.append(QStringLiteral(" | ")); - for (int col = 0; col < 16; col++) { - uint8_t byte = block[row*16+col]; - if (!ok) - outLine.append('?'); - else if (byte >= 0x20 && byte <= 0x7E) - outLine.append((QChar)byte); - else - outLine.append('.'); - } - output.append(outLine); - } - - ui->memoryViewLabel->setText(output.join('\n')); + ui->memoryViewLabel->setText(output.join('\n')); } void MainWindow::on_memoryAdd1_clicked() { adjustMemoryAddress(1); } @@ -229,24 +227,23 @@ void MainWindow::on_memorySub10_clicked() { adjustMemoryAddress(-0x10); } void MainWindow::on_memorySub100_clicked() { adjustMemoryAddress(-0x100); } void MainWindow::adjustMemoryAddress(int offset) { - uint32_t address = ui->memoryViewAddress->text().toUInt(nullptr, 16); - address += offset; - ui->memoryViewAddress->setText(QString("%1").arg(address, 8, 16, QLatin1Char('0'))); - updateMemory(); + uint32_t address = ui->memoryViewAddress->text().toUInt(nullptr, 16); + address += offset; + ui->memoryViewAddress->setText( + QString("%1").arg(address, 8, 16, QLatin1Char('0'))); + updateMemory(); } -void MainWindow::on_writeByteButton_clicked() -{ - uint32_t address = ui->memoryViewAddress->text().toUInt(nullptr, 16); - uint8_t value = (uint8_t)ui->memoryWriteValue->text().toUInt(nullptr, 16); - emu->writeVirtual(value, address, ARM710::V8); - updateMemory(); +void MainWindow::on_writeByteButton_clicked() { + uint32_t address = ui->memoryViewAddress->text().toUInt(nullptr, 16); + uint8_t value = (uint8_t)ui->memoryWriteValue->text().toUInt(nullptr, 16); + emu->writeVirtual(value, address, ARM710::V8); + updateMemory(); } -void MainWindow::on_writeDwordButton_clicked() -{ - uint32_t address = ui->memoryViewAddress->text().toUInt(nullptr, 16); - uint32_t value = ui->memoryWriteValue->text().toUInt(nullptr, 16); - emu->writeVirtual(value, address, ARM710::V32); - updateMemory(); +void MainWindow::on_writeDwordButton_clicked() { + uint32_t address = ui->memoryViewAddress->text().toUInt(nullptr, 16); + uint32_t value = ui->memoryWriteValue->text().toUInt(nullptr, 16); + emu->writeVirtual(value, address, ARM710::V32); + updateMemory(); } diff --git a/WindQt/mainwindow.h b/WindQt/mainwindow.h index 636374a..efd848a 100644 --- a/WindQt/mainwindow.h +++ b/WindQt/mainwindow.h @@ -1,59 +1,58 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H -#include -#include #include "../WindCore/emubase.h" #include "pdascreenwindow.h" +#include +#include namespace Ui { class MainWindow; } -class MainWindow : public QMainWindow -{ - Q_OBJECT +class MainWindow : public QMainWindow { + Q_OBJECT public: - explicit MainWindow(EmuBase *emu, QWidget *parent = nullptr); - ~MainWindow() override; + explicit MainWindow(EmuBase* emu, QWidget* parent = nullptr); + ~MainWindow() override; private slots: - void execTimer(); + void execTimer(); - void on_startButton_clicked(); - void on_stopButton_clicked(); - void on_stepInsnButton_clicked(); - void on_stepTickButton_clicked(); + void on_startButton_clicked(); + void on_stopButton_clicked(); + void on_stepInsnButton_clicked(); + void on_stepTickButton_clicked(); - void on_addBreakButton_clicked(); + void on_addBreakButton_clicked(); - void on_removeBreakButton_clicked(); + void on_removeBreakButton_clicked(); - void on_memoryViewAddress_textEdited(const QString &arg1); - void on_memoryAdd1_clicked(); - void on_memoryAdd4_clicked(); - void on_memoryAdd10_clicked(); - void on_memoryAdd100_clicked(); - void on_memorySub1_clicked(); - void on_memorySub4_clicked(); - void on_memorySub10_clicked(); - void on_memorySub100_clicked(); + void on_memoryViewAddress_textEdited(const QString& arg1); + void on_memoryAdd1_clicked(); + void on_memoryAdd4_clicked(); + void on_memoryAdd10_clicked(); + void on_memoryAdd100_clicked(); + void on_memorySub1_clicked(); + void on_memorySub4_clicked(); + void on_memorySub10_clicked(); + void on_memorySub100_clicked(); - void on_writeByteButton_clicked(); + void on_writeByteButton_clicked(); - void on_writeDwordButton_clicked(); + void on_writeDwordButton_clicked(); private: - QElapsedTimer elapsedTimer; - Ui::MainWindow *ui; - PDAScreenWindow pdaScreen; - EmuBase *emu; - QTimer *timer; - void updateScreen(); - void updateBreakpointsList(); - void updateMemory(); - void adjustMemoryAddress(int offset); + QElapsedTimer elapsedTimer; + Ui::MainWindow* ui; + PDAScreenWindow pdaScreen; + EmuBase* emu; + QTimer* timer; + void updateScreen(); + void updateBreakpointsList(); + void updateMemory(); + void adjustMemoryAddress(int offset); }; #endif // MAINWINDOW_H diff --git a/WindQt/pdascreenwindow.cpp b/WindQt/pdascreenwindow.cpp index 4531c5b..0eae0ae 100644 --- a/WindQt/pdascreenwindow.cpp +++ b/WindQt/pdascreenwindow.cpp @@ -1,203 +1,273 @@ #include "pdascreenwindow.h" #include -PDAScreenWindow::PDAScreenWindow(EmuBase *emu, QWidget *parent) : - QWidget(parent), - emu(emu), - lcd(new QLabel(this)) -{ - setWindowTitle("WindEmu"); - setFixedSize(emu->getDigitiserWidth(), emu->getDigitiserHeight()); - lcd->setGeometry(emu->getLCDOffsetX(), emu->getLCDOffsetY(), emu->getLCDWidth(), emu->getLCDHeight()); - - const char *who = emu->getDeviceName(); - if (strcmp(who, "Osaris") == 0) { - // some cheap and cheerful placeholders - int bitW = (emu->getDigitiserWidth() - emu->getLCDWidth()) / 2; - int bitH = emu->getDigitiserHeight() / 5; - int leftX = 0; - int rightX = bitW + emu->getLCDWidth(); - (new QLabel("Word", this))->setGeometry(leftX, bitH * 0, bitW, bitH); - (new QLabel("Sheet", this))->setGeometry(leftX, bitH * 1, bitW, bitH); - (new QLabel("Data", this))->setGeometry(leftX, bitH * 2, bitW, bitH); - (new QLabel("Agenda", this))->setGeometry(leftX, bitH * 3, bitW, bitH); - (new QLabel("Extras", this))->setGeometry(leftX, bitH * 4, bitW, bitH); - (new QLabel("EPOC", this))->setGeometry(rightX, bitH * 0, bitW, bitH); - (new QLabel("Menu", this))->setGeometry(rightX, bitH * 1, bitW, bitH); - (new QLabel("Copy/Paste", this))->setGeometry(rightX, bitH * 2, bitW, bitH); - (new QLabel("Zoom In", this))->setGeometry(rightX, bitH * 3, bitW, bitH); - (new QLabel("Zoom Out", this))->setGeometry(rightX, bitH * 4, bitW, bitH); - } else if (strcmp(who, "Series 5mx") == 0) { - int leftW = emu->getLCDOffsetX(); - int leftH = emu->getLCDHeight() / 5; - (new QLabel("➡️", this))->setGeometry(0, leftH * 0, leftW, leftH); - (new QLabel("📄", this))->setGeometry(0, leftH * 1, leftW, leftH); - (new QLabel("📡", this))->setGeometry(0, leftH * 2, leftW, leftH); - (new QLabel("+", this))->setGeometry(0, leftH * 3, leftW, leftH); - (new QLabel("-", this))->setGeometry(0, leftH * 4, leftW, leftH); - - int barX = 50; - int barY = leftH * 5; - int barW = (emu->getDigitiserWidth() - barX) / 8; - int barH = emu->getDigitiserHeight() - emu->getLCDHeight(); - (new QLabel("System", this))->setGeometry(0, barY, barX, barH); - (new QLabel("Word", this))->setGeometry(barX + barW * 0, barY, barW, barH); - (new QLabel("Sheet", this))->setGeometry(barX + barW * 1, barY, barW, barH); - (new QLabel("Contacts", this))->setGeometry(barX + barW * 2, barY, barW, barH); - (new QLabel("Agenda", this))->setGeometry(barX + barW * 3, barY, barW, barH); - (new QLabel("Email", this))->setGeometry(barX + barW * 4, barY, barW, barH); - (new QLabel("Calc", this))->setGeometry(barX + barW * 5, barY, barW, barH); - (new QLabel("Jotter", this))->setGeometry(barX + barW * 6, barY, barW, barH); - (new QLabel("Extras", this))->setGeometry(barX + barW * 7, barY, barW, barH); - } +PDAScreenWindow::PDAScreenWindow(EmuBase* emu, QWidget* parent) + : QWidget(parent), emu(emu), lcd(new QLabel(this)) { + setWindowTitle("WindEmu"); + setFixedSize(emu->getDigitiserWidth(), emu->getDigitiserHeight()); + lcd->setGeometry(emu->getLCDOffsetX(), emu->getLCDOffsetY(), + emu->getLCDWidth(), emu->getLCDHeight()); + + const char* who = emu->getDeviceName(); + if (strcmp(who, "Osaris") == 0) { + // some cheap and cheerful placeholders + int bitW = (emu->getDigitiserWidth() - emu->getLCDWidth()) / 2; + int bitH = emu->getDigitiserHeight() / 5; + int leftX = 0; + int rightX = bitW + emu->getLCDWidth(); + (new QLabel("Word", this))->setGeometry(leftX, bitH * 0, bitW, bitH); + (new QLabel("Sheet", this))->setGeometry(leftX, bitH * 1, bitW, bitH); + (new QLabel("Data", this))->setGeometry(leftX, bitH * 2, bitW, bitH); + (new QLabel("Agenda", this))->setGeometry(leftX, bitH * 3, bitW, bitH); + (new QLabel("Extras", this))->setGeometry(leftX, bitH * 4, bitW, bitH); + (new QLabel("EPOC", this))->setGeometry(rightX, bitH * 0, bitW, bitH); + (new QLabel("Menu", this))->setGeometry(rightX, bitH * 1, bitW, bitH); + (new QLabel("Copy/Paste", this))->setGeometry(rightX, bitH * 2, bitW, bitH); + (new QLabel("Zoom In", this))->setGeometry(rightX, bitH * 3, bitW, bitH); + (new QLabel("Zoom Out", this))->setGeometry(rightX, bitH * 4, bitW, bitH); + } else if (strcmp(who, "Series 5mx") == 0) { + int leftW = emu->getLCDOffsetX(); + int leftH = emu->getLCDHeight() / 5; + (new QLabel("➡️", this))->setGeometry(0, leftH * 0, leftW, leftH); + (new QLabel("📄", this))->setGeometry(0, leftH * 1, leftW, leftH); + (new QLabel("📡", this))->setGeometry(0, leftH * 2, leftW, leftH); + (new QLabel("+", this))->setGeometry(0, leftH * 3, leftW, leftH); + (new QLabel("-", this))->setGeometry(0, leftH * 4, leftW, leftH); + + int barX = 50; + int barY = leftH * 5; + int barW = (emu->getDigitiserWidth() - barX) / 8; + int barH = emu->getDigitiserHeight() - emu->getLCDHeight(); + (new QLabel("System", this))->setGeometry(0, barY, barX, barH); + (new QLabel("Word", this))->setGeometry(barX + barW * 0, barY, barW, barH); + (new QLabel("Sheet", this))->setGeometry(barX + barW * 1, barY, barW, barH); + (new QLabel("Contacts", this)) + ->setGeometry(barX + barW * 2, barY, barW, barH); + (new QLabel("Agenda", this)) + ->setGeometry(barX + barW * 3, barY, barW, barH); + (new QLabel("Email", this))->setGeometry(barX + barW * 4, barY, barW, barH); + (new QLabel("Calc", this))->setGeometry(barX + barW * 5, barY, barW, barH); + (new QLabel("Jotter", this)) + ->setGeometry(barX + barW * 6, barY, barW, barH); + (new QLabel("Extras", this)) + ->setGeometry(barX + barW * 7, barY, barW, barH); + } } void PDAScreenWindow::updateScreen() { - uint8_t *lines[1024]; - QImage img(emu->getLCDWidth(), emu->getLCDHeight(), QImage::Format_Grayscale8); - for (int y = 0; y < img.height(); y++) - lines[y] = img.scanLine(y); - emu->readLCDIntoBuffer(lines, false); + uint8_t* lines[1024]; + QImage img(emu->getLCDWidth(), emu->getLCDHeight(), + QImage::Format_Grayscale8); + for (int y = 0; y < img.height(); y++) + lines[y] = img.scanLine(y); + emu->readLCDIntoBuffer(lines, false); - lcd->setPixmap(QPixmap::fromImage(std::move(img))); + lcd->setPixmap(QPixmap::fromImage(std::move(img))); } #ifdef Q_OS_MAC static EpocKey resolveKey(int key, int vk) { - // Although Cocoa/Carbon's virtual keycodes include - // modifiers, Qt doesn't expose them through QKeyEvent... - switch (key) { - case Qt::Key_Control: return EStdKeyLeftFunc; - case Qt::Key_Shift: return EStdKeyLeftShift; - case Qt::Key_Alt: return EStdKeyMenu; - case Qt::Key_Meta: return EStdKeyLeftCtrl; - } - - // https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX10.6.sdk/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h#L182 - switch (vk) { - case 0x00: return (EpocKey)'A'; - case 0x01: return (EpocKey)'S'; - case 0x02: return (EpocKey)'D'; - case 0x03: return (EpocKey)'F'; - case 0x04: return (EpocKey)'H'; - case 0x05: return (EpocKey)'G'; - case 0x06: return (EpocKey)'Z'; - case 0x07: return (EpocKey)'X'; - case 0x08: return (EpocKey)'C'; - case 0x09: return (EpocKey)'V'; - case 0x0B: return (EpocKey)'B'; - case 0x0C: return (EpocKey)'Q'; - case 0x0D: return (EpocKey)'W'; - case 0x0E: return (EpocKey)'E'; - case 0x0F: return (EpocKey)'R'; - - case 0x10: return (EpocKey)'Y'; - case 0x11: return (EpocKey)'T'; - case 0x12: return (EpocKey)'1'; - case 0x13: return (EpocKey)'2'; - case 0x14: return (EpocKey)'3'; - case 0x15: return (EpocKey)'4'; - case 0x16: return (EpocKey)'6'; - case 0x17: return (EpocKey)'5'; - case 0x19: return (EpocKey)'9'; - case 0x1A: return (EpocKey)'7'; - case 0x1C: return (EpocKey)'8'; - case 0x1D: return (EpocKey)'0'; - case 0x1F: return (EpocKey)'O'; - - case 0x20: return (EpocKey)'U'; - case 0x22: return (EpocKey)'I'; - case 0x23: return (EpocKey)'P'; - case 0x24: return EStdKeyEnter; - case 0x25: return (EpocKey)'L'; - case 0x26: return (EpocKey)'J'; - case 0x27: return EStdKeySingleQuote; - case 0x28: return (EpocKey)'K'; - case 0x2B: return EStdKeyComma; - case 0x2D: return (EpocKey)'N'; - case 0x2E: return (EpocKey)'M'; - case 0x2F: return EStdKeyFullStop; - - case 0x30: return EStdKeyTab; - case 0x31: return EStdKeySpace; - case 0x33: return EStdKeyBackspace; - case 0x35: return EStdKeyEscape; - - case 0x7B: return EStdKeyLeftArrow; - case 0x7C: return EStdKeyRightArrow; - case 0x7D: return EStdKeyDownArrow; - case 0x7E: return EStdKeyUpArrow; - } - - return EStdKeyNull; + // Although Cocoa/Carbon's virtual keycodes include + // modifiers, Qt doesn't expose them through QKeyEvent... + switch (key) { + case Qt::Key_Control: + return EStdKeyLeftFunc; + case Qt::Key_Shift: + return EStdKeyLeftShift; + case Qt::Key_Alt: + return EStdKeyMenu; + case Qt::Key_Meta: + return EStdKeyLeftCtrl; + } + + // https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX10.6.sdk/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h#L182 + switch (vk) { + case 0x00: + return (EpocKey)'A'; + case 0x01: + return (EpocKey)'S'; + case 0x02: + return (EpocKey)'D'; + case 0x03: + return (EpocKey)'F'; + case 0x04: + return (EpocKey)'H'; + case 0x05: + return (EpocKey)'G'; + case 0x06: + return (EpocKey)'Z'; + case 0x07: + return (EpocKey)'X'; + case 0x08: + return (EpocKey)'C'; + case 0x09: + return (EpocKey)'V'; + case 0x0B: + return (EpocKey)'B'; + case 0x0C: + return (EpocKey)'Q'; + case 0x0D: + return (EpocKey)'W'; + case 0x0E: + return (EpocKey)'E'; + case 0x0F: + return (EpocKey)'R'; + + case 0x10: + return (EpocKey)'Y'; + case 0x11: + return (EpocKey)'T'; + case 0x12: + return (EpocKey)'1'; + case 0x13: + return (EpocKey)'2'; + case 0x14: + return (EpocKey)'3'; + case 0x15: + return (EpocKey)'4'; + case 0x16: + return (EpocKey)'6'; + case 0x17: + return (EpocKey)'5'; + case 0x19: + return (EpocKey)'9'; + case 0x1A: + return (EpocKey)'7'; + case 0x1C: + return (EpocKey)'8'; + case 0x1D: + return (EpocKey)'0'; + case 0x1F: + return (EpocKey)'O'; + + case 0x20: + return (EpocKey)'U'; + case 0x22: + return (EpocKey)'I'; + case 0x23: + return (EpocKey)'P'; + case 0x24: + return EStdKeyEnter; + case 0x25: + return (EpocKey)'L'; + case 0x26: + return (EpocKey)'J'; + case 0x27: + return EStdKeySingleQuote; + case 0x28: + return (EpocKey)'K'; + case 0x2B: + return EStdKeyComma; + case 0x2D: + return (EpocKey)'N'; + case 0x2E: + return (EpocKey)'M'; + case 0x2F: + return EStdKeyFullStop; + + case 0x30: + return EStdKeyTab; + case 0x31: + return EStdKeySpace; + case 0x33: + return EStdKeyBackspace; + case 0x35: + return EStdKeyEscape; + + case 0x7B: + return EStdKeyLeftArrow; + case 0x7C: + return EStdKeyRightArrow; + case 0x7D: + return EStdKeyDownArrow; + case 0x7E: + return EStdKeyUpArrow; + } + + return EStdKeyNull; } #else #error "Unsupported platform (for now! fix me in pdascreenwindow.cpp)" static EpocKey resolveKey(int key) { - // Placeholder, doesn't work for all keys - switch (key) { - case Qt::Key_Apostrophe: return EStdKeySingleQuote; - case Qt::Key_Backspace: return EStdKeyBackspace; - case Qt::Key_Escape: return EStdKeyEscape; - case Qt::Key_Enter: return EStdKeyEnter; - case Qt::Key_Return: return EStdKeyEnter; - case Qt::Key_Alt: return EStdKeyMenu; - case Qt::Key_Tab: return EStdKeyTab; + // Placeholder, doesn't work for all keys + switch (key) { + case Qt::Key_Apostrophe: + return EStdKeySingleQuote; + case Qt::Key_Backspace: + return EStdKeyBackspace; + case Qt::Key_Escape: + return EStdKeyEscape; + case Qt::Key_Enter: + return EStdKeyEnter; + case Qt::Key_Return: + return EStdKeyEnter; + case Qt::Key_Alt: + return EStdKeyMenu; + case Qt::Key_Tab: + return EStdKeyTab; #ifdef Q_OS_MAC - case Qt::Key_Meta: return EStdKeyLeftCtrl; + case Qt::Key_Meta: + return EStdKeyLeftCtrl; #else - case Qt::Key_Control: return EStdKeyLeftCtrl; + case Qt::Key_Control: + return EStdKeyLeftCtrl; #endif - case Qt::Key_Down: return EStdKeyDownArrow; - case Qt::Key_Period: return EStdKeyFullStop; + case Qt::Key_Down: + return EStdKeyDownArrow; + case Qt::Key_Period: + return EStdKeyFullStop; #ifdef Q_OS_MAC - case Qt::Key_Control: return EStdKeyLeftFunc; + case Qt::Key_Control: + return EStdKeyLeftFunc; #else - case Qt::Key_Meta: return EStdKeyLeftFunc; + case Qt::Key_Meta: + return EStdKeyLeftFunc; #endif - case Qt::Key_Shift: return EStdKeyLeftShift; - case Qt::Key_Right: return EStdKeyRightArrow; - case Qt::Key_Left: return EStdKeyLeftArrow; - case Qt::Key_Comma: return EStdKeyComma; - case Qt::Key_Up: return EStdKeyUpArrow; - case Qt::Key_Space: return EStdKeySpace; - } - - if (key >= '0' && key <= '9') return (EpocKey)key; - if (key >= 'A' && key <= 'Z') return (EpocKey)key; - return EStdKeyNull; + case Qt::Key_Shift: + return EStdKeyLeftShift; + case Qt::Key_Right: + return EStdKeyRightArrow; + case Qt::Key_Left: + return EStdKeyLeftArrow; + case Qt::Key_Comma: + return EStdKeyComma; + case Qt::Key_Up: + return EStdKeyUpArrow; + case Qt::Key_Space: + return EStdKeySpace; + } + + if (key >= '0' && key <= '9') + return (EpocKey)key; + if (key >= 'A' && key <= 'Z') + return (EpocKey)key; + return EStdKeyNull; } #endif - -void PDAScreenWindow::keyPressEvent(QKeyEvent *event) -{ - emu->log("KeyPress: QtKey=%d nativeVirtualKey=%x nativeModifiers=%x", event->key(), event->nativeVirtualKey(), event->nativeModifiers()); - EpocKey k = resolveKey(event->key(), event->nativeVirtualKey()); - if (k != EStdKeyNull) - emu->setKeyboardKey(k, true); +void PDAScreenWindow::keyPressEvent(QKeyEvent* event) { + emu->log("KeyPress: QtKey=%d nativeVirtualKey=%x nativeModifiers=%x", + event->key(), event->nativeVirtualKey(), event->nativeModifiers()); + EpocKey k = resolveKey(event->key(), event->nativeVirtualKey()); + if (k != EStdKeyNull) + emu->setKeyboardKey(k, true); } -void PDAScreenWindow::keyReleaseEvent(QKeyEvent *event) -{ - EpocKey k = resolveKey(event->key(), event->nativeVirtualKey()); - if (k != EStdKeyNull) - emu->setKeyboardKey(k, false); +void PDAScreenWindow::keyReleaseEvent(QKeyEvent* event) { + EpocKey k = resolveKey(event->key(), event->nativeVirtualKey()); + if (k != EStdKeyNull) + emu->setKeyboardKey(k, false); } - -void PDAScreenWindow::mousePressEvent(QMouseEvent *event) -{ - emu->updateTouchInput(event->x(), event->y(), true); +void PDAScreenWindow::mousePressEvent(QMouseEvent* event) { + emu->updateTouchInput(event->x(), event->y(), true); } -void PDAScreenWindow::mouseReleaseEvent(QMouseEvent *event) -{ - emu->updateTouchInput(event->x(), event->y(), false); +void PDAScreenWindow::mouseReleaseEvent(QMouseEvent* event) { + emu->updateTouchInput(event->x(), event->y(), false); } -void PDAScreenWindow::mouseMoveEvent(QMouseEvent *event) -{ - if (event->buttons() & Qt::LeftButton) - emu->updateTouchInput(event->x(), event->y(), true); +void PDAScreenWindow::mouseMoveEvent(QMouseEvent* event) { + if (event->buttons() & Qt::LeftButton) + emu->updateTouchInput(event->x(), event->y(), true); } diff --git a/WindQt/pdascreenwindow.h b/WindQt/pdascreenwindow.h index e18ca78..74a6db6 100644 --- a/WindQt/pdascreenwindow.h +++ b/WindQt/pdascreenwindow.h @@ -1,29 +1,28 @@ #ifndef PDASCREENWINDOW_H #define PDASCREENWINDOW_H -#include -#include #include "emubase.h" +#include +#include -class PDAScreenWindow : public QWidget -{ - Q_OBJECT +class PDAScreenWindow : public QWidget { + Q_OBJECT private: - EmuBase *emu; - QLabel *lcd; + EmuBase* emu; + QLabel* lcd; public: - explicit PDAScreenWindow(EmuBase *emu, QWidget *parent = nullptr); + explicit PDAScreenWindow(EmuBase* emu, QWidget* parent = nullptr); public slots: - void updateScreen(); + void updateScreen(); protected: - void keyPressEvent(QKeyEvent *event) override; - void keyReleaseEvent(QKeyEvent *event) override; - void mousePressEvent(QMouseEvent *event) override; - void mouseReleaseEvent(QMouseEvent *event) override; - void mouseMoveEvent(QMouseEvent *event) override; + void keyPressEvent(QKeyEvent* event) override; + void keyReleaseEvent(QKeyEvent* event) override; + void mousePressEvent(QMouseEvent* event) override; + void mouseReleaseEvent(QMouseEvent* event) override; + void mouseMoveEvent(QMouseEvent* event) override; }; #endif // PDASCREENWINDOW_H diff --git a/WindWasm/main.cpp b/WindWasm/main.cpp index c05ba67..ad19550 100644 --- a/WindWasm/main.cpp +++ b/WindWasm/main.cpp @@ -1,129 +1,189 @@ #include "../WindCore/emubase.h" #include "../WindCore/windermere.h" -#include -#include #include +#include +#include -EmuBase *emu; +EmuBase* emu; // SDL_Window *window; -SDL_Surface *surface; +SDL_Surface* surface; static EpocKey resolveKey(SDLKey sym) { - switch (sym) { - case SDLK_BACKSPACE: return EStdKeyBackspace; - case SDLK_TAB: return EStdKeyTab; - case SDLK_RETURN: return EStdKeyEnter; - case SDLK_ESCAPE: return EStdKeyEscape; - case SDLK_SPACE: return EStdKeySpace; - case SDLK_QUOTE: return EStdKeySingleQuote; - case SDLK_COMMA: return EStdKeyComma; - case SDLK_PERIOD: return EStdKeyFullStop; - case SDLK_0: return (EpocKey)'0'; - case SDLK_1: return (EpocKey)'1'; - case SDLK_2: return (EpocKey)'2'; - case SDLK_3: return (EpocKey)'3'; - case SDLK_4: return (EpocKey)'4'; - case SDLK_5: return (EpocKey)'5'; - case SDLK_6: return (EpocKey)'6'; - case SDLK_7: return (EpocKey)'7'; - case SDLK_8: return (EpocKey)'8'; - case SDLK_9: return (EpocKey)'9'; - case SDLK_a: return (EpocKey)'A'; - case SDLK_b: return (EpocKey)'B'; - case SDLK_c: return (EpocKey)'C'; - case SDLK_d: return (EpocKey)'D'; - case SDLK_e: return (EpocKey)'E'; - case SDLK_f: return (EpocKey)'F'; - case SDLK_g: return (EpocKey)'G'; - case SDLK_h: return (EpocKey)'H'; - case SDLK_i: return (EpocKey)'I'; - case SDLK_j: return (EpocKey)'J'; - case SDLK_k: return (EpocKey)'K'; - case SDLK_l: return (EpocKey)'L'; - case SDLK_m: return (EpocKey)'M'; - case SDLK_n: return (EpocKey)'N'; - case SDLK_o: return (EpocKey)'O'; - case SDLK_p: return (EpocKey)'P'; - case SDLK_q: return (EpocKey)'Q'; - case SDLK_r: return (EpocKey)'R'; - case SDLK_s: return (EpocKey)'S'; - case SDLK_t: return (EpocKey)'T'; - case SDLK_u: return (EpocKey)'U'; - case SDLK_v: return (EpocKey)'V'; - case SDLK_w: return (EpocKey)'W'; - case SDLK_x: return (EpocKey)'X'; - case SDLK_y: return (EpocKey)'Y'; - case SDLK_z: return (EpocKey)'Z'; - case SDLK_UP: return EStdKeyUpArrow; - case SDLK_DOWN: return EStdKeyDownArrow; - case SDLK_RIGHT: return EStdKeyRightArrow; - case SDLK_LEFT: return EStdKeyLeftArrow; - case SDLK_RSHIFT: return EStdKeyRightShift; - case SDLK_LSHIFT: return EStdKeyLeftShift; - case SDLK_RCTRL: return EStdKeyRightCtrl; - case SDLK_LCTRL: return EStdKeyLeftCtrl; - case SDLK_RALT: return EStdKeyMenu; - case SDLK_LALT: return EStdKeyMenu; - case SDLK_LSUPER: return EStdKeyLeftFunc; - case SDLK_RSUPER: return EStdKeyRightFunc; - } - return EStdKeyNull; + switch (sym) { + case SDLK_BACKSPACE: + return EStdKeyBackspace; + case SDLK_TAB: + return EStdKeyTab; + case SDLK_RETURN: + return EStdKeyEnter; + case SDLK_ESCAPE: + return EStdKeyEscape; + case SDLK_SPACE: + return EStdKeySpace; + case SDLK_QUOTE: + return EStdKeySingleQuote; + case SDLK_COMMA: + return EStdKeyComma; + case SDLK_PERIOD: + return EStdKeyFullStop; + case SDLK_0: + return (EpocKey)'0'; + case SDLK_1: + return (EpocKey)'1'; + case SDLK_2: + return (EpocKey)'2'; + case SDLK_3: + return (EpocKey)'3'; + case SDLK_4: + return (EpocKey)'4'; + case SDLK_5: + return (EpocKey)'5'; + case SDLK_6: + return (EpocKey)'6'; + case SDLK_7: + return (EpocKey)'7'; + case SDLK_8: + return (EpocKey)'8'; + case SDLK_9: + return (EpocKey)'9'; + case SDLK_a: + return (EpocKey)'A'; + case SDLK_b: + return (EpocKey)'B'; + case SDLK_c: + return (EpocKey)'C'; + case SDLK_d: + return (EpocKey)'D'; + case SDLK_e: + return (EpocKey)'E'; + case SDLK_f: + return (EpocKey)'F'; + case SDLK_g: + return (EpocKey)'G'; + case SDLK_h: + return (EpocKey)'H'; + case SDLK_i: + return (EpocKey)'I'; + case SDLK_j: + return (EpocKey)'J'; + case SDLK_k: + return (EpocKey)'K'; + case SDLK_l: + return (EpocKey)'L'; + case SDLK_m: + return (EpocKey)'M'; + case SDLK_n: + return (EpocKey)'N'; + case SDLK_o: + return (EpocKey)'O'; + case SDLK_p: + return (EpocKey)'P'; + case SDLK_q: + return (EpocKey)'Q'; + case SDLK_r: + return (EpocKey)'R'; + case SDLK_s: + return (EpocKey)'S'; + case SDLK_t: + return (EpocKey)'T'; + case SDLK_u: + return (EpocKey)'U'; + case SDLK_v: + return (EpocKey)'V'; + case SDLK_w: + return (EpocKey)'W'; + case SDLK_x: + return (EpocKey)'X'; + case SDLK_y: + return (EpocKey)'Y'; + case SDLK_z: + return (EpocKey)'Z'; + case SDLK_UP: + return EStdKeyUpArrow; + case SDLK_DOWN: + return EStdKeyDownArrow; + case SDLK_RIGHT: + return EStdKeyRightArrow; + case SDLK_LEFT: + return EStdKeyLeftArrow; + case SDLK_RSHIFT: + return EStdKeyRightShift; + case SDLK_LSHIFT: + return EStdKeyLeftShift; + case SDLK_RCTRL: + return EStdKeyRightCtrl; + case SDLK_LCTRL: + return EStdKeyLeftCtrl; + case SDLK_RALT: + return EStdKeyMenu; + case SDLK_LALT: + return EStdKeyMenu; + case SDLK_LSUPER: + return EStdKeyLeftFunc; + case SDLK_RSUPER: + return EStdKeyRightFunc; + } + return EStdKeyNull; } void emuEventLoop() { - // printf("Doing it\n"); - emu->executeUntil(emu->currentCycles() + (emu->getClockSpeed() / 64)); + // printf("Doing it\n"); + emu->executeUntil(emu->currentCycles() + (emu->getClockSpeed() / 64)); - uint8_t *lines[480]; + uint8_t* lines[480]; - SDL_LockSurface(surface); - int baseX = emu->getLCDOffsetX(); - int baseY = emu->getLCDOffsetY(); - int height = emu->getLCDHeight(); - for (int y = 0; y < height; y++) { - lines[y] = (uint8_t *)surface->pixels + (surface->pitch * (y + baseY)) + (baseX * 4); - } - emu->readLCDIntoBuffer(lines, true); - SDL_UnlockSurface(surface); - SDL_Flip(surface); + SDL_LockSurface(surface); + int baseX = emu->getLCDOffsetX(); + int baseY = emu->getLCDOffsetY(); + int height = emu->getLCDHeight(); + for (int y = 0; y < height; y++) { + lines[y] = (uint8_t*)surface->pixels + (surface->pitch * (y + baseY)) + + (baseX * 4); + } + emu->readLCDIntoBuffer(lines, true); + SDL_UnlockSurface(surface); + SDL_Flip(surface); - SDL_Event event; - while (SDL_PollEvent(&event)) { - if (event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) { - EpocKey k = resolveKey(event.key.keysym.sym); - if (k != EStdKeyNull) - emu->setKeyboardKey(k, (event.key.state == SDL_PRESSED)); - } else if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) { - if (event.button.button == SDL_BUTTON_LEFT) - emu->updateTouchInput(event.button.x, event.button.y, (event.button.state == SDL_PRESSED)); - } else if (event.type == SDL_MOUSEMOTION) { - emu->updateTouchInput(event.motion.x, event.motion.y, (event.motion.state & SDL_BUTTON(1))); - } - } + SDL_Event event; + while (SDL_PollEvent(&event)) { + if (event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) { + EpocKey k = resolveKey(event.key.keysym.sym); + if (k != EStdKeyNull) + emu->setKeyboardKey(k, (event.key.state == SDL_PRESSED)); + } else if (event.type == SDL_MOUSEBUTTONDOWN || + event.type == SDL_MOUSEBUTTONUP) { + if (event.button.button == SDL_BUTTON_LEFT) + emu->updateTouchInput(event.button.x, event.button.y, + (event.button.state == SDL_PRESSED)); + } else if (event.type == SDL_MOUSEMOTION) { + emu->updateTouchInput(event.motion.x, event.motion.y, + (event.motion.state & SDL_BUTTON(1))); + } + } } -int main(int argc, char **argv) { - emu = new Windermere::Emulator; - emu->setLogger([](const char *str) { - printf("%s\n", str); - }); - FILE *f = fopen("rom/5mx.bin", "rb"); - fread(emu->getROMBuffer(), 1, 10485760, f); - fclose(f); +int main(int argc, char** argv) { + emu = new Windermere::Emulator; + emu->setLogger([](const char* str) { printf("%s\n", str); }); + FILE* f = fopen("rom/5mx.bin", "rb"); + fread(emu->getROMBuffer(), 1, 10485760, f); + fclose(f); - if (SDL_Init(SDL_INIT_TIMER|SDL_INIT_VIDEO) != 0) { - printf("SDL_Init failed: %s\n", SDL_GetError()); - return 1; - } - surface = SDL_SetVideoMode(emu->getDigitiserWidth(), emu->getDigitiserHeight(), 32, SDL_SWSURFACE); - if (surface == NULL) { - printf("SDL_SetVideoMode failed: %s\n", SDL_GetError()); - return 1; - } + if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO) != 0) { + printf("SDL_Init failed: %s\n", SDL_GetError()); + return 1; + } + surface = SDL_SetVideoMode(emu->getDigitiserWidth(), + emu->getDigitiserHeight(), 32, SDL_SWSURFACE); + if (surface == NULL) { + printf("SDL_SetVideoMode failed: %s\n", SDL_GetError()); + return 1; + } - EM_ASM("SDL.defaults.copyOnLock = false; SDL.defaults.discardOnLock = true; SDL.defaults.opaqueFrontBuffer = false;"); + EM_ASM("SDL.defaults.copyOnLock = false; SDL.defaults.discardOnLock = true; " + "SDL.defaults.opaqueFrontBuffer = false;"); - emscripten_set_main_loop(&emuEventLoop, 64, 1); + emscripten_set_main_loop(&emuEventLoop, 64, 1); - return 0; + return 0; } -- 2.45.2