3

I've been working through the problems in a game based around building a Turing Complete machine.

One of the final problems asks you to implement the call and return instructions. This makes it seem like they're part of the ISA and need to be implemented in the microarchitecture.

Is this accurate? Or are call and return usually built from simpler instructions?

Connor
  • 375
  • 1
  • 8
  • 2
    "Usually" [shifted over time](https://en.m.wikipedia.org/wiki/Function_(computer_programming)#History). – greybeard Aug 23 '23 at 09:24
  • @greybeard I've updated the question to make it clear I'm referring to modern ISAs! – Connor Aug 23 '23 at 09:27
  • Define "modern". – Finbarr Aug 23 '23 at 09:34
  • "Modern" is everything up to the 90es. Anything past that is post-modern. – Simon Richter Aug 23 '23 at 11:10
  • Interestingly, the J1 CPU has a bit reserved in the instruction for return. This means the CPU can be loading the return address off the stack as another instruction executes, meaning that a return from subroutine takes zero clock cycles to execute. – Rocketmagnet Aug 23 '23 at 11:14
  • 4
    @SimonRichter We're talking electronics here, not art. Everything <1990 is _ancient_ and everything <2000 is _very old_. Meaning that architectures like AVR and PIC are very much outdated and the general trend to move away from these started around 2005-2010. – Lundin Aug 23 '23 at 12:00
  • 1
    yeah, x86 really kind of broke our progress machine on architectures. Many of the original instructions are still *implemented* (in microcode) on modern x86s, but really, if your instruction is not super common (jump, compare (not) equal, …) and was there before 2000, chances are your modern program will be much faster if it uses other, later added instructions, even on x86. (There's *C string optimized functions for doing things like finding the length of a string* in x86. The hell.) – Marcus Müller Aug 24 '23 at 00:10
  • @MarcusMüller Your comment sounds very interesting but I didn't fully follow it. Are you saying that the x86 instruction set is full of bloat and therefore slowed the development of better architectures? In which case, should I avoid their implementation? – Connor Aug 24 '23 at 07:47
  • 1
    @Connoryes, x86 carries around 40 yeara of baggage. Because it's hard to built a good modern microprocessor based on architecture that seemed like a good idea in the 1980s, much of this baggage is rather slowly emulated in complex microcode. If you're a compiler developer, you have to very carefully read the Intel manuals for each new processor generation, try and benchmark a lot of things to generate good machine code, which hopefully makes good use of the modern hardware. X86 very clearly is a giant ISA, full of historical compromise, and not very consistent. I surely wouldn't implement it. – Marcus Müller Aug 24 '23 at 08:05
  • 1
    @Connor I agree with Marcus; if you're implementing something and can choose, RISC-V is probably the state of the art choice. For just studying, the various iterations of ARM are a good choice. MIPS/68k are simpler but older. The various proprietary microcontroller instruction sets are .. also weird. – pjc50 Aug 24 '23 at 09:40

1 Answers1

7

The short answer for any reasonable definition of modern is "yes". Even little things like PIC16 have call and return. ARM, for historical reasons, spells CALL as "bl" and RETURN as "mov pc, lr".

Given how frequently that functionality is needed, there's no sense in forcing the programmer to build it from more complex instructions, and there are serious problems if your processor supports interrupts and CALL/RETURN aren't atomic. You basically must have an atomic "return from interrupt" instruction unless you want problems when an interrupt arrives in the middle of returning from an interrupt.

pjc50
  • 46,540
  • 4
  • 64
  • 126
  • 1
    Some instruction sets use "JSR" (Jump to Subroutine) in place of "CALL" (same fucntion, different name...) – Peter Bennett Aug 23 '23 at 15:50
  • 2
    There are many ways to return on ARM, especially if THUMB is involved. Depending on the compilation environment, one may also see `bx lr` or `pop {pc}`, or `pop {r3}` + `bx r3` etc., or even equivalents implemented with `ldm` or `ldr`. Fundamentally they either "branch with exchange" (which allows for switching between ARM and THUMB modes) to some register, or else explicitly store a value in the program counter. – Karl Knechtel Aug 23 '23 at 19:02
  • 1
    I agree with this answer, but I'm not sure "serious problems" is quite the right language to use, more that it makes things more complicated than "modern" programming tends to have to deal with. – Ben Burns Aug 23 '23 at 20:24
  • @KarlKnechtel Does ARM use the stack for jumping in function calls that go deeper than a single call? – Connor Aug 24 '23 at 07:48
  • 1
    @Connor yes, it does. Arm is just a family of different ISAs, and a huge family if different microarchitectures, so not all have the same amount of memory and CPU state handling, but on anything remotely modern that's called arm, you get switchable stack pointers, to make things like context switching easier. – Marcus Müller Aug 24 '23 at 08:09
  • 1
    Again, what you call a stack is more or less an interpretation of what you can use an address register for, so be careful when mixing software concepts with hardware concepts. In some architectures, you can build a concept like "stack" easily from hardware instructions, or there is a one-to-one correspondence, in others you just program that concept in less specialized instructions. Arm is typically more in the latter camp. When it comes to stack, that's fairly cleanly representable in thumb2 instructions. – Marcus Müller Aug 24 '23 at 08:11
  • @BenBurns can you find an architecture which (a) has interrupts and (b) does not have an atomic "return from interrupt" instruction? – pjc50 Aug 24 '23 at 09:37
  • 1
    @MarcusMüller right; ARM is designed to be highly symmetric and elegant - the program counter, link register and stack pointer registers are just ordinary registers, the last 3 of 16, that can be selected like any other. THUMB adds more specialized instructions to work with them, because the ordinary data-manipulation opcodes can only afford three bits to specify register operands and thus don't have access to them. – Karl Knechtel Aug 24 '23 at 14:38