News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

16-bit DOS port of Jeff's PLAY code

Started by MichaelW, February 27, 2007, 04:34:51 AM

Previous topic - Next topic

MichaelW

Playing with the code that member Jeff posted here, 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]
eschew obfuscation