;  PUSH_POP.ASM
      PAGE     50,132

code SEGMENT WORD PUBLIC 'CODE'

   ASSUME   CS:code,DS:code,ES:code

   ORG      00h

; == Procedure to Set Environment and Call Test Procedure ==

main proc near          ; main procedure

   jmp  start

   null_word     DW  0  ; stack unloading zone
   near_address  DW  0  ; temporary near call address

start:

   mov   ax,1           ; get
   mov   bx,2           ; tracer
   mov   cx,3           ; values
   mov   dx,4           ; into
   mov   bp,5           ; all
   mov   si,6           ; to
   mov   di,7           ; registers
   push  cs             ; test
   pop   ds             ; ability
   push  cs             ; to save and
   pop   es             ; restore all values
   
   add   ax,0           ; set the
   clc                  ; flags to
   cld                  ; specific values

   call  test_proc      ; call test procedure

   mov   ah,04Ch        ; setup for return
   int   21h            ; return to DOS

   ret

main  endp

; ==== Procedure to Test Save and Restore for Near CALL ====

test_proc  proc  near

   call push_pop        ; call push and pop procedure

   mov   ax,0           ; clear
   mov   bx,0           ; all
   mov   cx,0           ; registers
   mov   dx,0           ; of
   mov   bp,0           ; tracer
   mov   di,0           ; values
   mov   si,0           ; to 
   push  si             ; test
   pop   ds             ; restore
   push  si             ; of
   pop   es             ; start values

   sub   ax,ax          ; alter
   std                  ; the
   stc                  ; flags too

   ret

test_proc  endp

; ========== Procedure to PUSH/POP All Registers ===========

push_pop  proc  near

   pushf                   ; push the flags
   push  ax                ; push
   push  bx                ; all
   push  cx                ; other
   push  dx                ; general
   push  bp                ; purpose
   push  di                ; registers
   push  si                ;
   push  ds                ;
   push  es                ;

   push  ax                ; double push ax and bp to
   push  bp                ; save any passed parameters
   pushf                   ; save flags too
   mov   bp,sp             ; prepare for indirect CALL
   add   bp,26             ; point to resumption offset
   mov   ax,[bp]           ; get into register then
   mov   near_address,ax   ;  into call offset address
   popf                    ; restore flags
   pop   bp                ; restore any parameters 
   pop   ax                ; passed in ax or bp

   call  near_address      ; recursively call original proc

   pop   es                ; restore
   pop   ds                ; all
   pop   si                ; general
   pop   di                ; use
   pop   bp                ; register
   pop   dx                ; values
   pop   cx                ;
   pop   bx                ; 
   pop   ax                ;
   popf                    ; restore flag values

   pop   null_word         ; adjust stack to original return

   ret

push_pop  endp

; ==========================================================

code ENDS   ; end of code segment

        end main ; end assembly


