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!


    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).

    [edit]

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

    Your late addition to the question tries to add 'register preservation' to the subroutine. It does not work because the movem instruction, while pushing those D3 and D4 registers, also changes A7. So, your instructions that load A0 and A1 need to account for that by specifying an offset that is 8 more:

    SWAP_SUB: 
     movem.l d3-d4,-(a7)
     movea.l 12(a7),a0  
     movea.l 16(a7),a1  
     ...   
     movem.l (a7)+,d3-d4
     rts
    

    If your intent was to preserve the registers as per Eric Eidt's recommendation, then D5 is still missing from the list. With 3 longword registers on the list, the original offsets need to become 12 more:

    SWAP_SUB: 
     movem.l d3-d5,-(a7)
     movea.l 16(a7),a0
     movea.l 20(a7),a1
     ...   
     movem.l (a7)+,d3-d5
     rts
    

    But since the subroutine only changes the low words of D3, D4, and D5, it is better to use movem.w for a faster execution and less stack memory consumption. The original offsets then need to become only 6 more:

    SWAP_SUB: 
     movem.w d3-d5,-(a7)
     movea.l 10(a7),a0
     movea.l 14(a7),a1
     ...   
     movem.w (a7)+,d3-d5
     rts