Skip to content
Merged
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
638 changes: 638 additions & 0 deletions samples/game2048/Program.cs

Large diffs are not rendered by default.

1,026 changes: 1,026 additions & 0 deletions samples/game2048/chr_game2048.s

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions samples/game2048/game2048.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk" >

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

</PropertyGroup>

<ItemGroup>
<PackageReference Include="dotnes" Version="$(PackageVersion)" />
<PackageReference Include="dotnes.mesen" Version="2.1.1" />
</ItemGroup>

</Project>
6 changes: 4 additions & 2 deletions src/dotnes.tasks/Utilities/IL2NESWriter.Arithmetic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -504,8 +504,10 @@ void HandleAddSub(bool isAdd)

if (loadedLocal.IsWord)
{
// 16-bit local: remove LDA $lo, LDX $hi, JSR pushax, LDA #1 (4 instructions)
RemoveLastInstructions(4);
// When _ushortInAX is true, WriteLdc returned early (no pushax/LDA emitted)
// so only LDA $lo + LDX $hi (2 instructions) need removal.
// When false, pushax was emitted: LDA $lo + LDX $hi + JSR pushax + LDA #1 (4).
RemoveLastInstructions(_ushortInAX ? 2 : 4);
if (isAdd)
{
// INC lo; BNE +3; INC hi
Expand Down
19 changes: 18 additions & 1 deletion src/dotnes.tasks/Utilities/IL2NESWriter.ILDispatch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1955,6 +1955,22 @@ public void Write(ILInstruction instruction, string operand)
}
}

// If we found a pusha, check it wasn't consumed by a popa
// (e.g. from an unrelated add expression like p1 = 4 + i * 6).
if (pushaIdx2 >= 0)
{
for (int bi = pushaIdx2 + 1; bi < block.Count; bi++)
{
if (block[bi].Opcode == Opcode.JSR
&& block[bi].Operand is LabelOperand popaLbl
&& popaLbl.Label == "popa")
{
pushaIdx2 = -1; // consumed — ignore it
break;
}
}
}

if (pushaIdx2 >= 0 && pushaIdx2 > 0)
{
// Found pusha with intervening stloc instructions
Expand Down Expand Up @@ -3032,7 +3048,8 @@ or ILOpCode.Ldc_i4_3 or ILOpCode.Ldc_i4_4 or ILOpCode.Ldc_i4_5
// Fastcall functions (pal_bg, pal_spr, pal_all, vram_unrle) expect
// pointer in A:X, not on cc65 stack. Replace pushax+size with just LDA/LDX.
if (_ldlocByteArrayLabel != null && operand is nameof(NESLib.pal_bg)
or nameof(NESLib.pal_spr) or nameof(NESLib.pal_all) or nameof(NESLib.vram_unrle))
or nameof(NESLib.pal_spr) or nameof(NESLib.pal_all) or nameof(NESLib.vram_unrle)
or nameof(NESLib.set_vram_update))
{
// WriteLdloc emitted: LDA #lo, LDX #hi, JSR pushax, LDX #$00, LDA #size
RemoveLastInstructions(5);
Expand Down
7 changes: 5 additions & 2 deletions src/dotnes.tasks/Utilities/IL2NESWriter.LocalVariables.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,12 @@ void WriteLdc(byte operand)
// Check if the next instruction can handle A:X directly
bool nextIsShift = Instructions is not null && Index + 1 < Instructions.Length &&
Instructions[Index + 1].OpCode is ILOpCode.Shr or ILOpCode.Shr_un or ILOpCode.Shl;
bool nextIsAddSub = _runtimeValueInA && Instructions is not null && Index + 1 < Instructions.Length &&
// When A:X holds a ushort, the next Add/Sub/Div/Rem should operate on
// A:X directly — no need to push to the C stack first. This matches the
// behavior of WriteLdc(ushort) which also skips pushax for Add/Sub.
bool nextIsAddSub = Instructions is not null && Index + 1 < Instructions.Length &&
Instructions[Index + 1].OpCode is ILOpCode.Add or ILOpCode.Sub;
bool nextIsDivRem = _runtimeValueInA && Instructions is not null && Index + 1 < Instructions.Length &&
bool nextIsDivRem = Instructions is not null && Index + 1 < Instructions.Length &&
Instructions[Index + 1].OpCode is ILOpCode.Div or ILOpCode.Rem;
bool nextIsBitwise = Instructions is not null && Index + 1 < Instructions.Length &&
Instructions[Index + 1].OpCode is ILOpCode.And or ILOpCode.Or or ILOpCode.Xor;
Expand Down
Loading