Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion Source/AVRDisassembler/AVRDisassembler/Disassembler.cs
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -32,7 +35,8 @@ public IEnumerable<AssemblyStatement> 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();

Expand All @@ -44,6 +48,30 @@ public IEnumerable<AssemblyStatement> 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<IOperand> { operands.First() };
}
}

var statement = new AssemblyStatement(opcode, operands)
{
Offset = offset,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)";
}
}
13 changes: 6 additions & 7 deletions Source/AVRDisassembler/AVRDisassembler/OpCodeIdentification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ private static IEnumerable<IOpCode> 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)
{
Expand Down Expand Up @@ -98,17 +98,16 @@ private static IEnumerable<IOpCode> 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)
}
}

private static IEnumerable<IOpCode> IdentifyWithFirstNibble0010(byte nb2, byte nb3, byte nb4)
{
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;
}
Expand All @@ -131,12 +130,12 @@ private static IEnumerable<IOpCode> IdentifyWithFirstNibble0101(byte nb2, byte n

private static IEnumerable<IOpCode> 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<IOpCode> 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<IOpCode> IdentifyWithFirstNibble1000(byte nb2, byte nb3, byte nb4)
Expand Down
33 changes: 22 additions & 11 deletions Source/AVRDisassembler/AVRDisassembler/OperandExtraction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public static IEnumerable<IOperand> 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");
Expand Down Expand Up @@ -78,6 +79,14 @@ public static IEnumerable<IOperand> 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----");
Expand Down Expand Up @@ -225,16 +234,18 @@ public static IEnumerable<IOperand> 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))
{
Expand Down