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
8 changes: 8 additions & 0 deletions src/RP2040.Core/Cpu/InstructionDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace RP2040.Core.Cpu;

public sealed unsafe class InstructionDecoder : IDisposable

Check warning on line 9 in src/RP2040.Core/Cpu/InstructionDecoder.cs

View workflow job for this annotation

GitHub Actions / Unit Tests

Make sure that using "unsafe" is safe here. (https://rules.sonarsource.com/csharp/RSPEC-6640)

Check warning on line 9 in src/RP2040.Core/Cpu/InstructionDecoder.cs

View workflow job for this annotation

GitHub Actions / Unit Tests

Make sure that using "unsafe" is safe here. (https://rules.sonarsource.com/csharp/RSPEC-6640)
{
public static InstructionDecoder Instance { get; } = new InstructionDecoder();

Expand Down Expand Up @@ -153,6 +153,8 @@
new OpcodeRule(0xFE00, 0x1E00, &ArithmeticOps.SubsImmediate3),
// SUBS (Register)
new OpcodeRule(0xFE00, 0x1A00, &ArithmeticOps.SubsRegister),
// LDR (register)
new OpcodeRule(0xFE00, 0x5800, &MemoryOps.LdrRegister),
// ================================================================
// GROUP 8: Mask 0xF800 (5 bits significant - Most Generic)
// ================================================================
Expand All @@ -176,6 +178,12 @@
new OpcodeRule(0xF800, 0x2000, &BitOps.Movs),
// LDMIA (Load Multiple Increment After)
new OpcodeRule(0xF800, 0xC800, &MemoryOps.Ldmia),
// LDR (literal)
new OpcodeRule(0xF800, 0x4800, &MemoryOps.LdrLiteral),
// LDR (imm5)
new OpcodeRule(0xF800, 0x6800, &MemoryOps.LdrImmediate),
// LDR (SP, imm8)
new OpcodeRule(0xF800, 0x9800, &MemoryOps.LdrSpRelative),
// LSLS (Rd, Rm, imm5)
new OpcodeRule(0xF800, 0x0000, &BitOps.LslsImm5),
// ================================================================
Expand Down Expand Up @@ -217,7 +225,7 @@

private static void HandleUndefined(ushort opcode, CortexM0Plus cpu)
{
throw new Exception($"Undefined Opcode: 0x{opcode:X4} PC={cpu.Registers.PC:X8}");

Check warning on line 228 in src/RP2040.Core/Cpu/InstructionDecoder.cs

View workflow job for this annotation

GitHub Actions / Unit Tests

'System.Exception' should not be thrown by user code. (https://rules.sonarsource.com/csharp/RSPEC-112)

Check warning on line 228 in src/RP2040.Core/Cpu/InstructionDecoder.cs

View workflow job for this annotation

GitHub Actions / Unit Tests

'System.Exception' should not be thrown by user code. (https://rules.sonarsource.com/csharp/RSPEC-112)
}

[ExcludeFromCodeCoverage]
Expand Down
62 changes: 62 additions & 0 deletions src/RP2040.Core/Cpu/Instructions/MemoryOps.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,45 @@

namespace RP2040.Core.Cpu.Instructions;

public static unsafe class MemoryOps

Check warning on line 7 in src/RP2040.Core/Cpu/Instructions/MemoryOps.cs

View workflow job for this annotation

GitHub Actions / Unit Tests

Make sure that using "unsafe" is safe here. (https://rules.sonarsource.com/csharp/RSPEC-6640)

Check warning on line 7 in src/RP2040.Core/Cpu/Instructions/MemoryOps.cs

View workflow job for this annotation

GitHub Actions / Unit Tests

Make sure that using "unsafe" is safe here. (https://rules.sonarsource.com/csharp/RSPEC-6640)
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void LdrImmediate(ushort opcode, CortexM0Plus cpu)
{
var rt = opcode & 0x7;
var rn = (opcode >> 3) & 0x7;
var imm5 = (uint)((opcode >> 6) & 0x1F) << 2;

cpu.Registers[rt] = ReadWordWithCycles(cpu, cpu.Registers[rn] + imm5);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void LdrLiteral(ushort opcode, CortexM0Plus cpu)
{
var rt = (opcode >> 8) & 0x7;
var imm8 = (uint)(opcode & 0xFF) << 2;
var nextPc = cpu.Registers.PC + 2;
var addr = (nextPc & 0xFFFFFFFC) + imm8;
cpu.Registers[rt] = ReadWordWithCycles(cpu, addr);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void LdrRegister(ushort opcode, CortexM0Plus cpu)
{
var rt = opcode & 0x7;
var rn = (opcode >> 3) & 0x7;
var rm = (opcode >> 6) & 0x7;
cpu.Registers[rt] = ReadWordWithCycles(cpu, cpu.Registers[rn] + cpu.Registers[rm]);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void LdrSpRelative(ushort opcode, CortexM0Plus cpu)
{
var rt = (opcode >> 8) & 0x7;
var imm8 = (uint)(opcode & 0xFF) << 2;
cpu.Registers[rt] = ReadWordWithCycles(cpu, cpu.Registers.SP + imm8);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Pop(ushort opcode, CortexM0Plus cpu)
{
Expand Down Expand Up @@ -207,4 +244,29 @@
cpu.Registers[rn] += writeBackOffset;
cpu.Cycles += (int)regCount;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint ReadWordWithCycles(CortexM0Plus cpu, uint address)
{
var region = address >> 28;

switch (region)
{
case <= BusInterconnect.REGION_SRAM:
cpu.Cycles += 1;
break;
case 0x4: // APB/AHB
case 0x5:
cpu.Cycles += 2;
break;
// SIO (Single-cycle IO)
case 0xD:
break;
default:
cpu.Cycles += 1; // Fallback
break;
}

return cpu.Bus.ReadWord(address);
}
}
31 changes: 31 additions & 0 deletions src/RP2040.Core/Helpers/InstructionEmiter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,37 @@ public static ushort Ldmia(uint rn, uint registerList)
return (ushort)(0xC800 | (rn & 0x7) << 8 | registerList & 0xFF);
}

public static ushort LdrImmediate(uint rt, uint rn, uint imm)
{
var imm5 = imm >> 2;
if (rt > 7 || rn > 7)
throw new ArgumentException(LowRegisterIndexOutOfRange);
return (ushort)(0x6800 | (imm5 & 0x1F) << 6 | (rn & 0x7) << 3 | (rt & 0x7));
}

public static ushort LdrLiteral(uint rt, uint imm)
{
var imm8 = imm >> 2;
if (rt > 7)
throw new ArgumentException(LowRegisterIndexOutOfRange);
return (ushort)(0x4800 | (rt & 0x7) << 8 | (imm8 & 0xFF));
}

public static ushort LdrRegister(uint rt, uint rn, uint rm)
{
if (rt > 7 || rn > 7 || rm > 7)
throw new ArgumentException(LowRegisterIndexOutOfRange);
return (ushort)(0x5800 | (rm & 0x7) << 6 | (rn & 0x7) << 3 | (rt & 0x7));
}

public static ushort LdrSpRelative(uint rt, uint imm)
{
var imm8 = imm >> 2;
if (rt > 7)
throw new ArgumentException(LowRegisterIndexOutOfRange);
return (ushort)(0x9800 | (rt & 0x7) << 8 | (imm8 & 0xFF));
}

public static ushort LslsImm5(uint rd, uint rm, uint imm5)
{
if (rd > 7 || rm > 7)
Expand Down
6 changes: 6 additions & 0 deletions tests/RP2040.Core.Tests/Cpu/InstructionDecoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@ public static TheoryData<string, ushort, ulong> GetInstructionTestCases()
Add("Mrs", (ushort)(InstructionEmiter.Mrs(R0, 5) & 0xFFFF), &SystemOps.Mrs);
Add("Msr", (ushort)(InstructionEmiter.Msr(8, R0) & 0xFFFF), &SystemOps.Msr);

// Load Operations
Add("LdrImmediate", InstructionEmiter.LdrImmediate(R0, R1, 4), &MemoryOps.LdrImmediate);
Add("LdrLiteral", InstructionEmiter.LdrLiteral(R2, 0x10), &MemoryOps.LdrLiteral);
Add("LdrRegister", InstructionEmiter.LdrRegister(R3, R4, R5), &MemoryOps.LdrRegister);
Add("LdrSpRelative", InstructionEmiter.LdrSpRelative(R6, 0x20), &MemoryOps.LdrSpRelative);

Add("Ldmia", InstructionEmiter.Ldmia(R0, (1 << R1) | (1 << R2)), &MemoryOps.Ldmia);

// Push / Pop
Expand Down
Loading