;This program moves a car under mouse control
	  mov    ax, 0     ; start mouse
	  int    33h
	  mov    ax, 1
	  int    33h            ;make certain it is not seen
car_loop: call   draw_car
	  call   delay
	  call   erase_car
	  call   mouse_pos
	  mov    ax, 3
	  int    33h
	  or     bx, bx
	  jz     car_loop       ; no mouse button pressed

	  mov   ax, 4C00H
	  int   21h             ;return to DOS
car_row   db     10
car_col   db     30

;  input and output:  car_row and car_col

mouse_pos:  push     ax
	     push     bx
	     push     cx
	     push     dx
	     mov      ax, 3
	     int      33h
; cx = mouse position 0 - 639
; dx = mouse position vert 0 - 199
	     cmp      cx, 400
	     ja       right
	     cmp      cx, 200
	     ja       vert
	     sub      car_col, 1
	     jmp      vert
right:       add      car_col, 1
vert:        cmp      dx, 75
	     jb       up
	     cmp      dx, 125
	     jb       rand_exit
	     add      car_row, 1
	     jmp      rand_exit
up:          sub      car_row, 1
rand_exit:    pop      dx
	      pop      cx
	      pop      bx
	      pop      ax

erase_car:       push   ax
		 push   bx
		 push   cx
		 push   dx
		 mov    al, ' '
		 mov    bl, 07h
		 mov    cx, 1
		 mov    dh, car_row
		 mov    dl, car_col
		 call   paint
		 add    dh, 1
		 sub    dl, 2
		 mov    cx, 5
		 call   paint
		 pop    dx
		 pop    cx
		 pop    bx
		 pop    ax

;         input (dh, dl) row and col of where to paint car
draw_car: push   ax
	  push   bx
	  push   cx
	  push   dx
	  mov    dh,    car_row
	  mov    dl,    car_col
	  mov    al, 1                 ;happy face
	  mov    cx, 1
	  mov    bl, 0Eh               ;yellow on black
	  call   paint
	  add    dh, 1
	  sub    dl, 2                 ;position of first car
	  mov    al, 0C8h              ;left side of car
	  mov    bl, 01h               ;blue on black
	  call   paint
	  add    dl, 1
	  mov    cx, 3
	  mov    al, 0CDh              ;char for middle of car
	  call   paint
	  add    dl, 3
	  mov    cx, 1
	  mov    al, 0BCh              ;right side of car
	  call   paint
	  mov    dh, 25
	  mov    dl, 25
	  call  set_pos       ; get rid of cursor so we can't see it
	  pop   dx
	  pop   cx
	  pop   bx
	  pop   ax

;      input    dh = row
;               dl = col
set_pos:  push   ax
	  push   bx
	  mov    bh, 0                 ;page 0
	  mov    ah, 2                 ;function set cursor
	  int    10h
	  pop    bx
	  pop    ax
;  paints chars at the current cursor location
;         input  = cx num of char
;                  al = ascii char
;                  bl = attrib
paint:    push   ax
	  push   bx
	  cmp    cx, 0
	  je     paint_done
	  call   set_pos
	  mov    bh, 0                 ;page 0
	  mov    ah, 9                 ;function for writing a char
	  int    10h
	  pop    bx
	  pop    ax
;  Delay routine, if we had no delay, then things would move so rapidly
;  we could not tell what was going on, and could not move the paddle
;  fast enough to keep up with the play!
      PUSH  AX             ; save registers
      PUSH  DX
      MOV   DH,25          ; get cursor off screen area
      MOV   DL,0           ;      (cleaner appearence)
      CALL  set_pos
      SUB   AX,AX          ; zero frequency for rest
      MOV   DX,6           ; delay of 0.06 secs is reasonable
      CALL  NOTE           ; execute delay
      POP   DX             ; restore registers
      POP   AX
      RET                  ; return to caller

