Playing with the code that member Jeff posted here (http://www.masm32.com/board/index.php?topic=1789.0), in the first attachment Tetris.zip, I decided to try porting it? to 16-bit DOS, adding the code necessary to support a ms-resolution timer tick and implement the Beep and Sleep functions. The attachment contains the result.
Edit:
This is a replacement for fast_tmr.asm that uses the RTC to generate periodic interrupts at the default rate of 1024 interrupts per second.
.data
  prevIsr70 dd 0
  tickCount dd 0
.code
IODELAY MACRO
 REPEAT 10
  jmp $+2
 ENDM
ENDM
InitFastTimer proc
  ; Hook the RTC interrupt (70h). The Get Interrupt Vector
  ; function returns the current vector in ES:BX.
  ;
  mov ax, 3570h
  int 21h
  mov WORD PTR prevIsr70, bx
  mov WORD PTR prevIsr70[2], es
  ; The Set Interrupt Vector function expects the
  ; address of the new handler in DS:DX.
  ;
  push ds
  push cs
  pop ds
  mov dx, OFFSET Isr70
  mov ax, 2570h
  int 21h
  pop ds
  ; Set the rate selection divider control in status register
  ; A to .976 microsecond, or 1024 interrupts per second.
  ;
  cli
  mov al, 0Ah      ; Address of status register A
  or al, 80h      ; Set bit 7 to disable NMI
  out 70h, al      ; Write to address port
  IODELAY
  in al, 71h      ; Get current value
  and al, 0F0h     ; Clear lower nibble
  or al, 6       ; And set to value 6
  IODELAY
  out 71h, al      ; Write it back
  ; Enable the periodic interrupt by setting bit 6 of
  ; status register B.
  ;
  mov al, 0Bh      ; Address of status register B
  or al, 80h      ; Set bit 7 to disable NMI
  out 70h, al      ; Write to address port
  IODELAY
  in al, 71h      ; Get current value
  or al, 40h      ; Set bit 6
  IODELAY
  out 71h, al      ; Write it back
  mov al, 0Dh      ; Set the address port to status
  out 70h, al      ; register D and enable NMI
  IODELAY
  in al, 71h      ; Do dummy read
  ; Unmask (allow) IRQ 8 (necessary for some systems).
  ;
  in  al, 0A1h     ; Get current mask for PIC 2
  and al, NOT 1    ; Clear mask for IRQ 8
  out 0A1h, al     ; Write it back
  ; Program system timer 2 for LSB then MSB, mode 3, binary.
  ;  bit 7-6: 10   = timer 2
  ;  bit 5-4: 11   = R/W LSB then MSB
  ;  bit 3-1: 011  = mode 3, periodic square wave
  ;  bit 0:  0   = binary
  ;
  mov al, 10110110b
  out 43h, al
  sti
  ret
InitFastTimer endp
TermFastTimer proc
  ; Restore RTC status register B to normal.
  ;
  cli
  mov al, 0Bh      ; Address of status register B
  or al, 80h      ; Set bit 7 to disable NMI
  out 70h, al      ; Write to address port
  IODELAY
  in al, 71h      ; Get current value
  and al, NOT 40h    ; Clear bit 6
  IODELAY
  out 71h, al      ; Write it back
  mov al, 0Dh      ; Set the address port to status
  out 70h, al      ; register D and enable NMI
  IODELAY
  in al, 71h      ; Do dummy read
  sti
  ; Unhook the RTC interrupt.
  ;
  push ds
  mov dx, WORD PTR prevIsr70
  mov ds, WORD PTR prevIsr70[2]
  mov ax, 2570h
  int 21h
  pop ds
  ret
TermFastTimer endp
; This is the new handler for the system timer tick interrupt.
; The SS override is necessary because DS may not be set to
; our data segment when the interrupt is called. For the
; Microsoft memory models other than tiny, the startup code
; will effectively move the stack into DGROUP and set SS=DS.
Isr70 proc
  push ax
  ; Update the tick count.
  ;
  inc ss:tickCount
  ; Do not pass interrupt to previous handler, but must
  ; do dummy read of status register C.
  ;
  mov al, 0Ch      ; Address of status register C
  or al, 80h      ; Set bit 7 to disable NMI
  out 70h, al      ; Write to address port
  IODELAY
  in al, 71h      ; Do dummy read
  IODELAY
  mov al, 0Dh      ; Set the address port to status
  out 70h, al      ; register D and enable NMI
  IODELAY
  in al, 71h      ; Do dummy read
  ; For a hardware interrupt the last handler in the
  ; handler chain must issue an EOI to the interrupt
  ; controller, and since in this case IRQ 8 is from
  ; the slave PIC we must issue an EOI to both,
  ; starting with the slave.
  ;
  mov al, 20h      ; non-specific EOI
  out 0A0h, al     ; PIC 2 (slave)
  mov al, 20h      ; non-specific EOI
  out 20h, al      ; PIC 1 (master)
  pop ax
  iret
Isr70 endp
Sleep proc wMilliseconds:WORD
  movzx eax, wMilliseconds
  add eax, tickCount
 @@:
  cmp tickCount, eax
  jb @B
  ret
Sleep endp
[attachment deleted by admin]