im compiling a timer program to display the time required to execute a program
i tried to execute this file(time7.exe) but it has encountered an illegal instruction..
why does it happen?
i try to debug it using turbo debugger but to no avail...

r there anything wrong with the code?? :shock:

the error pop-up window reads:
16bit MS-DOS Subsystem
c:\WINNT\system32\cmd.exe - time7.exe
the NTVDM CPU has encountered an illegal instuction.
CS:015c IP:f31d OP:ff ff ff ff ff

here i include the source code...

LIBSEG           segment byte public "LIB"
assume cs:LIBSEG , ds:LIBSEG

include mac.inc
includelib alib.lib
extrn word_to_dec_stdout:far
extrn dword_to_dec_stdout:far
extrn stdout_string:far
extrn quad_multiply1:far
extrn quad_divide:far

timer_low equ 046ch
timer_mode equ 43h
timer0 equ 40h

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -(  TIME   )

start:
           call  calibrate_timer
           call  start_timer

   call CHECK_DOS_MEMORY  ; program to be evaluated time
   
           call  read_timer
           call  convert_timer
           call  display_timer

public CHECK_DOS_MEMORY
CHECK_DOS_MEMORY proc far
push cx
        sub     bx,bx
        mov     es,bx
        mov     bx,es:[413h]            ;get mem. size in 1k blocks
        mov cl,6
        shl bx,cl
;
; compute our final program location in paragraphs
;  ax = our final offset
;
        mov cx,bx
        sub cx,ax
        mov ax,cx
        pop cx
retf
CHECK_DOS_MEMORY endp


public start_timer
start_timer proc far
apush ax,dx,ds
pushf
cli
;
; initialize the 8253 to count down max count of 65536 by setting zero
;
mov al,00110100b ;select mode
out timer_mode,al ;request mode
call delay
sub ax,ax ;starting count
out timer0,al
call delay
out timer0,al
;
; wait for timer tick before starting
;
sti
call delay
in al,timer0
mov ah,al
twait: call delay
in al,timer0
cmp al,ah
je twait
call delay
;
;wait for interrupt
;
sub dx,dx
mov ds,dx ;point at seg 0
mov dx,word ptr ds:
ilop: mov ax,word ptr ds:
cmp ax,dx
je ilop
;
; restart the timer back at count of zero again.
;
mov al,00110100b ;select mode
out timer_mode,al ;request mode
call delay
sub ax,ax ;starting count
out timer0,al
call delay
out timer0,al
;
; get the current bios time of day
;
mov ax,word ptr ds:
mov cs:interrupt_count,ax
popf
apop ds,dx,ax
retf
start_timer endp

delay: jmp d1
d1: jmp d2
d2: jmp d3
d3: jmp d4
d4: ret


public read_timer
read_timer proc far
apush ds,es
pushf
cli
mov ax,cs
mov ds,ax
xor ax,ax
mov es,ax
;
; stop timer by setting mode to zero
;
out timer_mode,al ;timer interrupts off
call delay
in al,timer0
call delay
mov ah,al
in al,timer0
xchg ah,al
neg ax
mov timer_count,ax ;ax now has 16 bit timer count
;
; read interrupt count from bios
;
mov ax,es:
sub ax,interrupt_count
mov interrupt_count,ax
;
; restart the timer by resetting default value of control word
;
mov al,00110110b ;binary,mode 3,timer 0
out timer_mode,al
mov al,0
call delay
out timer0,al
call delay
out timer0,al
;
; return values to caller
;
mov ax,timer_count
mov dx,interrupt_count

sub ax,calibrate
sbb dx,0 ;calibrate timer value
popf
exit: apop es,ds
retf
read_timer endp

public CONVERT_TIMER
CONVERT_TIMER proc far
apush si,ds
mov si,cs
mov ds,si

mov cx,word ptr timer_convert+2
mov bx,word ptr timer_convert
call quad_multiply1 ;result to dx,cx,bx,ax
mov si,word ptr hundred_thousand+2
mov di,word ptr hundred_thousand
call quad_divide ;result dx,ax  remainder cx,bx

