Skip to content

Commit

Permalink
Add Offset to ILInstruction
Browse files Browse the repository at this point in the history
This will be necessary for implementing branching instructions like:

    IL_001d: bne.un.s IL_002c
    ....
    IL_002c: call void [neslib]NES.NESLib::ppu_on_all()

We can get the value while iterating through IL, like:

    while (blob.RemainingBytes > 0)
    {
        int offset = blob.Offset;
        //...
        yield return new ILInstruction(opCode, offset, intValue, stringValue, byteValue);
    }
  • Loading branch information
jonathanpeppers committed Sep 19, 2024
1 parent 7cf4309 commit 2963331
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 142 deletions.
47 changes: 29 additions & 18 deletions src/dotnes.tasks/Utilities/IL2NESWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ public IL2NESWriter(Stream stream, bool leaveOpen = false, ILogger? logger = nul

record Local(int Value, int? Address = null);

public void Write(ILOpCode code, ushort sizeOfMain)
public void Write(ILInstruction instruction, ushort sizeOfMain)
{
switch (code)
switch (instruction.OpCode)
{
case ILOpCode.Nop:
break;
Expand Down Expand Up @@ -176,22 +176,22 @@ public void Write(ILOpCode code, ushort sizeOfMain)
Stack.Push(Stack.Pop() ^ Stack.Pop());
break;
default:
throw new NotImplementedException($"OpCode {code} with no operands is not implemented!");
throw new NotImplementedException($"OpCode {instruction.OpCode} with no operands is not implemented!");
}
previous = code;
previous = instruction.OpCode;
}

public void Write(ILOpCode code, int operand, ushort sizeOfMain)
public void Write(ILInstruction instruction, int operand, ushort sizeOfMain)
{
switch (code)
switch (instruction.OpCode)
{
case ILOpCode.Nop:
break;
case ILOpCode.Ldc_i4:
case ILOpCode.Ldc_i4_s:
if (operand > ushort.MaxValue)
{
throw new NotImplementedException($"{code} not implemented for value larger than ushort: {operand}");
throw new NotImplementedException($"{instruction.OpCode} not implemented for value larger than ushort: {operand}");
}
else if (operand > byte.MaxValue)
{
Expand Down Expand Up @@ -223,14 +223,14 @@ public void Write(ILOpCode code, int operand, ushort sizeOfMain)
WriteLdloc(Locals[operand], sizeOfMain);
break;
default:
throw new NotImplementedException($"OpCode {code} with Int32 operand is not implemented!");
throw new NotImplementedException($"OpCode {instruction.OpCode} with Int32 operand is not implemented!");
}
previous = code;
previous = instruction.OpCode;
}

public void Write(ILOpCode code, string operand, ushort sizeOfMain)
public void Write(ILInstruction instruction, string operand, ushort sizeOfMain)
{
switch (code)
switch (instruction.OpCode)
{
case ILOpCode.Nop:
break;
Expand All @@ -240,7 +240,18 @@ public void Write(ILOpCode code, string operand, ushort sizeOfMain)
Write(NESInstruction.LDX, 0x85);
Write(NESInstruction.JSR, Labels[nameof(pushax)]);
Write(NESInstruction.LDX, 0x00);
Write(ILOpCode.Ldc_i4_s, operand.Length, sizeOfMain);
if (operand.Length > ushort.MaxValue)
{
throw new NotImplementedException($"{instruction.OpCode} not implemented for value larger than ushort: {operand}");
}
else if (operand.Length > byte.MaxValue)
{
WriteLdc(checked((ushort)operand.Length), sizeOfMain);
}
else
{
WriteLdc((byte)operand.Length, sizeOfMain);
}
break;
case ILOpCode.Call:
switch (operand)
Expand Down Expand Up @@ -283,14 +294,14 @@ public void Write(ILOpCode code, string operand, ushort sizeOfMain)
Stack.Push(Stack.Peek());
break;
default:
throw new NotImplementedException($"OpCode {code} with String operand is not implemented!");
throw new NotImplementedException($"OpCode {instruction.OpCode} with String operand is not implemented!");
}
previous = code;
previous = instruction.OpCode;
}

public void Write(ILOpCode code, ImmutableArray<byte> operand, ushort sizeOfMain)
public void Write(ILInstruction instruction, ImmutableArray<byte> operand, ushort sizeOfMain)
{
switch (code)
switch (instruction.OpCode)
{
case ILOpCode.Ldtoken:
if (ByteArrayOffset == 0)
Expand All @@ -310,9 +321,9 @@ public void Write(ILOpCode code, ImmutableArray<byte> operand, ushort sizeOfMain
ByteArrays.Add(operand);
break;
default:
throw new NotImplementedException($"OpCode {code} with byte[] operand is not implemented!");
throw new NotImplementedException($"OpCode {instruction.OpCode} with byte[] operand is not implemented!");
}
previous = code;
previous = instruction.OpCode;
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion src/dotnes.tasks/Utilities/ILInstruction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ namespace dotnes;
/// <summary>
/// Holds info about IL
/// </summary>
record ILInstruction(ILOpCode OpCode, int? Integer = null, string? String = null, ImmutableArray<byte>? Bytes = null);
record ILInstruction(ILOpCode OpCode, int Offset = 0, int? Integer = null, string? String = null, ImmutableArray<byte>? Bytes = null);
40 changes: 19 additions & 21 deletions src/dotnes.tasks/Utilities/Transpiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,19 @@ private Dictionary<string, ushort> CalculateAddressLabels(ushort sizeOfMain)
{
if (instruction.Integer != null)
{
writer.Write(instruction.OpCode, instruction.Integer.Value, sizeOfMain);
writer.Write(instruction, instruction.Integer.Value, sizeOfMain);
}
else if (instruction.String != null)
{
writer.Write(instruction.OpCode, instruction.String, sizeOfMain);
writer.Write(instruction, instruction.String, sizeOfMain);
}
else if (instruction.Bytes != null)
{
writer.Write(instruction.OpCode, instruction.Bytes.Value, sizeOfMain);
writer.Write(instruction, instruction.Bytes.Value, sizeOfMain);
}
else
{
writer.Write(instruction.OpCode, sizeOfMain);
writer.Write(instruction, sizeOfMain);
}
}

Expand Down Expand Up @@ -180,35 +180,34 @@ public void Write(Stream stream)
/// </summary>
protected virtual void FirstPass(Dictionary<string, ushort> labels, out ushort sizeOfMain, out byte locals)
{
using var mainWriter = new IL2NESWriter(new MemoryStream(), logger: _logger)
using var writer = new IL2NESWriter(new MemoryStream(), logger: _logger)
{
UsedMethods = UsedMethods,
};
mainWriter.SetLabels(labels);
writer.SetLabels(labels);
foreach (var instruction in ReadStaticVoidMain())
{
_logger.WriteLine($"{instruction}");

if (instruction.Integer != null)
{
mainWriter.Write(instruction.OpCode, instruction.Integer.Value, sizeOfMain: 0);
writer.Write(instruction, instruction.Integer.Value, sizeOfMain: 0);
}
else if (instruction.String != null)
{
mainWriter.Write(instruction.OpCode, instruction.String, sizeOfMain: 0);
writer.Write(instruction, instruction.String, sizeOfMain: 0);
}
else if (instruction.Bytes != null)
{
mainWriter.Write(instruction.OpCode, instruction.Bytes.Value, sizeOfMain: 0);
writer.Write(instruction, instruction.Bytes.Value, sizeOfMain: 0);
}
else
{
mainWriter.Write(instruction.OpCode, sizeOfMain: 0);
writer.Write(instruction, sizeOfMain: 0);
}
}
mainWriter.Flush();
sizeOfMain = checked((ushort)mainWriter.BaseStream.Length);
locals = checked((byte)mainWriter.LocalCount);
writer.Flush();
sizeOfMain = checked((ushort)writer.BaseStream.Length);
locals = checked((byte)writer.LocalCount);
}

/// <summary>
Expand All @@ -219,23 +218,21 @@ protected virtual void SecondPass(ushort sizeOfMain, IL2NESWriter writer)
{
foreach (var instruction in ReadStaticVoidMain())
{
_logger.WriteLine($"{instruction}");

if (instruction.Integer != null)
{
writer.Write(instruction.OpCode, instruction.Integer.Value, sizeOfMain);
writer.Write(instruction, instruction.Integer.Value, sizeOfMain);
}
else if (instruction.String != null)
{
writer.Write(instruction.OpCode, instruction.String, sizeOfMain);
writer.Write(instruction, instruction.String, sizeOfMain);
}
else if (instruction.Bytes != null)
{
writer.Write(instruction.OpCode, instruction.Bytes.Value, sizeOfMain);
writer.Write(instruction, instruction.Bytes.Value, sizeOfMain);
}
else
{
writer.Write(instruction.OpCode, sizeOfMain);
writer.Write(instruction, sizeOfMain);
}
}
}
Expand All @@ -262,6 +259,7 @@ public IEnumerable<ILInstruction> ReadStaticVoidMain()

while (blob.RemainingBytes > 0)
{
int offset = blob.Offset;
ILOpCode opCode = DecodeOpCode(ref blob);

OperandType operandType = GetOperandType(opCode);
Expand Down Expand Up @@ -349,7 +347,7 @@ public IEnumerable<ILInstruction> ReadStaticVoidMain()
throw new NotSupportedException($"{opCode}, OperandType={operandType} is not supported.");
}

yield return new ILInstruction(opCode, intValue, stringValue, byteValue);
yield return new ILInstruction(opCode, offset, intValue, stringValue, byteValue);
}
}
}
Expand Down
Loading

0 comments on commit 2963331

Please sign in to comment.