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
3 changes: 1 addition & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ jobs:
unit-tests:
name: Unit Tests
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
Expand Down Expand Up @@ -60,4 +59,4 @@ jobs:
- name: End SonarQube Analysis
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: dotnet sonarscanner end /d:sonar.login="${SONAR_TOKEN}"
run: dotnet sonarscanner end /d:sonar.login="${SONAR_TOKEN}"
10 changes: 8 additions & 2 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 @@ -74,10 +74,14 @@
new OpcodeRule(0xFFC0, 0x4340, &ArithmeticOps.Muls),
// MVNS Rd, Rm
new OpcodeRule(0xFFC0, 0x43C0, &BitOps.Mvns),
// LSLS Rd, Rm, #0
new OpcodeRule(0xFFC0, 0x0000, &BitOps.LslsZero),
// LSRS (Register) - Encoding T2
new OpcodeRule(0xFFC0, 0x40C0, &BitOps.LsrsRegister),
// LSLS (Register) - Encoding T2
new OpcodeRule(0xFFC0, 0x4080, &BitOps.LslsRegister),
// LSLS Rd, Rm, #0
new OpcodeRule(0xFFC0, 0x0000, &BitOps.LslsZero),
// LSRS Rd, Rm, #0 (Shift 32)
new OpcodeRule(0xFFC0, 0x0800, &BitOps.LsrsImm32),
// Rev16 Rd, Rn
new OpcodeRule(0xFFC0, 0xBA40, &BitOps.Rev16),
// REVSH Rd, Rm
Expand Down Expand Up @@ -178,6 +182,8 @@
new OpcodeRule(0xF800, 0xC800, &MemoryOps.Ldmia),
// LSLS (Rd, Rm, imm5)
new OpcodeRule(0xF800, 0x0000, &BitOps.LslsImm5),
// LSRS (Rd, Rm, imm5)
new OpcodeRule(0xF800, 0x0800, &BitOps.LsrsImm5),
// ================================================================
// GROUP 9: Mask 0xBF00
// ================================================================
Expand Down Expand Up @@ -217,7 +223,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 226 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 226 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
79 changes: 77 additions & 2 deletions src/RP2040.Core/Cpu/Instructions/BitOps.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,17 +140,23 @@ public static void LslsRegister(ushort opcode, CortexM0Plus cpu)
var valRdn = ptrRdn;
var shift = (int)(cpu.Registers[rm] & 0xFF);

if (shift == 0)
{
cpu.Registers.N = (int)valRdn < 0;
cpu.Registers.Z = (valRdn == 0);
return;
}

var extended = (ulong)valRdn << shift;
var result = shift >= 32 ? 0 : (uint)extended;

var calcCarry = (extended & 0x1_0000_0000) != 0;
var finalCarry = (shift == 0) ? (cpu.Registers.GetC() != 0) : calcCarry;

ptrRdn = result;

cpu.Registers.N = (int)result < 0;
cpu.Registers.Z = (result == 0);
cpu.Registers.C = finalCarry;
cpu.Registers.C = calcCarry;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand All @@ -168,6 +174,75 @@ public static void LslsZero(ushort opcode, CortexM0Plus cpu)
cpu.Registers.Z = (valRm == 0);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void LsrsImm5(ushort opcode, CortexM0Plus cpu)
{
// LSRS Rd, Rm, #imm5
var imm5 = (opcode >> 6) & 0x1F;
var rm = (opcode >> 3) & 0x7;
var rd = opcode & 0x7;

ref var ptrRd = ref cpu.Registers[rd];
var valRm = cpu.Registers[rm];

var result = valRm >> imm5;
var carry = ((valRm >> (imm5 - 1)) & 1) != 0;

ptrRd = result;

cpu.Registers.N = false; // (result >> 31) will be always 0 if shift >= 1
cpu.Registers.Z = (result == 0);
cpu.Registers.C = carry;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void LsrsImm32(ushort opcode, CortexM0Plus cpu)
{
// LSRS Rd, Rm, #0
var rm = (opcode >> 3) & 0x7;
var rd = opcode & 0x7;

ref var ptrRd = ref cpu.Registers[rd];
var valRm = cpu.Registers[rm];

ptrRd = 0;

cpu.Registers.N = false;
cpu.Registers.Z = true;
cpu.Registers.C = (int)valRm < 0; // Bit 31
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void LsrsRegister(ushort opcode, CortexM0Plus cpu)
{
var rdn = opcode & 0x7;
var rm = (opcode >> 3) & 0x7;

ref var ptrRdn = ref cpu.Registers[rdn];
var valRdn = ptrRdn;
var shift = (int)(cpu.Registers[rm] & 0xFF);

// Fast Guard
if (shift == 0)
{
cpu.Registers.N = (int)valRdn < 0;
cpu.Registers.Z = (valRdn == 0);
return;
}

var result = shift >= 32 ? 0 : valRdn >> shift;

var rawCarryBit = (valRdn >> ((shift - 1) & 0x1F)) & 1;
var limitMask = (32 - shift) >> 31;
var carry = (rawCarryBit & ~limitMask) != 0;

ptrRdn = result;

cpu.Registers.N = (int)result < 0;
cpu.Registers.Z = (result == 0);
cpu.Registers.C = carry;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void MovRegister(ushort opcode, CortexM0Plus cpu)
{
Expand Down
16 changes: 16 additions & 0 deletions src/RP2040.Core/Helpers/InstructionEmiter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,22 @@ public static ushort LslsRegister(uint rdn, uint rm)
return (ushort)(0x4080 | ((rm & 7) << 3) | rdn);
}

public static ushort LsrsImm5(uint rd, uint rm, uint imm5)
{
if (rd > 7 || rm > 7)
throw new ArgumentException(LowRegisterIndexOutOfRange);
if (imm5 > 31)
throw new ArgumentException("Immediate too large for LSLS");
return (ushort)(0x0800 | (imm5 & 0x1F) << 6 | ((rm & 7) << 3) | (rd & 7));
}

public static ushort LsrsRegister(uint rdn, uint rm)
{
if (rdn > 7 || rm > 7)
throw new ArgumentException(LowRegisterIndexOutOfRange);
return (ushort)(0x40C0 | ((rm & 7) << 3) | rdn);
}

public static ushort Revsh(uint rd, uint rm)
{
if (rd > 7 || rm > 7)
Expand Down
3 changes: 3 additions & 0 deletions tests/RP2040.Core.Tests/Cpu/InstructionDecoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ public static TheoryData<string, ushort, ulong> GetInstructionTestCases()
Add("LslsImm", InstructionEmiter.LslsImm5(R5, R5, 18), &BitOps.LslsImm5);
Add("LslsImmZero", InstructionEmiter.LslsImm5(R5, R5, 0), &BitOps.LslsZero);
Add("LslsRegister", InstructionEmiter.LslsRegister(R5, R0), &BitOps.LslsRegister);
Add("LsrsImm", InstructionEmiter.LsrsImm5(R5, R5, 18), &BitOps.LsrsImm5);
Add("LsrsImm32", InstructionEmiter.LsrsImm5(R1, R1, 0), &BitOps.LsrsImm32);
Add("LsrsRegister", InstructionEmiter.LsrsRegister(R5, R0), &BitOps.LsrsRegister);
Add("Mvns", InstructionEmiter.Mvns(R0, R2), &BitOps.Mvns);
Add("Orrs", InstructionEmiter.Orrs(R5, R0), &BitOps.Orrs);
Add("Rev", InstructionEmiter.Rev(R0, R1), &BitOps.Rev);
Expand Down
Loading