-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSelfTest.cpp
188 lines (162 loc) · 4.37 KB
/
SelfTest.cpp
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#include "ConfigurableFirmata.h"
#include "SelfTest.h"
#include "Variable.h"
#include "VariableVector.h"
#include "VariableDynamicStack.h"
#ifdef ESP32
#include <esp_log.h>
#endif
const char* SELFTTEST_TAG = "SELFTEST";
void ASSERT(bool x)
{
if (!x)
{
ESP_LOGE(SELFTTEST_TAG, "Assertion failed");
delay(1000);
throw stdSimple::ExecutionEngineException("Assertion failed");
}
}
void ASSERT(bool condition, const char* message)
{
if (!condition)
{
ESP_LOGE(SELFTTEST_TAG, "%s", message);
delay(1000);
throw stdSimple::ExecutionEngineException(message);
}
}
bool SelfTest::PerformSelfTest()
{
_statusFlag = true;
PerformMemoryAnalysis();
// If this fails a second time, the memory management is broken
PerformMemoryAnalysis();
ValidateMemoryManager();
// ValidateMemoryManager();
ValidateExecutionStack();
UnalignedAccessWorks();
CompilerBehavior();
return _statusFlag;
}
void SelfTest::PerformMemoryAnalysis()
{
const int SIZE_TO_TEST = 1024 * 70;
int* mem = (int*)malloc(SIZE_TO_TEST);
for (int i = 0; i < SIZE_TO_TEST / 4; i++)
{
mem[i] = i;
}
for (int i = 0; i < SIZE_TO_TEST / 4; i++)
{
if (mem[i] != i)
{
// You better get a new board if this happens
ESP_LOGE(SELFTTEST_TAG, "Memory broken");
Firmata.sendString(F("HARDWARE ERROR: Memory broken"));
_statusFlag = false;
free(mem);
return;
}
}
free(mem);
}
void SelfTest::ValidateMemoryManager()
{
// Need to patch the C++ library to fix a runtime bug that exists in the C runtime of the Arduino Due:
// There's no limit to the amount of memory that can be allocated, the CPU just crashes if you try to use it.
#if defined __SAM3X8E__ && !defined SIM
void* data = malloc(1024 * 1024);
const int maxMemToTest = 96;
ASSERT(data == nullptr, "Memory allocation error: Can allocate more memory than available. Please consult the documentation");
const int oneK = 1024;
void* ptrs[maxMemToTest];
int idx = 0;
int totalAllocsSucceeded = 0;
while (idx < maxMemToTest)
{
void* mem = malloc(oneK);
ptrs[idx] = mem;
if (mem == nullptr)
{
break;
}
idx++;
}
totalAllocsSucceeded = idx;
while (idx >= 0)
{
free(ptrs[idx]);
idx--;
}
Firmata.sendStringf(F("Total memory available after init: %dkb"), totalAllocsSucceeded);
ASSERT(totalAllocsSucceeded >= 82, "Not enough free memory after init");
#endif
// Validate this variable has the correct size
ASSERT(sizeof(Variable) == 12, "Size of Variable type is not correct. Ensure the compiler uses 1-byte struct packing");
Variable temp;
byte* startAddr = (byte*) &temp;
byte* dataAddr = (byte*)&temp.Int32;
ASSERT(dataAddr - startAddr == 4, "Size of Variable type is not correct. Ensure the compiler uses 1-byte struct packing");
}
void SelfTest::ValidateExecutionStack()
{
VariableDynamicStack st(10);
Variable a;
a.Type = VariableKind::Int32;
a.Int32 = 10;
st.push(a);
Variable b = st.top();
ASSERT(b.Int32 == 10, "Element is not at top of stack");
st.pop();
ASSERT(st.empty(), "Stack is not empty");
b.Int32 = 0xFFFF;
st.push(b);
Variable c = st.top();
st.pop();
ASSERT(b.Int32 == c.Int32, "Element not found");
st.push(b);
st.pop();
st.push(c);
ASSERT(b.Int32 == 0xFFFF, "Internal selftest error: Stack overwrites instances");
st.pop();
st.push(a);
st.push(b);
c = st.nth(1);
ASSERT(c.Int32 == a.Int32, "Internal selftest error: Stack count doesn't fit");
}
void SelfTest::UnalignedAccessWorks()
{
int64_t* ptrStart = (int64_t*)malloc(64);
volatile int64_t* ptr = ptrStart;
*ptr = -1;
volatile int64_t* ptr2 = ptr;
ASSERT(*ptr2 == *ptr, "Pointer access error");
ptr = AddBytes(ptr, 4);
*ptr = 10;
ptr2 = ptr;
ASSERT(*ptr2 == *ptr, "Unable to read 8-byte values from 4-byte aligned addresses");
volatile int* iPtr = (int*)AddBytes(ptr, 1);
*iPtr = 5;
ASSERT(*iPtr == 5, "Error in unaligned memory access");
// 64 bit values can only be read from 4-byte aligned addresses on the Cortex-M3 (Arduino due) it seems. Changing the constant below to 1 or 2 crashes the CPU
ptr = AddBytes(ptrStart, 4);
*ptr = 10;
ASSERT(*ptr == 10, "64 Bit memory access error");
free(ptrStart);
int* data = (int*)malloc(64);
int* data2 = AddBytes(data, 2);
*data2 = 4711;
free(data);
}
void SelfTest::CompilerBehavior()
{
/*int a = 2;
int b = 5;
int& ref = a;
ref = 3;
ASSERT(a == 3, "Reference behavior error");
ref = b;
ref = 7;
ASSERT(a == 3, "Reference behavior error");
ASSERT(b == 7, "Reference behavior error");*/
}