Last active
November 29, 2024 18:50
-
-
Save gregorygaines/2dbbb84ac85b262cc86d7d0b061225e3 to your computer and use it in GitHub Desktop.
Decoding the ARM7TDMI Instruction set. Article at https://www.gregorygaines.com/blog/decoding-the-arm7tdmi-instruction-set-game-boy-advance/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type Instruction func(opcode uint32, arm *ARM7TDMI) | |
func DecodeARMInstruction(opcode uint32) Instruction { | |
switch { | |
case IsBranchAndBranchExchange(opcode): | |
return BranchAndBranchExchange; | |
case IsBlockDataTransfer(opcode): | |
return BlockDataTransfer; | |
case IsBranchAndBranchWithLink(opcode): | |
return BranchAndBranchWithLink; | |
case IsSoftwareInterrupt(opcode): | |
return SoftwareInterrupt | |
case IsUndefined(opcode): | |
return Undefined | |
case IsSingleDataTransfer(opcode): | |
return SingleDataTransfer | |
case IsSingleDataSwap(opcode): | |
return SingleDataSwap | |
case IsMultiply(opcode): | |
return Multiply | |
case IsHalfwordDataTransferRegister(opcode): | |
return HalfwordDataTransferRegister | |
case IsHalfwordDataTransferImmediate(opcode): | |
return HalfwordDataTransferImmediate | |
case IsPSRTransferMRS(opcode): | |
return PSRTransferMRS | |
case IsPSRTransferMSR(opcode): | |
return PSRTransferMSR | |
case IsDataProcessing(opcode): | |
return DataProcessing | |
} | |
return UnimplementedARMInstruction | |
} | |
func IsBranchAndBranchExchange(opcode uint32) bool { | |
const branchAndExchangeFormat = 0b0000_0001_0010_1111_1111_1111_0001_0000 | |
const formatMask = 0b0000_1111_1111_1111_1111_1111_1111_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == branchAndExchangeFormat | |
} | |
func IsBlockDataTransfer(opcode uint32) bool { | |
const blockDataTransferFormat = 0b0000_1000_0000_0000_0000_0000_0000_0000 | |
const formatMask = 0b0000_1110_0000_0000_0000_0000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == blockDataTransferFormat | |
} | |
func IsBranchAndBranchWithLink(opcode uint32) bool { | |
const branchFormat = 0b0000_1010_0000_0000_0000_0000_0000_0000 | |
const branchWithLinkFormat = 0b0000_1011_0000_0000_0000_0000_0000_0000 | |
const formatMask = 0b0000_1111_0000_0000_0000_0000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == branchFormat || extractedFormat == branchWithLinkFormat | |
} | |
func IsSoftwareInterrupt(opcode uint32) bool { | |
const softwareInterruptFormat = 0b0000_1111_0000_0000_0000_0000_0000_0000 | |
const formatMask = 0b0000_1111_0000_0000_0000_0000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == softwareInterruptFormat | |
} | |
func IsUndefined(opcode uint32) bool { | |
const undefinedFormat = 0b0000_0110_0000_0000_0000_0000_0001_0000 | |
const formatMask = 0b0000_1110_0000_0000_0000_0000_0001_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == undefinedFormat | |
} | |
func IsSingleDataTransfer(opcode uint32) bool { | |
const singleDataTransferFormat = 0b0000_0100_0000_0000_0000_0000_0000_0000 | |
const formatMask = 0b0000_1100_0000_0000_0000_0000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == singleDataTransferFormat | |
} | |
func IsSingleDataSwap(opcode uint32) bool { | |
const singleDataSwapFormat = 0b0000_0001_0000_0000_0000_0000_1001_0000 | |
const formatMask = 0b0000_1111_1000_0000_0000_1111_1111_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == singleDataSwapFormat | |
} | |
func IsMultiply(opcode uint32) bool { | |
const multiplyFormat = 0b0000_0000_0000_0000_0000_0000_1001_0000 | |
const multiplyLongFormat = 0b0000_0000_1000_0000_0000_0000_1001_0000 | |
const formatMask = 0b0000_1111_1000_0000_0000_0000_1111_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == multiplyFormat || extractedFormat == multiplyLongFormat | |
} | |
func IsHalfwordDataTransferRegister(opcode uint32) bool { | |
const halfwordDataTransferRegisterFormat = 0b0000_0000_0000_0000_0000_0000_1001_0000 | |
const formatMask = 0b0000_1110_0100_0000_0000_1111_1001_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == halfwordDataTransferRegisterFormat | |
} | |
func IsHalfwordDataTransferImmediate(opcode uint32) bool { | |
const halfwordDataTransferImmediateFormat = 0b0000_0000_0100_0000_0000_0000_1001_0000 | |
const formatMask = 0b0000_1110_0100_0000_0000_0000_1001_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == halfwordDataTransferImmediateFormat | |
} | |
func IsPSRTransferMRS(opcode uint32) bool { | |
const mrsFormat = 0b0000_0001_0000_1111_0000_0000_0000_0000 | |
const formatMask = 0b0000_1111_1011_1111_0000_0000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == mrsFormat | |
} | |
func IsPSRTransferMSR(opcode uint32) bool { | |
const msrFormat = 0b0000_0001_0010_0000_1111_0000_0000_0000 | |
const formatMask = 0b0000_1101_1011_0000_1111_0000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == msrFormat | |
} | |
func IsDataProcessing(opcode uint32) bool { | |
const dataProcessingFormat = 0b0000_0000_0000_0000_0000_0000_0000_0000 | |
const formatMask = 0b0000_1100_0000_0000_0000_0000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == dataProcessingFormat | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type Instruction func(opcode uint16, arm *ARM7TDMI) | |
func DecodeTHUMBInstruction(opcode uint16) Instruction { | |
switch { | |
case IsTHUMBSoftwareInterrupt(opcode): | |
return THUMBSoftwareInterrupt | |
case IsUnconditionalBranch(opcode): | |
return UnconditionalBranch | |
case IsConditionalBranch(opcode): | |
return ConditionalBranch | |
case IsMultipleLoadStore(opcode): | |
return MultipleLoadstore | |
case IsLongBranchWithLink(opcode): | |
return LongBranchWithLink | |
case IsAddOffsetToStackPointer(opcode): | |
return AddOffsetToStackPointer | |
case IsPushPopRegisters(opcode): | |
return PushPopRegisters | |
case IsLoadStoreHalfword(opcode): | |
return LoadStoreHalfword | |
case IsSPRelativeLoadStore(opcode): | |
return SPRelatvieLoadStore | |
case IsLoadAddress(opcode): | |
return LoadAddress | |
case IsLoadStoreWithImmediateOffset(opcode): | |
return LoadStoreWithImmediateOffset | |
case IsLoadStoreWithRegisterOffset(opcode): | |
return LoadStoreWithRegisterOffset | |
case IsLoadStoreSignExtendedByteHalfword(opcode): | |
return LoadStoreSignExtendedByteHalfword | |
case IsPCRelativeLoad(opcode): | |
return PCRelativeLoad | |
case IsHiRegisterOperationsBranchExchange(opcode): | |
return HiRegisterOperationsBranchExchange | |
case IsALUOperations(opcode): | |
return ALUOperations | |
case IsMoveCompareAddSubtractImmediate(opcode): | |
return MoveCompareAddSubtractImmediate | |
case IsAddSubtract(opcode): | |
return AddSubtract | |
case IsMoveShiftedRegister(opcode): | |
return MoveShiftedRegister | |
} | |
return UnimplementedTHUMBInstruction | |
} | |
func IsTHUMBSoftwareInterrupt(opcode uint16) bool { | |
const softwareInterruptFormat = 0b1101_1111_0000_0000 | |
const formatMask = 0b1111_1111_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == softwareInterruptFormat | |
} | |
func IsUnconditionalBranch(opcode uint16) bool { | |
const unconditionalBranchFormat = 0b1110_0000_0000_0000 | |
const formatMask = 0b1111_1000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == unconditionalBranchFormat | |
} | |
func IsConditionalBranch(opcode uint16) bool { | |
const conditionalBranchFormat = 0b1101_0000_0000_0000 | |
const formatMask = 0b1111_0000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == conditionalBranchFormat | |
} | |
func IsMultipleLoadStore(opcode uint16) bool { | |
const multipleLoadStoreFormat = 0b1100_0000_0000_0000 | |
const formatMask = 0b1111_0000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == multipleLoadStoreFormat | |
} | |
func IsLongBranchWithLink(opcode uint16) bool { | |
const longBranchWithLinkFormat = 0b1111_0000_0000_0000 | |
const formatMask = 0b1111_0000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == longBranchWithLinkFormat | |
} | |
func IsAddOffsetToStackPointer(opcode uint16) bool { | |
const addOffsetToStackPointerFormat = 0b1011_0000_0000_0000 | |
const formatMask = 0b1111_1111_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == addOffsetToStackPointerFormat | |
} | |
func IsPushPopRegisters(opcode uint16) bool { | |
const pushPopRegistersFormat = 0b1011_0100_0000_0000 | |
const formatMask = 0b1111_0110_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == pushPopRegistersFormat | |
} | |
func IsLoadStoreHalfword(opcode uint16) bool { | |
const loadStoreHalfwordFormat = 0b1000_0000_0000_0000 | |
const formatMask = 0b1111_0000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == loadStoreHalfwordFormat | |
} | |
func IsSPRelativeLoadStore(opcode uint16) bool { | |
const spRelativeLoadStoreFormat = 0b1001_0000_0000_0000 | |
const formatMask = 0b1111_0000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == spRelativeLoadStoreFormat | |
} | |
func IsLoadAddress(opcode uint16) bool { | |
const loadAddressFormat = 0b1010_0000_0000_0000 | |
const formatMask = 0b1111_0000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == loadAddressFormat | |
} | |
func IsLoadStoreWithImmediateOffset(opcode uint16) bool { | |
const loadStoreImmediateOffsetFormat = 0b0110_0000_0000_0000 | |
const formatMask = 0b1110_0000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == loadStoreImmediateOffsetFormat | |
} | |
func IsLoadStoreWithRegisterOffset(opcode uint16) bool { | |
const loadStoreRegisterOffsetFormat = 0b0101_0000_0000_0000 | |
const formatMask = 0b1111_0010_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == loadStoreRegisterOffsetFormat | |
} | |
func IsLoadStoreSignExtendedByteHalfword(opcode uint16) bool { | |
const loadStoreSignExtendedByteHalfwordFormat = 0b0101_0010_0000_0000 | |
const formatMask = 0b1111_0010_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == loadStoreSignExtendedByteHalfwordFormat | |
} | |
func IsPCRelativeLoad(opcode uint16) bool { | |
const pcRelativeLoadFormat = 0b0100_1000_0000_0000 | |
const formatMask = 0b1111_1000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == pcRelativeLoadFormat | |
} | |
func IsHiRegisterOperationsBranchExchange(opcode uint16) bool { | |
const hiRegisterOperationsBranchExchangeFormat = 0b0100_0100_0000_0000 | |
const formatMask = 0b1111_1100_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == hiRegisterOperationsBranchExchangeFormat | |
} | |
func IsALUOperations(opcode uint16) bool { | |
const aluOperationsFormat = 0b0100_0000_0000_0000 | |
const formatMask = 0b1111_1100_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == aluOperationsFormat | |
} | |
func IsMoveCompareAddSubtractImmediate(opcode uint16) bool { | |
const moveCompareAddSubtractImmediateFormat = 0b0010_0000_0000_0000 | |
const formatMask = 0b1110_0000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == moveCompareAddSubtractImmediateFormat | |
} | |
func IsAddSubtract(opcode uint16) bool { | |
const addSubtractFormat = 0b0001_1000_0000_0000 | |
const formatMask = 0b1111_1000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == addSubtractFormat | |
} | |
func IsMoveShiftedRegister(opcode uint16) bool { | |
const moveShiftedRegistersFormat = 0b0000_0000_0000_0000 | |
const formatMask = 0b1110_0000_0000_0000 | |
var extractedFormat = opcode & formatMask | |
return extractedFormat == moveShiftedRegistersFormat | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment