Skip to content

Commit

Permalink
New test to check if external timer interrupts are handled properly (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinferrare authored Aug 23, 2024
1 parent 40f8339 commit b2b7e7e
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 17 deletions.
2 changes: 1 addition & 1 deletion tests/Spice86.Tests/CSharpOverrideHelperTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class CSharpOverrideHelperTest {
private readonly ILoggerService _loggerServiceMock = Substitute.For<ILoggerService>();

private ProgramExecutor CreateDummyProgramExecutor() {
ProgramExecutor res = new MachineCreator().CreateProgramExecutorFromBinName("add");
ProgramExecutor res = new MachineCreator().CreateProgramExecutorFromBinName("add", false, false);
Machine machine = res.Machine;
// Setup stack
machine.Cpu.State.SS = 0;
Expand Down
13 changes: 7 additions & 6 deletions tests/Spice86.Tests/MachineCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,20 @@ namespace Spice86.Tests;
using Spice86.Shared.Interfaces;

public class MachineCreator {
public ProgramExecutor CreateProgramExecutorFromBinName(string binName, bool recordData = false) {
return CreateProgramExecutorForBin($"Resources/cpuTests/{binName}.bin", recordData);
public ProgramExecutor CreateProgramExecutorFromBinName(string binName, bool enablePit, bool recordData) {
return CreateProgramExecutorForBin($"Resources/cpuTests/{binName}.bin", enablePit, recordData);
}

public ProgramExecutor CreateProgramExecutorForBin(string binPath, bool recordData = false) {
public ProgramExecutor CreateProgramExecutorForBin(string binPath, bool enablePit, bool recordData) {
Configuration configuration = new Configuration {
// making sure int8 is not going to be triggered during the tests
InstructionsPerSecond = 10000000,
Exe = binPath,
// Don't expect any hash for the exe
ExpectedChecksumValue = Array.Empty<byte>(),
InitializeDOS = false,
DumpDataOnExit = recordData
DumpDataOnExit = recordData,
TimeMultiplier = enablePit ? 1 : 0,
// Use instructions per second based timer for predictability if timer is enabled
InstructionsPerSecond = enablePit ? 100000 : null
};

ILoggerService loggerService = Substitute.For<LoggerService>(new LoggerPropertyBag());
Expand Down
26 changes: 16 additions & 10 deletions tests/Spice86.Tests/MachineTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ static MachineTest() {

[Fact]
public void TestExecutionBreakpoints() {
ProgramExecutor programExecutor = CreateProgramExecutor("add", true);
ProgramExecutor programExecutor = CreateProgramExecutor("add", false, true);
Machine machine = programExecutor.Machine;
State state = machine.CpuState;
MachineBreakpoints machineBreakpoints = machine.MachineBreakpoints;
Expand All @@ -52,7 +52,7 @@ public void TestExecutionBreakpoints() {

[Fact]
public void TestMemoryBreakpoints() {
ProgramExecutor programExecutor = CreateProgramExecutor("add");
ProgramExecutor programExecutor = CreateProgramExecutor("add", false, false);
Machine machine = programExecutor.Machine;
MachineBreakpoints machineBreakpoints = machine.MachineBreakpoints;
IMemory memory = machine.Memory;
Expand Down Expand Up @@ -289,7 +289,13 @@ public void TestSelfModifyInstructions() {
expected[0x05] = 0x00;
TestOneBin("selfmodifyinstructions", expected);
}

[Fact]
public void TestExternalInt() {
byte[] expected = new byte[6];
expected[0x00] = 0x01;
TestOneBin("externalint", expected, 0xFFFFFFF, true);
}

[Theory]
[InlineData(0b0011110000000000, 0b0010000000000001, 0, 0b0011110000000000, true, true)] // result is same as dest, flags unaffected
[InlineData(0b0000000000000001, 0b0000000000000000, 1, 0b0000000000000010, false, false)] // shift one bit
Expand Down Expand Up @@ -352,22 +358,22 @@ private Machine TestOneBin(string binName) {
}

[AssertionMethod]
private Machine TestOneBin(string binName, byte[] expected) {
Machine machine = Execute(binName);
private Machine TestOneBin(string binName, byte[] expected, long maxCycles=100000L, bool enablePit = false) {
Machine machine = Execute(binName, maxCycles, enablePit);
IMemory memory = machine.Memory;
CompareMemoryWithExpected(memory, expected, 0, expected.Length);
return machine;
}

private ProgramExecutor CreateProgramExecutor(string binName, bool recordData = false) {
return new MachineCreator().CreateProgramExecutorFromBinName(binName, recordData);
private ProgramExecutor CreateProgramExecutor(string binName, bool enablePit, bool recordData) {
return new MachineCreator().CreateProgramExecutorFromBinName(binName, enablePit, recordData);
}

[AssertionMethod]
private Machine Execute(string binName) {
using ProgramExecutor programExecutor = CreateProgramExecutor(binName);
private Machine Execute(string binName, long maxCycles, bool enablePit) {
using ProgramExecutor programExecutor = CreateProgramExecutor(binName, enablePit, false);
// Add a breakpoint after a million cycles to ensure no infinite loop can lock the tests
programExecutor.Machine.MachineBreakpoints.ToggleBreakPoint(new AddressBreakPoint(BreakPointType.CYCLES, 100000L,
programExecutor.Machine.MachineBreakpoints.ToggleBreakPoint(new AddressBreakPoint(BreakPointType.CYCLES, maxCycles,
(breakpoint) => {
Assert.Fail($"Test ran for {((AddressBreakPoint)breakpoint).Address} cycles, something is wrong.");
}, true), true);
Expand Down
51 changes: 51 additions & 0 deletions tests/Spice86.Tests/Resources/cpuTests/asmsrc/externalint.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
;00: 01
; compile it with fasm
use16
start:
mov ax,0
mov ss,ax
mov sp,2
mov dx,0
; setup int 8 handler
mov word[8*4], inthandler
mov word[8*4+2], cs
; setup PIT8254 frequency
MOV AL, 00110110B ; Send setup CW to Counter 0
OUT 43H, AL
MOV AL, 51h ; 1,193,180 / 1000 (1 ms) = ~1193 = 2251h
OUT 40H, AL ; send low byte to counter 0
MOV AL, 22h
OUT 40H, AL ; send high byte to counter 0
; setup PIC to enable external interrupts
MOV AL, 0 ; unmask all interrupts
OUT 21H, AL

; enable ints
sti
mov ecx,0FFFFFFh
waitloopstart:
; add various garbage instructions to test that the cfg graph doenst link the inthandler iret to them
inc ax
mov bx,ax
shr bx,1
loop waitloopstart
; check that int handler was called at least once
cmp dx,word 0
setnz al
movzx ax, al
push ax
hlt

inthandler:
push AX
MOV DX, 1
MOV AL, 20H ; acknowledge int to PIC
OUT 20H, AL
pop AX
iret

; bios entry point at offset fff0
rb 65520-$
jmp start
rb 65535-$
db 0ffh
Binary file not shown.

0 comments on commit b2b7e7e

Please sign in to comment.