From d23c714ec77ae4de349a3b60898f8689a72f4ca5 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 5 Apr 2022 11:23:54 -0400 Subject: [PATCH] Build in an optional post hoc validation. TODO: validate. --- InstructionSets/PowerPC/Decoder.cpp | 52 +++++++++++++------ InstructionSets/PowerPC/Decoder.hpp | 18 +++---- .../DingusdevPowerPCTests.mm | 2 +- .../Clock SignalTests/PowerPCDecoderTests.mm | 2 +- 4 files changed, 48 insertions(+), 26 deletions(-) diff --git a/InstructionSets/PowerPC/Decoder.cpp b/InstructionSets/PowerPC/Decoder.cpp index 40d9baf62..106c4fdac 100644 --- a/InstructionSets/PowerPC/Decoder.cpp +++ b/InstructionSets/PowerPC/Decoder.cpp @@ -10,9 +10,23 @@ using namespace InstructionSet::PowerPC; -Decoder::Decoder(Model model) : model_(model) {} +namespace { -Instruction Decoder::decode(uint32_t opcode) { +template Instruction instruction(uint32_t opcode, bool is_supervisor = false) { + // If validation isn't required, there's nothing to do here. + if constexpr (!validate_reserved_bits) { + return Instruction(operation, opcode, is_supervisor); + } + + // Otherwise, validation depends on operation + // (and, in principle, processor model). + return Instruction(operation, opcode, is_supervisor); +} + +} + +template +Instruction Decoder::decode(uint32_t opcode) { // Quick bluffer's guide to PowerPC instruction encoding: // // There is a six-bit field at the very top of the instruction. @@ -32,16 +46,16 @@ Instruction Decoder::decode(uint32_t opcode) { // currently check the value of reserved bits. That may need to change // if/when I add support for extended instruction sets. -#define Bind(mask, operation) case mask: return Instruction(Operation::operation, opcode); -#define BindSupervisor(mask, operation) case mask: return Instruction(Operation::operation, opcode, true); +#define Bind(mask, operation) case mask: return instruction(opcode); +#define BindSupervisor(mask, operation) case mask: return instruction(opcode, true); #define BindConditional(condition, mask, operation) \ case mask: \ - if(condition(model_)) return Instruction(Operation::operation, opcode); \ - return Instruction(opcode); + if(condition(model)) return instruction(opcode); \ + return instruction(opcode); #define BindSupervisorConditional(condition, mask, operation) \ case mask: \ - if(condition(model_)) return Instruction(Operation::operation, opcode, true); \ - return Instruction(opcode); + if(condition(model)) return instruction(opcode, true); \ + return instruction(opcode); #define Six(x) (unsigned(x) << 26) #define SixTen(x, y) (Six(x) | ((y) << 1)) @@ -64,7 +78,7 @@ Instruction Decoder::decode(uint32_t opcode) { case 0: case 1: case 2: case 3: case 4: case 5: case 8: case 9: case 10: case 11: case 12: case 13: case 16: case 17: case 18: case 19: case 20: - return Instruction(Operation::bcx, opcode); + return instruction(opcode); default: return Instruction(opcode); } @@ -318,26 +332,26 @@ Instruction Decoder::decode(uint32_t opcode) { // stwcx. and stdcx. switch(opcode & 0b111111'0000'0000'0000'0000'111111111'1) { - case 0b011111'0000'0000'0000'0000'010010110'1: return Instruction(Operation::stwcx_, opcode); + case 0b011111'0000'0000'0000'0000'010010110'1: return instruction(opcode); case 0b011111'0000'0000'0000'0000'011010110'1: - if(is64bit(model_)) return Instruction(Operation::stdcx_, opcode); + if(is64bit(model)) return instruction(opcode); return Instruction(opcode); } // std and stdu switch(opcode & 0b111111'00'00000000'00000000'000000'11) { - case 0b111110'00'00000000'00000000'000000'00: return Instruction(Operation::std, opcode); + case 0b111110'00'00000000'00000000'000000'00: return instruction(opcode); case 0b111110'00'00000000'00000000'000000'01: - if(is64bit(model_)) return Instruction(Operation::stdu, opcode); + if(is64bit(model)) return instruction(opcode); return Instruction(opcode); case 0b111010'00'00000000'00000000'000000'10: - if(is64bit(model_)) return Instruction(Operation::lwa, opcode); + if(is64bit(model)) return instruction(opcode); return Instruction(opcode); } // sc if((opcode & 0b111111'00'00000000'00000000'000000'1'0) == 0b010001'00'00000000'00000000'000000'1'0) { - return Instruction(Operation::sc, opcode); + return instruction(opcode); } #undef Six @@ -348,3 +362,11 @@ Instruction Decoder::decode(uint32_t opcode) { return Instruction(opcode); } + +template class InstructionSet::PowerPC::Decoder; +template class InstructionSet::PowerPC::Decoder; +template class InstructionSet::PowerPC::Decoder; + +template class InstructionSet::PowerPC::Decoder; +template class InstructionSet::PowerPC::Decoder; +template class InstructionSet::PowerPC::Decoder; diff --git a/InstructionSets/PowerPC/Decoder.hpp b/InstructionSets/PowerPC/Decoder.hpp index 389ec40d3..6b25cd780 100644 --- a/InstructionSets/PowerPC/Decoder.hpp +++ b/InstructionSets/PowerPC/Decoder.hpp @@ -38,16 +38,16 @@ constexpr bool is601(Model model) { /*! Implements PowerPC instruction decoding. - This is an experimental implementation; it has not yet undergone significant testing. + @c model Indicates the instruction set to decode. + + @c validate_reserved_bits If set to @c true, check that all + reserved bits are 0 and produce an invalid opcode if not. Otherwise does no + inspection of reserved bits. + + TODO: determine what specific models of PowerPC do re: reserved bits. */ -struct Decoder { - public: - Decoder(Model model); - - Instruction decode(uint32_t opcode); - - private: - Model model_; +template struct Decoder { + Instruction decode(uint32_t opcode); }; } diff --git a/OSBindings/Mac/Clock SignalTests/DingusdevPowerPCTests.mm b/OSBindings/Mac/Clock SignalTests/DingusdevPowerPCTests.mm index 623007530..538a4c51a 100644 --- a/OSBindings/Mac/Clock SignalTests/DingusdevPowerPCTests.mm +++ b/OSBindings/Mac/Clock SignalTests/DingusdevPowerPCTests.mm @@ -138,7 +138,7 @@ NSString *offset(Instruction instruction) { NSString *const wholeFile = [[NSString alloc] initWithData:testData encoding:NSUTF8StringEncoding]; NSArray *const lines = [wholeFile componentsSeparatedByString:@"\n"]; - InstructionSet::PowerPC::Decoder decoder(InstructionSet::PowerPC::Model::MPC601); + InstructionSet::PowerPC::Decoder decoder; for(NSString *const line in lines) { // Ignore empty lines and comments. if([line length] == 0) { diff --git a/OSBindings/Mac/Clock SignalTests/PowerPCDecoderTests.mm b/OSBindings/Mac/Clock SignalTests/PowerPCDecoderTests.mm index 7d2618de3..79e1076e6 100644 --- a/OSBindings/Mac/Clock SignalTests/PowerPCDecoderTests.mm +++ b/OSBindings/Mac/Clock SignalTests/PowerPCDecoderTests.mm @@ -119,7 +119,7 @@ namespace { // MARK: - Decoder - (void)decode:(const uint32_t *)stream { - InstructionSet::PowerPC::Decoder decoder(InstructionSet::PowerPC::Model::MPC601); + InstructionSet::PowerPC::Decoder decoder; for(int c = 0; c < 32; c++) { instructions[c] = decoder.decode(stream[c]); }