; test1.asm
;
; this program is designed to demonstrate simplified stack-based
; parameter passing using TASM's directives.
;
        IDEAL
        MODEL small
        p486

        STACK   400h

        DATASEG
        CODESEG
        STARTUPCODE
        call    Example pascal, 2, 0, 3
        EXITCODE

proc Example pascal
        USES    bx
        ARG     slope:WORD, intercept:WORD, X:WORD
        LOCAL   alpha:WORD
        mov     ax,[X]
        mov     bx,[slope]
        imul    bx
        mov     [alpha],bx
        adc     ax,[intercept]
        ret
endp Example
        END
-+--- TEST1.ASM ends

This silly example doesn't do much of anything, but it does show how to use the
directives I mentioned.  (MASM probably has similar mechanisms.)  The variables
I've called slope, intercept, and X are passed in as words on the stack. 
Because I've specified a 486 CPU, the stack frame is generated with the ENTER
instruction.  I've also told the assembler that I want one word of local
variable space (which isn't really used) and that the BX register is used but
should be restored.  Here's what's generated by TASM (the comments are, of
course, generated by me.)

push   0002             ; push parameters on stack from left to right
push   0000             ; (implied by use of keyword 'pascal')
push   0003             ;
call   #test1#25        ; make the call -- 
mov    ah,4C            ; no stack cleanup here (also due to 'pascal')
int    21

enter  0002,00          ; alloc 2 bytes of space, bp = stack frame ptr
push   bx               ; save USES registers
mov    ax,[bp+04]       ; TASM automatically figures out addr of X
mov    bx,[bp+08]       ; this is mov bx,[slope]
imul   bx               ; no translation required
mov    [bp-02],bx       ; this is mov [alpha],bx
adc    ax,[bp+06]       ; adc ax,[intercept]
pop    bx               ; TASM restores the USES registers in correct order
leave                   ; restore stack and BP register
ret    0006             ; ret & throw away passed parameters 
                        ;  (it's the pascal calling convention)

Just as it's essential for a carpenter to know how to pound a nail with a
hammer, even if he uses a pneumatic nail gun most of the time, I think it's
essential for programmers to know how to manually set up a stack frame even
while I advocate the use of the automatic method.  And of course, as you
mentioned in your post, it's usually preferable to pass parameters in registers
for both speed and memory (stack) conservation.
