Created
June 21, 2020 23:07
-
-
Save matanlurey/0f6019c1e7535f14f9f306cd9e83e307 to your computer and use it in GitHub Desktop.
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
import 'package:binary/binary.dart'; | |
import 'package:collection/collection.dart'; | |
import 'package:meta/meta.dart'; | |
/// An **internal** package representing all known `THUMB` instruction sets. | |
/// | |
/// For testing, individual [BitPattern] implementations are accessible as | |
/// static fields (e.g. `[$01$moveShiftedRegister]`), and a sorted | |
/// [BitPatternGrpup] is accessible as [allFormats]. | |
abstract class ThumbInstructionSet { | |
/// Move shifted register. | |
static final $01$moveShiftedRegister = BitPatternBuilder.parse( | |
'000P_POOO_OOSS_SDDD', | |
).build('01:MOVE_SHIFTED_REGISTER'); | |
/// Add and subtract. | |
static final $02$addAndSubtract = BitPatternBuilder.parse( | |
'0001_11PN_NNSS_SDDD', | |
).build('02:ADD_AND_SUBTRACT'); | |
/// Move, compare, add, and subtract immediate. | |
static final $03$moveCompareAddAndSubtractImmediate = BitPatternBuilder.parse( | |
'001P_PDDD_OOOO_OOOO', | |
).build('03:MOVE_COMPARE_ADD_AND_SUBTRACT_IMMEDIATE'); | |
/// ALU operation. | |
static final $04$aluOperation = BitPatternBuilder.parse( | |
'0100_00PP_PPSS_SDDD', | |
).build('04:ALU_OPERATION'); | |
/// High register operations and branch exchange. | |
static final $05$highRegisterOperationsAndBranch = BitPatternBuilder.parse( | |
'0100_01PP_HJSS_SDDD', | |
).build('05:HIGH_REGISTER_OPERATIONS_AND_BRANCH_EXCHANGE'); | |
/// PC-relkative load. | |
static final $06$pcRelativeLoad = BitPatternBuilder.parse( | |
'0100_1DDD_WWWW_WWWW', | |
).build('06:PC_RELATIVE_LOAD'); | |
/// Load and store with relative offset. | |
static final $07$loadAndStoreWithRelativeOffset = BitPatternBuilder.parse( | |
'0101_LB0O_OONN_NDDD', | |
).build('07:LOAD_AND_STORE_WITH_RELATIVE_OFFSET'); | |
/// Load and store sign-extended byte and half-word. | |
static final $08$loadAndStoreSignExtended = BitPatternBuilder.parse( | |
'0101_HS1O_OOBB_BDDD', | |
).build('08:LOAD_AND_STORE_SIGN_EXTENDED_BYTE_AND_HALFWORD'); | |
/// Load and store with immediate offset. | |
static final $09$loadAndStoreWithImmediateOffset = BitPatternBuilder.parse( | |
'011B_LOOO_OONN_NDDD', | |
).build('09:LOAD_AND_STORE_WITH_IMMEDIATE_OFFSET'); | |
/// Load and store halfword. | |
static final $10$loadAndStoreHalfword = BitPatternBuilder.parse( | |
'1000_LOOO_OOBB_BDDD', | |
).build('10:LOAD_AND_STORE_HALFWORD'); | |
/// SP-relative load and store. | |
static final $11$spRelativeLoadAndStore = BitPatternBuilder.parse( | |
'1001_LDDD_WWWW_WWWW', | |
).build('11:SP_RELATIVE_LOAD_AND_STORE'); | |
/// Load address. | |
static final $12$loadAddress = BitPatternBuilder.parse( | |
'1010_SDDD_WWWW_WWWW', | |
).build('12:LOAD_ADDRESS'); | |
/// Add offset to stack pointer. | |
static final $13$addOffsetToStackPointer = BitPatternBuilder.parse( | |
'1011_0000_SWWW_WWWW', | |
).build('13:ADD_OFFSET_TO_STACK_POINTER'); | |
/// Push and pop registers. | |
static final $14$pushAndPopRegisters = BitPatternBuilder.parse( | |
'1011_L10R_TTTT_TTTT', | |
).build('14:PUSH_AND_POP_REGISTERS'); | |
/// Multiple load and store. | |
static final $15$multipleLoadAndStore = BitPatternBuilder.parse( | |
'1100_LBBB_TTTT_TTTT', | |
).build('15:MULTIPLE_LOAD_AND_STORE'); | |
/// Conditional branch. | |
static final $16$conditionalBranch = BitPatternBuilder.parse( | |
'1101_CCCC_SSSS_SSSS', | |
).build('16:CONDITIONAL_BRANCH'); | |
/// Software interrupt. | |
static final $17$softwareInterrupt = BitPatternBuilder.parse( | |
'1101_1111_VVVV_VVVV', | |
).build('17:SOFTWARE_INTERRUPT'); | |
/// Unconditional branch. | |
static final $18$unconditionalBranch = BitPatternBuilder.parse( | |
'1110_0OOO_OOOO_OOOO', | |
).build('18:UNCONDITIONAL_BRANCH'); | |
/// Long branch with link. | |
static final $19$longBranchWithLink = BitPatternBuilder.parse( | |
'1111_HOOO_OOOO_OOOO', | |
).build('19:LONG_BRANCH_WITH_LINK'); | |
/// A collection of all the known formats in [ThumbInstructionSet], sorted. | |
static final BitPatternGroup<List<int>, BitPattern<List<int>>> allFormats = [ | |
$01$moveShiftedRegister, | |
$02$addAndSubtract, | |
$03$moveCompareAddAndSubtractImmediate, | |
$04$aluOperation, | |
$05$highRegisterOperationsAndBranch, | |
$06$pcRelativeLoad, | |
$07$loadAndStoreWithRelativeOffset, | |
$08$loadAndStoreSignExtended, | |
$09$loadAndStoreWithImmediateOffset, | |
$10$loadAndStoreHalfword, | |
$11$spRelativeLoadAndStore, | |
$12$loadAddress, | |
$13$addOffsetToStackPointer, | |
$14$pushAndPopRegisters, | |
$15$multipleLoadAndStore, | |
$16$conditionalBranch, | |
$17$softwareInterrupt, | |
$18$unconditionalBranch, | |
$19$longBranchWithLink, | |
].toGroup(); | |
/// Format used to match and decode this instruction. | |
final BitPattern<List<int>> format; | |
const ThumbInstructionSet._(this.format) : assert(format != null); | |
@override | |
bool operator ==(Object o) { | |
if (identical(this, o)) { | |
return true; | |
} else if (o is ThumbInstructionSet && identical(format, o.format)) { | |
return const MapEquality<Object, Object>().equals(toJson(), o.toJson()); | |
} else { | |
return false; | |
} | |
} | |
@override | |
int get hashCode => const MapEquality<Object, Object>().hash(toJson()); | |
/// Must provide a JSON representation. | |
Map<String, Object> toJson(); | |
@override | |
String toString() => '$runtimeType $toJson()'; | |
} | |
/// Decoded object from [ThumbInstructionSet.$01$moveShiftedRegister]. | |
class MoveShiftedRegister extends ThumbInstructionSet { | |
static final _format = ThumbInstructionSet.$01$moveShiftedRegister; | |
/// OpCode (2-bits). | |
final int opcode; | |
/// Offset (5-bits). | |
final int offset; | |
/// Register `S` (3-bits). | |
final int registerS; | |
/// Register `D` (3-bits). | |
final int registerD; | |
/// Creates a [MoveShiftedRegister] by decoding [bits]. | |
factory MoveShiftedRegister.decodeBits(int bits) { | |
return MoveShiftedRegister.fromList(_format.capture(bits)); | |
} | |
/// Creates a [MoveShiftedRegister] converting a previously [decoded] list. | |
factory MoveShiftedRegister.fromList(List<int> decoded) { | |
return MoveShiftedRegister( | |
opcode: decoded[0], | |
offset: decoded[1], | |
registerS: decoded[2], | |
registerD: decoded[3], | |
); | |
} | |
/// Creates a [MoveShiftedRegister] from the provided variables. | |
/// | |
/// > **NOTE**: Bits are **not** checked for correctness or size! | |
MoveShiftedRegister({ | |
@required this.opcode, | |
@required this.offset, | |
@required this.registerS, | |
@required this.registerD, | |
}) : assert(opcode != null), | |
assert(offset != null), | |
assert(registerS != null), | |
assert(registerD != null), | |
super._(_format); | |
@override | |
Map<String, Object> toJson() { | |
return { | |
'Op': opcode, | |
'Offset5': offset, | |
'Rs': registerS, | |
'Rd': registerD, | |
}; | |
} | |
} | |
/// Decoded object from [ThumbInstructionSet.$02$addAndSubtract]. | |
class AddAndSubtract extends ThumbInstructionSet { | |
static final _format = ThumbInstructionSet.$02$addAndSubtract; | |
/// OpCode (2-bits). | |
final int opcode; | |
/// Register `N` or Offset (3-bits). | |
final int registerNOrOffset3; | |
/// Register `S`. | |
final int registerS; | |
/// Register `D`. | |
final int registerD; | |
/// Creates a [AddAndSubtract] by decoding [bits]. | |
factory AddAndSubtract.decodeBits(int bits) { | |
return AddAndSubtract.fromList(_format.capture(bits)); | |
} | |
/// Creates a [AddAndSubtract] converting a previously [decoded] list. | |
factory AddAndSubtract.fromList(List<int> decoded) { | |
return AddAndSubtract( | |
opcode: decoded[0], | |
registerNOrOffset3: decoded[1], | |
registerS: decoded[2], | |
registerD: decoded[3], | |
); | |
} | |
/// Creates a [AddAndSubtract] from the provided variables. | |
/// | |
/// > **NOTE**: Bits are **not** checked for correctness or size! | |
AddAndSubtract({ | |
@required this.opcode, | |
@required this.registerNOrOffset3, | |
@required this.registerS, | |
@required this.registerD, | |
}) : assert(opcode != null), | |
assert(registerNOrOffset3 != null), | |
assert(registerS != null), | |
assert(registerD != null), | |
super._(_format); | |
@override | |
Map<String, Object> toJson() { | |
return { | |
'Op': opcode, | |
'Rn/Offset3': registerNOrOffset3, | |
'Rs': registerS, | |
'Rd': registerD, | |
}; | |
} | |
} | |
/// Decoded object from [ThumbInstructionSet.$03$moveCompareAddAndSubtractImmediate]. | |
class MoveCompareAddAndSubtractImmediate extends ThumbInstructionSet { | |
static final _format = | |
ThumbInstructionSet.$03$moveCompareAddAndSubtractImmediate; | |
/// OpCode (2-bits). | |
final int opcode; | |
/// Register `D` (3-bits). | |
final int registerD; | |
/// Offset (8-bits). | |
final int offset; | |
/// Creates a [MoveCompareAddAndSubtractImmediate] by decoding [bits]. | |
factory MoveCompareAddAndSubtractImmediate.decodeBits(int bits) { | |
return MoveCompareAddAndSubtractImmediate.fromList(_format.capture(bits)); | |
} | |
/// Creates a [MoveCompareAddAndSubtractImmediate] converting a previously [decoded] list. | |
factory MoveCompareAddAndSubtractImmediate.fromList(List<int> decoded) { | |
return MoveCompareAddAndSubtractImmediate( | |
opcode: decoded[0], | |
registerD: decoded[1], | |
offset: decoded[2], | |
); | |
} | |
/// Creates a [MoveCompareAddAndSubtractImmediate] from the provided variables. | |
/// | |
/// > **NOTE**: Bits are **not** checked for correctness or size! | |
MoveCompareAddAndSubtractImmediate({ | |
@required this.opcode, | |
@required this.registerD, | |
@required this.offset, | |
}) : assert(opcode != null), | |
assert(offset != null), | |
assert(registerD != null), | |
super._(_format); | |
@override | |
Map<String, Object> toJson() { | |
return { | |
'Op': opcode, | |
'Rd': registerD, | |
'Offset8': offset, | |
}; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment