📄 txtdeb.asm
字号:
TITLE txtdeb.asm - Text Mgr's Debugger support
;==========================================================================
;
; Module: txtdeb.asm - Text Mgr's Debugger support
; System: Quick BASIC Interpreter
;
;=========================================================================*/
.xlist
include version.inc
TXTDEB_ASM = ON
includeOnce architec
includeOnce context
includeOnce heap
includeOnce lister
includeOnce opcontrl
includeOnce opid
includeOnce opmin
includeOnce opstmt
includeOnce opintrsc
IncludeOnce opaftqb4
includeOnce parser
includeOnce pcode
includeOnce qbimsgs
includeOnce scanner
includeOnce txtint
includeOnce txtmgr
includeOnce ui
.list
EXTRN B$SASS:FAR
assumes DS,DATA
assumes SS,DATA
assumes ES,NOTHING
sBegin DATA
PUBLIC cWatch
cWatch DW 0 ;number of Watch expressions in system
pWatch DW 0 ;used during WatchInfo
fWatchBuild DB 0 ;non-zero if tWatch contains out-of-date info
;Watch table contains 1 entry for every watch expression/watchpoint
WT_ST STRUC
WT_oRs DW 0 ;identifies text table with watch expression
WT_otxStart DW 0 ;text offset to start of watch expression
WT_otxEnd DW 0 ;text offset to end of watch expression
WT_filler DB 0 ;WT_value needs to be even byte aligned
WT_valTyp DB 0 ;type of value
WT_value DB 8 DUP(?) ;holds R8,R4,I4,I2, or SD
WT_ST ENDS
EVEN
;runtime needs string descriptors on even byte boundaries.
tWatch DB (WATCH_MAX+1) * SIZE WT_ST DUP(0) ; "+1" is for instant watch
tWatchEnd LABEL WORD
sEnd DATA
sBegin CODE
;These opcodes mark the start and end of WATCH expressions
;
PUBLIC tOpWatch
tOpWatch LABEL WORD
opTabStart W
opTabEntry W,opEndProg
opTabEntry W,opWatchExp
opTabEntry W,opWatchStop
opTabEntry W,opEot
;Table of all the opcodes (1) that are opBreakPoint
;
tOpBp LABEL WORD
opTabStart BP
opTabEntry BP,opBreakPoint
opTabEntry BP,opEot
;These opcodes can cause screen I/O
; opcodes opPrintSpc opPrintTab opPrintComma opPrintSemi opPrintEos
; opPrintItemComma opPrintItemSemi and opPrintItemEos are all caught
; by executors, so we don't cause screen flicker on File I/O.
;
; END/EXIT FUNCTION/DEF can cause I/O if their caller included
; the function invocation within any I/O stmt, i.e.
; PAINT (x,y),FNx
; This causes screen flicker for every END/EXIT DEF/FUNCTION/SUB but
; fNextStmtDoesIO() would have to add a lot of slow special-case code
; to catch the cases where the function was not within an I/O stmt.
;
;Certain control structure opcodes must also be included in the
;list since they branch past the bol/bos of other statements
;which may contain I/O opcodes.
tOpIO LABEL WORD
opTabStartAll IO
opTabEntry IO,opStElseLabDirect
;The reason EndDef, EndProc, ExitProc are listed here is
;for the case when the user does something like:
; PAINT (x,y),FNx(z)
opTabEntry IO,opStEndDef
opTabEntry IO,opEndSingleDef
opTabEntry IO,opStEndProc
opTabEntry IO,opStExitProc
opTabEntry IO,opStGotoDirect
opTabEntry IO,opStGosubDirect
opTabEntry IO,opStRunMain
opTabEntry IO,opStRunLabel
opTabEntry IO,opStBload1
opTabEntry IO,opStBload2
opTabEntry IO,opStCircle
opTabEntry IO,opStCircleColor
opTabEntry IO,opStCls
opTabEntry IO,opStColor
opTabEntry IO,opStDraw
opTabEntry IO,opStFiles0
opTabEntry IO,opStFiles1
opTabEntry IO,opStGraphicsGet
opTabEntry IO,opStGraphicsPut
opTabEntry IO,opStInput
opTabEntry IO,opStKey
opTabEntry IO,opStKeyMap
opTabEntry IO,opStLine
opTabEntry IO,opStLineColor
opTabEntry IO,opStLineStyle
opTabEntry IO,opStLineStyleColor
opTabEntry IO,opStLineInput
opTabEntry IO,opStLocate
opTabEntry IO,opStPaint2
opTabEntry IO,opStPaint3
opTabEntry IO,opStPalette0
opTabEntry IO,opStPalette2
opTabEntry IO,opStPaletteUsing
opTabEntry IO,opStPoke
opTabEntry IO,opStPreset
opTabEntry IO,opStPresetColor
opTabEntry IO,opStPset
opTabEntry IO,opStPsetColor
opTabEntry IO,opStRandomize1
opTabEntry IO,opStScreen
opTabEntry IO,opStShell0
opTabEntry IO,opStShell1
opTabEntry IO,opStSystem
opTabEntry IO,opStView
opTabEntry IO,opStView0
opTabEntry IO,opStViewPrint0
opTabEntry IO,opStViewPrint2
opTabEntry IO,opStViewScreen
opTabEntry IO,opStWidth2
opTabEntry IO,opStWindow
opTabEntry IO,opStWindow0
opTabEntry IO,opStWindowScreen
opTabEntry IO,opFnInkey_
opTabEntry IO,opFnInput_1
opTabEntry IO,opFnInput_2
opTabEntry IO,opFnPeek
opTabEntry IO,opFnPoint2
opTabEntry IO,opFnScreen2
opTabEntry IO,opFnScreen3
opTabEntry IO,opFnShell
opTabEntry IO,opStLoop
opTabEntry IO,opStWend
opTabEntry IO,opStNext
opTabEntry IO,opStNextId
opTabEntry IO,opStSelectCase
opTabEntry IO,opStRandomize0
opTabEntry IO,opBol
IO_bosMin EQU IO_opBol
opTabEntry IO,opBolSp
opTabEntry IO,opBolInclude
opTabEntry IO,opBolIncludeSp
opTabEntry IO,opBolLab
opTabEntry IO,opBolLabSp
opTabEntry IO,opBos
opTabEntry IO,opBosSp
opTabEntry IO,opEot
;Table of opcodes used by ToggleBp to ensure that BP line is not a
;CASE, CASE ELSE, or END CASE statement.
tOpCaseStmt LABEL WORD
opTabStart CASESTMT
opTabEntry CASESTMT,opStCase
opTabEntry CASESTMT,opStCaseTo
opTabEntry CASESTMT,opStCaseElse
opTabEntry CASESTMT,opStEndSelect
CASESTMT_CASEMAX = CASESTMT_opStEndSelect
opTabEntry CASESTMT,opBol
opTabEntry CASESTMT,opBolLab
opTabEntry CASESTMT,opBolSp
opTabEntry CASESTMT,opBolLabSp
opTabEntry CASESTMT,opBolInclude
opTabEntry CASESTMT,opBolIncludeSp
opTabEntry CASESTMT,opEot
sEnd CODE
sBegin CP
assumes cs,CP
;--------------------------------------------------------------
; BASIC Debugging support functions
;--------------------------------------------------------------
;**************************************************************
; boolean fBpSet(otxBol)
; Purpose:
; Return TRUE if indicated line has a breakpoint set.
; Entry:
; otxBol = text offset to beginning of line opcode for line
; grs.fDirect must be FALSE
; Exit:
; al = ax = non-zero if breakpoint was set
; dx = text offset to opBreakPoint, or where opBreakPoint
; could be inserted
;
;**************************************************************
cProc fBpSet,<PUBLIC,FAR>
parmW otxBol
cBegin
DbAssertRelB [grs.GRS_fDirect],e,FALSE,CP,<fBpSet: fDirect TRUE>
mov dx,[otxBol]
DbChk Otx,dx ;error if bx > txdCur.bdlText.cbLogical
;bx = otx to opcode to skip
FbSkipLoop:
xchg ax,dx ;pass otx to TxtSkipOp in ax
call TxtSkipOp ;skip opBol[Lab][Sp] (or opStSub) opcode
push ax ;save ax = otx to potential opBreakPoint
call GetDescannedOpcode ;ax = opcode at text offset ax
pop dx ;dx = otx to potential opBreakPoint
cmp ax,opNoList1
je FbSkipLoop ;brif got an opNoList1
cmp ax,opStSub
je FbSkipLoop ;brif we want to skip a SUB opcode
cmp ax,opStFunction
je FbSkipLoop ;brif we want to skip a FUNCTION opcode
cmp ax,opStDefFn
je FbSkipLoop ;brif we want to skip a DEF FN opcode
sub cx,cx ;prepare to return FALSE
cmp ax,opBreakPoint
jne FbExit ;brif breakpoint is not set
dec cx ;return TRUE
FbExit:
xchg ax,cx ;return boolean in ax
cEnd
;**************************************************************
; GetDescannedOpcode
; Entry:
; ax = text offset into current text table
; Exit:
; ax = opcode
;
;**************************************************************
GetDescannedOpcode PROC NEAR
call GetWOtx ;ax = opcode at text offset ax
cmp [txdCur.TXD_scanState],SS_EXECUTE
jne GdNotExec ;brif not scanned to SS_EXECUTE
push ax
call DescanOpcode ;ax = descanned opcode
GdNotExec:
and ah,HIGH OPCODE_MASK
ret
GetDescannedOpcode ENDP
;**************************************************************
; ToggleBp(ln)
; Purpose:
; Sets or Reset a breakpoint at the indicated line.
; For most lines, the opBreakPoint is inserted immediately
; after the opBolXXX. For SUB, FUNCTION, and DEF FNs,
; the opBreakPoint is inserted immediately after the
; opStSub/Function/DefFn opcode so when the procedure is
; invoked, the breakpoint will be executed.
; Exit:
; [17]if no error occurs then ax = 0 otherwise
; [17] ax = txtErr.errcode = error code
; cBreakpoints - Incremented or decremented.
;
;**************************************************************
cProc ToggleBp,<PUBLIC,FAR>,<si>
parmW ln
cBegin
call TxtDescanCP
push [ln]
call OtxOfLn ;ax = text offset to start of line
cCall fBpSet,<ax> ;ax = 0 if line has no breakpoint
mov si,dx ;si = dx = otx to opBreakPoint
or ax,ax
jne TglBpSet ;brif breakpoint is set
;if target statement of break point is CASE, CASE ELSE, or END SELECT
;then report an error
push si
PUSHI ax,<CODEOFFSET tOpCaseStmt>
call TxtFindOp ;dl = txtFindIndex
cmp dl,CASESTMT_CASEMAX
ja SetBp ;brif hit end of line before case
mov [txtErr.TXER_fDirect],0 ;error not in direct mode
mov [txtErr.TXER_oRs],UNDEFINED ;don't try to position cursor
mov ax,MSG_NoBpCase ;"no bp on case clause or end select"
mov [txtErr.TXER_errCode],ax
jmp SHORT TgbErrExit
SetBp:
;si = text offset to where BreakPoint is to be inserted
;make room for new breakpoint opcode by copying old text up in memory
;
push si
PUSHI ax,2
call TxtMoveUp
je TgbExit ;return FALSE if no memory
push si
PUSHI ax,opBreakPoint
call PutWOtx ;insert breakpoint pcode in text table
;Update program counter, prs.otxDef fields for affected PRSs,
; and linked lists through this text table's pcode
mov bx,si ;bx = updated otxInsert
inc bx
inc bx ;bx = offset beyond inserted pcode
call TxtInsUpdate
jmp SHORT TgbExit
;si = text offset to breakpoint to be deleted
TglBpSet:
push si
inc si
inc si
push si
call TxtDelete
TgbExit:
xor ax,ax ;return ax = 0 for no error
TgbErrExit:
cEnd
;**************************************************************
; ClrBpAll()
; Purpose:
; Reset all breakpoints in the loaded program.
;
; Input:
; fCountBp - If fCountBp is TRUE then the breakpoints are only counted.
;
;**************************************************************
PUBLIC ClrBpTxt
ClrBpTxt PROC NEAR
push si ;save caller's si
call TxtDescanCP
sub si,si ;start at beginning of text table
CbLoop:
push si
PUSHI ax,<CODEOFFSET tOpBp>
call TxtFindOp ;ax = offset to next opBreakPoint
;dl = [txtFindIndex]
cmp dl,BP_opEot
je CbDone ;brif done with loop
xchg si,ax ;si = otxNext
push si
lea ax,[si+2] ;ax = offset beyond opBreakPoint
push ax
call TxtDelete ;delete the break point
jmp SHORT CbLoop
CbDone:
mov ax,sp ;return TRUE (non-zero)
pop si ;restore caller's si
ret
ClrBpTxt ENDP
PUBLIC ClrBpAll
cProc ClrBpAll,<FAR,PUBLIC>
cBegin ClrBpAll
mov bx,CPOFFSET ClrBpTxt
call ForEachTxtTbl
cEnd ClrBpAll
;**************************************************************
; SkipStop
; Purpose:
; If the next opcode to be executed is an opStStop
; or opBreakPoint, skip it. This is called by the
; user interface for SingleStep and GoTillCursor
; so the user doesn't have to step twice for a stmt
; that has a STOP or BREAK-POINT.
; Entry:
; grs.oRsCur, grs.otxCONT and grs.fDirect identify
; next opcode to be executed
; Exit:
; grs.otxCONT is bumped by 2 if it was opStStop or opBreakPoint
;
;**************************************************************
cProc SkipStop,<PUBLIC,FAR>
cBegin
mov ax,[grs.GRS_otxCONT]
inc ax
je DontSkipIt ;brif can't CONT
dec ax
call GetDescannedOpcode ;ax = opcode at text offset ax
cmp ax,opBreakPoint
je SkipIt
cmp ax,opStStop
jne DontSkipIt
SkipIt:
add [grs.GRS_otxCONT],2
DontSkipIt:
cEnd
;Table of opcodes skipped over while tracing
tNops LABEL WORD
DW opLabSp ; Moved these 2 to start of table
DW opLab ; to make special case easier.
DW opStConst
DW opStData
DW opStDeclare
DW opStDefType
DW opStRem
DW opQuoteRem
DW opStShared
DW opStStatic
DW opStType
DW opStEndType
DW op_Static
DW op_Dynamic
DW op_Include
DW opBol
DW opBolSp
DW opBolInclude
DW opBolIncludeSp
DW opBolLab
DW opBolLabSp
DW opBos
DW opBosSp
DW opEndProg
CW_TNOPS EQU ($-tNops) SHR 1
;**************************************************************
; boolean FAR FExecutable()
; Purpose:
; Called by User Interface code to determine if we need to
; show the tracing of the next statement.
;
; WARNING !!! WARNING !!! WARNING !!! WARNING !!! WARNING
;
; Slime. This routine is currently only called from
; DebugTrace to determine whether or not we should stop
; on the current line. For this case we need to skip past
; opLab[Sp] so we recognize that we need to break on lines
; like "10 foo: print" or on included lines with line #'s
; (which get opBolInclude + opLab). If this routine is
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -