Fix M100 Free Memory Checker

M100 had numerious changes and quit working.   Part of the problem is
the overloading of the SERIAL_PROTOCOL functions.   Also, some of the
address arithmatic was changed to use char *ptr and passing ptr into the
SERIAL_PROTOCOL functions caused them to try to print a string instead
of a number.     M100 is working again.   Let's keep it that way!

M100 has been expanded to now have a function  int
free_memory_is_corrupted()  that can be called from other code to see if
the free space is still contiguous.  It may make sense to add a flag to
control its verbose nature but right now, the extra chit chat is very
helpful to know int free_memory_is_corrupted()  is doing the right thing
and what it found at various points when it was called.     A 'Show &
Tell' is coming up with int free_memory_is_corrupted().
This commit is contained in:
Roxy-3D 2017-04-10 15:20:20 -05:00 committed by Roxy-3D
parent 3b82db5fe9
commit ba85faabc0

View file

@ -55,7 +55,8 @@ extern char __bss_end;
char* top_of_stack(); char* top_of_stack();
int how_many_E5s_are_here(char*); int how_many_E5s_are_here(char*);
int free_memory_is_corrupted(); // int not bool!!!! it will tell us how many blocks of
// free memory it found.
void gcode_M100() { void gcode_M100() {
static bool m100_not_initialized = true; static bool m100_not_initialized = true;
char* sp, *ptr; char* sp, *ptr;
@ -69,18 +70,26 @@ void gcode_M100() {
// probably caused by bad pointers. Any unexpected values will be flagged in // probably caused by bad pointers. Any unexpected values will be flagged in
// the right hand column to help spotting them. // the right hand column to help spotting them.
// //
SERIAL_ECHOPAIR("\n__brkval : 0x", hex_word((uint16_t)__brkval) );
SERIAL_ECHOPAIR("\n__bss_end : 0x", hex_word((uint16_t)&__bss_end));
//
// With out malloc() we need to be smart and use &__bss_end
//
ptr = __brkval ? __brkval : &__bss_end;
SERIAL_ECHOPAIR("\nstart of free space : 0x", hex_word((uint16_t)ptr));
sp = top_of_stack();
SERIAL_ECHOLNPAIR("\nStack Pointer : 0x", hex_word((uint16_t)sp));
#if ENABLED(M100_FREE_MEMORY_DUMPER) // Disable to remove Dump sub-command #if ENABLED(M100_FREE_MEMORY_DUMPER) // Disable to remove Dump sub-command
if (code_seen('D')) { if (code_seen('D')) {
ptr = __brkval ? __brkval : &__bss_end;
// //
// We want to start and end the dump on a nice 16 byte boundry even though // We want to start and end the dump on a nice 16 byte boundry even though
// the values we are using are not 16 byte aligned. // the values we are using are not 16 byte aligned.
// //
SERIAL_ECHOPAIR("\nbss_end : 0x", hex_word((uint16_t)ptr)); ptr = (char*) ((uint16_t) ptr & 0xfff0);
ptr = (char*)((uint32_t)ptr & 0xfff0); sp = (char*) ((uint16_t) sp | 0x000f);
sp = top_of_stack();
SERIAL_ECHOLNPAIR("\nStack Pointer : 0x", hex_word((uint16_t)sp));
sp = (char*)((uint32_t)sp | 0x000f);
n = sp - ptr; n = sp - ptr;
// //
// This is the main loop of the Dump command. // This is the main loop of the Dump command.
@ -89,6 +98,8 @@ void gcode_M100() {
print_hex_word((uint16_t)ptr); // Print the address print_hex_word((uint16_t)ptr); // Print the address
SERIAL_CHAR(':'); SERIAL_CHAR(':');
for (i = 0; i < 16; i++) { // and 16 data bytes for (i = 0; i < 16; i++) { // and 16 data bytes
if (i==8)
SERIAL_CHAR('-');
print_hex_byte(*(ptr + i)); print_hex_byte(*(ptr + i));
SERIAL_CHAR(' '); SERIAL_CHAR(' ');
} }
@ -97,6 +108,7 @@ void gcode_M100() {
SERIAL_CHAR((*(ptr + i) == (char)0xe5) ? ' ' : '?'); SERIAL_CHAR((*(ptr + i) == (char)0xe5) ? ' ' : '?');
SERIAL_EOL; SERIAL_EOL;
ptr += 16; ptr += 16;
idle();
} }
return; return;
} }
@ -106,11 +118,8 @@ void gcode_M100() {
// other vital statistics that define the memory pool. // other vital statistics that define the memory pool.
// //
if (code_seen('F')) { if (code_seen('F')) {
#if 0 int max_cnt = -1, block_cnt = 0;
int max_addr = (int) __brkval ? __brkval : &__bss_end; uint16_t max_addr=0;
int max_cnt = 0;
#endif
int block_cnt = 0;
ptr = __brkval ? __brkval : &__bss_end; ptr = __brkval ? __brkval : &__bss_end;
sp = top_of_stack(); sp = top_of_stack();
n = sp - ptr; n = sp - ptr;
@ -121,19 +130,21 @@ void gcode_M100() {
if (j > 8) { if (j > 8) {
SERIAL_ECHOPAIR("Found ", j); SERIAL_ECHOPAIR("Found ", j);
SERIAL_ECHOLNPAIR(" bytes free at 0x", hex_word((uint16_t)(ptr + i))); SERIAL_ECHOLNPAIR(" bytes free at 0x", hex_word((uint16_t)(ptr + i)));
if (j > max_cnt) {
max_cnt = j;
max_addr = (uint16_t) ptr + i;
}
i += j; i += j;
block_cnt++; block_cnt++;
} }
#if 0
if (j > max_cnt) { // We don't do anything with this information yet
max_cnt = j; // but we do know where the biggest free memory block is.
max_addr = (int) ptr + i;
}
#endif
} }
} }
if (block_cnt > 1) if (block_cnt > 1) {
SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area."); SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.");
SERIAL_ECHOPAIR("\nLargest free block is ", max_cnt);
SERIAL_ECHOLNPAIR(" bytes big at 0x", hex_word(max_addr));
}
SERIAL_ECHOLNPAIR("free_memory_is_corrupted() = ", free_memory_is_corrupted());
return; return;
} }
// //
@ -144,13 +155,9 @@ void gcode_M100() {
if (code_seen('C')) { if (code_seen('C')) {
int x = code_value_int(); // x gets the # of locations to corrupt within the memory pool int x = code_value_int(); // x gets the # of locations to corrupt within the memory pool
SERIAL_ECHOLNPGM("Corrupting free memory block.\n"); SERIAL_ECHOLNPGM("Corrupting free memory block.\n");
ptr = __brkval ? __brkval : &__bss_end;
SERIAL_ECHOPAIR("\nbss_end : ", ptr);
ptr += 8; ptr += 8;
sp = top_of_stack(); sp = top_of_stack();
SERIAL_ECHOPAIR("\nStack Pointer : ", sp); n = sp - ptr - 250; // -250 just to keep us from finding interrupt activity that
SERIAL_ECHOLNPGM("\n");
n = sp - ptr - 64; // -64 just to keep us from finding interrupt activity that
// has altered the stack. // has altered the stack.
j = n / (x + 1); j = n / (x + 1);
for (i = 1; i <= x; i++) { for (i = 1; i <= x; i++) {
@ -167,13 +174,11 @@ void gcode_M100() {
// //
if (m100_not_initialized || code_seen('I')) { // If no sub-command is specified, the first time if (m100_not_initialized || code_seen('I')) { // If no sub-command is specified, the first time
SERIAL_ECHOLNPGM("Initializing free memory block.\n"); // this happens, it will Initialize. SERIAL_ECHOLNPGM("Initializing free memory block.\n"); // this happens, it will Initialize.
ptr = __brkval ? __brkval : &__bss_end; // Repeated M100 with no sub-command will not destroy the // Repeated M100 with no sub-command will not destroy the
SERIAL_ECHOPAIR("\nbss_end : ", ptr); // state of the initialized free memory pool. // state of the initialized free memory pool.
ptr += 8; ptr += 8;
sp = top_of_stack();
SERIAL_ECHOPAIR("\nStack Pointer : ", sp);
SERIAL_ECHOLNPGM("\n"); SERIAL_ECHOLNPGM("\n");
n = sp - ptr - 64; // -64 just to keep us from finding interrupt activity that n = sp - ptr - 250; // -250 just to keep us from finding interrupt activity that
// has altered the stack. // has altered the stack.
SERIAL_ECHO(n); SERIAL_ECHO(n);
SERIAL_ECHOLNPGM(" bytes of memory initialized.\n"); SERIAL_ECHOLNPGM(" bytes of memory initialized.\n");
@ -181,8 +186,8 @@ void gcode_M100() {
*(ptr + i) = (char)0xe5; *(ptr + i) = (char)0xe5;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
if (*(ptr + i) != (char)0xe5) { if (*(ptr + i) != (char)0xe5) {
SERIAL_ECHOPAIR("? address : ", ptr + i); SERIAL_ECHOPAIR("? address : ", hex_word(ptr+i) );
SERIAL_ECHOPAIR("=", *(ptr + i)); SERIAL_ECHOPAIR("=", hex_byte(*(ptr + i)) );
SERIAL_ECHOLNPGM("\n"); SERIAL_ECHOLNPGM("\n");
} }
} }
@ -212,5 +217,36 @@ int how_many_E5s_are_here(char* p) {
return -1; return -1;
} }
int free_memory_is_corrupted() {
char *sp, *ptr;
int block_cnt = 0, i, j, n;
ptr = __brkval ? __brkval : &__bss_end;
sp = top_of_stack();
n = sp - ptr;
// Scan through the range looking for the biggest block of 0xE5's we can find
for (i = 0; i < n; i++) {
if (*(ptr + i) == (char)0xe5) {
j = how_many_E5s_are_here(ptr + i);
if (j > 8) {
// SERIAL_ECHOPAIR("Found ", j);
// SERIAL_ECHOLNPAIR(" bytes free at 0x", hex_word((uint16_t)(ptr + i)));
i += j;
block_cnt++;
}
}
}
// if (block_cnt > 1) {
// SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.");
// SERIAL_ECHOLNPAIR("\nLargest free block is ", max_cnt);
// }
return block_cnt;
}
#endif #endif