;
; dx,ax now contains the total number of micro seconds, cx,bx = remainder
;
cmp cx,1
je round_up
cmp bx,0c350h ;(100000/2)
jb compute_seconds
round_up:
add ax,1
adc dx,0 ;round up 1

compute_seconds:
mov bx,dx
xor dx,dx
xor cx,cx
mov si,word ptr million+2
mov di,word ptr million
call quad_divide ;compute seconds & microseconds
;
; dx,ax = seconds   cx,bx = microseconds
;
apop ds,si
retf

CONVERT_TIMER endp

public display_timer
DISPLAY_TIMER proc far
apush si,ds

mov si,cs
mov ds,si
mov seconds,ax
mov word ptr microseconds+2,cx
mov word ptr microseconds,bx

mov si,offset msg1
call stdout_string ;display 'Elapsed time ="

mov ax,seconds
call word_to_dec_stdout ;seconds
mov si,offset message_sec
call stdout_string

mov ax,word ptr microseconds
mov dx,word ptr microseconds+2
call dword_to_dec_stdout
mov si,offset message_micro
call stdout_string
apop ds,si
retf
DISPLAY_TIMER endp

public calibrate_timer
calibrate_timer proc far
apush ax,bx,cx,dx
mov cs:calibrate,0
mov cs:seconds,0
mov cx,8
ct_lp1: push cx
        call start_timer
call read_timer
add cs:seconds,ax
pop cx
loop ct_lp1

mov ax,cs:seconds
mov cl,3
shr ax,cl
mov cs:calibrate,ax

mov cx,5000
ct_lp: call delay
loop ct_lp
apop dx,cx,bx,ax
retf
calibrate_timer endp
;--------------------------------------------------------------------------

timer_count dw 0 ;read from 8253
interrupt_count dw 0 ;read from BIOS

microseconds dd 0 ;total microseconds
seconds dw 0 ;total seconds

calibrate dw 0 ;calibration factor from read_timer

timer_convert dd 83809 ;838.096 nsec per tick
hundred_thousand dd 100000
million dd 1000000

msg1 db 0dh,0ah,0dh,0ah,'Elapsed time = ',0
message_sec db ' (seconds)   ',0
message_micro db ' (Micro seconds)',0dh,0ah,0


LIBSEG ENDS
end start

Posted on 2007-05-09 01:30:25 by wogok
Doesn't start: need some kind of exit? At the moment it just carries on into the CHECK_DOS_MEMORY proc, so who
knows where it will end up?
Posted on 2007-05-09 01:40:36 by sinsi
but i did put the end start right at the end of the code...

jus below the LIBSEG ENDS...

so...

Posted on 2007-05-09 01:47:27 by wogok
All "end start" does is tell the linker where the entry point is - you still need to exit to DOS

start:
  ;blah blah blah
  mov ah,4ch
  int 21h
Posted on 2007-05-09 02:15:17 by sinsi
Dear Sinsi,

thanks 4 the reply!! :D

yaya..i had include it..and it realy works!!
now it has the time output display..

actually this is the first time im using MASM!!
it took me 1week to learn all d basic stuff!!

do u think this program can be use to measure RAM(memory) speed accurately?


Posted on 2007-05-09 02:34:01 by wogok
I think that the clock only goes 1.19MHz whereas memory is in the nanosecond range, so...nope
Maybe someone can refute this?
Posted on 2007-05-09 05:20:16 by sinsi
This would probably work.

;  INT 15h,  86h (134)      Wait                                XT-286, AT
;
;    Waits a specified number of microseconds before returning control to
;    the caller.
;
;      On entry:      AH        86h
;                      CX:DX      Number of microseconds to elapse
;
;      Returns:      Carry      Set if error or wait in progress, else
;                                cleared
;
;      Notes:        This service is not available for the PC, PCjr, and
;                      the XT.
;
;                      The real-time clock is used to count the number of
;                      microseconds.
;
;      The granularity of the time is 976 microseconds. (1/1000 second)
;                    1,000,000 microseconds = 1 second
Posted on 2007-05-09 20:50:45 by skywalker
Dear skywalker,

i dont really catch the meaning... :shock:
mayb can u xplain a little bit more...

anyway, thanks ya!!!  :D
Posted on 2007-05-09 21:03:00 by wogok