Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

PB/DOS: Clock in the Corner using a BASIC ISR

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • PB/DOS: Clock in the Corner using a BASIC ISR

    Code:
    '==============================================================================
    '
    '  ISR Test Code for PB/DOS
    '  Donated to the Public Domain
    '
    '  Original concept and some code by Alan Earnshaw ([email protected])
    '  Perfected (grin) by Dave Navarro, Jr. ([email protected])
    '
    '  This example shows how to write an Interrupt Service Routine (ISR) using
    '  Basic code with only enough assembler to set things up.
    '
    '==============================================================================
     
    ClockOn
     
    SLEEP
     
    ClockOff
     
    SUB ClockOn()
     
      DIM OldAddr AS SHARED DWORD
     
      ! mov  Word Ptr CS: SaveDS, DS   ;store PowerBASIC Data segment
     
      GetInterruptVector &H1C, OldAddr
      SetInterruptVector &H1C, CODEPTR32(ClockISR)
     
    END SUB
     
    SUB ClockOff()
     
      DIM OldAddr AS SHARED DWORD
     
      SetInterruptVector &H1C, OldAddr
     
    END SUB
     
    SUB SetInterruptVector(BYVAL Intr?, BYVAL NewAddr???) LOCAL
      ! push ds            ; save DS
      ! mov ah, &H25       ; set AH to 25h (function number)
      ! mov al, Intr?      ; set AL to interrupt vector being redirected
      ! lds DX, NewAddr???
      ! int &H21           ; call DOS services
      ! pop ds             ; restore DS
    END SUB
     
    SUB GetInterruptVector(BYVAL Intr?, VAddr???) LOCAL PUBLIC
      ! push ds            ; save DS
      ! push si            ; save SI
      ! mov ah, &H35       ; set AH to 35h (function number)
      ! mov al, Intr?      ; set AL to interrupt vector
      ! int &H21           ; call DOS services (ES:BX now holds address)
      ! lds si, VAddr???   ; get a pointer to VSeg??
      ! mov ds:[si+2], es  ; copy ES (segment address) into VSeg??
      ! mov ds:[si], bx    ; copy BX (offset address) into VOff??
      ! pop si             ; restore SI
      ! pop ds             ; restore DS
    END SUB
     
    SUB ISR () PRIVATE
     
      DIM IsrStack AS STATIC STRING * 1024  '1k stack (probably too much)
      DIM Counter AS STATIC INTEGER
     
    SaveDS:
      ! dw 0
    SaveSS:
      ! dw 0
    SaveSP:
      ! dw 0
     
    ClockISR:
      ! push ax                       ; save the general registers
      ! push bx
      ! push cx
      ! push dx
      ! push si
      ! push di
      ! push bp
      ! push ds
      ! push es
      ! push bp
      ! pushf                         ; save the flags register
      ! cli                           ; suspend all maskable interrupts
     
      ! mov Word Ptr CS:SaveSS, SS    ; save current stack segment
      ! mov Word Ptr CS:SaveSP, SP    ; save current stack pointer
      ! mov DS, Word Ptr CS:SaveDS    ; restore PowerBASIC data segment
     
      ' Create a local stack frame
      ! mov SS, Word Ptr CS:SaveDS    ; SS must equal DS for PowerBASIC runtime
      ! lea BX, IsrStack              ; get address of the local stack frame
      ! add BX, 1024                  ; point to the end of the fixed-length string
      ! mov SP, BX                    ; set the stack pointer
     
    ' ** Your Basic code goes here **
     
      IF Counter = 0 THEN
        LOCATE 1, 72, 0
        COLOR 14,0
        PRINT TIME$;
        Counter = 18      '18 ticks per second
      END IF
      DECR Counter
     
    ' ** End of Basic code
     
      ! mov SP, Word Ptr CS:SaveSP ; restore the original stack segment
      ! mov SS, Word Ptr CS:SaveSS ;  and stack pointer before restoring the registers
     
      ! popf               ; restore the flags register
      ! pop bp             ; restore the general registers
      ! pop es
      ! pop ds
      ! pop bp
      ! pop di
      ! pop si
      ! pop dx
      ! pop cx
      ! pop bx
      ! pop ax
      ! sti                ; re-enable maskable interrupt processing
      ! iret               ; return from our interrupt handler
     
    END SUB

    -------------
    PowerBASIC Support
    mailto:[email protected][email protected]</A>

    Home of the BASIC Gurus
    www.basicguru.com

  • #2
    The PowerBASIC runtime library is not reentrant. The above code may
    appear to work for a while, but it will inevitably crash, or worse.
    It is not possible to safely use BASIC code inside a hardware interrupt
    handler.

    ------------------
    Tom Hanlin
    PowerBASIC Staff

    Comment


    • #3
      For some reason, my computer doesn't realize that it's supposed to crash.

      I started this code yesterday afternoon at 1:30pm after reading your reply and almost 13 hours later it's still running just fine.

      I do know from talks with Bob that you are 100% correct about the PowerBASIC runtime not being re-entrant, however, with proper care this technique has worked just fine for myself and lots of other PB programmers who have used it since Alan and I first came up with it.

      Extreme Caution is definitely advised, but there's no need to cause a panic.

      --Dave


      ------------------
      Home of the BASIC Gurus
      www.basicguru.com
      Home of the BASIC Gurus
      www.basicguru.com

      Comment


      • #4
        "Proper care" would mean writing it wholly in assembly, without reference to any BASIC runtime library support. At some point, your code is guaranteed to crash: maybe sooner, maybe later, but always. Now, let's keep the discussions out of the Source Code forum, please: take it to PB/DOS if you have more to say.

        ------------------
        Tom Hanlin
        PowerBASIC Staff

        Comment

        Working...
        X