Files
N2T/projects/12/MemoryTest/Memory.jack
2020-11-15 13:57:48 -05:00

121 lines
4.4 KiB
Plaintext

// 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/Memory.jack
/**
* This library provides two services: direct access to the computer's main
* memory (RAM), and allocation and recycling of memory blocks. The Hack RAM
* consists of 32,768 words, each holding a 16-bit binary number.
*/
class Memory {
static Array ram;
static Array heap;
static Array freeList;
/** Initializes the class. */
function void init() {
let ram = 0;
let heap = 2048;
let freeList = heap;
let freeList[0] = 0; // next
let freeList[1] = 14334; // length
return;
}
/** Returns the RAM value at the given address. */
function int peek(int address) {
return ram[address];
}
/** Sets the RAM value at the given address to the given value. */
function void poke(int address, int value) {
let ram[address] = value;
return;
}
/** Finds an available RAM block of the given size and returns
* a reference to its base address. */
function int alloc(int size) {
var Array previousBlock;
var Array currentBlock;
var Array resultBlock;
var int currentBlockSize;
var int remainingSize;
var int currentBlockNext;
if (freeList = 0) {
return 0;
}
// XXX: I am not happy with having the whole code duplicated just because
// we have the "special case" that we select the first block.
// Using the first block is a special case, because we have to
// update freeList instead of simply taking the block out of the list
// by doing `let previousBlock.next = currentBlock.next`.
let currentBlockSize = freeList[1];
if (currentBlockSize > size) {
let remainingSize = currentBlockSize - size;
let resultBlock = freeList;
if (remainingSize < 4) {
// If remainingSize is smaller than 4 it does not make sense to split
// the block. Just return it as a whole.
let freeList = freeList[0]; // point to freeList.next
} else {
// If remainingSize is big enough we split the block. In that case
// we have to update the size of the block we return as well as
// the block (aka the remainder of the current block).
let resultBlock[1] = size;
let freeList = resultBlock + 2 + size;
let freeList[0] = resultBlock[0];
let freeList[1] = currentBlockSize - size - 2;
}
return resultBlock + 2;
}
let previousBlock = freeList;
// The following excludes the first block which is what we want
// because we handled it separately before.
while (~(previousBlock[0] = 0)) {
let currentBlock = previousBlock[0];
let currentBlockSize = currentBlock[1];
if (currentBlockSize > size) {
let resultBlock = currentBlock;
let remainingSize = currentBlockSize - size;
if (remainingSize < 4) {
let previousBlock[0] = resultBlock[0];
} else {
let resultBlock[1] = size;
let currentBlock = resultBlock + 2 + size;
let currentBlock[0] = resultBlock[0];
let currentBlock[1] = currentBlockSize - size - 2;
let previousBlock[0] = currentBlock;
}
return resultBlock;
} else {
let previousBlock = currentBlock;
}
}
// Not enough heap available. Call defragment and try again.
return 0;
}
/** De-allocates the given object (cast as an array) by making
* it available for future allocations. */
function void deAlloc(Array o) {
var Array currentBlock;
if (freeList = 0) {
let freeList = o - 2;
}
let currentBlock = freeList;
while (~(currentBlock[0] = 0)) {
let currentBlock = currentBlock[0];
}
let currentBlock[0] = o - 2;
return;
}
}