1

I am trying to write a procedure that will stop the execution for n*55ms by using the INT 08h, but I haven't been able to find anything useful so far.
How do I use this interrupt?

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
Konrad Nosal
  • 51
  • 1
  • 3

3 Answers3

2

The basic idea would be to get the existing IVT entry for this interrupt (the four bytes at 0x000:0x0020) and save them somewhere, then replace those four bytes with the segment and offset of your interrupt handler. Your interrupt handler will be called 18.2 times per second, and your interrupt handler should "jump far" to the old interrupt handler (using the four bytes you saved initially).

When you are done (e.g. if/when your program exits back to DOS or something) you'd restore the original four bytes at 0x000:0x0020.

For the n*55 ms part of it, you'd set a global variable to n+1, and your interrupt handler would decrement that global variable. When the global variable has been decremented to 0 you know that the amount of time that has passed is between n*55 ms and (n+1)*55 ms.

Note that this lack of precision is due to the variability in time between you installing your interrupt handler and the first IRQ occurring (e.g. the timer's IRQ could occur immediately after you install the interrupt handler, or up to 55 ms after you install your interrupt handler). If you wait for the first timer IRQ to occur and then let your code run for n*55 ms, you can stop your code after "exactly" n*55 ms.

Also, make sure that your interrupt handler saves any registers it uses (including segment registers) and restores them before doing the "jmp far". It is possible to decrement a value and compare with zero without using any registers (and therefore possible to avoid saving and restoring registers you use because you didn't use any). For example (NASM):

interruptHandler:
    sub word [cs:globalCounter],1
    je .counterIsZero
    jmp far [cs:oldInterruptHandler]

.counterIsZero:
Brendan
  • 35,656
  • 2
  • 39
  • 66
  • Maybe a mention of `cli/sti` together with installing own IVT value would be worth of it. Just to make sure it doesn't sound so simple as writing two values into RAM (because it is not). – Ped7g Jan 18 '17 at 07:37
2

You can read the output of int 08h through INT 1Ah, AH=0 service or directly at memory address 0040h:006C.

; cx = "n" to wait "at least n*55ms", will modify cx
DelayProcedure:
  push  ax
  push  ds
  mov   ax,40h
  mov   ds,ax

  ; make sure that the delay will take "at least n*55ms"
  ; by waiting for first incomplete (<= 55ms) tick
  mov   ax,[6Ch]
.waitFirstForOneTickHappen:
  nop
  cmp   [6Ch],ax
  je    .waitFirstForOneTickHappen

  ; remove the loop above to get "at most n*55ms" behaviour
  ; (which may be more practical for some situations, like animation syncing)

  ; wait "at most n*55ms" ticks
.waitNticks:
  mov   ax,[6Ch]
.waitForTick:
  nop
  cmp   [6Ch],ax
  je    .waitForTick
  loop  .waitNticks

  ; restore ds, ax and return
  pop   ds
  pop   ax
  ret

(I didn't debug it, just wrote it from head, so no guarantee it will work)

Plus maybe it would be nice (from power usage point of view) to put there several nops into those loops... like 4-8 of them (than again cmp+je is very likely as low-power as nop on modern x86).

Ped7g
  • 16,236
  • 3
  • 26
  • 63
  • coundn't you just simply `inc cx` instead of coding the extra loop in the beginning? – Tommylee2k Jan 18 '17 at 09:26
  • 1
    @Tommylee2k technically not (different behaviour for cx=0), practically yes. Actually practically I think the "0 to n*55ms" delay is more wanted, than "at least n*55ms", so for my own code I would remove that first loop completely... But then again, in all of my DOS apps I rather synced to Vsync, the 18.2/s ticker was not of much use for me as I was usually working with graphics, where 55ms was too long with 60Hz display. – Ped7g Jan 18 '17 at 10:00
  • 1
    logically i'd except a function that is told "sleep" for 0 x 55ms to NOT sleep 3.6 seconds (for this case I'd use 0xffff), so this change would even be a fix ;) however, wait() is a functions I never use; Imo programs that need a sleep are bad design ( this is no offense, sync'ing isn't sleeping :-P ) – Tommylee2k Jan 18 '17 at 10:40
  • 1
    @Tommylee2k ok, sounds valid all of it, I can agree (then again many questions on SO smells with "bad design", but there's no point to argue, and sometimes they may have valid reasons). At least I updated the source a bit to make it obvious that first part is sort of optional. :) – Ped7g Jan 18 '17 at 10:54
  • The original question involves "stop execution of other code after n*55ms". Spinning in a polling loop like this can't work for "stop execution of other code after n*55ms" - you'd stop the execution of that other code as soon as you begin waiting. – Brendan Jan 19 '17 at 00:17
  • Argh - misread (sorry), and this crippled website won't allow me to delete/fix my erroneous comment(!). – Brendan Jan 19 '17 at 00:23
  • @Brendan from the OP it actually feels somewhat confused, so I wouldn't be extremely surprised if you are right, but I'm sure part of it made perfect sense also as "I want delay procedure", so I posted it, just in case. It's up to OP to clear it out :). Actually I got one downvote, but if it was OP displaying "I didn't want this", then it didn't work, I have no idea and I still think this is reasonable "delay()" proc. :) – Ped7g Jan 19 '17 at 03:55
1

You can refer to Ralph Browns Interrupt List to get the relevant information for INT 08h.

Depending on your usage scenario, you can choose between two choices:

Whatever your usage scenario may be, this explains it very well.

So there are two possibilities for an occurring INT 08h - a hardware or a software interrupt. It is not clear which one you were referring to with your question.

zx485
  • 28,498
  • 28
  • 50
  • 59