; Crt Correction 1.2
; by Thomas Lack¢, http://togye.host.sk
IDEAL
MODEL LARGE,PASCAL
P386

DATASEG
  extrn OldDivError:dword
  extrn Per1ms:dword,Seg0040:word
  Sec100Minus=15
  MinDOSTime=500

CODESEG
public TestCPUType,TestCPUSpeed,Delay,XDelay,NewDivError

macro inc2 Reg
  dec  Reg
  dec  Reg
endm

proc TestCPUType near ; function:Byte
  mov  bx,sp
  and  sp,not 3
  pushfd
  pop  eax
  mov  edx,eax
  xor  eax,240000h ; flags AC & ID
  push eax
  popfd
  pushfd
  pop  eax
  push edx
  popfd
  mov  sp,bx
  xor  eax,edx
  test eax,40000h
  jz   @@386 ; couldn't change AC flag -> 386
  test eax,200000h
  jz   @@486 ; couldn't change ID flag -> 486
  xor  eax,eax
  inc  eax
  db   0Fh,0A2h ; CPUID
  and  ah,0Fh
  dec  ah
  mov  al,ah
  cmp  al,4
  jb   @@586
  ret
@@586:
  mov  al,4
  ret
@@386:
  mov  al,2
  ret
@@486:
  mov  al,3
  ret
endp

proc Wait1ms near ; ES:DI ® timer, BL ® timer, DX:AX ®/¯ ñloops
  sub  ax,1
  sbb  dx,0
  db 72h,5 ; jc 5
  cmp  bl,[es:di]
  je   Wait1ms
  ret
endp

proc TestCPUSpeed
  mov  es,[Seg0040]
  mov  di,6Ch
  mov  ax,-1
  cwd
  mov  bl,[es:di]
@@wait:
  cmp  bl,[es:di]
  je   @@wait
  inc  bl
  call Wait1ms
  shl  eax,16
  shrd eax,edx,16
  xor  edx,edx
  neg  eax
  dec  eax
  xor  ecx,ecx
  mov  cl,55
  div  ecx
  mov  [Per1ms],eax
  ret
endp

proc Delay  ms:word
proc XDelay ms:word
local H:byte,M:byte,S:byte,X:byte
  mov  cx,[ms]
  jcxz @@exit1
  cmp  cx,MinDOSTime
  jae  @@dostime
  mov  es,[Seg0040]
  xor  di,di
  mov  bl,[es:di]
@@wait:
  mov  ax,[word ptr Per1ms]
  mov  dx,[word ptr Per1ms+2]
  call Wait1ms
  loop @@wait
@@exit1:
  ret
@@dostime: ; time checking through DOS
  mov  ah,2Ch
  int  21h
  mov  [H],ch
  mov  [M],cl
  mov  [S],dh
  mov  [X],dl
  ; time to reach
  mov  ax,[ms]
  sub  ax,Sec100Minus
  xor  dx,dx
  mov  cx,10
  div  cx
  add  al,[X]
  adc  ah,0
  mov  cl,100
  div  cl
  mov  [X],ah
  cbw
  add  al,[S]
  mov  cl,60
  div  cl
  mov  [S],ah
  cbw
  add  al,[M]
  div  cl
  mov  [M],ah
  add  [H],al
  mov  ah,2Ch
@@again: ; loop until reached
  int  21h
  cmp  [H],24
  jb   @@nc
  add  ch,24
@@nc:
  cmp  [H],ch
  jb   @@exit2
  ja   @@again
  cmp  [M],cl
  jb   @@exit2
  ja   @@again
  cmp  [S],dh
  jb   @@exit2
  ja   @@again
  cmp  [X],dl
  ja   @@again
@@exit2:
  ret
endp
endp

proc NewDivError ; INT 0 handler for run-time error 200
  push bp
  mov  bp,sp
  push es bx
  les  bx,[bp+2]
  cmp  [word ptr es:bx],0F1F7h ; caused by "div cx"
  je   @@catched
  pop  bx es bp
  jmp  [OldDivError] ; jump to original handler
@@catched:
  add  [word ptr bp+2],2 ; change return address (jump through div)
  cmp  [OldDivError],0
  je   @@restored
  push ds dx
  mov  ax,2500h
  lds  dx,[OldDivError]
  int  21h ; restore original handler
  pop  dx ds
  xor  eax,eax
  mov  [OldDivError],eax
@@restored:
  pop  bx es bp
  mov  ax,0FFFFh ; division result (max)
  iret
endp

END