Mill Computing, Inc. Forums The Mill Architecture new CALL opcode variants (suggestion)


  • Author
  • jm
    Post count: 3
    #710 |

    The Mill is the best surprise in a long long time (except for Intel?), congratulations.

    While thinking about my pet instruction set architecture, I came across an instruction I’d like the ideal CPU to have. Noting that the Mill doesn’t have a Carry this may be even more interesting.

    The CALL and the RETURN instructions are to be modified to allow multiple return addresses. These addresses follow the CALL opcode, and RETURN optionally returns to an address in this list.
    So CALL has variants that specify how many addresses to skip, and RETURN has variants that select which address to return to.
    Probably only a single address suffices, as a list is untypical.

    The typical application for this instruction is the very common pattern (at least it should be):

    var error: boolean;
    value, error = myFunction(…); // return both a value and an error status
    if error then …; // error is handled
    … // only value is used from here on

    The modified CALL/RETURN instructions eliminate the need for the IF (or a carry). Flow is controlled directly from the callee.

    This is actually similar to a once popular asssembly programming technique for the Z80: the return address was used as a pointer to pass constant arguments (placed right after the CALL opcode) to the callee. So in the case of the Z80, it had to advance through them before it could return. It could of course also use some of the arguments, like described above, to “return” to a different address. The Mill could make this zero-cost.

    So this is the more generic usage the Mill instruction might support, extending the limited scope presented above. Instead of engaging in a calling ritual (dropping values on the Belt and the callee storing them), support for accessing values relative to the return address could be added. With it the callee can fetch the arguments at the time they are needed, or not at all if they are not needed, as is so often the case with optional arguments.

    Note that only statically known values can be passed in this way. Dynamic values require an alternative codepath.

    In the example of the Z80 the CALL was typically used to call the “OS” at a fixed entry point and the arguments would specify the service requested. It made for a call-extender for which there is much less need these days. Though history has a habit of repeating itself…

    This feature requires unconventional calling conventions. The Mill has the opportunity to get them right.

    I presume both mechanisms presented allow for decent performance enhancements. Perhaps they solve the problem of LISP’s multiple return values as discussed in the metadata topic.

    Can’t wait to have a Mill in my pocket. If one of these instructions ends up in them, remember me 🙂

  • Ivan Godard
    Post count: 689

    I very much agree that there is a real need for better support for call-unwinding on exception conditions. We actually had a facility several years ago that was somewhat like what you suggest. However, there were problems.

    One problem was that such a convention requires the callee to know details about the caller’s expected protocol, breaking function isolation. Alternatively, we could define a kind of universal protocol, but that would have costs for calls that didn’t need the full generality. There were encoding issues too – remember that a single Mill instruction can contain several calls, and what with needing to represent the target address and the argument list, adding another whole address did not fit well. However, what finally caused us to drop the idea was the realization that we didn’t need a call variant anyway.

    The chosen resolution takes advantage of the ability of Mill calls to return more than one result, cheaply. That is, your myFunction is directly expressible in Mill hardware. So the cost of the semantics is the branch to test the error condition. With phasing (you did see the Execution talk?) the branch can be in the same instruction as the call and still see the result of the call as its predicate. The branch operation naturally carries the error-handling address that would have to be present in the fancy call operation anyway, but does not require any encoding contortions or special call semantics. So making the error handling explicit puts it in the caller (where it belongs on isolation grounds) and has zero latency cost and no power or encoding cost beyond what having the callee do the branch would need anyway.

    This also gets us out of the protocol business; protocols should be app- or language-level, not dictated by the hardware. For example, a caller/callee could agree to have several possible post-call continuations reflecting various detected conditions and represented by a returned enum that the caller switches on.

    You separately mention the possibility of passing arguments as addresses after the call operation. Besides such an approach not being encodable on a Mill, it also does not work on any modern Harvard-architecture CPU (Harvard has separate i- and d-caches with unique datapaths for each). In general data accesses to code would have to be satisfied from below the join point of the hierarchy, which is at least a painful 10+ cycles away from the CPU. In contrast, having the caller use a LEA operation to drop a pointer onto the belt is a one-cycle operation in the caller, and will almost certainly be overlapped with other operation in the Mill’s wide issue. When the callee dereferences the pointer (if it needs to) then it is quite likely to find the data in the d$1 cache, the latency of which can be hidden using the Mill deferred load facility.

    There’s another issue that will be touched on in the upcoming talk on Security and Reliability: the caller and callee may not be in the same security domain (called a Turf in Mill-speak), so the callee may not have rights to access the code of the caller in the first place, even if the address is to a data location that it does have rights to.

    We are a long way from the Z80 🙂

    • jm
      Post count: 3

      Sometime gods must become humans, I imagine that must be very tiring to them, speaking to lowly creatures 🙂

      So thank you. It is a pleasure seeing your work. I would prefer to be an investor! 😉

      Indeed I have not had the opportunity to assist all videos in detail, I reside in a low-bandwidth part of the world.

      > You separately mention the possibility of passing arguments as addresses after the call operation.

      Actually I did not think of them as addresses, just as offsets or literals (of which an additional return address could be one). Addresses could be passed, but that would very quickly run into the mismatch well exemplified with the problems this gives in the context of a Harvard architecture.

      > We are a long way from the Z80 🙂

      I know you are. This is an earthquake. The result of a life of dedication. Beautiful. How long do you think it will take before hackers can have /their/ $10 Mill uC?

      • Ivan Godard
        Post count: 689

        > So thank you. It is a pleasure seeing your work. I would prefer to be an investor! 😉

        Actually you can be, if you are either a non-US national, or are an accredited investor per Regulation D of the SEC. If either apply, sign up for the Investor’s Mailing :ist at (the list sign-up explains the regulations).

        > How long do you think it will take before hackers can have /their/ $10 Mill uC?

        Longer than anyone would like 🙁 Don’t hold your breath, but we will get there eventually.

You must be logged in to reply to this topic.