Announcement

Collapse

New Sub-Forum

In an effort to help make sure there are appropriate categories for topics of discussion that are happening, there is now a sub-forum for databases and database programming under Special Interest groups. Please direct questions, etc., about this topic to that sub-forum moving forward. Thank you.
See more
See less

Interrupt + String Parameter = Crash ???

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

  • Interrupt + String Parameter = Crash ???

    Recently I ran into a quite strange bug which I will try to describe
    below, hoping that somebody will be able to explain it to me.
    I started developing a procedure which displays a red blinking cursor
    in SCREEN 12, hooking up interrupt &H1C. (I used the code posted in
    the source code section of this forum which connects an interrupt
    to PB code.)
    The procedure itself worked fine, but the problem started when I
    combined it with a procedure which accepts string parameters. Under
    Windows98, the program shuts down and I get a message: "This program
    attempted to execute an invalid instruction." In DOS mode, the system
    freezes and I have to reboot.
    When tracing the program line by line, the error ocurred upon the
    very last "END SUB" statement executing. The alert shown by Windows
    indicated as error location the address 0001:6E0C. The offset value
    (6E0C) was exactly the value of the CS register in the PB watch
    window when debugging the program. This causes me to think that
    something in this code is altering the stack, so that the segment
    value is popped off in place of the offset value when returning from
    the SUB. (This is only my assumption; I do not have enough knowledge
    to find out what exactly caused the error.)
    I tried to isolate the bug in a relatively small amount of code,
    which follows below. (This code does not do something very
    meaningful apart from reproducing the mentioned error; the original
    program was much longer of course.)

    There was NO ERROR when I made ONLY ONE out of the following changes:
    - when leaving out the "csrshow" call in SUB "stringtest"
    - when leaving out the whole SELECT CASE block in SUB "stringtest".
    - when leaving out any single other line in this SUB, except
    "FOR...NEXT" and "PRINT char".
    - even when I changed the parameter string in the "stringtest" call
    (e.g. "This is only a small text" instead of "This is only a small
    line"), while the rest of the code remained the same.
    Strange, not?
    I tried it on two different systems, one under Windows98, another under
    Windows95 (and also in DOS mode), the result was the same.

    I would be very thankful if somebody could give me an explanation
    about this strange bug, so I would know how to prevent this problem.

    Hans Ruegg.


    Code follows:
    '=================================================================
    $ERROR ALL ON
    DEFINT A-Z

    DECLARE SUB csrinit ()
    DECLARE SUB csrend ()
    DECLARE SUB csrshow (BYVAL x1??, BYVAL y1??)
    DECLARE SUB csrhide ()
    DECLARE SUB csrint ()
    DECLARE SUB stringtest (txt$)

    SCREEN 12
    LINE (10,10)-(630,470), 3, BF
    stringtest "This is only a small line"
    SCREEN 0
    END

    '============ This is the test SUB which produces the error. ===============
    SUB stringtest (txt$)
    csrinit
    FOR ch = 1 TO 80
    IF ch > LEN(txt$) THEN EXIT FOR 'When commenting out either this line
    char = ASCII(txt$, ch) 'OR this one, no error occurs.
    PRINT char;
    SELECT CASE char 'When commenting out this SELECT block,
    CASE 174: COLOR 14 'no error occurs.
    CASE 175: COLOR 12
    END SELECT
    NEXT ch
    csrshow 400, 150
    LOCATE 25,1: PRINT "Press any key to continue - or to crash"
    DO: m$=INKEY$: LOOP WHILE m$="" 'When commenting out this loop,
    'no error occurs.
    csrend
    END SUB

    '========== Following SUBs are for the graphic cursor. ======================

    SUB csrinit () 'Initializes the interrupt
    DIM cx1 AS SHARED WORD
    DIM cy1 AS SHARED WORD
    DIM cflag AS SHARED BYTE
    DIM scrs?(12)
    cflag=0: cx1=0: cy1=0 'Initialize cursor to coordinates (0,0)
    GET (0,0)-(7,1), scrs? 'Save screen area under the cursor
    DEF SEG = VARSEG(scrs?(0)) 'Copy this array
    buf$ = PEEK$(VARPTR(scrs?(0)),12) 'to the area reserved
    DEF SEG = CODESEG(Scrsave) 'in the code segment
    POKE$ CODEPTR(Scrsave), buf$
    DEF SEG
    ! MOV WORD CS:SaveDS, DS 'Save PowerBasic DS for the Interrupt handler
    DEF SEG = 0
    OldOff = PEEKI(&H70) 'Save old Interrupt Vector (Int. &H1C)
    OldSeg = PEEKI(&H72)
    ! CLI
    POKEL &H70, CODEPTR32(CsrISR) 'Set new Interrupt Vector
    ! STI
    DEF SEG
    ! PUSH AX ;Copy old Vector to the area
    ! MOV AX, OldOff ;reserved in the code segment
    ! MOV WORD CS:OldO, AX
    ! MOV AX, OldSeg
    ! MOV WORD CS:OldS, AX
    ! POP AX
    END SUB

    SUB csrend () 'Restores the original Int &H1C handler
    ! PUSH AX
    ! PUSH BX
    ! PUSH ES
    ! MOV AX, WORD CS:OldO
    ! MOV BX, 0
    ! MOV ES, BX
    ! MOV BX, &H70
    ! CLI
    ! MOV WORD ES:[BX], AX
    ! MOV AX, WORD CS:OldS
    ! MOV WORD ES:[BX+2], AX
    ! STI
    ! POP ES
    ! POP BX
    ! POP AX
    END SUB

    SUB csrshow (BYVAL x1??, BYVAL y1??) 'Makes the cursor visible
    DIM cx1 AS SHARED WORD 'at given coordinates
    DIM cy1 AS SHARED WORD
    DIM cflag AS SHARED BYTE
    DIM scrs?(12)
    IF x1??>632 OR y1??>478 THEN EXIT SUB '(Cursor outside screen area)
    ! CLI
    GET (x1??,y1??)-(x1??+7,y1??+1), scrs? 'Save screen area
    DEF SEG = VARSEG(scrs?(0)) 'at cursor location
    buf$ = PEEK$(VARPTR(scrs?(0)),12)
    DEF SEG = CODESEG(Scrsave)
    POKE$ CODEPTR(Scrsave), buf$
    DEF SEG
    cx1 = x1??: cy1 = y1??: cflag = 2 'Set new coordinates
    ! STI
    END SUB

    SUB csrhide () 'Hides the cursor while the
    DIM cx1 AS SHARED WORD 'interrupt handler remains active
    DIM cy1 AS SHARED WORD
    DIM cflag AS SHARED BYTE
    DIM scrs?(12)
    ! CLI
    DEF SEG = CODESEG(Scrsave)
    buf$ = PEEK$(CODEPTR(Scrsave),12)
    DEF SEG = VARSEG(scrs?(0))
    POKE$ VARPTR(scrs?(0)), buf$
    DEF SEG 'Restore screen area
    PUT (cx1,cy1), scrs?, PSET 'at cursor location
    cflag=0
    ! STI
    END SUB

    SUB csrint () 'Cursor interrupt handler
    DIM ISRStack AS STATIC STRING*2048
    DIM scrs(12) AS STATIC BYTE
    DIM ccounter AS STATIC BYTE
    DIM cx1 AS SHARED WORD
    DIM cy1 AS SHARED WORD
    DIM cflag AS SHARED BYTE

    Scrsave: '12 bytes to save screen area
    ! DD 0 ;at cursor location
    ! DD 0 ;(8x2 pixels)
    ! DD 0
    OldO:
    ! DW 0 ;Variable: Old Handler offset
    OldS: 'and segment
    ! DW 0
    SaveDS: 'Variable: saves PB Data Segment
    ! DW 0
    SaveSS: 'Variable: saves PB Stack Segment
    ! DW 0
    SaveSP: 'Variable: saves PB Stack Pointer
    ! DW 0

    CsrISR: 'Interrupt handler starts here
    ! PUSH AX
    ! PUSH BX
    ! PUSH CX
    ! PUSH DX
    ! PUSH SI
    ! PUSH DI
    ! PUSH BP
    ! PUSH DS
    ! PUSH ES
    ! PUSHF
    ! CLI
    ! CLD

    ! MOV WORD CS:SaveSS, SS ; Save PB environment
    ! MOV WORD CS:SaveSP, SP

    ! MOV DS, WORD CS:SaveDS
    ! MOV SS, WORD CS:SaveDS ; Set up local stack frame
    ! LEA BX, ISRStack
    ! ADD BX, 2048
    ! MOV SP, BX

    IF cflag=2 THEN 'Cursor location has changed
    DEF SEG = CODESEG(Scrsave) '-> copy saved screen area
    buf$ = PEEK$(CODEPTR(Scrsave),12) 'in an array to be used by PUT
    DEF SEG = VARSEG(scrs(0))
    POKE$ VARPTR(scrs(0)), buf$
    DEF SEG
    cflag=1
    END IF
    IF cflag=0 THEN GOTO nocursor 'Cursor invisible, do nothing
    INCR ccounter
    IF (ccounter AND &H7F) >= 8 THEN
    IF (ccounter AND &H80) = 0 THEN 'cursor is off
    GET (cx1,cy1)-(cx1+7,cy1+1), scrs '-> save screen area at cursor
    DEF SEG = VARSEG(scrs(0)) ' location...
    buf$ = PEEK$(VARPTR(scrs(0)),12)
    DEF SEG = CODESEG(Scrsave)
    POKE$ CODEPTR(Scrsave), buf$
    DEF SEG
    LINE (cx1,cy1)-(cx1+7,cy1+1), 12, BF '...and turn cursor on
    ccounter = &H80
    ELSE 'cursor is on
    PUT (cx1,cy1), scrs, PSET '-> turn cursor off by restoring
    ccounter=0 ' the original screen
    END IF
    END IF

    nocursor:
    ! MOV SP, WORD CS:SaveSP ; Cleanup at end
    ! MOV SS, WORD CS:SaveSS
    ! POPF
    ! POP ES
    ! POP DS
    ! POP BP
    ! POP DI
    ! POP SI
    ! POP DX
    ! POP CX
    ! POP BX
    ! POP AX
    ! JMP DWORD CS:OldO
    ! STI
    ! IRET

    END SUB


Working...
X