// This file is part of www.nand2tetris.org // and the book "The Elements of Computing Systems" // by Nisan and Schocken, MIT Press. // File name: projects/12/MemoryTest/Main.jack /** Test program for the OS Memory class. */ class Main { /** Test Memory.peek(), poke(), alloc() and deAlloc(). * * This test is also a diagnostic. RAM[17000] is incremented before and * after every call so that the failure point can be accurately determined * when using command line testing. Return values from all alloc() calls * are also stored in the test results to aid debugging. */ function void main() { var int temp; var Array a, b, c, out; let out = 17000; // Address where test results will be stored. // Test poke() and peek(). let out[0] = 10; // poke test do Memory.poke(out + 1, 333); // RAM[17001] = 333 let out[0] = 11; // peek test let temp = Memory.peek(out + 1); let out[2] = temp + 1; // RAM[17002] = 334 let out[0] = 12; // peek/poke test complete // Allocate a memory block. // Validate that the returned block is entirely within the heap, // Test aborts if the block is not valid. let out[0] = 20; let a = Memory.alloc(20); let out[3] = a; // RAM[17003] = block address let out[0] = 21; do Main.checkRange(a, 20); let out[0] = 22; // Allocate a SMALLER memory block. // Validate that the returned block is entirely within the heap, // and that it does not overlap block 'a'. // Test aborts if the block is not valid or overlaps. // // Common failure: first block was not removed from free list so space // for this block was found within the first block. let out[0] = 30; let b = Memory.alloc(3); let out[4] = b; // RAM[17004] = block address let out[0] = 31; do Main.checkRange(b, 3); let out[0] = 32; do Main.checkOverlap(b, 3, a, 3); let out[0] = 33; // Allocate a memory block. // Validate that the returned block is entirely within the heap, // and that it does not overlap blocks 'a' or 'b'. // Test aborts if the block is not valid or overlaps. let out[0] = 40; let c = Memory.alloc(500); let out[5] = c; // RAM[17005] = block address let out[0] = 41; do Main.checkRange(c, 500); let out[0] = 42; do Main.checkOverlap(c, 500, a, 3); let out[0] = 43; do Main.checkOverlap(c, 500, b, 3); let out[0] = 44; // Deallocate blocks 'a' and 'b', retaining 'c'. // // Common failure: free list corrupted by deAlloc(). let out[0] = 50; do Memory.deAlloc(a); let out[0] = 51; do Memory.deAlloc(b); let out[0] = 52; // Allocate a memory block. // Validate that the returned block is entirely within the heap, // and that it does not overlap blocks 'c'. // Test aborts if the block is not valid or overlaps. // // Common failure: free list corrupted by deAlloc(). let out[0] = 60; let b = Memory.alloc(3); let out[6] = b; // RAM[17006] = block address let out[0] = 61; do Main.checkRange(b, 3); let out[0] = 62; do Main.checkOverlap(b, 3, c, 500); let out[0] = 63; // Deallocate blocks 'b' and 'c'. let out[0] = 70; do Memory.deAlloc(c); let out[0] = 71; do Memory.deAlloc(b); let out[0] = 72; // Test that deallocated blocks are placed on the free list and can // be reused. let out[0] = 70; let a = Memory.alloc(8000); let out[7] = a; // RAM[17007] = block address let out[0] = 71; do Main.checkRange(a, 8000); let out[0] = 72; do Memory.deAlloc(a); let out[0] = 73; let a = Memory.alloc(7000); let out[0] = 74; do Main.checkRange(a, 7000); let out[0] = 75; do Memory.deAlloc(a); let out[8] = a; // RAM[17008] = block address // Test complete. let out[0] = 100; // At this point all allocated blocks have been deallocated. // // You can inspect the free list and confirm that all of the heap is // contained in the free segments. // // If you implemented defragmentation in dealloc(), the free list // should contain only one segment, consisting of the entire heap. return; } /** Check that block a(a_len) is in the heap. * * If the block begins or ends outside of the heap, calls Sys.halt() */ function void checkRange(int a, int a_len) { var int a_high; let a_high = (a + a_len)-1; if ((a < 2048) | ((a_high) > 16383)) { // Block is not entirely within heap. do Sys.halt(); } return; } /** Check that block a(a_len) does not overlap block b(b_len). * Assumes that both blocks have been range checked. * * If the blocks overlap, calls Sys.halt() */ function void checkOverlap(int a, int a_len, int b, int b_len) { var int a_high, b_high; let a_high = (a + a_len)-1; let b_high = (b + b_len)-1; if ( ~ ((a > b_high) | (a_high < b))) { // Block overlaps excluded range. do Sys.halt(); } return; } }