Goto subroutine

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Goto subroutine

ChesterPerry
This is a way to implement a goto subroutine and a return from it.
The script is stupid, just to test the approach and to be easy to understand.
Please give me a feedback, I'm an hobbyist and I have nobody to check with my solutions.

// R0 = constant value
// R15 = return address
// @tmp = address sets by routine

        @1 // Set constant value
        D=A
        @R0
        M=D
       
        // GOSUB
        @POS01 // Set return address
        D=A
        @R15 // Save it
        M=D
        @ROUTINE // Routine call
        0;JMP

(POS01)
        @TMP
        D=A
        @100
        M=D
        @TMP
        M=0
       
        // GOSUB ROUTINE
        @POS02
        D=A
        @R15
        M=D
        @ROUTINE
        0;JMP
       
(POS02)
        @TMP
        D=A
        @101
        M=D
        @TMP
        M=0

(END) // Program end
        @END
        0;JMP
       
        // [ROUTINE]
(ROUTINE)
        @R0 // Set tmp=R0
        D=M
        @TMP
        M=D
        @R15 // Retrieve return address
        A=M // GOTO at return address
        0;JMP
Reply | Threaded
Open this post in threaded view
|

Re: Goto subroutine

WBahn
Administrator
I took a very quick glance at your code and it looks like you've got the right idea.

Reply | Threaded
Open this post in threaded view
|

Re: Goto subroutine

rleininger
In reply to this post by ChesterPerry
I ran your code in the Hack CPU emulator, and I believe it does call the subroutine successfully twice.  Normally a subroutine/function would be expected to not leave any execution artifacts in active RAM or the CPU registers.  Yours leaves the return address (22) from the second call in R15 (RAM[15]).  The A and D registers should be returned to their state before the function call before returning.  

Have you taken the second part of the course?  If not, I encourage you to do so.  The generalization of subroutine/function calls is treated for the Hack computer in the first of these chapters.

Most modern real CPUs include both hardware and, in some cases, specific machine code instructions, along with a memory allocation model, to facilitate a much cleaner way implement this important capability.  The Hack computer design, lacking these elements, does it entirely with software and fixed RAM segment allocations.  
Reply | Threaded
Open this post in threaded view
|

Re: Goto subroutine

ChesterPerry
Thank you for your replay.
I bought the second edition two weeks ago, now I'm studying chapter 4 (Machine Language), and as said I'm an old hobbyist with only experience in web programming. So I don't know a lot of things! Surely I'll go through the second part.
I'm aware of R15 value but I didn't care about it because I didn't know about the no artifact law, lesson understand.
The first solution I see is rewrite the sub this way to get rid of the R15 value:

(ROUTINE)
        @R0 // Set tmp=R0
        D=M
        @TMP
        M=D
        @R15 // Retrieve return address
        D=M // Reset M
        M=0 // Reset M
        A=D // GOTO at return address
        0;JMP
Reply | Threaded
Open this post in threaded view
|

Re: Goto subroutine

ivant
This post was updated on .
ChesterPerry wrote
I'm aware of R15 value but I didn't care about it because I didn't know about the no artifact law, lesson understand.
I don't think there is such a law at all. It all boils down to call conventions and there are a many different ones even on the same computer architecture. For example, C and Pascal use different calling conventions[1].

I think rleininger might be thinking about interrupt handlers. There you do need to restore all the registers as interrupts can happen at any time. But HACK doesn't have interrupts.

As far as I remember (and I haven't checked very recently) R14 and R15 were temporary registers. This means that you should not presume that their values are retained during a subroutine call.

---
[1]  For example, in C the stack is cleaned up by the caller, while in Pascal it's cleaned up by the called procedure. The Pascal convention is sometimes faster, because in x86 architecture you can return and move the stack pointer in a single instruction.

But the C convention supports functions with variable number of arguments, like printf(), while Pascal convention does not.
Reply | Threaded
Open this post in threaded view
|

Re: Goto subroutine

WBahn
Administrator
Your subroutine must restore memory to values that the calling code relies on being unchanged. Which memory values that applies to depends on your calling convention and who is responsible for what. For memory that the calling code does not assume will be left unchanged, there is no fundamental reason why the calling convention must do anything particular with that memory. However, from a security standpoint, information left in that memory is leaked to the caller, which may not be desirable. In the N2T projects, security implications are way beyond the scope of the course, but it's still worth considering if you are interested in those kinds of issues. But don't let them interfere with meeting the functional requirements of the projects.
Reply | Threaded
Open this post in threaded view
|

Re: Goto subroutine

rleininger
In reply to this post by ivant
No, I was talking about cleaning up the stack, but I didn't want to get into that because ChesterPerry probably isn't familiar with that idea yet.  He will get a dose of proper function handling for the Hack computer when the VM is introduced in the second part of the course.  This is also where the mechanism of software interrupts (as Ivant says, the Hack computer has no hardware interrupts) is also introduced.  But, software interrupts are generally serviced by function calls.

The observation of Ivant about there being no artifact "law" is correct, though when the calling program depends of their values for correct operation going forward.  It's merely considered a "good practice" although for internal, fixed-purpose registers (A, D), and sometimes for general purpose registers,  it would might be a necessity action.  For the PC, it's an absolute necessity, as your program demonstrates.

I agree with Ivant about R15.  I was merely using it as an example of a subroutine/function call artifact.  At this point in the course, R15 is a general purpose register and whether or not its pre-call value needed to be preserved through a function call would depend on its specific use in the calling program context.
Reply | Threaded
Open this post in threaded view
|

Re: Goto subroutine

ChesterPerry
I know the stack and the POP-PUSH-FIFO mechanism, it is the lack of these commands and memory managment in Hack assembly that conducted me to my (poor) solution. From now on I'll try to stick to the "no artifact law" as a sort of Garbage Collection.
I'll go on the study.
Reply | Threaded
Open this post in threaded view
|

Re: Goto subroutine

rleininger
This post was updated on .
Don't think what you did was wasted effort.  Many of the techniques you developed will come up again.

The stack data structure proves to be a very simple and efficient mechanism to implement function calls.  It's such a pervasive solution that, as you suggest, most real microprocessor architectures implement both hardware and machine language instructions to manage one.  BTW, the stack is a last in-first out (LIFO) data structure.  A data structure with the first in-first out (FIFO) property is normally called a queue.

The only real architecture that I have any current familiarity with, but definitely not expertise, is MIPS.  It certainly provides hardware/instruction assistance for using a stack.  In fact, the MIPS architecture identifies specific CPU registers (a law?) whose value must be preserved across function calls and others for which it need not be (but might).  How this is done is mostly handled by convention (not a law), but it is the programmer's responsibility to insure it gets done.  Since the stack may also be used to pass arguments to a function when required, and perhaps a return value, its also the programmer's responsibility to manage this (for MIPS, at least) also.  Although MIPS is a sometimes dogmatic (a law) in some cases about some of this.

Opting for hardware architecture and ISA simplicity, the Hack computer does not provide hardware/machine language assistance to implement and manage a stack, but does it completely with software and some rigid RAM memory use conventions.