Assembly DOS program

Assembly DOS program
typescript
Ethan Jackson

I need to write a program in Assembly for DOSBOX using MASM.

Task: Write a resident (TSR) program for DOS that changes the keyboard repeat rate every second in a cyclic manner, from the slowest to the fastest setting. The program must unload the initialization section upon completion.

Program requirements:

DOS + MASM environment.

Terminate the program using: INT 27h.

Interrupt handler installation method: Manually modify the Interrupt Vector Table using the MOV instruction.

Calling the previous interrupt handler: Use a far CALL with the flags register pushed onto the stack beforehand.

Position of the call to the previous handler: At the end of the new interrupt handler.

My code:

.MODEL small .STACK 100h .DATA old_handler_offset DW 0 old_handler_segment DW 0 TickCounter db 0 CurrentRate db 0 RepeatRates db 32 dup (?) .CODE InitRepeatRates proc mov cx, 32 mov si, offset RepeatRates mov al, 1Fh FillLoop: mov [si], al dec al inc si loop FillLoop ret InitRepeatRates endp int_handler proc far push ax push bx push dx push si0 push es push di inc cs:TickCounter cmp cs:TickCounter, 18 jl skip_update mov cs:TickCounter, 0 xor si, si mov al, cs:CurrentRate mov si, x mov al, cs:RepeatRates[si] inc cs:CurrentRate cmp cs:CurrentRate, 32 jb no_reset mov cs:CurrentRate, 0 no_reset: wait_input_ready: in al, 64h test al, 02h jnz wait_input_ready mov al, 0F3h out 60h, al wait_data_ready: in al, 64h test al, 02h jnz wait_data_ready mov al, cs:RepeatRates[si] out 60h, al skip_update: pushf push word ptr cs:old_handler_segment push word ptr cs:old_handler_offset retf pop di pop es pop si pop dx pop bx pop ax iret int_handler endp start: mov ax, @DATA mov ds, ax call InitRepeatRates xor ax, ax mov es, ax mov ax, es:[1Ch*4] mov old_handler_offset, ax mov ax, es:[1Ch*4+2] mov old_handler_segment, ax cli mov word ptr es:[1Ch*4], offset int_handler mov ax, seg int_handler mov word ptr es:[1Ch*4+2], ax sti mov dx, offset start int 27h END start

The program compiles successfully, but after I run and exit it, DOS stops responding to keyboard input. Please help, i don`t know what to do with it. Or offer general advice for coding TSR's in DOS? Thanks in advance, any help is very much appreciated!

Answer

The conditions for using int 27h are not met

Your program is an .EXE executable for which CS does not point at the PSP, and that is a requirement for using int 27h.
Even if you solved this detail, you would still be left with invalid accesses to your program's variables through the cs: segment override prefix as in your executable CS does not point at the .DATA section.

The best solution would be to use the .COM executable file format. All the segment registers start out equal to each other and conveniently pointing at the PSP.

Calling the previous interrupt handler: Use a far CALL with the flags register pushed onto the stack beforehand.

pushf push word ptr cs:old_handler_segment push word ptr cs:old_handler_offset retf

You don't actually call the previous handler! The retf instruction consumes the 2 pushes, so the old handler only 'sees' the pushed flags.
The 'old_handler' will return through the iret instruction but there will be no far return address waiting on the stack.

... pushf push cs push offset Back push word ptr cs:old_handler_segment push word ptr cs:old_handler_offset retf Back: pop di ...

or use a far call:

... pushf callf dword ptr cs:old_handler_offset pop di ...

The .COM file (I did not yet look at the keyboard stuff):

ORG 256 jmp start old_handler_offset DW 0 old_handler_segment DW 0 TickCounter db 0 CurrentRate db 0 RepeatRates db 32 dup (0) InitRepeatRates: mov cx, 32 mov si, offset RepeatRates mov al, 1Fh FillLoop: mov [si], al dec al inc si loop FillLoop ret int_handler: push ax push bx push dx push si push es push di inc cs:TickCounter cmp cs:TickCounter, 18 jl skip_update mov cs:TickCounter, 0 xor si, si mov al, cs:CurrentRate mov si, x <<<<<<<< ?????? mov al, cs:RepeatRates[si] inc cs:CurrentRate cmp cs:CurrentRate, 32 jb no_reset mov cs:CurrentRate, 0 no_reset: wait_input_ready: in al, 64h test al, 02h jnz wait_input_ready mov al, 0F3h out 60h, al wait_data_ready: in al, 64h test al, 02h jnz wait_data_ready mov al, cs:RepeatRates[si] out 60h, al skip_update: pushf push cs push offset Back push word ptr cs:old_handler_segment push word ptr cs:old_handler_offset retf Back: pop di pop es pop si pop dx pop bx pop ax iret ; ----------------------------- start: mov ax, @DATA mov ds, ax call InitRepeatRates xor ax, ax mov es, ax mov ax, es:[1Ch*4] mov old_handler_offset, ax mov ax, es:[1Ch*4+2] mov old_handler_segment, ax cli mov word ptr es:[1Ch*4], offset int_handler mov ax, seg int_handler mov word ptr es:[1Ch*4+2], ax sti mov dx, offset start int 27h

Related Articles