Search code examples
assemblycalling-conventionmotorola68000

68000 Assembly - Passing Parameters via Stack in a Sorting Routine


I'm implementing a sorting algorithm in 68000 assembly and decided to use the stack to pass parameters to a subroutine that swaps two elements in an array. I want to make sure I'm handling the stack correctly and efficiently.

Specifically, before calling the SWAP_SUB subroutine, I push the addresses of the two elements onto the stack using pea.l, then retrieve them inside the subroutine using offsets from A7.

Here’s the full code:

      ORG $8000

START:
      moveq.l #len-1,d7  
OUTER_LOOP:
      lea.l array,a0     
      moveq.l #len-2,d6  

INNER_LOOP:
      move.b (a0)+,d2   
      cmp.b (a0),d2
      blt.s DO_SWAP  

NO_SWAP:
      subq.l #1,d6
      bge.s INNER_LOOP
      
      subq.l #1,d7
      bge.s OUTER_LOOP
      
      SIMHALT

DO_SWAP:
     pea.l (a0)  
     pea.l -1(a0)  
     bsr.s SWAP_SUB  
     addq.l #8,a7  
     bra.s NO_SWAP 

SWAP_SUB: 
     movem.l d3-d4,-(a7) ;new line
                         
     move.l 4(a7),a0  
     move.l 8(a7),a1  
     
     move.b (a0),d3  
     move.b (a1),d4  

     lsl.w #8,d3  
     or.w d4,d3  
     rol.w #8,d3  
     move.w d3,d5  
     lsr.w #8,d5  
     move.b d5,(a0)  
     andi.w #$00FF,d3  
     move.b d3,(a1)  
     
     movem.l (a7)+,d3-d4 ;new line

     rts  

array   DC.B 5,3,8,1,7       
len     EQU 5                

    END START


Questions:

  1. Did I correctly use the stack for passing parameters? Are there any potential issues with my approach?
  2. Is there a general way to set up the stack when passing parameters to a subroutine?
  3. Can this code be simplified in any way?

Solution

    1. Did I correctly use the stack for passing parameters? Are there any potential issues with my approach?
    2. Is there a general way to set up the stack when passing parameters to a subroutine?

    The stack aspect is fine. The cleanup is in place. And really you can pass your parameters anyway you like. Either in registers, pushed on the stack in your preferred order, a mixture of registers and stack, or even through passing a single address that directs the callee to a chunk of memory that contains the actual parameters (GEM on the Atari did it that way). The choice is yours.

    1. Can this code be simplified in any way?

    Some people might cry out: you must be joking!

    • Why do you use that many instructions (and clobber that many registers) for such a simple task?

        SWAP_SUB: 
         movea.l 4(a7), a0
         movea.l 8(a7), a1 
         move.b  (a1), d0
         move.b  (a0), (a1)
         move.b  d0, (a0)
         rts
      
    • Why do you keep using a construct that leaves the loop and then has to unconditionally BRA back? Just write the opposite condition for your blt.s DO_SWAP:

         bge.s   NOSWAP
         pea.l   (a0)
         pea.l   -1(a0)
         bsr.s   SWAP_SUB
         addq.l  #8, a7
        NOSWAP:
      

    Too many iterations

     subq.l #1,d6
     bge.s INNER_LOOP
     
     subq.l #1,d7
     bge.s OUTER_LOOP
    

    Why did you use BGE here? D7 was setup with 4 (5-1). The outer loop runs through 4, 3, 2, 1, and 0 which is 5 times, but it's simply impossible to correctly have 5 comparisons in an array that only consists of 5 elements! The solution is to stick with the trustworthy BNE. Alternatively, use the DBNE instruction that I explained just now in great detail in my answer to one of your previous questions.

    (This might not solve all the issues in this bubble sort).