-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathDataErrorChecking.cs
More file actions
119 lines (96 loc) · 3.77 KB
/
DataErrorChecking.cs
File metadata and controls
119 lines (96 loc) · 3.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
using System;
using Diz.Core.Interfaces;
using Diz.Core.model;
using Diz.Core.util;
using Diz.Cpu._65816;
using Diz.LogWriter.util;
namespace Diz.LogWriter;
public class DataErrorChecking
{
public class DataErrorInfo
{
public int Offset { get; init; }
public string Msg { get; init; }
}
public ILogCreatorDataSource<IData> Data { get; init; }
protected ISnesApi<IData> SnesApi => Data.Data.GetSnesApi();
public event EventHandler<DataErrorInfo> ErrorNotifier;
public void ReportError(int offset, string msg) =>
ErrorNotifier?.Invoke(this, new DataErrorInfo {Offset = offset, Msg = msg});
private void ErrorIfOperand(int offset)
{
if (SnesApi.GetFlag(offset) == FlagType.Operand)
ReportError(offset, "Bytes marked as operands formatted as Data.");
}
private void ErrorIfAdjacentOperandsSeemWrong(int startingOffset)
{
var flag = SnesApi.GetFlag(startingOffset);
if (flag != FlagType.Operand)
return;
var byteLengthFollowing = RomUtil.GetByteLengthForFlag(flag);
for (var i = 1; i < byteLengthFollowing; ++i)
{
var expectedFlag = GetFlagButSwapOpcodeForOperand(startingOffset);
var anyFailed = false;
anyFailed |= !ErrorIfBoundsLookWrong(startingOffset, i);
anyFailed |= !ErrorIfUnexpectedFlagAt(startingOffset + i, expectedFlag);
// note: use bitwise-or so we don't short circuit. both checks need to run independently so they both report errors
if (anyFailed)
return;
}
}
private FlagType GetFlagButSwapOpcodeForOperand(int offset)
{
var flag = SnesApi.GetFlag(offset);
return flag == FlagType.Opcode ? FlagType.Operand : flag;
}
private void ErrorIfBranchToNonInstruction(int offset)
{
var ia = Data.GetIntermediateAddress(offset, true);
if (ia >= 0 && IsOpcodeOutboundJump(offset) && !DoesIndirectAddressPointToOpcode(ia))
ReportError(offset, "Branch or jump instruction to a non-instruction.");
}
private bool ErrorIfBoundsLookWrong(int startingOffset, int len)
{
if (IsOffsetInRange(startingOffset + len))
return true;
var flagDescription = Util.GetEnumDescription(GetFlagButSwapOpcodeForOperand(startingOffset));
ReportError(startingOffset, $"{flagDescription} extends past the end of the ROM.");
return false;
}
private bool ErrorIfUnexpectedFlagAt(int nextOffset, FlagType expectedFlag)
{
if (!IsOffsetInRange(nextOffset))
return false;
if (SnesApi.GetFlag(nextOffset) == expectedFlag)
return true;
var expectedFlagName = Util.GetEnumDescription(expectedFlag);
var actualFlagName = Util.GetEnumDescription(SnesApi.GetFlag(nextOffset));
var msg = $"Expected {expectedFlagName}, but got {actualFlagName} instead.";
ReportError(nextOffset, msg);
return false;
}
private bool DoesIndirectAddressPointToOpcode(int ia)
{
var offset = Data.ConvertSnesToPc(ia);
if (offset == -1)
return false;
return SnesApi.GetFlag(offset) == FlagType.Opcode;
}
private bool IsOpcodeOutboundJump(int offset)
{
return SnesApi.GetFlag(offset) == FlagType.Opcode &&
Data.GetInOutPoint(offset) == InOutPoint.OutPoint;
}
private bool IsOffsetInRange(int offset)
{
return offset >= 0 && offset < Data.GetRomSize();
}
public void CheckForErrorsAt(int offset)
{
// throw out some errors if stuff looks fishy
ErrorIfOperand(offset);
ErrorIfAdjacentOperandsSeemWrong(offset);
ErrorIfBranchToNonInstruction(offset);
}
}