;  Routine to play note on speaker
;      (AX)           Frequency in Hz (32 - 32000)
;      (DX)           Duration in units of 1/100 second
;      CALL  NOTE
;  Note: a frequency of zero, means rest (silence) for the indicated
;  time, allowing this routine to be used simply as a timing delay.
;  Definitions for timer gate control
CTRL      EQU   61H           ; timer gate control port
TIMR      EQU   00000001B     ; bit to turn timer on
SPKR      EQU   00000010B     ; bit to turn speaker on
;  Definitions of input/output ports to access timer chip
TCTL      EQU   043H          ; port for timer control
TCTR      EQU   042H          ; port for timer count values
;  Definitions of timer control values (to send to control port)
TSQW      EQU   10110110B     ; timer 2, 2 bytes, sq wave, binary
LATCH     EQU   10000000B     ; latch timer 2
;  Define 32 bit value used to set timer frequency
FRHI      EQU   0012H          ; timer frequency high (1193180 / 256)
FRLO      EQU   34DCH          ; timer low (1193180 mod 256)
      PUSH  AX          ; save registers
      PUSH  BX
      PUSH  CX
      PUSH  DX
      PUSH  SI
      MOV   BX,AX          ; save frequency in BX
      MOV   CX,DX          ; save duration in CX
;  We handle the rest (silence) case by using an arbitrary frequency to
;  program the clock so that the normal approach for getting the right
;  delay functions, but we will leave the speaker off in this case.
      MOV   SI,BX          ; copy frequency to BX
      OR    BX,BX          ; test zero frequency (rest)
      JNZ   NOT1           ; jump if not
      MOV   BX,256         ; else reset to arbitrary non-zero
;  Initialize timer and set desired frequency
NOT1: MOV   AL,TSQW          ; set timer 2 in square wave mode
      OUT   TCTL,AL
      MOV   DX,FRHI          ; set DX:AX = 1193180 decimal
      MOV   AX,FRLO          ;      = clock frequency
      DIV   BX               ; divide by desired frequency
      OUT   TCTR,AL          ; output low order of divisor
      MOV   AL,AH            ; output high order of divisor
      OUT   TCTR,AL
;  Turn the timer on, and also the speaker (unless frequency 0 = rest)
      IN    AL,CTRL          ; read current contents of control port
      OR    AL,TIMR          ; turn timer on
      OR    SI,SI            ; test zero frequency
      JZ    NOT2             ; skip if so (leave speaker off)
      OR    AL,SPKR          ; else turn speaker on as well
;  Compute number of clock cycles required at this frequency
NOT2: OUT   CTRL,AL          ; rewrite control port
      XCHG  AX,BX            ; frequency to AX
      MUL   CX               ; frequency times secs/100 to DX:AX
      MOV   CX,100           ; divide by 100 to get number of beats
      DIV   CX
      SHL   AX,1             ; times 2 because two clocks/beat
      XCHG  AX,CX            ; count of clock cycles to CX
;  Loop through clock cycles
NOT3:      CALL  RCTR          ; read initial count
;  Loop to wait for clock count to get reset. The count goes from the
;  value we set down to 0, and then is reset back to the set value
NOT4: MOV   DX,AX          ; save previous count in DX
      CALL  RCTR           ; read count again
      CMP   AX,DX          ; compare new count : old count
      JB    NOT4           ; loop if new count is lower
      LOOP  NOT3           ; else reset, count down cycles
;  Wait is complete, so turn off clock and return
      IN    AL,CTRL           ; read current contents of port
      AND   AL,0FFH-TIMR-SPKR ; reset timer/speaker control bits
; note that the above statement is an equation
      OUT   CTRL,AL           ; rewrite control port
      POP   SI                ; restore registers
      POP   DX
      POP   CX
      POP   BX
      POP   AX
      RET               ; return to caller
;  Routine to read count, returns current timer 2 count in AX
      MOV   AL,LATCH         ; latch the counter
      OUT   TCTL,AL          ; latch counter
      IN    AL,TCTR          ; read lsb of count
      MOV   AH,AL
      IN    AL,TCTR          ; read msb of count
      XCHG  AH,AL            ; count is in AX
      RET                    ; return to caller