// 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/11/ConvertToBin/Main.jack

/**
 * Unpacks a 16-bit number into its binary representation:
 * Takes the 16-bit number stored in RAM[8000] and stores its individual 
 * bits in RAM[8001..8016] (each location will contain 0 or 1).
 * Before the conversion, RAM[8001]..RAM[8016] are initialized to -1.
 * 
 * The program should be tested as follows:
 * 1) Load the program into the supplied VM emulator
 * 2) Put some value in RAM[8000]
 * 3) Switch to "no animation"
 * 4) Run the program (give it enough time to run)
 * 5) Stop the program
 * 6) Check that RAM[8001]..RAM[8016] contains the correct binary result, and
 *    that none of these memory locations contains -1.
 */
class Main {
    
    /**
     * Initializes RAM[8001]..RAM[8016] to -1,
     * and converts the value in RAM[8000] to binary.
     */
    function void main() {
	    var int value;
        do Main.fillMemory(8001, 16, -1); // sets RAM[8001]..RAM[8016] to -1
        let value = Memory.peek(8000);    // reads a value from RAM[8000]
        do Main.convert(value);           // performs the conversion
        return;
    }
    
    /** Converts the given decimal value to binary, and puts 
     *  the resulting bits in RAM[8001]..RAM[8016]. */
    function void convert(int value) {
    	var int mask, position;
    	var boolean loop;
    	
    	let loop = true;
    	while (loop) {
    	    let position = position + 1;
    	    let mask = Main.nextMask(mask);
    	
    	    if (~(position > 16)) {
    	
    	        if (~((value & mask) = 0)) {
    	            do Memory.poke(8000 + position, 1);
       	        }
    	        else {
    	            do Memory.poke(8000 + position, 0);
      	        }    
    	    }
    	    else {
    	        let loop = false;
    	    }
    	}
    	return;
    }
 
    /** Returns the next mask (the mask that should follow the given mask). */
    function int nextMask(int mask) {
    	if (mask = 0) {
    	    return 1;
    	}
    	else {
	    return mask * 2;
    	}
    }
    
    /** Fills 'length' consecutive memory locations with 'value',
      * starting at 'startAddress'. */
    function void fillMemory(int startAddress, int length, int value) {
        while (length > 0) {
            do Memory.poke(startAddress, value);
            let length = length - 1;
            let startAddress = startAddress + 1;
        }
        return;
    }
}
