From cd32b65a354224486a302375a8f33b0f11200777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Montiel=20Cardona?= Date: Mon, 2 Feb 2026 14:42:44 -0600 Subject: [PATCH 1/8] fix(arm): correct LS/LSLS flag handling and add LSRS variants Fix LSLS register shift behavior to set N and Z shift is zero and to compute carry from the shifted-out bit instead of reusing the previous C flag. Add missing LSRS implementations: - LsrsImm5 for shifts 1-31 - LsrsImm32 for #0 (treated as shift 32/zero result) - LsrsRegister for register-specified shifts These changes ensure correct N, Z, and C updates for logical shift right/left operations, handle the zero-shift fast path, and compute carry bits safely for edge cases (shift >= 32). --- src/RP2040.Core/Cpu/Instructions/BitOps.cs | 79 +++++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/src/RP2040.Core/Cpu/Instructions/BitOps.cs b/src/RP2040.Core/Cpu/Instructions/BitOps.cs index 41df678..92407fd 100644 --- a/src/RP2040.Core/Cpu/Instructions/BitOps.cs +++ b/src/RP2040.Core/Cpu/Instructions/BitOps.cs @@ -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)] @@ -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) { From c278fba2c0d9654eb977cf3a85c23549a448a508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Montiel=20Cardona?= Date: Mon, 2 Feb 2026 14:43:08 -0600 Subject: [PATCH 2/8] feat(decoder): add LSRS encodings and reorder LSLS zero rule Add support for LSRS register and immediate-32 encodings and register the LSRS immediate-5 opcode. Reorder the LSLS zero rule to maintain correct matching precedence among shift instructions. Why: - LSRS (register) T2 missing and is now mapped to BitOps.LsrsRegister, enabling register-based logical right shifts. - A special LSRS imm #32 case is handled via BitOps.LsrsImm32 to match ARM semantics for a shift of 32 producing defined results. - LSRS immediate-5 is added so immediate-form logical right shifts decode correctly. - LSLS zero rule is moved after the register forms to ensure more specific encodings are matched first and avoid accidental trapping of other shift encodings. --- src/RP2040.Core/Cpu/InstructionDecoder.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/RP2040.Core/Cpu/InstructionDecoder.cs b/src/RP2040.Core/Cpu/InstructionDecoder.cs index ef99387..ad65893 100644 --- a/src/RP2040.Core/Cpu/InstructionDecoder.cs +++ b/src/RP2040.Core/Cpu/InstructionDecoder.cs @@ -74,10 +74,14 @@ public InstructionDecoder() 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 @@ -178,6 +182,8 @@ public InstructionDecoder() 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 // ================================================================ From 20b66c77b40a3f98a730df953521b5b6ed414ee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Montiel=20Cardona?= Date: Mon, 2 Feb 2026 14:43:17 -0600 Subject: [PATCH 3/8] feat(asm): add LSRS encodings for imm5 and register forms Add two new helper emitters to InstructionEmiter: LsrsImm5 and LsrsRegister. LsrsImm5 encodes the logical shift right (immediate) variant with a 5-bit immediate and validates low-register indices and immediate range. LsrsRegister encodes the register-specified LSRS form and validates low-register indices. These helpers mirror existing shift encoders, provide consistent argument validation, and enable emitting LSRS instructions from higher level code. --- src/RP2040.Core/Helpers/InstructionEmiter.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/RP2040.Core/Helpers/InstructionEmiter.cs b/src/RP2040.Core/Helpers/InstructionEmiter.cs index 75cb1fb..32c66fd 100644 --- a/src/RP2040.Core/Helpers/InstructionEmiter.cs +++ b/src/RP2040.Core/Helpers/InstructionEmiter.cs @@ -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) From a6ed4b19d332761ebac4d65869f55107194158fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Montiel=20Cardona?= Date: Mon, 2 Feb 2026 14:43:31 -0600 Subject: [PATCH 4/8] test(cpu): add LSRS tests and extend LSLS tests Extend bitwise shift instruction tests to cover missing edge cases and ensure correct decoder/test table entries. - Add LSRS instruction entries to InstructionDecoderTests to include immediate, immediate-as-32, and register forms in the decoder test matrix. - Convert Lsls test class to abstract so both immediate and register variants can coexist and be extended. - Add new Lsls register tests: - verify result is zero and carry cleared when shifting by > 32 - verify shift-register operand is interpreted as an unsigned byte - Add a new Lsrs test class with immediate-mode tests: - basic right shift behavior and PC update - immediate 0 interpreted as logical shift by 32 - explicit carry behavior when a 1 is shifted out - shift by maximum immediate (31) coverage These changes improve coverage for shifts (LSL/LSR) and catch corner cases around shift widths and carry flag behavior. --- .../Cpu/InstructionDecoderTests.cs | 3 + .../Cpu/Instructions/BitOpsTests.cs | 230 +++++++++++++++++- 2 files changed, 232 insertions(+), 1 deletion(-) diff --git a/tests/RP2040.Core.Tests/Cpu/InstructionDecoderTests.cs b/tests/RP2040.Core.Tests/Cpu/InstructionDecoderTests.cs index 91cb326..e19d065 100644 --- a/tests/RP2040.Core.Tests/Cpu/InstructionDecoderTests.cs +++ b/tests/RP2040.Core.Tests/Cpu/InstructionDecoderTests.cs @@ -101,6 +101,9 @@ public static TheoryData 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); diff --git a/tests/RP2040.Core.Tests/Cpu/Instructions/BitOpsTests.cs b/tests/RP2040.Core.Tests/Cpu/Instructions/BitOpsTests.cs index 3cb2c8a..1d719fc 100644 --- a/tests/RP2040.Core.Tests/Cpu/Instructions/BitOpsTests.cs +++ b/tests/RP2040.Core.Tests/Cpu/Instructions/BitOpsTests.cs @@ -374,7 +374,7 @@ public void Should_BitwiseInvert_Value_And_UpdateNegativeFlag() } } - public class Lsls + public abstract class Lsls { public class Immediate : CpuTestBase { @@ -479,6 +479,234 @@ public void Should_ResultInZero_And_SetCarry_When_ShiftingBy32() Cpu.Registers.Z.Should().BeTrue(); // Result is 0 Cpu.Registers.C.Should().BeTrue(); // Bit 0 shifted out } + + [Fact] + public void Should_ResultInZero_And_ClearCarry_When_ShiftingLeftByMoreThan32() + { + // Arrange + var opcode = InstructionEmiter.LslsRegister(R0, R1); + Bus.WriteHalfWord(0x20000000, opcode); + + Cpu.Registers[R0] = 0xFFFFFFFF; + Cpu.Registers[R1] = 33; // Shift 33 + Cpu.Registers.C = true; + + // Act + Cpu.Step(); + + // Assert + Cpu.Registers[R0].Should().Be(0); + Cpu.Registers.Z.Should().BeTrue(); + Cpu.Registers.C.Should().BeFalse("LSL > 32 should set Carry to 0"); + } + + [Fact] + public void Should_InterpretShiftRegister_AsUnsignedByte() + { + // Arrange + var opcode = InstructionEmiter.LslsRegister(R0, R1); + Bus.WriteHalfWord(0x20000000, opcode); + + Cpu.Registers[R0] = 1; + Cpu.Registers[R1] = 0xFFFFFFFF; // Bottom byte is 0xFF (255) + + // Act + Cpu.Step(); + + // Assert + Cpu.Registers[R0].Should().Be(0); // 1 << 255 is 0 + Cpu.Registers.C.Should().BeFalse(); // Carry from huge shift is 0 + } + } + } + + public abstract class Lsrs + { + public class Immediate : CpuTestBase + { + [Fact] + public void Should_ShiftRight_ByImmediateValue() + { + // Port from JS: 'should execute a `lsrs r1, r1, #1` instruction' + // Arrange + var opcode = InstructionEmiter.LsrsImm5(R1, R1, 1); + Bus.WriteHalfWord(0x20000000, opcode); + + Cpu.Registers[R1] = 0b10; // 2 + Cpu.Registers.C = true; // Dirty Carry + + // Act + Cpu.Step(); + + // Assert + Cpu.Registers[R1].Should().Be(0b1); + Cpu.Registers.PC.Should().Be(0x20000002); + Cpu.Registers.C.Should().BeFalse(); // Bit 0 (0) shifted out + Cpu.Registers.N.Should().BeFalse(); + Cpu.Registers.Z.Should().BeFalse(); + } + + [Fact] + public void Should_PerformLogicalShiftRightBy32_When_ImmediateIsZero() + { + // Arrange + var opcode = InstructionEmiter.LsrsImm5(R1, R1, 0); + Bus.WriteHalfWord(0x20000000, opcode); + + Cpu.Registers[R1] = 0xFFFFFFFF; + + // Act + Cpu.Step(); + + // Assert + Cpu.Registers[R1].Should().Be(0u); + Cpu.Registers.C.Should().BeTrue(); + } + + [Fact] + public void Should_SetCarryFlag_When_OneIsShiftedOut() + { + // New Test: Explicitly checking carry behavior on standard shift + // Arrange + var opcode = InstructionEmiter.LsrsImm5(R0, R0, 1); + Bus.WriteHalfWord(0x20000000, opcode); + + Cpu.Registers[R0] = 0b11; // 3 -> Shift right 1 -> 1, Carry = 1 + Cpu.Registers.C = false; + + // Act + Cpu.Step(); + + // Assert + Cpu.Registers[R0].Should().Be(1); + Cpu.Registers.C.Should().BeTrue(); + } + + [Fact] + public void Should_ShiftRight_ByMaximumImmediate_31() + { + // Arrange + var opcode = InstructionEmiter.LsrsImm5(R0, R0, 31); + Bus.WriteHalfWord(0x20000000, opcode); + + Cpu.Registers[R0] = 0x80000000; // Bit 31 set + Cpu.Registers.C = true; + + // Act + Cpu.Step(); + + // Assert + Cpu.Registers[R0].Should().Be(1); // 0x80000000 >> 31 = 1 + Cpu.Registers.C.Should().BeFalse("Bit shifted out (bit 30) was 0"); + } + } + + public class Register : CpuTestBase + { + [Fact] + public void Should_Execute_LsrsRegister_StandardCase() + { + // Arrange + var opcode = InstructionEmiter.LsrsRegister(R5, R0); + Bus.WriteHalfWord(0x20000000, opcode); + + Cpu.Registers[R5] = 0xff00000f; + Cpu.Registers[R0] = 0xff003302; + + // Act + Cpu.Step(); + + // Assert + Cpu.Registers[R5].Should().Be(0x3fc00003); + Cpu.Registers.PC.Should().Be(0x20000002); + Cpu.Registers.C.Should().BeTrue(); + } + + [Fact] + public void Should_ResultInZero_When_ShiftingBy32() + { + // Port from JS: 'should return zero for `lsrs r2, r3` with 32 bit shift' + // Arrange + var opcode = InstructionEmiter.LsrsRegister(R2, R3); + Bus.WriteHalfWord(0x20000000, opcode); + + Cpu.Registers[R2] = 10; // ...00001010 + Cpu.Registers[R3] = 32; + Cpu.Registers.C = true; + + // Act + Cpu.Step(); + + // Assert + Cpu.Registers[R2].Should().Be(0); + Cpu.Registers.Z.Should().BeTrue(); + // Bit 31 of '10' is 0, so Carry should be 0 + Cpu.Registers.C.Should().BeFalse(); + } + + [Fact] + public void Should_ResultInZero_And_ClearCarry_When_ShiftingByMoreThan32() + { + // New Test: Edge case > 32 + // Arrange + var opcode = InstructionEmiter.LsrsRegister(R2, R3); + Bus.WriteHalfWord(0x20000000, opcode); + + Cpu.Registers[R2] = 0xFFFFFFFF; + Cpu.Registers[R3] = 33; // Shift > 32 + Cpu.Registers.C = true; + + // Act + Cpu.Step(); + + // Assert + Cpu.Registers[R2].Should().Be(0); + Cpu.Registers.Z.Should().BeTrue(); + Cpu.Registers.C.Should().BeFalse(); // For shift > 32, C becomes 0 + } + + [Fact] + public void Should_PreserveValue_And_PreserveCarry_When_ShiftIsZero() + { + // New Test: Shift by 0 (Register variant) + // Note: Unlike Immediate #0 (which means 32), Register 0 means 0. + // Arrange + var opcode = InstructionEmiter.LsrsRegister(R0, R1); + Bus.WriteHalfWord(0x20000000, opcode); + + Cpu.Registers[R0] = 0x12345678; + Cpu.Registers[R1] = 0; + Cpu.Registers.C = true; // Should persist + + // Act + Cpu.Step(); + + // Assert + Cpu.Registers[R0].Should().Be(0x12345678); + Cpu.Registers.C.Should() + .BeTrue("Shift by 0 in register mode should not affect Carry"); + Cpu.Registers.Z.Should().BeFalse(); + } + + [Fact] + public void Should_SetCarryToBit31_When_ShiftingBy32() + { + // Critical case: LSR by 32. Result is 0, Carry becomes original Bit 31. + // Arrange + var opcode = InstructionEmiter.LsrsRegister(R0, R1); + Bus.WriteHalfWord(0x20000000, opcode); + + Cpu.Registers[R0] = 0x80001234; // Bit 31 is 1 + Cpu.Registers[R1] = 32; + Cpu.Registers.C = false; + + // Act + Cpu.Step(); + + // Assert + Cpu.Registers[R0].Should().Be(0); + Cpu.Registers.C.Should().BeTrue("LSR by 32 should set Carry to original Bit 31"); + } } } From 1971e11141582e6b146d9aea2bd1a34f11db187b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Montiel=20Cardona?= Date: Mon, 2 Feb 2026 15:47:36 -0600 Subject: [PATCH 5/8] chore(ci): run unit tests on self-hosted runners Expand GitHub Actions matrix to include self-hosted runner and prevent the workflow from failing fast so all matrix jobs run. Add conditional step to add .NET global tools to PATH on the self-hosted runner, fixing missing tool availability when using self-hosted agents. Update job name to show the selected runner. --- .github/workflows/test.yml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c6080b1..f333f01 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,8 +9,14 @@ on: jobs: unit-tests: - name: Unit Tests - runs-on: ubuntu-latest + name: Unit Tests (${{ matrix.runner }}) + + strategy: + fail-fast: false + matrix: + runner: [ubuntu-latest, self-hosted] + + runs-on: ${{ matrix.runner }} steps: - name: Checkout code @@ -32,6 +38,10 @@ jobs: - name: Install SonarCloud scanner run: dotnet tool install --global dotnet-sonarscanner + - name: Add .NET tools to PATH (Self-Hosted fix) + if: matrix.runner == 'self-hosted' + run: echo "$HOME/.dotnet/tools" >> $GITHUB_PATH + - name: Restore dependencies run: dotnet restore @@ -60,4 +70,4 @@ jobs: - name: End SonarQube Analysis env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: dotnet sonarscanner end /d:sonar.login="${SONAR_TOKEN}" \ No newline at end of file + run: dotnet sonarscanner end /d:sonar.login="${SONAR_TOKEN}" From 327ce1f4da0ba354fe9abed6292bf986cf425308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Montiel=20Cardona?= Date: Mon, 2 Feb 2026 15:54:58 -0600 Subject: [PATCH 6/8] chore(ci): simplify unit-tests job matrix configurationSimplify the Git Actions unit-tests by collapsing the runner matrix into a single `runs-on` array and removing the explicit matrix strategy and runner name. This reduces workflow verbosity while preserving execution on both `ubuntu-latest` and `self-hosted` runners. --- .github/workflows/test.yml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f333f01..3fbf0c5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,14 +9,9 @@ on: jobs: unit-tests: - name: Unit Tests (${{ matrix.runner }}) - - strategy: - fail-fast: false - matrix: - runner: [ubuntu-latest, self-hosted] + name: Unit Tests - runs-on: ${{ matrix.runner }} + runs-on: [ubuntu-latest, self-hosted] steps: - name: Checkout code From 0e0abab09548eec03219a086ca5019e4ee8f259a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Montiel=20Cardona?= Date: Mon, 2 Feb 2026 15:56:37 -0600 Subject: [PATCH 7/8] chore(ci): simplify .NET tools PATH step in test workflow Remove conditional "Self-Hosted fix" check from the GitHub Actions test workflow and rename the step to "Add .NET tools to PATH". The step now always appends the .dotnet tools path to GITHUB_PATH instead of running only for self-hosted runners. This ensures the dotnet tools path is consistently available regardless of runner type and reduces conditional complexity in the workflow. --- .github/workflows/test.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3fbf0c5..65748af 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -33,8 +33,7 @@ jobs: - name: Install SonarCloud scanner run: dotnet tool install --global dotnet-sonarscanner - - name: Add .NET tools to PATH (Self-Hosted fix) - if: matrix.runner == 'self-hosted' + - name: Add .NET tools to PATH run: echo "$HOME/.dotnet/tools" >> $GITHUB_PATH - name: Restore dependencies From ae0dbb5c380bfe0c66bc8f723e7fe1de3d31b552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Montiel=20Cardona?= Date: Mon, 2 Feb 2026 21:15:05 -0600 Subject: [PATCH 8/8] ci: run unit tests on ubuntu-latest runner Change the GitHub Actions workflow to use the hosted ubuntu-latest runner instead of an array included self-hosted. Remove an unnecessary step that attempted to add .NET global tools to PATHsince the workflow does not rely on that step and dotnet tools are not required for the scanner installation in this context. This simplifies runner selection, avoids accidentally scheduling jobs on self-hosted machines, and cleans up redundant steps to make the CI flow clearer and more robust. --- .github/workflows/test.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 65748af..1e44895 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,9 +10,7 @@ on: jobs: unit-tests: name: Unit Tests - - runs-on: [ubuntu-latest, self-hosted] - + runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 @@ -33,9 +31,6 @@ jobs: - name: Install SonarCloud scanner run: dotnet tool install --global dotnet-sonarscanner - - name: Add .NET tools to PATH - run: echo "$HOME/.dotnet/tools" >> $GITHUB_PATH - - name: Restore dependencies run: dotnet restore