Friday, March 20, 2020

An interesting way to use the Program Counter in MACRO-11


  If you're like me, you enjoy reading well written pieces of MACRO-11 code, in order to grow your skill with it (if you're like me you also enjoy 60s muscle cars, tequila, and the music of the Grateful Dead, but those are subjects for a different post).

  I was reading the code for a boot rom the other day and noticed a clever use of the PC. This rom had a subroutine  that  needed to execute another subroutine twice, then return. If I needed to do that, I'd likely have done something like this...

A:       jsr  PC,B
          (finish
          booting
          here)

B:      (do
         other
         stuff)
         jsr  PC,C
         jsr  PC,C
         rts  PC

C:     (do
        some
        processing)
        rts PC

  But this rom took advantage of the fact that C is adjacent to the end of B. That allowed it to save a few bytes of code. It did...

A:      jsr  PC,B
          (finish
          booting
          here)

B:      (do
         other
         stuff)
         jsr   PC,(PC)

C:   (do
      some
      processing)
      rts    PC

  
  So, have a look at the rom's version of B. It takes advantage of the fact that while the JSR instruction is executing, the PC is already updated to point to the next instruction, which, due to the adjacent location, is at C, and calls it as (PC). That saves a word over calling it as jsr   PC,C. 

       004717                         A:      jsr     PC,(PC)    
vs
       004767  000000           A:      jsr     PC,C
  .
  It save a word, since (PC) is addressing mode 1 (register deferred) - the register contains the address. JSR  PC,C uses mode 6 (indexed, called relative when the PC is the register) - the address is the register value+an offset contained in a word following the instruction.

  Additionally, you  see that there is only one call to C, and no RTS to A in the rom's version of routine B. That's because, when C executes its RTS instruction, it returns to the address following its call in B - which is the beginning of C. C then executes again, and when it hits its rts instruction this time, it causes a return to routine A. That saves several more bytes.

  So, it's not something I'll be making use of everyday, and it can be argued it's a less supportable way to code this, since it will take the next programmer a little thought to figure out what's going on - but it's a handy couple of tricks to know if you're ever tight on space.