[Back to TSR SWAG index] [Back to Main SWAG index] [Original]

    {
    > I would like to include a clock in my current project which will be
    > updated once a minute.  Instead of constantly checking the computer's clock
    > and waiting for it to change, I would like to use an interrupt.

    This one has even a hot key handler.  If you want to update it once per
    minute, bump a counter within the interrupt 1Ch handler till it reaches the
    value 60*18.2.  Then refresh the screen.
    }

    Program Clock;

    {$G+,R-,S-,M 1024, 0, 0 }

    uses
      Dos;

    Const
      x           = 71;                   { x location on screen }
      y           = 1;                    { y location on screen }
      Keyboard    = 9;                    { Hardware keyboard interrupt }
      TimerTick   = $1C;                  { Gets called 18.2 / second }
      VideoOffset = 160 * (y - 1) + 2 * x;{ Offset in display memory }
      yellow      = 14;
      blue        = 1;
      attribute   = blue * 16 + yellow;   { Clock colours }
      VideoBase   : Word = $B800;         { Segment of display memory }
      ActiveFlag  : ShortInt = -1;        { 0: on, -1: off }

    Var
      OrgInt9,                             { Saved interrupt 9 vector }
      OrgInt1Ch : Pointer;              { Saved interrupt 1Ch vector }
      VideoMode : Byte absolute $0000:$0449;

    { Display a string using Dos services (avoid WriteLn, save memory) }

    Procedure DisplayString(s : String); Assembler;

    ASM
      PUSH   DS
      XOR    CX, CX
      LDS    SI, s
      LODSB
      MOV    CL, AL
      JCXZ   @EmptyString
      CLD
     @NextChar:
      LODSB
      XCHG   AX, DX
      MOV    AH, 2
      INT    21h
      LOOP   @NextChar
     @EmptyString:
      POP    DS
    end;

    { Returns True if a real time clock could be found }
    Function HasRTClock : Boolean; Assembler;

    ASM
      XOR    AL, AL
      MOV    AH, 2
      INT    1Ah
      JC     @NoRTClock
      INC    AX
     @NoRTCLock:
    end;

    { Release Dos environment }
    Procedure ReleaseEnvironment; Assembler;
    ASM
      MOV    ES, [PrefixSeg]
      MOV    ES, ES:[002Ch]
      MOV    AH, 49h
      INT    21h
    end;

    { INT 9 handler intercepting Alt-F11 }
    Procedure ToggleClock; Interrupt; Assembler;
    Const
      F11      = $57;                  { 'F11' make code }
      BiosSeg  = $40;                  { Segment of BIOS data area }
      AltMask  = $08;                  { Bitmask of Alt key }
      KbdFlags = $17;                  { Byte showing keyboard status }

    ASM
      STI
      IN     AL, 60h

     { F11 pressed? }
      CMP    AL, F11
      JNE    @PassThru

     { Alt-key pressed? }
      PUSH   BiosSeg
      POP    ES
      MOV    AL, ES:[KbdFlags]
      AND    AL, AltMask
      CMP    AL, AltMask
      JNE    @PassThru

     { Flip status flag, force EOI and leave routine }
      NOT    [ActiveFlag]
      IN     AL, 61h
      MOV    AH, AL
      OR     AL, 80h
      OUT    61h, AL
      MOV    AL, AH
      OUT    61h, AL
      CLI
      MOV    AL, 20h
      OUT    20h, AL
      STI
      JMP    @Exit

     @PassThru:
      CLI
      PUSHF
      CALL   DWord Ptr [OrgInt9]
     @Exit:
    end;  { ToggleClock }

    { Convert a packed BCD byte to ASCII character }
    Procedure Digit; Assembler;
    ASM
      PUSH   AX
      CALL   @HiNibble
      POP    AX
      CALL   @LoNibble
      RETN

     @HiNibble:
      SHR    AL, 4
      JMP    @MakeAscii
     @LoNibble:
      AND    AL, 0Fh
     @MakeAscii:
      OR     AL, '0'
      STOSW
    end;

    { INT 1Ch handler that displays a clock on the right hand side of the screen }
    Procedure DisplayClock; Interrupt; Assembler;
    ASM
      CMP    [ActiveFlag], 0
      JNE    @Exit
      CLD
      MOV    AH, 2
      INT    1Ah
      MOV    ES, [VideoBase]
      MOV    DI, VideoOffset
      MOV    AH, attribute
      MOV    AL, CH
      CALL   Digit
      MOV    AL, ':'
      STOSW
      MOV    AL, CL
      CALL   Digit
      MOV    AL, ':'
      STOSW
      MOV    AL, DH
      CALL   Digit
      PUSHF
      CALL   DWord Ptr [OrgInt1Ch]
     @Exit:
    end;

    Begin
      If VideoMode = 7 Then
        VideoBase := $B000;
      GetIntVec(TimerTick, OrgInt1Ch);
      SetIntVec(TimerTick, @DisplayClock);
      GetIntVec(Keyboard, OrgInt9);
      SetIntVec(Keyboard, @ToggleClock);
      SwapVectors;
      ReleaseEnvironment;
      DisplayString('CLOCK installed.  <Alt-F11> toggles on/off');
      Keep(0);
    end.

[Back to TSR SWAG index] [Back to Main SWAG index] [Original]