From 7ef8b2047897df7493c117e4a1b2f22fa09ecb8c Mon Sep 17 00:00:00 2001 From: Michael Dittrich Date: Sun, 25 Jan 2026 17:16:48 +0100 Subject: [PATCH] Fix #6 CLR gives wrong register CES: fix mask Automatic simplification: AND Rr, Rr -> TST Rr EOR Rr, Rr -> CLR Rr ADD Rr, Rr -> LSL Rr ADC Rr, Rr -> ROL Rr --- .../AVRDisassembler/Disassembler.cs | 30 ++++++++++++++++- .../InstructionSet/OpCodes/Arithmetic/ANDI.cs | 2 +- .../InstructionSet/OpCodes/Arithmetic/CBR.cs | 2 +- .../InstructionSet/OpCodes/Arithmetic/CLR.cs | 2 +- .../InstructionSet/OpCodes/Arithmetic/ORI.cs | 2 +- .../InstructionSet/OpCodes/Arithmetic/SBR.cs | 2 +- .../InstructionSet/OpCodes/Arithmetic/TST.cs | 2 +- .../InstructionSet/OpCodes/Bits/LSL.cs | 2 +- .../InstructionSet/OpCodes/Bits/ROL.cs | 2 +- .../AVRDisassembler/OpCodeIdentification.cs | 13 ++++---- .../AVRDisassembler/OperandExtraction.cs | 33 ++++++++++++------- 11 files changed, 65 insertions(+), 27 deletions(-) diff --git a/Source/AVRDisassembler/AVRDisassembler/Disassembler.cs b/Source/AVRDisassembler/AVRDisassembler/Disassembler.cs index e894538..6722b33 100644 --- a/Source/AVRDisassembler/AVRDisassembler/Disassembler.cs +++ b/Source/AVRDisassembler/AVRDisassembler/Disassembler.cs @@ -1,6 +1,9 @@ using System.Collections.Generic; using System.Linq; using AVRDisassembler.InstructionSet.OpCodes; +using AVRDisassembler.InstructionSet.OpCodes.Arithmetic; +using AVRDisassembler.InstructionSet.OpCodes.Bits; +using AVRDisassembler.InstructionSet.Operands; using IntelHexFormatReader; namespace AVRDisassembler @@ -32,7 +35,8 @@ public IEnumerable Disassemble() var opcodes = OpCodeIdentification.IdentifyOpCode(bytes).ToList(); // TODO: make a preference configurable if synonyms exist. - // For now, just pick the first item. + // Indistinguishable Mnemonics: CBR = ANDI, SBR = ORI + // For now, just pick the first item (more common). var opcode = opcodes.Any() ? opcodes.First() : new DATA(); @@ -44,6 +48,30 @@ public IEnumerable Disassemble() var type = opcode.GetType(); var operands = OperandExtraction.ExtractOperands(type, bytes); + + // check special cases where the Mnemonic can be simplified + // if both operands are the same register TODO: add tests + // AND Rr, Rr -> TST Rr + // EOR Rr, Rr -> CLR Rr + // ADD Rr, Rr -> LSL Rr + // ADC Rr, Rr -> ROL Rr + + if (type == typeof(AND) || type == typeof(EOR) || type == typeof(ADD) || type == typeof(ADC)) + { + if (operands.First().Value == operands.Last().Value) + { + if (type == typeof(AND)) + opcode = new TST(); + else if (type == typeof(EOR)) + opcode = new CLR(); + else if (type == typeof(ADD)) + opcode = new LSL(); + else if (type == typeof(ADC)) + opcode = new ROL(); + operands = new List { operands.First() }; + } + } + var statement = new AssemblyStatement(opcode, operands) { Offset = offset, diff --git a/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/ANDI.cs b/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/ANDI.cs index 73e6b80..4eef393 100644 --- a/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/ANDI.cs +++ b/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/ANDI.cs @@ -2,6 +2,6 @@ { public class ANDI : OpCode { - public override string Comment => "Logical AND with Immediate"; + public override string Comment => "Logical AND with Immediate - same as: Clear Bits in Register (CBR)"; } } diff --git a/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/CBR.cs b/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/CBR.cs index 12bf988..47a8c79 100644 --- a/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/CBR.cs +++ b/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/CBR.cs @@ -2,6 +2,6 @@ { public class CBR : OpCode { - public override string Comment => "Clear Bits in Register"; + public override string Comment => "Clear Bits in Register - same as: Logical AND with Immediate (ANDI)"; } } diff --git a/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/CLR.cs b/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/CLR.cs index 5bd2859..74eb4b7 100644 --- a/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/CLR.cs +++ b/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/CLR.cs @@ -2,6 +2,6 @@ { public class CLR : OpCode { - public override string Comment => "Clear Register"; + public override string Comment => "Clear Register - short for: EOR Rd,Rd (Exclusive OR on same registers)"; } } diff --git a/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/ORI.cs b/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/ORI.cs index 61e6b5f..ad9b1a9 100644 --- a/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/ORI.cs +++ b/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/ORI.cs @@ -2,6 +2,6 @@ { public class ORI : OpCode { - public override string Comment => "Logical OR with Immediate"; + public override string Comment => "Logical OR with Immediate - same as: Set Bits in Register (SBR)"; } } diff --git a/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/SBR.cs b/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/SBR.cs index 920d04f..ea7854c 100644 --- a/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/SBR.cs +++ b/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/SBR.cs @@ -2,6 +2,6 @@ { public class SBR : OpCode { - public override string Comment => "Set Bits in Register"; + public override string Comment => "Set Bits in Register - same as: Logical OR with Immediate (ORI)"; } } diff --git a/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/TST.cs b/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/TST.cs index 2ba2d78..240f784 100644 --- a/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/TST.cs +++ b/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Arithmetic/TST.cs @@ -2,6 +2,6 @@ { public class TST : OpCode { - public override string Comment => "Test for Zero or Minus"; + public override string Comment => "Test for Zero or Minus - short for: AND Rd,Rd (Logical AND on same registers)"; } } diff --git a/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Bits/LSL.cs b/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Bits/LSL.cs index 1007bbc..a5c6eea 100644 --- a/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Bits/LSL.cs +++ b/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Bits/LSL.cs @@ -2,6 +2,6 @@ { public class LSL : OpCode { - public override string Comment => "Logical Shift Left"; + public override string Comment => "Logical Shift Left - short for: ADD Rd,Rd (Add without Carry on same registers)"; } } diff --git a/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Bits/ROL.cs b/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Bits/ROL.cs index 8ef71ed..0dac807 100644 --- a/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Bits/ROL.cs +++ b/Source/AVRDisassembler/AVRDisassembler/InstructionSet/OpCodes/Bits/ROL.cs @@ -2,6 +2,6 @@ { public class ROL : OpCode { - public override string Comment => "Rotate Left through Carry"; + public override string Comment => "Rotate Left through Carry - short for: ADC Rd,Rd (Add with Carry on same registers)"; } } diff --git a/Source/AVRDisassembler/AVRDisassembler/OpCodeIdentification.cs b/Source/AVRDisassembler/AVRDisassembler/OpCodeIdentification.cs index 0ca766d..9655bba 100644 --- a/Source/AVRDisassembler/AVRDisassembler/OpCodeIdentification.cs +++ b/Source/AVRDisassembler/AVRDisassembler/OpCodeIdentification.cs @@ -59,7 +59,7 @@ private static IEnumerable IdentifyWithFirstNibble0000(byte nb2, byte n { case 0b01: yield return new CPC(); yield break; case 0b10: yield return new SBC(); yield break; - case 0b11: yield return new ADD(); yield return new LSL(); yield break; + case 0b11: yield return new ADD(); yield break; // yield return new LSL(); // These are special cases handled in Disassembler (simplified versions with only one register as both registers are the same) } switch (nb2) { @@ -98,8 +98,7 @@ private static IEnumerable IdentifyWithFirstNibble0001(byte nb2, byte n case 0b00: yield return new CPSE(); yield break; case 0b01: yield return new CP(); yield break; case 0b10: yield return new SUB(); yield break; - case 0b11: yield return new ADC(); yield return new ROL(); - break; + case 0b11: yield return new ADC(); yield break; // yield return new ROL(); // These are special cases handled in Disassembler (simplified versions with only one register as both registers are the same) } } @@ -107,8 +106,8 @@ private static IEnumerable IdentifyWithFirstNibble0010(byte nb2, byte n { switch (nb2 >> 2) { - case 0b00: yield return new AND(); yield return new TST(); yield break; - case 0b01: yield return new CLR(); yield return new EOR(); yield break; + case 0b00: yield return new AND(); yield break; // yield return new TST(); // These are special cases handled in Disassembler (simplified versions with only one register as both registers are the same) + case 0b01: yield return new EOR(); yield break; // yield return new CLR(); // These are special cases handled in Disassembler (simplified versions with only one register as both registers are the same) case 0b10: yield return new OR(); yield break; case 0b11: yield return new MOV(); yield break; } @@ -131,12 +130,12 @@ private static IEnumerable IdentifyWithFirstNibble0101(byte nb2, byte n private static IEnumerable IdentifyWithFirstNibble0110(byte nb2, byte nb3, byte nb4) { - yield return new ORI(); yield return new SBR(); + yield return new SBR(); yield return new ORI(); // indistinguishable opcodes, SBR more likely } private static IEnumerable IdentifyWithFirstNibble0111(byte nb2, byte nb3, byte nb4) { - yield return new ANDI(); yield return new CBR(); + yield return new CBR(); yield return new ANDI(); // indistinguishable opcodes, CBR more likely } private static IEnumerable IdentifyWithFirstNibble1000(byte nb2, byte nb3, byte nb4) diff --git a/Source/AVRDisassembler/AVRDisassembler/OperandExtraction.cs b/Source/AVRDisassembler/AVRDisassembler/OperandExtraction.cs index 56dfe76..93009a3 100644 --- a/Source/AVRDisassembler/AVRDisassembler/OperandExtraction.cs +++ b/Source/AVRDisassembler/AVRDisassembler/OperandExtraction.cs @@ -21,7 +21,8 @@ public static IEnumerable ExtractOperands(Type type, byte[] bytes) { typeof(ADC), typeof(ADD), typeof(AND), typeof(CP), typeof(CPC), typeof(CPSE), typeof(EOR), typeof(MOV), - typeof(MUL), typeof(OR), typeof(SBC), typeof(SUB) + typeof(MUL), typeof(OR), typeof(SBC), typeof(SUB), + //typeof(LSL), typeof(ROL), typeof(TST), typeof(CLR) // These are special cases handled in Disassembler (simplified versions with only one register as both registers are the same) }.Contains(type)) { var vals = new[] { bytes[0], bytes[1] }.MapToMask("------rd ddddrrrr"); @@ -78,6 +79,14 @@ public static IEnumerable ExtractOperands(Type type, byte[] bytes) yield break; } + // TODO: Verify DES encoding (make test case) + if (type == typeof(DES)) + { + var vals = new[] { bytes[0], bytes[1] }.MapToMask("-------- KKKK----"); + yield return new Operand(OperandType.ConstantData, vals['K']); + yield break; + } + if (type == typeof(SER)) { var vals = new[] { bytes[0], bytes[1] }.MapToMask("-------- dddd----"); @@ -225,16 +234,18 @@ public static IEnumerable ExtractOperands(Type type, byte[] bytes) yield break; } - if (new[] - { - typeof(DES), typeof(LSL), typeof(ROL), typeof(TST), - typeof(CLR) - }.Contains(type)) - { - var vals = new[] { bytes[0], bytes[1] }.MapToMask("------dd dddddddd"); - yield return new Operand(OperandType.DestinationRegister, vals['d']); - yield break; - } + // These are special cases handled in Disassembler (simplified versions with only one register as both registers are the same) + + //if (new[] + //{ + // typeof(DES) // DES has different encoding than the others, got extra handling above + // //, typeof(LSL), typeof(ROL), typeof(TST), typeof(CLR) + //}.Contains(type)) + //{ + // var vals = new[] { bytes[0], bytes[1] }.MapToMask("------dd dddddddd"); + // yield return new Operand(OperandType.DestinationRegister, vals['d']); + // yield break; + //} if (new[] { typeof(FMUL), typeof(FMULS), typeof(FMULSU), typeof(MULSU) }.Contains(type)) {