Search code examples
assemblynand2tetris

Having trouble with asm logic using nand2tetris


So I have been trying out nand2tetris, and got to the chapter about assembly language and how it can be used and implemented. I did the mult.asm successfully, and wanted to challenge myself to try to create a code that can find the factorial output of a number for any input by the user, so far this is all of my code


// ================================= Factorial ==================================
// This program calculates the Factorial F of a given number n 
//  At run time:
//      - The user should enter the value of n into R0. R0.e. RAM[0]
//      - The program then calculate the factorial of n    R0.e. F(n)=n!
//           F(n) = n*(n-1)*(n-2)*......*2*1
//      - The result F(n) should be saved in RAM[1]
//          -- You should also consider the F(0) case.
// ==============================================================================


// put your code here

    //set tracker for current loop
    @R1
    M=0
    @R2
    M=1
    @R3
    M=0
    @R4
    M=0
    @R5
    M=0
    @R6
    M=0

(LOOP)
    @R6
    D=M     //D=R6
    @R1
    M=M+D
    @R2
    D=M     //D = R2
    @R4
    M=D     //R4 = R2
    @R0
    D=D-M   //D = R2 - R0
    @END
    D;JGE   //If (R2-R0) > 0 goto END
    @STEP
    D;JLT   //If (R2-R0) < 0 goto STEP


(STEP)
    //Multiplication begins
    // Gets R4 from R6.
    @R6
    D=M // wrting data of r6 into d register

    // Add R1 to it.
    @R1
    D=D+M

    // And write the result back to R6.
    @R6
    M=D

    // Reduce R4 by 1.
    @R4
    D=M-1
    M=D

    // If R4 is still > 0 then loop.
    @STEP
    D;JGT
    //Multiplication ends

    @R2
    M=M+1   //R2++

    @LOOP
    0;JMP   //Got LOOP
(END)
    @END
    0;JMP   //Infinite loop

The problem I have now is that the loop works, and the counter for my loop to execute the multiplication loop stops at the right time, but the output is somehow a few values higher than what is expected. I.E when I enter 3! it comes out with 8 instead of 6. Any advice would be great thanks!

I am trying to get a factorial output of any number that I put in, the counter is working correctly and stopping at the right time, but the final output is wrong


Solution

  • Some general comments:

    • Spend some time improving your code comments. This will not only help people trying to read your code, but it will get you thinking about it as well, and you will likely find the problem. For example, what do R0-R6 represent? Currently, you only document a few of them, and it's unclear if you're using them properly. Your current in-code comments don't really help -- "And write the result back to R6" is not a useful comment. The code itself usually documents what it is doing (unless you're being tricky); good comments explain why you are doing something. When writing assembly-language, I always find it useful to write the code in a higher-level language (say, something like python) first. This not only lets you validate that the algorithm is correct (you can run the code!), but that code then becomes the general code comments for your assembly-language code, as well as a skeleton for creating that code.
    • Run the program with several different values for R0 and make a table of the results. Is there a pattern to the error? Is it constant or related in some way to R0? This may give you a clue as to what the error is.
    • Try single-stepping through your program in order to find out where things are going wrong. The CPU emulator has a breakpoint feature that will let you stop and examine your state at any point in the code, this is handy for checking state each time through the loop. Documentation is at the end of the emulator tutorial: https://www.nand2tetris.org/_files/ugd/44046b_f63aba2611944e82974c9c5d5a3821fe.pdf
    • As a total side-note, you may find this document that I wrote up analyzing the best way to do multiplication on the HACK machine of interest; it demonstrates some useful machine-language programming techniques: https://drive.google.com/file/d/1jrDe3tru_IWzLpZjbXFmdKU7E0fy77e6/view?usp=share_link (though I admit, I probably should take my own advice and improve the comments!)