Catching errors

From BeebWiki
Jump to: navigation, search

Normally, if you call a routine, such as an MOS entry point, if an error occurs, the error handler on BRKV is jumped to. ARM, 32016 and PDP11 systems allow you to call a routine and have an error status returned to the calling program instead of an error being generated, for instance:

   ; ARM                 ; 32016              ; PDP-11
   SWI "XOS_CLI"         SVC OS_CLI           EMT OS_CLI
   BVS  error_occured    BFS error_occured    BVS error_occured

The following code allows you to do exactly the same on the 6502.

   brkv=&202:zp=&A8
   
   \ xos_call - call inline address, catching any returned error
   \ ===========================================================
   \ Called with
   \   JSR  xos_call
   \   EQUW dest
   \ On entry, A,X,Y hold entry parameters
   \ On exit,  V clear - no error, A,X,Y,P hold return parameters
   \           V set   - error, A=ERR, &FD=>error block
   \
   .xos_call
   PHA:TXA:PHA                     :\ Stack holds X, A, main
   LDA brkv+1:PHA:LDA brkv+0:PHA
   LDA oldSP:PHA:TSX:STX oldSP     :\ Stack holds oldSP, oldbrkv, X, A, main
   LDA #error DIV 256:STA brkv+1   :\ Redirect BRKV
   LDA #error AND 255:STA brkv+0
   LDA #(return-1)DIV 256:PHA
   LDA #(return-1)AND 255:PHA      :\ Stack return address
   PHA:PHA:PHA:PHA                 :\ Make space to hold dest and X, A
   LDA zp+1:PHA:LDA zp:PHA:CLC     :\ Save zp workspace
   LDA &106,X:STA zp:ADC #2:STA &106,X     :\ Get mainline address and step
   LDA &107,X:STA zp+1:ADC #0:STA &107,X   :\ past inline dest address
   TYA:PHA:TSX                     :\ Save Y, get new SP
   LDY #2:LDA (zp),Y:STA &107,X
   DEY:LDA (zp),Y:STA &106,X       :\ Copy inline address to stack
   LDA &10E,X:STA &105,X           :\ Copy A to top of stack
   LDA &10D,X:STA &104,X           :\ Copy X to top of stack
   :
   \ Stack holds Y, zp, X, A, dest, return, oldSP, oldbrkv, X, A, main
   :
   PLA:TAY:PLA:STA zp:PLA:STA zp+1 :\ Restore Y and zp workspace
   PLA:TAX:PLA:PHP:RTI             :\ Restore X, A, jump to stacked dest addr
   :
   .return                         :\ Stack holds oldSP, oldbrkv, X, A, main
   PHA:TXA:TSX                     :\ Stack A
   STA &105,X:PLA:STA &105,X       :\ Copy X, A to top of stack
   PLA:STA oldSP                   :\ Restore oldSP
   PLA:STA brkv+0:PLA:STA brkv+1   :\ Restore BRKV
   PLA:TAX:PLA:RTS                 :\ Get returned X, A and return to main
   :
   .error
   LDX oldSP:TXS:PLA:STA oldSP     :\ Restore oldSP
   PLA:STA brkv+0:PLA:STA brkv+1   :\ Restore BRKV
   PLA:PLA:LDY #0:LDA (&FD),Y      :\ Drop X, A, get error number
   BIT P%-1:RTS                    :\ Set V from inline &FD byte and return
   :
   .oldSP
   EQUB 0                          :\ Saved stack pointer

As an example, the following call tries to do BGET#0 which raises a "Channel" error. Catching the error returns the error with V set, A=222 and &FD pointing to the error block.

   LDY  #0
   JSR  xos_call
   EQUW OSBGET

Calls to xos_call can recursively call xos_call again. Each call takes 8 bytes on the stack, and initially needs 16 bytes free.

See also