title 'DDT86 1.1 10/2/81' ; ; modified 5/14/81 R. Silberstein ; modified 6/15/81 R. Silberstein ; modified 8/12/81 R. Silberstein ; modified 9/6/81 R. Silberstein ; modified 9/16/81 R. Silberstein ; modified 10/1/81 R. Silberstein ; ; ; ***************************************** ; * * ; * D D T 8 0 8 6 - 8 0 8 8 * ; * * ; ***************************************** ; debug equ 00h ;if set, use direct bios calls for console io ; ddt_org equ 100h ;origin of this module lasmorg equ ddt_org+1300h ;origin of disassembler asmorg equ ddt_org+2200h ;origin of assembler ; cseg ; org 005ch fcb rb 10h fcb2 rb 14h buff rb 80h ; org lasmorg disem: mov ax,0 ret 4 ;remove parameters from stack ; org asmorg assem: mov ax,0 ret 4 ;remove parameters from stack ; org ddt_org jmp ddt86 ;ccp transfers control here jmp conin jmp plmconout jmp plmgetline jmp asment ;get here on error in assem (pl/m) jmp plmset ;assembler link to ddt set/verify ; bdosint: int bdosi ;this is only here for user to patch ;actual bdos link gets set from here bdosintloc equ offset bdosint bdosintnum equ offset bdosint+1 ; bdosi equ 224 ;bdos interrupt number stsize equ 96 ;stack size nbps equ 2 ;number of breakpoints ; ifmask16 equ 0200h ;16-bit IF mask ifmask8 equ 02h ;8-bit IF mask ; lf equ 0ah ;line feed cr equ 0dh ;carriage return eol equ cr ctls equ 13h ;ascii ctl-s ; ; ******************************************* ; * * ; * m e s s a g e s * ; * * ; ******************************************* ; copyright db ' COPYRIGHT (C) 1981, DIGITAL RESEARCH ' ; signon db 'DDT86 1.','1' or 80h ; DATE DB ' 10/02/81 ' regname db 'A','X' or 80h db 'B','X' or 80h db 'C','X' or 80h db 'D','X' or 80h db 'S','P' or 80h db 'B','P' or 80h db 'S','I' or 80h db 'D','I' or 80h segreg db 'C','S' or 80h db 'D','S' or 80h db 'S','S' or 80h db 'E','S' or 80h db 'I','P' or 80h ; flagname db 'ODITSZAPC' flagbits db 5,6,7,8,9,10,12,14,16 ; segnames db 'C','S' or 80h db 'D','S' or 80h db 'E','S' or 80h db 'S','S' or 80h db 'X','1' or 80h db 'X','2' or 80h db 'X','3' or 80h db 'X','4' or 80h ; closem db cr,lf,'CANNOT CLOS','E' or 80h loadm db cr,lf,'INSUFFICIENT MEMOR','Y' or 80h makem db cr,lf,'NO SPAC','E' or 80h memm db cr,lf,'MEMORY REQUEST DENIE','D' or 80h openm db cr,lf,'NO FIL','E' or 80h readm db ' START EN','D' or 80h verm db cr,lf,'VERIFY ERROR AT',' ' or 80h writem db cr,lf,'DISK WRITE ERRO','R' or 80h ; ; **************************************************** ; * * ; * i n i t i a l i z a t i o n * ; * * ; **************************************************** ; setbdosint: ;copy vector at 0:bdosi*4 to (bdosi+1)*4 mov al,byte ptr .bdosintnum ;get bdos interrupt # inc al mov byte ptr .ddtbdosintnum,al ;ddt uses the next interrupt internally sub ah,ah shl ax,1 shl ax,1 ;bdos int # * 4 mov di,ax ;[di] points to new bdos interrupt vector mov si,ax sub si,4 ;[si] points to actual bdos interrupt vector push ds ;save ds sub ax,ax mov es,ax ;set es and ds to 0 to move interrupt vectors mov ds,ax mov cx,4 rep movs al,al ;copy bdos interrupt vector to next int vector pop ds ;restore ds ret ; checkcmdtail: ;if command tail not empty, assume E command mov si,offset buff mov ah,0 lods al ;get count from command tail or al,al jz cctret ;nothing to do if tail empty cmp al,conbuffmax jbe movcom mov al,conbuffmax ;truncate, if needed movcom: mov cx,ax ;count to [cx] mov di,offset conbuff push ds pop es ;point destination to ddt seg rep movs al,al ;copy command tail into ddt command buff mov al,eol stos al ;store terminator call execute ;command tail is assumed E command cctret: ret ; ddt86: cld MOV CCPSS,SS MOV CCPSP,SP ;SAVE CCP STACK POINTER MOV USERSS,SS MOV USERSP,SP ;INITIALIZE USER'S MACHINE STATE TO CCP STACK ; pushf pop ax ;get flags and ax,ifmask16 ;mask to IF bit mov sysif,ah ;save system IF state mov userfl,ax ;initialize user's flags to sysif ; mov ax,cs cli ;entering critical region mov ss,ax ;set ss = cs mov sp,offset stackp ;set up stack pointer test sysif,ifmask8 ;see if interrupts were enabled jz d0 ;don't turn them on if they were off sti d0: ;exiting critical region ; call setbdosint ;copy vector since ddt uses bdosi+1 internally ; test savevecflag,0ffh ;ddt interrupts saved on each g/t/u? jnz d1 ;if so, don't initialize here call bpvect ;if not, initialize them here d1: if debug ; sub ax,ax mov es,ax mov si,bdosi * 4 + 2 mov ax,es:[si] ;get bdos segment mov es,ax mov biosentryseg,ax mov di,biosentryoff mov al,81h stos al mov al,0c3h stos al mov al,0h stos al mov al,25h stos al mov al,0ffh stos al mov al,0d3h stos al mov al,0cbh stos al ; endif ; mov si,offset signon ;get sign on message call printm ;and print it ; CALL VERSION CMP AL,30H ;SEE IF WE ARE UNDER FILE SYSTEM III (MP/M) MOV BH,0 JC D2 ;IF EARLIER VERSION, SKIP MOV DL,0FEH CALL SETERRMODE ;SO BDOS RETURNS TO DDT ON FILE ERRORS MOV BH,1 D2: MOV ERRMODE,BH ; call checkcmdtail ;if non-blank, do E command ; ; ************************************************* ; * * ; * w o r k i n g l o o p * ; * * ; ************************************************* ; start: cld ;direction flag points up mov sp,offset stackp ;make sure stack is right call crlf ;print crlf mov al,'-' ;and prompt call conout call getline ;get command line call conin ;read first char cmp al,eol jz start CMP AL,';' JZ START ;IGNORE COMMENT LINES sub al,'A' ;check range for valid command jb err cmp al,'Z'-'A' ja err shl al,1 ;* 2 (2 bytes per ctable entry) mov ah,0 xchg ax,bx mov numreq,1 ;most commands require an argument mov wmode,0 ;most commands are not word mode call word ptr ctable [bx] ;immed call command routine jmps start ;start over ; err: call crlf mov al,'?' ;error handler call conout ;print error char jmps start ;stack maybe messed up, keep this jmp ; ; ************************************************** ; * * ; * c o m m a n d j u m p t a b l e * ; * * ; ************************************************** ; ctable dw assm ;assemble mnemonics DW BLOCKCOMPARE ;COMPARE MEMORY BLOCKS dw err dw display ;display memory dw execute ;load user program for execution dw fill ;fill memory with constant dw gouser ;go to user program dw hexmath ;compute hex sum and difference dw ifcb ;input file control block dw err dw err dw lassm ;disassemble memory dw move ;move block dw err dw err dw err dw err dw read ;read file dw setmem ;set memory dw trace ;trace program execution dw untrace ;untraced program execution dw verify ;display file info dw write ;write memory block to disk dw xcom ;display/alter CPU state dw err dw err ; ; ************************************************* ; * * ; * b d o s i n t e r f a c e * ; * * ; ************************************************* ; bdos: ;this interrupt instruction is overwritten on initialization ;the actual int # used is the one at bdosint: + 1 ddtbdosintnum equ offset bdos + 1 ; int bdosi ret ; if debug ; bios: callf dword ptr biosentryoff ret ; endif ; if debug ; consin: mov bx,9 call bios push ax call conout pop ax ret ; endif ; if not debug ; consin: mov cl,1 call bdos ret ; endif ; if debug ; conout: mov bx,0ch mov cl,al jmp bios ; endif ; if not debug ; conout: mov cl,2 mov dl,al call bdos ret ; endif ; rdconbuff: mov cl,10 call bdos ret ; if debug ; constat: mov bx,6 jmp bios ; endif ; if not debug ; constat: mov cl,11 call bdos ret ; endif ; VERSION: MOV CL,12 JMP BDOS ; open: mov cl,15 call bdos inc al ;test for 0ffh returned jz openerr ret openerr: mov si,offset openm jmps errm ; close: mov cl,16 call bdos inc al jz closeerr ret closeerr: mov si,offset closem jmps errm ; delete: mov cl,19 jmp bdos ; readsec: mov cl,20 jmp bdos ; writesec: mov cl,21 call bdos or al,al jnz writeerr ret writeerr: mov si,offset writem jmps errm ; make: mov cl,22 call bdos inc al jz makeerr ret makeerr: mov si,offset makem jmps errm ; setdma: mov cl,26 jmp bdos ; SETERRMODE: MOV CL,45 JMP BDOS ; setdmab: mov cl,51 jmp bdos ; getmaxmem: mov cl,53 call bdos inc al jz memerr ret ; allocabsmem: mov cl,56 call bdos ; inc al ; jz memerr NOP NOP NOP NOP ;REPLACE INC AL, JZ MEMERR ret memerr: mov si,offset memm jmps errm ; freemem: mov cl,57 jmp bdos ; load: mov cl,59 call bdos inc ax ;test for 0ffffh returned jz loaderr ret loaderr: mov si,offset loadm ; errm: call printm jmp start ; plmconout: push bp mov bp,sp mov ax,4[bp] call conout pop bp ret 2 ; plmgetline: push bp call getline pop bp ;restore bp for pl/m ret ; ; **************************************************** ; * * ; * c o n s o l e i / o r o u t i n e s * ; * * ; **************************************************** ; if debug ; ctlx: mov al,'#' call conout call crlf getline: mov conptr,0 get0: call consin cmp al,3 jz ctlc cmp al,8 jz backsp cmp al,24 ;ctl-x jz ctlx cmp al,cr jz getlinedone cmp conptr,conbuffmax jnb getlinedone mov di,offset conbuff ;normal character store add di,conptr mov [di],al inc conptr jmps get0 getlinedone: mov di,offset conbuff add di,conptr mov byte ptr [di],eol mov conptr,0 ret backsp: cmp conptr,0 jz get0 dec conptr call blank mov al,8 call conout jmps get0 ctlc: mov cl,0 mov dl,0 jmp bdos ; endif ; if not debug ; getline: mov dx,offset conbuffhdr call rdconbuff mov bl,conbuffcnt mov bh,0 add bx,offset conbuff mov byte ptr [bx], eol mov conptr,0 ret ; endif ; conin: mov si,offset conbuff add si,conptr lods al inc conptr ;fall thru to upper upper: cmp al,'a' ;less than 'a' jb upret ;or cmp al,'z' ;greater than 'z' ja upret ;then no change and al,5fh ;else convert to uc upret: ret ; ctlchek: ;check for ctl-s, ctl-q and ctl-c call constat ;keypress? or al,al ;zero? jz ctlexit ;no keypress so return call consin ;if keypress then get the data cmp al,ctls ;check for ctl-s jz kwait jmp start ;any other key will restart kwait: call consin ;if ctl-s then wait for another keypress ctlexit: ret ; crlf: mov al,cr ;send cr and lf to console call conout mov al,lf call conout ret ; CRLFCHK: ;DO CRLF AND CHECK FOR ABORT CALL CRLF CALL CTLCHEK RET ; blank: ;print a blank. mov al,' ' call conout ret ; tabs: ;print # blanks in cx push cx call blank pop cx loop tabs ret ; printm: ;print the message at [si] on console ;end of message indicated by parity set. lods al ;get a byte test al,80h ;check for end of message jnz pquit ;quit if parity set push si call conout ;otherwise display byte pop si jmps printm ;print more message pquit: and al,7fh ;strip parity call conout ;print last byte ret ; ascout: ;output [al] in ascii cmp al,' ' jb perout ;less than blank? cmp al,7eh jna ascend perout: mov al,'.' ;output '.' ascend: call conout ;else output ascii ret ; print8or16: ;print byte or word at es:[si] depending on wmode mov ax,es:[si] test wmode,1 jz printbyte jmps printword ; printdword: ;print double word as ssss:oooo ; called with: ; es = segment ; di = offset push di mov ax,es call printword ;print segment mov al,':' call conout pop ax ; printword: ;print value in [ax] as 4 hex digits push ax mov al,ah call printbyte pop ax ; printbyte: ;print value in [al] as 2 hex digits push ax mov cl,4 shr al,cl ;shift al right 4 places call printnibble ;output upper nibble pop ax ;restore al (now we do lower nibble) ; printnibble: ;print value in low 4 bits of [al] as a hex digit and al,0fh ;mask upper 4 bits add al,90h daa adc al,40h daa call conout ret ; ; ************************************** ; * * ; * file name parsing routines * ; * * ; ************************************** ; parse: ;parse into fcb whose offset is in [di] push cs pop es ;set es=cs push di ;save fcb address sub al,al mov cx,36 ;fcblen rep stos al ;initialize fcb to 0 pop di ;restore fcb address ; parse2: ;enter here to parse without clearing ;assumes es = cs from parse: mov fcbadr,di ;save fcb address inc di ;point to first byte of filename call setupdisk ;check for d: and set drive byte mov cx,8 call fillfield ;first item was disk, now get filename mov cx,3 ;length of file type cmp lastchar,'.' jz filltype call fillbl ;fill type with blanks if no '.' jmps parseret filltype: call fillfield ;if '.', fill field from console buff parseret: call scanq ;count '?'s in fcb mov al,lastchar ret ;with last char scanned in [al] parseerr: jmp err ; setupdisk: ;set byte 0 of fcb according to char in fcb (1) call conin mov lastchar,al cmp al,' ' jz setupdisk ;deblank input cmp al,eol jz s1 ;can't be drive, decrement conptr to rescan call conin cmp al,':' jnz s0 ;not a drive, subtract 2 from conptr to rescan mov al,lastchar ;get drive char sub al,'A'-1 dec di ;point to fcb (0) stos al ;store drive byte ret s0: dec conptr s1: dec conptr ret ; pdelim: ;check char in [al] for delimiter; return ZF if so. mov di,offset delims mov cx,ndelims repnz scas al ;look in table ret ; fillfield: ;count in [cx], dest ptr in [di] call conin mov lastchar,al ;save last char scanned cmp al,'*' jnz notast call fillq ;fill with '?' jmps fillfield ;continue till delimiter notast: push di push cx call pdelim pop cx pop di jz fillbl ;if delimiter, fill field with ' ' jcxz parseerr ;error if count exceeded stos al ;store char in fcb dec cx ;decrement count jmps fillfield fillq: mov al,'?' jmps fillx fillbl: mov al,' ' fillx: jcxz filldone rep stos al ;store '?' or ' ' filldone: ret ; scanq: ;count '?'s in fcb, return ZF set if found mov di,fcbadr inc di ;point to first char of filename mov cx,11 ;11 chars to check mov al,'?' repnz scas al ret ; ; *********************************** ; * * ; * user CPU state routines * ; * * ; *********************************** ; chkreg: ;if reg name in [ax] is valid, return with ;register number in regnum ;else go to error processor mov cx,totreg+1 ;number of names to check + 1 mov di,offset regname push cs pop es repnz scas ax jcxz checkerr ;not a valid reg name mov dx,totreg sub dx,cx mov regnum,dx ;save reg number ret ; checkflag: ;check for valid flag name mov cx,nflag+1 ;number of names to check + 1 mov di,offset flagname push cs pop es repnz scas al jcxz checkerr ;not a valid flag name mov dx,nflag sub dx,cx mov regnum,dx ;save flag number ret ; checkerr: jmp err ; setreg: ;set reg whose number is in [cx] to value in [ax] mov si,offset userreg add si,cx add si,cx mov [si],ax ret ; printflags: ;print values of flags mov cx,0 pf0: push cx ;save count call printflag pop cx inc cx cmp cx,9 jb pf0 ret ; setflag: ;set flag whose # is in [cx] to value in [bx] mov si,offset flagbits add si,cx lods al mov cl,al mov ax,0fffeh ror ax,cl ror bx,cl and userfl,ax or userfl,bx ret ; printflagname: ;print flag name whose # is in [cx] mov si,offset flagname add si,cx lods al ;get flag name call conout ret ; getflag: ;check flag whose # is in [cx] ;return with ZF set if flag is set mov ax,1 mov si,offset flagbits add si,cx mov cl,[si] ;get flagbits (flagnum) ror ax,cl ;get mask into position and ax,userfl ;see if bit set in CPU state ret ; printflagval: ;print value of flag (as 0 or 1) whose # is in [cx] call getflag mov al,'0' jz pf2 ;if flag not set, print '0' mov al,'1' ;else print '1' pf2: call conout ret ; printflag: ;print flag (as flagname of '-') whose # is in [cx] mov si,offset flagname add si,cx ;point to flag name push word ptr [si] ;save flag char call getflag pop ax ;get flag char jnz pname ;if flag set, use flag char mov al,'-' ;else print hyphen pname: call conout ret ; PREG1: ;PRINT FIRST 6 REGISTER NAMES (FOR 40 COLUMNS) MOV CX,0 MOV NREG,6 JMPS PR0 PREG2: ;PRINT NEXT 7 REGISTER NAMES (FOR 40 COLUMNS) MOV CX,6 JMPS PR00 printregs: ;print register values mov cx,0 PR00: MOV NREG,13 pr0: call testregcl ;see if reg should be printed jnb pr2 ;don't print if carry not set push cx call printregval call blank pop cx pr2: inc cx CMP CL,NREG jb pr0 ret ; printregval: ;print value of reg whose # is in [cx] mov si,offset userreg add si,cx add si,cx lods ax call printword ret ; printregname: ;print name of reg whose # is in [cx] mov si,offset regname add si,cx add si,cx call printm ret ; testregcl: ;see if reg whose # is in [cl] should be printed ;return with carry set if so test segflag,0ffh jnz printit ;print all reg's if segflag set cmp cl,11 ;otherwise, see if [cl] has seg reg # ja printit cmp cl,8 ret printit: stc ret ; SETUPHDR: call crlf mov cx,11 call tabs ;leave space for flags mov cx,0 RET ; PREGHDR1: ;PRINT HEADER FOR FIRST 6 REGS (FOR 40 COL) CALL SETUPHDR MOV NREG,6 JMPS PRH0 PREGHDR2: ;PRINT HEADER FOR NEXT 7 REGISTERS CALL BLANK MOV CX,6 JMPS PRH00 printregheader: ;print header for registers CALL SETUPHDR PRH00: MOV NREG,13 prh0: call testregcl ;see if reg should be printed jnb prh1 ;don't print if carry not set push cx call printregname mov cx,3 call tabs pop cx prh1: inc cx CMP CL,NREG jb prh0 ret ; printinstr: ;disassemble instruction at [cs:ip] mov es,usercs mov si,userip test disempresent,0ffh jz pi1 push es push si test segflag,0ffh jz pi0 call crlf pi0: call disem ret pi1: mov al,es:[si] call printbyte ret ; printseginfo: ;print name, start and end address of segment whose ;number is in [al] if length is non-zero. mov cl,al ;save seg number mov bl,6 mul bl ;6 bytes per segment in base page add ax,offset basepagesave mov si,ax ;si now points to entry in base page lods ax ;get low 16 bits of length mov bx,ax ;save in bx lods al ;get high nibble of length mov dl,al ;save it mov ah,0 or ax,bx ;test for zero length jz psiret ;if zero, no display lods ax ;get base push bx ;save low (length) push dx ;save high (length) push ax ;save base mov ch,0 ;zero high byte of segment # shl cx,1 ;* 2 (2 bytes per segment name) add cx,offset segnames ;cx now points to segment name push cx ;save it call crlf pop si call printm ;print segment name call blank pop es ;get base push es ;save base mov di,0 call printdword ;print start address call blank pop bx ;get base pop ax ;get high (len) mov cl,12 shl ax,cl ;move ls nibble of al to ms nibble of ah add ax,bx ;add ms nibble of length to base mov es,ax pop di ;get low (len) call printdword ;print end address psiret: ret ; setcpustate: ;set users regs after E command MOV AX,CCPSS MOV USERSS,AX MOV AX,CCPSP MOV USERSP,AX ;RESET USER STACK POINTER TO CCP STACK mov ax,bx ;get ds base in [ax] (returned from bdos load) mov userds,ax ;set user's ds mov usercs,ax mov useres,ax mov type1seg,ax mov type2seg,ax mov es,ax test es:byte ptr .5, 1 ;test 8080 flag jz not8080 mov ax,100h ;default for userip, lasloc, disloc jmps setdone not8080: mov ax,es:.3 ;get cs base mov usercs,ax mov type1seg,ax mov ax,es:.15 ;get es base or ax,ax jz sc1 mov useres,ax ;set it if there was one sc1: mov ax,es:.21 ;get ss base or ax,ax jz setdone mov userss,ax ;set it if there was one mov ax,es:.18 ;get stack length mov usersp,ax ;set user's sp sub ax,ax ;userip, lasloc, disloc = 0 for non-8080 model setdone: mov userip,ax mov lasloc,ax ret ; ; ********************************************* ; * * ; * breakpoint/single step procedures * ; * * ; ********************************************* ; setbp: ;set breakpoint at address stored in dword at [di] les si,[di] ;point [es]:[si] to breakpoint location mov al,0cch ;int 3 instruction xchg al,es:[si] ;set breakpoint and fetch instruction mov 4[di],al ;save user instruction in breakpoint table inc bpcnt ;increment breakpoint count ret ; bpclear: ;clear breakpoint table sub cx,cx mov cl,bpcnt ;get # of bp's to clear mov si,offset brk1loc ;point to bp table bpcloop: jcxz bpend ;0..quit lods ax ;get bp offset push ax ;save it lods ax ;get bp segment mov es,ax lods al ;get inst byte pop di ;get bp offset stos al ;store user instruction back loop bpcloop mov bpcnt,0 ;zero bp counter bpend: ret ; BPV: TEST SAVEVECFLAG,0FFH JZ BPVECTRET bpvect: ;set up breakpoint/single step vectors call savevect mov dx,0 mov es,dx ;make sure dest is absolute 0 mov di,4 ;set up single step vector mov ax,offset ssentry ;single step entry point stos ax ;save at ss vector mov ax,cs stos ax ;save cs mov di,12 ;set up breakpoint vector mov ax,offset breakentry ;set up bp vector stos ax ;save at bp vector mov ax,cs stos ax ;save cs BPVECTRET: ret ; savevect: ;save previous contents of 0:4 thru 0:f mov si,4 mov di,offset vectorsave push ds pop es ;point to ddt segment mov cx,12 push ds mov dx,0 mov ds,dx rep movs al,al pop ds svret: ret ; restorevect: ;restore previous contents of 0:4 thru 0:f test savevecflag,0ffh jz rvret mov si,offset vectorsave mov di,4 mov cx,12 mov dx,0 mov es,dx rep movs al,al rvret: ret ; SETDEFSEG: ;SET DEFAULT TYPE1SEG, LASLOC mov di,userip mov lasloc,di ;set disassembler offset mov es,usercs mov type1seg,es ;set type1seg segment RET ; breakaddr: ;print address where break occurred call crlf mov al,'*' call conout mov ax,userds mov type2seg,ax ;set type2 segment to userds CALL SETDEFSEG call printdword ;print break address ret ; breakentry: ;breakpoint entry mov breakfl,1 jmps savecpu ;common code for break and single step ssentry: ;single step entry mov breakfl,0 savecpu: mov userax,ax mov userbx,bx mov usercx,cx mov userdx,dx mov usersi,si mov userdi,di mov userbp,bp mov usersp,sp mov useres,es mov userds,ds mov userss,ss mov bp,sp mov ax,[bp] mov userip,ax mov ax,2[bp] mov usercs,ax mov ax,4[bp] mov userfl,ax ; mov ax,cs mov ds,ax mov ss,ax mov sp,offset stackp ; test sysif,ifmask8 ;see whether interrupts should be enabled jz sav0 sti sav0: add usersp,6 ;to make up for stacked cs, ip, and fl cld call restorevect test breakfl,0ffh jz sst0 ; break0: ;continuation of break processing dec userip ;adjust user ip for breakpoint instr call bpclear ;clear all breakpoints test skipbdos,0ffh ;were we originally in trace mode? jnz sst00 ;if so, continue tracing ; tracedone: call breakaddr jmp start ; sst00: ;get here on breakpoint on return from bdos mov skipbdos,0 ;no longer tracing thru bdos sst0: ;continuation of single step processing and userfl,0feffh ;clear user trap flag TEST USERIFOFF,1 JZ SST1 MOV USERIFOFF,0 OR USERFL,200H ;RESTORE USER IF SST1: dec tracecount jz tracedone CALL CTLCHEK ;CHECK FOR ABORT test traceprint,0ffh jz tracerestore call xnohdr ;display regs without header ; tracerestore: ;enter here when in trace mode mov es,usercs mov si,userip mov ax,word ptr .bdosintloc ;get bdos interrupt instruction cmp ax,es:[si] ;see if instruction to be traced is bdos int jnz tr00 mov brk1seg,es add si,2 ;point to instruction after bdos int mov brk1loc,si mov di,offset brk1loc call setbp ;set breakpoint at return from bdos mov skipbdos,1 ;so we know we were in trace mode when we hit bp jmps rstore ;without setting single step flag tr00: MOV AX,USERFL OR AX,100H ;SET TRACE FLAG TEST AX,200H ;IS USER IF SET? JZ TR01 AND AX,NOT 200H ;CLEAR IT (SO WE DON'T END UP IN INT HANDLER) MOV ES,USERCS MOV SI,USERIP MOV BL,ES:[SI] ;GET INSTRUCTION TO EXECUTE CMP BL,0FAH ;IS IT CLI? JZ TR01 CMP BL,0CFH ;IRET? JZ TR01 CMP BL,09DH ;POPF? JZ TR01 CMP BL,0CDH ;INT? JZ TR01 MOV USERIFOFF,1 ;SET FLAG SO DDT86 WILL TURN IF BACK ON TR01: MOV USERFL,AX rstore: ;enter here when in G mode CALL BPV cli mov sp,offset userreg ;point to reg save area pop ax pop bx pop cx pop dx pop savesp pop bp pop si pop di pop ds ;throw away cs pop ds pop savess pop es mov ss,savess ;restore stack mov sp,savesp push userfl ;flags push usercs ;cs push userip ;ip iret ;transfer to user program ; ; ********************************** ; * * ; * miscellaneous routines * ; * * ; ********************************** ; delim: cmp al,eol jz delret cmp al,',' jz delret cmp al,' ' jz delret cmp al,':' delret: ret ; hexcon: sub al,'0' cmp al,10 jb hexret add al,('0' - 'A' + 10) and 0ffh cmp al,16 jnb hexerr cmp al,10 jb hexerr hexret: ret hexerr: jmp err ; plmset: ;get here when assembler wants to set memory mov bp,sp ;for parameter fetching mov ax,2[bp] ;get value in [al] mov es,type1seg ;segment used in A command is in type1 seg mov di,4[bp] ;get offset from stack call setbyte ;set and verify inc di ;increment offset jnz psret ;if incremented offset is non-zero, return jmp start ;otherwise exit A command, since wrap occurred psret: ret 4 ;remove 2 parameters ; set8or16: ;set byte or word at es:[di] depending on wmode test wmode,1 jz setbyte ;fall through to setword ; setword: ;set word at es:[di] to [ax] and verify ; ; NOTE: THIS CODE COULD BE REPLACED BY THE FOLLOWING 4 INSTRUCTIONS ; FOR SYSTEMS IN WHICH MEMORY CAN ONLY BE ADDRESSED BY WORDS. ; HOWEVER, THIS WILL WRAP AROUND AND MODIFY LOCATIONS 0 IF ; [DI] CONTAINS 0FFFEH. ; ; MOV ES:[DI],AX ; CMP ES:[DI],AX ; JNZ BADVER ; RET ; push ax ;save hi byte call setbyte ;set low byte pop ax mov al,ah inc di ;point to next location jz sret ;don't set byte if wraparound occurred ;fall thru to setbyte ; setbyte: ;set byte at es:[di] to [al] and verify mov es:[di],al ;store byte cmp es:[di],al ;see if it got stored jnz badver sret: ret ; badver: push di push es mov si,offset verm call printm ;print verify error message pop es pop di call printdword jmp start ; inc1or2: ;inc pointer at [si] by 1 or 2, depending on wmode ;return with carry flag set if wrap occurred mov al,wmode and ax,1 ;mask to 0 or 1 inc ax ;increment value is now 1 or 2 add [si],ax ;increment pointer cmp [si],ax ;test for wraparound ret ; getnumber: ;get number from input buffer ;returns: ;bx = value of number from input ;al = last character scanned (delimiter) ;ah = blank flag (0 = blank, 1 = non-blank) sub bx,bx ;initialize value to 0 mov ah,bh ;initialize blank flag to blank getn0: call conin call delim ;check for delimiter jz getnret ;delimiter found, exit mov cl,4 shl bx,cl ;make room for new nibble call hexcon ;convert ascii to binary add bl,al ;add nibble mov ah,1 ;blank flag = non-blank jmps getn0 getnret: ret ; getoffset: ;get offset from input line ;offset is a non-blank number not followed by ':' ;returns: ;al = last char scanned (delimiter) ;bx = value call getnumber ;get value to bx or ah,ah ;check for blank entry jz geterr ;don't allow blank entry cmp al,':' ;check delimiter for ':' jz geterr ;don't allow ':' delimiter ret ; getlastoffset: ;same as getoffset but delimiter must be a cr call getoffset cmp al,eol jnz geterr ret geterr: jmp err ; checkword: ;check for 'W' following command letter call conin cmp al,'W' jnz chret mov wmode,1 ret chret: dec conptr ;to rescan character ret ; checkreg: ;check for valid segment register prefix - : ;called with: ;bl = first char ;bh = second char ;returns: ;si = offset to register, if found ;zf = found flag (1 = found, 0 = not found) or bh,80h ;since they are defined like that mov bp,offset segreg ;point to seg reg names sub si,si ;initialize index to 0 check0: cmp bx,[bp+si] ;is it a seg reg name jz checkret add si,2 ;point to next name cmp si,8 ;check for done (4 seg reg names) jnz check0 or si,si ;unset zero flag checkret: ret ; checksegreg: ;check for valid seg reg name ;if found, return contents of seg reg ;else reset input pointer for rescan ;returns: ;dx = seg reg value ;zf = valid seg reg (1 = valid, 0 = not valid) push conptr ;save input pointer for possible rescan call conin push ax call conin push ax call conin cmp al,':' ;valid seg reg must have colon pop bx pop cx mov bh,cl xchg bl,bh jnz notsr call checkreg ;see if it's a valid name jnz notsr mov bp,offset usercs ;point to saved user seg reg's mov dx,[bp+si] ;get value of user seg reg pop cx ;throw away saved input pointer ret notsr: pop conptr ;reset for rescan ret ; getsegandoff: ;get user location specification ;may be one of the following forms: ; ;nnnn ;sr:nnnn ;mmmm:nnnn ;if numreq set, is invalid ;called with: ;di = offset of 4 byte area containing ;numreq must have been initialized by calling routine call checksegreg ;see if there is a segment prefix jz gets0 call getnumber ;no segment prefix, check for number or ah,ah ;was there one? jz gets3 mov dx,bx ;move number to dx cmp al,':' ;was delimiter a ':' jnz gets2 gets0: call getoffset ;segment prefix present, must have number mov [di],bx ;number goes to mov 2[di],dx ;first number (or sr) goes to ret gets2: mov [di],dx ;only one number, put it in getsret: ret gets3: test numreq,0ffh ;blank field, see if ok jz getsret ;ok, return with no change at [di] jmp err ;number was required ; ; ***************************** ; * * ; * disk i/o routines * ; * * ; ***************************** ; readfile: ;read file in fcb into memory described in mcb ;when done, mcb will have base and length of block to free mov ax,mcbbase mov startreadseg,ax mov endreadseg,ax mov dmaseg,ax sub ax,ax mov startreadoff,ax mov endreadoff,ax rf0: mov dx,dmaseg call setdmab ;set dma base mov dmaoff,0 rf1: mov dx,dmaoff call setdma ;set dma offset cmp mcblen,8 ;8 paragraphs per sector jb readerr ;if less than 8 pp's left, not enough memory mov dx,offset fcb call readsec or al,al ;test value returned from bdos jnz readdone add mcbbase,8 ;point mcb to next available paragraph sub mcblen,8 ;decrement # of available paragraphs mov ax,dmaoff add al,7fh ;add sector size - 1 mov endreadoff,ax MOV AX,DMASEG MOV ENDREADSEG,AX add dmaoff,80h ;increment dma offset jnz rf1 ;if no wrap occurred, simply continue add dmaseg,1000h ;else increment dma segment jmps rf0 readdone: MOV DX,OFFSET FCB CALL CLOSE ret readerr: jmp loaderr ; writefile: ;write block at startwriteloc - endwriteloc to file in fcb mov ax,startwriteoff mov cl,4 shr ax,cl ;divide offset by 16 - truncate ls nibble add ax,startwriteseg ;compute absolute paragraph number mov mcbbase,ax mov dmaseg,ax mov bx,ax ;store start paragraph # in [bx] mov ax,endwriteoff shr ax,cl add ax,endwriteseg ;calculate absolute paragraph number of end sub ax,bx ;compute # of paragraphs to write jb wferr ;start can't be > end mov mcblen,ax ;store # paragraphs to write mov dx,offset fcb call delete TEST ERRMODE,0FFH JZ WF00 INC AL ;DID DELETE RETURN 0FFH? JNZ WF00 ;IF NOT, OK OR AH,AH ;SEE IF EXTENDED OR PHYSICAL ERROR JNZ WFERR ;IF SO, DON'T CONTINUE WF00: mov dx,offset fcb call make wf0: mov dx,dmaseg call setdmab mov dmaoff,0 ;clear dma offset wf1: mov dx,dmaoff call setdma mov dx,offset fcb call writesec sub mcblen,8 ;8 paragraphs per sector jb writedone add dmaoff,80h ;increment dma pointer jnz wf1 ;loop if no wrap occurred add dmaseg,1000h ;if wrap occurred, increment dma segment jmps wf0 writedone: ret wferr: jmp err ; eject ; ; ********************************** ; * * ; * a - assemble mnemonics * ; * * ; ********************************** ; assm: test assempresent,0ffh jz asmerr mov asmspsav,sp ;save in case of error in pl/m mov di,offset type1loc call getsegandoff ;get start address asm0: push type1seg ;for pl/m call push type1loc ;for pl/m call call assem ;returns offset of next available byte cmp ax,type1loc ;test for no input jna asmret ;done unless greater than original type1loc mov type1loc,ax ;update type1loc jmps asm0 asmret: ret asmerr: jmp err asment: ;arrive here on input error in pl/m mov sp,asmspsav ;reset stack to where it was jmps asm0 ;go back for more input ; ; ***************************** ; * * ; * B - BLOCK COMPARE * ; * * ; ***************************** ; BLOCKCOMPARE: mov di,offset type2loc call getsegandoff call getoffset ;get end offset mov usermax,bx cmp al,eol jz cmperr ;need 3 arguments sub bx,type2loc jb cmperr ;error if start > end mov ax,type2seg mov userseg2,ax ;default to same seg as source mov di,offset userloc2 call getsegandoff ;get destination address cmp al,eol jnz cmperr ;error if more than 3 arguments CMP0: LES SI,DWORD PTR TYPE2LOC MOV AL,ES:[SI] LES SI,DWORD PTR USERLOC2 CMP AL,ES:[SI] JZ CMPCONT CALL CRLFCHK MOV DI,OFFSET TYPE2LOC CALL PRINTERROR CALL BLANK CALL BLANK MOV DI,OFFSET USERLOC2 CALL PRINTERROR CMPCONT: INC TYPE2LOC MOV AX,TYPE2LOC CMP USERMAX,AX JC CMPDONE INC USERLOC2 JZ CMPDONE ;PREVENT WRAPAROUND JMPS CMP0 ; CMPDONE: RET CMPERR: JMP ERR ; PRINTERROR: ;PRINT DWORD AT [DI], BYTE POINTED TO BY DWORD LES DI,[DI] MOV AL,ES:[DI] PUSH AX ;SAVE BYTE AT ES:DI CALL PRINTDWORD CALL BLANK POP AX CALL PRINTBYTE RET ; ; ****************************** ; * * ; * d - display memory * ; * * ; ****************************** ; display: mov numreq,0 ;ok to have no entries mov ax,type2seg mov disseg,ax ;default to type2 seg call checkword TEST COL40,0FFH JZ DIS01 TEST WMODE,1 JNZ DIS00 MOV AL,ND40 JMPS DIS02 DIS00: MOV AL,NDW40 ;CHARS PER LINE FOR DW IN 40 COL MODE JMPS DIS02 DIS01: MOV AL,ND80 ;16 BYTES PER LINE IN NORMAL MODE DIS02: MOV LINEMAX,AL mov di,offset disloc call getsegandoff cmp al, ',' mov ax,disseg mov type2seg,ax ;update default type2 seg jnz dis0 ;must be cr, no dismax entered call getlastoffset ;get dismax jmps dis1 dis0: mov bx,disloc ;no dismax entered, calculate default MOV AL,LINEMAX MOV CL,NLINES MUL CL DEC AL ADD BX,AX cmp bx,disloc ;see if we went over ffff jnb dis1 mov bx,0ffffh ;set dismax if we wrapped around dis1: mov dismax,bx disp3: CALL CRLFCHK les di,dword ptr disloc mov tdisp,di call printdword disp4: call blank les si,dword ptr disloc call print8or16 mov si,offset disloc call inc1or2 jb disp6 ;stop if wrap occurred mov ax,disloc sub ax,tdisp ;calculate # bytes printed on line CMP AL,LINEMAX ;SEE IF LINE FULL jz disp6 mov ax,disloc cmp ax,dismax ;check for done jna disp4 disp6: call blank disp7: mov es,disseg mov si,tdisp mov al,es:[si] call ascout inc tdisp jz disp8 ;stop if wrap occurred mov ax,tdisp cmp ax,disloc jnz disp7 cmp ax,dismax ja disp8 jmps disp3 disp8: ret ; ; ****************************************** ; * * ; * e - load program for execution * ; * * ; ****************************************** ; cmd db 'CMD' ; execute: call conin cmp al,eol ;check for no filename jz eerr ;don't allow no filename dec conptr ;to rescan character mov di,offset fcb call parse jz eerr ;no '?' or '*' allowed cmp al,eol jnz eerr ;eol must follow filename push cs pop es ;set es = cs cmp es:fcb+9, ' ' ;see if filetype blank jnz ex0 mov si,offset cmd mov di,offset fcb+9 mov cx,3 rep movs al,al ;set filetype to 'CMD' if empty ex0: mov dx,offset fcb call open ;see if file exists mov mcbext,0ffh ;free all allocations below DDT86 mov dx,offset mcb call freemem ;free all memory previously allocated under DDT mov dx,offset fcb call load ;load user program push bx ;save ds base call setcpustate pop dx ;get ds base back call setdmab ;set dma base mov dx,80h call setdma ;default to 80h in user's DS MOV DX,OFFSET FCB CALL CLOSE mov mode,'E' mov si,0 mov di,offset basepagesave push ds pop es ;set es to ddt's segment mov ax,userds push ds ;save it mov ds,ax mov cx,48 rep movs al,al ;copy user's base page into ddt save area pop ds ;restore ds call verify ;display load info DEC CONPTR ;TO RESCAN CR JMP IFCB ;TO CLEAR FCB eerr: jmp err ; ; *************************** ; * * ; * f - fill memory * ; * * ; *************************** ; fill: call checkword ;check for 'FW' mov di,offset type2loc call getsegandoff call getoffset ;get end address mov usermax,bx ;save end address call getlastoffset ;get fill constant test wmode,1 jnz fil0 or bh,bh ;if not wmode, high byte must be 0 jnz filerr fil0: mov cx,usermax ;get end address sub cx,type2loc ;compare for valid range jb filerr ;error if start > end fil1: les di,dword ptr type2loc mov ax,bx ;get fill constant call set8or16 mov si,offset type2loc call inc1or2 jb filret ;stop if wrap occurred mov ax,type2loc cmp ax,usermax jbe fil1 filret: ret filerr: jmp err ; ; ********************************** ; * * ; * g - go to user program * ; * * ; ********************************** ; gouser: mov ax,usercs mov goseg,ax ;default goseg = usercs mov ax,userip mov goloc,ax ;default goloc = userip mov numreq,0 ;number not required in G command mov di,offset goloc call getsegandoff ;get start address cmp al,eol jz gorestore ;if eol, no breakpoints set mov ax,goseg mov brk1seg,ax mov brk2seg,ax ;defaults for breakpoint segments = goseg mov di,offset brk1loc call getsegandoff ;get first breakpoint push ax ;save terminating char mov di,offset brk1loc call setbp ;save breakpoint in table pop ax ;get char cmp al,eol jz gorestore ;only one breakpoint mov di,offset brk2loc call getsegandoff ;get second breakpoint cmp al,eol jnz goerr ;only 2 breakpoints allowed mov di,offset brk2loc call setbp ;set second breakpoint gorestore: mov skipbdos,0 ;make sure it's 0 since we aren't in T/U mode mov ax,goseg mov usercs,ax ;usercs = goseg mov ax,goloc mov userip,ax ;userip = goloc jmp rstore ;restore user CPU state goerr: call bpclear ;in case any were set jmp err ; ; ; ************************ ; * * ; * h - hex math * ; * * ; ************************ ; hexmath: call getoffset push bx ;save first value call getlastoffset pop ax ;get first value push ax ;save a copy add ax,bx push bx ;save second value push ax ;save sum call crlf pop ax ;get sum call printword ;print sum call blank pop bx ;get second value pop ax ;get first value sub ax,bx call printword ;print difference ret ; ; **************************************** ; * * ; * i - input file control block * ; * * ; **************************************** ; ifcb: push conptr ;save input pointer mov di,offset fcb call parse cmp al,eol jnz i0 ;only one filename dec conptr ;to rescan eol and blank second filename in fcb i0: mov di,offset fcb2 call parse2 ;parse second filename push ds pop es ;point to DDT's ds pop conptr ;restore input pointer mov di,81h ;move command tail to [es]:[di] sub cx,cx ;zero count i1: call conin ;get char from command tail cmp al,eol ;end of command tail? jz i2 stos al ;store in user's base page inc cx ;increment count jmps i1 ;loop until eol i2: mov al,0 stos al ;store 0 at end of string mov es:.80h,cl ;store count at start of buffer cmp mode,'E' jnz idone ;if no file loaded with E command, we're done mov si,offset fcb mov di,si mov es,userds add cx,38 ;total bytes to move = # in command + 36 (fcb) ; +2 (0 at end of command and count byte) rep movs al,al ;move fcb from ddt86 basepage to user's basepage idone: ret ierr: jmp err ; ; ********************************** ; * * ; * l - list assembly code * ; * * ; ********************************** ; lassm: test disempresent,0ffh jz laserr mov lascntsw,0 ;don't use count if end addr specified mov numreq,0 ;ok if no entries mov ax,type1seg mov lasseg,ax ;default to type1 seg mov di,offset lasloc call getsegandoff cmp al,eol mov ax,lasseg mov type1seg,ax ;update default type1 seg jz las0 call getlastoffset ;if ',', get end address jmps las1 las0: mov lascntsw,1 ;disassemble fixed # of instructions MOV AL,NLINES MOV LASCNT,AL mov bx,0ffffh ;set lasmax to big number las1: mov lasmax,bx las2: mov di,lasloc cmp di,lasmax ja lasret push di CALL CRLFCHK pop di mov es,lasseg push es push di ;for disem call (PL/M) call printdword call blank call disem cmp ax,lasloc jb lasret ;stop if wrap occurred mov lasloc, ax test lascntsw,0ffh jz las2 dec lascnt jnz las2 lasret: ret laserr: jmp err ; ; ************************** ; * * ; * m - move block * ; * * ; ************************** ; move: mov di,offset type2loc call getsegandoff call getoffset ;get end offset mov usermax,bx cmp al,eol jz moverr ;need 3 arguments sub bx,type2loc jb moverr ;error if start > end mov ax,type2seg mov userseg2,ax ;default to same seg as source mov di,offset userloc2 call getsegandoff ;get destination address cmp al,eol jnz moverr ;error if more than 3 arguments mov0: les si,dword ptr type2loc mov al,es:[si] ;get source byte les di,dword ptr userloc2 call setbyte ;put destination byte inc type2loc jz movret ;don't allow wraparound inc userloc2 jz movret ;don't allow wraparound in destination segment mov ax,type2loc cmp ax,usermax ;check for done jna mov0 movret: ret moverr: jmp err ; ; ************************* ; * * ; * r - read file * ; * * ; ************************* ; read: call conin ;get first command char cmp al,eol ;check for no input jz rerr ;filename must be included in command dec conptr ;to rescan first char mov di,offset fcb call parse jz rerr ;no '?' or '*' allowed cmp al,eol jnz rerr ;no parameters after filename mov dx,offset fcb call open mov mcblen,0ffffh ;largest memory request mov dx,offset mcb call getmaxmem ;get size of largest chuck of memory mov dx,offset mcb call allocabsmem ;allocate block returned from getmaxmem call readfile ;read file into memory block mov mcbext,0 ;only free memory at mbase mov dx,offset mcb call freemem ;free memory not used in read (read updated mcb) mov ax,startreadseg mov type2seg,ax ;set default type2 segment to file just read mov type1seg,ax ;also type1 segment sub ax,ax mov disloc,ax ;display pointer offset = 0 mov lasloc,ax ;list pointer offset = 0 mov mode,'R' ;last disk input was read (not execute) call verify ret rerr: jmp err ; ; ************************** ; * * ; * s - set memory * ; * * ; ************************** ; setmem: call checkword ;check for 'SW' mov di,offset type2loc call getsegandoff set0: call crlf les di,dword ptr type2loc call printdword call blank les si,dword ptr type2loc call print8or16 call blank call getline call conin cmp al,eol jz set2 cmp al,'.' jz setret dec conptr ;to rescan first character call getlastoffset mov ax,bx ;get new value to ax test wmode,1 jnz set1 or bh,bh jnz seterr ;must be < 256 if not SW set1: les di,dword ptr type2loc call set8or16 set2: mov si,offset type2loc call inc1or2 jnb set0 setret: ret seterr: jmp err ; ; *************************************** ; * * ; * t - trace program execution * ; * * ; *************************************** ; trace: mov traceprint,1 trace0: ;untrace enters here with traceprint = 0 call conin cmp al,'S' ;check for TS mov ah,1 jz tr0 ;if TS, set segflag to 1 dec ah ;else set segflag to 0, and dec conptr ;decrement pointer to rescan character tr0: mov segflag,ah ;print segment registers or not mov tracecount,1 ;default to 1 instruction trace call getnumber cmp al,eol jnz traceerr ;only 1 parameter allowed or ah,ah ;see if a number was entered jz trace1 ;skip if no number typed mov tracecount,bx ;store number of instructions to trace trace1: call xdisp ;display CPU state jmp tracerestore ;restore user's CPU state and return traceerr: jmp err ; ; ****************************************** ; * * ; * u - untraced program execution * ; * * ; ****************************************** ; untrace: mov traceprint,0 jmps trace0 ;common code with trace command ; ; ********************************* ; * * ; * v - display file info * ; * * ; ********************************* ; verify: mov al,mode cmp al,'R' jz verifyr cmp al,'E' jz verifye jmp err ;neither R nor E command done verifyr: call crlf mov si,offset readm call printm call crlf les di,dword ptr startreadoff call printdword call blank les di,dword ptr endreadoff call printdword ret ; verifye: call crlf mov cx,3 call tabs mov si,offset readm call printm ;print header mov al,0 ;initialize count to 0 v0: push ax ;save it pop ax ;get count push ax ;save it call printseginfo ;print name, start, end of segment if non-zero pop ax ;get count inc al ;increment it cmp byte ptr basepagesave+5,1 ;check for 8080 model jz verret ;no more segments if 8080 model cmp al,8 ;max of 8 segments described in base page jb v0 ;done when count = 8 verret: ret ; ; ****************************************** ; * * ; * w - write memory block to disk * ; * * ; ****************************************** ; write: mov ax,startreadseg mov startwriteseg,ax mov ax,startreadoff mov startwriteoff,ax mov ax,endreadseg mov endwriteseg,ax mov ax,endreadoff mov endwriteoff,ax call conin cmp al,eol ;check for no parameters jz werr ;must have a filename dec conptr ;to rescan first char mov di,offset fcb call parse ;get filename jz werr ;don't allow '?' or '*' cmp al,eol jnz w0 ;not end of input - must be 2 parameters cmp mode,'R' ;see if a file was read in jnz werr ;no file read - must have start, end addresses jmps w1 ;continue with write w0: mov ax,type1seg mov startwriteseg,ax ;set default to userds mov di,offset startwriteoff call getsegandoff ;get start address cmp al,eol jz werr ;need 2 parameters mov ax,startwriteseg mov endwriteseg,ax ;end defaults to start mov di,offset endwriteoff call getsegandoff ;get end address cmp al,eol jnz werr ;no more than 2 parameters w1: call writefile mov dx,offset fcb call close ret werr: jmp err ; ; *************************************** ; * * ; * x - display/alter CPU state * ; * * ; *************************************** ; xdisp: ;display CPU state CALL SETDEFSEG ;SET TYPE1SEG, LASLOC TO CS:IP TEST COL40,0FFH JNZ XD40 call printregheader xnohdr: ;entry point to display CPU state without header TEST COL40,0FFH JNZ XNH40 call crlf call printflags call blank call printregs call printinstr ;disassemble instruction at [cs:ip] ret ; XD40: CALL PREGHDR1 MOV AL,1 JMPS XD0 XNH40: MOV AL,0 XD0: PUSH AX ;SAVE HEADER/NO HEADER FLAG CALL CRLF CALL PRINTFLAGS CALL BLANK CALL PREG1 CALL CRLF POP AX DEC AL JNZ XD1 CALL PREGHDR2 CALL CRLF XD1: CALL PREG2 CALL PRINTINSTR RET xcom: mov segflag,1 ;display seg reg's in x command call conin cmp al,eol ;check for command by itself jz xdisp ;if so, simply display CPU state mov xtemp,al ;else save char call conin cmp al,eol ;check for single character after X jz xflag ;if so, must be a flag name mov ah,xtemp ;else it's a reg name or al,80h ;since names are declared that way xchg al,ah ;since that's how it is in memory call chkreg ;check for valid reg name + store number in regnum call conin cmp al,eol jnz xerr ;eol must follow reg name x0: call crlf mov cx,regnum call printregname call blank mov cx,regnum call printregval call blank call getline call conin cmp al,'.' jz xret ;done when '.' entered dec conptr ;else rescan character call getnumber cmp al,eol jnz xerr ;eol must follow number or ah,ah ;see if non-blank entry jz xnext ;if blank, go to next reg mov cx,regnum mov ax,bx ;get new value cmp cl,8 ;are we updating cs? jnz x1 mov type1seg,ax ;if so, update default type1 segment x1: cmp cl,9 ;are we updating ds? jnz x2 mov type2seg,ax ;if so, update default type2 segment x2: call setreg xnext: inc regnum cmp regnum,totreg jb x0 ret xerr: jmp err ; xflag: mov al,xtemp ;get flag name call checkflag ;check for valid flag name call crlf mov cx,regnum ;restore flag number call printflagname call blank mov cx,regnum call printflagval call blank call getline call getnumber cmp al,eol jnz xerr ;eol must follow number or ah,ah ;see if non-blank entry jz xret ;if blank, done cmp bx,1 ja xerr ;flag value must be 0 or 1 mov cx,regnum call setflag xret: ret ; eject ; ********************************* ; * * ; * d a t a a r e a * ; * * ; ********************************* ; ; user regs must be in cseg, others may be in dseg ; userax dw 0 userbx dw 0 usercx dw 0 userdx dw 0 usersp dw 0 userbp dw 0 usersi dw 0 userdi dw 0 usercs dw 0 userds dw 0 userss dw 0 useres dw 0 userip dw 0 userfl dw 0 userreg equ userax ; savess dw 0 ;temp holder for sp savesp dw 0 ;temp holder for sp ; breakfl rs 1 ;break/single step flag (must be in CS) ; endcs equ $ ; dseg org offset endcs ; ; CCP STACK LOCATION ; CCPSS DW 0 CCPSP DW 0 ; ; console buffer declarations ; conbuffmax equ 64 conbuffhdr db conbuffmax conbuffcnt db 0 conbuff rs conbuffmax+1 ;leave room for eol conptr dw 0 ; ; a command declarations ; assempresent db 1 ;assembler in memory flag asmspsav rw 1 ;temporary save for stack pointer ; ; d command declarations ; disloc dw 0 ;offset for display disseg dw 0 ;segment for display dismax rw 1 ;end offset of display tdisp rw 1 ;temporary storage for disloc LINEMAX DB 0 ;# OF BYTES PER LINE ND80 DB 16 ;16 BYTES PER LINE IN 80 COL MODE ND40 DB 6 ;6 BYTES PER LINE IN 40 COL MODE NDW40 DB 8 ;8 BYTES (4 WORDS) FOR DW IN 40 COL MODE NLINES DB 12 ;DEFAULT NUMBER OF LINES FOR L, D COMMANDS ; ; g command declarations ; goloc dw 0 goseg dw 0 vectorsave rs 12 ;save area for bytes at 0004h to 000fh bpcnt db 0 ;breakpoint count brk1loc dw 0 brk1seg dw 0 brk1byt db 0 brk2loc dw 0 brk2seg dw 0 brk2byt db 0 ; ; l command declarations ; lasloc dw 0 lasseg dw 0 lasmax dw 0 lascntsw rb 1 ;# instructions specified or not lascnt rb 1 ;number of instructions to disassemble disempresent db 1 ;disassembler in memory flag ; ; r command declarations ; startreadoff rw 1 ;offset where file read starts startreadseg rw 1 ;segment where file read starts endreadoff rw 1 ;offset where file read ends endreadseg rw 1 ;segment where file read ends dmaoff rw 1 ;offset of 20-bit dma address dmaseg rw 1 ;segment of 20-bit dma address ; ; t/u command declarations ; tracecount rw 1 ;number of instructions to trace traceprint rb 1 ;display CPU state on each step flag skipbdos db 0 ;set when trace suspended during BDOS call USERIFOFF DB 0 ;SET WHEN DDT86 MUST REENABLE USER IF ; ; w command declarations ; startwriteoff rw 1 ;offset where file write starts startwriteseg rw 1 ;segment where file write starts endwriteoff rw 1 ;offset where file write ends endwriteseg rw 1 ;segment where file write ends ; ; x command declarations ; NREG DB 0 ;CURRENT NUMBER OF REGISTER NAMES TO DISPLAY ;(MAY DIFFER FOR 40 COLUMN MODE) TOTREG EQU 13 ;TOTAL NUMBER OF REGISTER NAMES nflag equ 9 ;number of flag names segflag db 1 ;print segment register flag regnum rw 1 ;temp for reg/flag number xtemp rb 1 ;temp for first char of reg name ; type1loc dw 0 ;offset for type 1 commands type1seg dw 0 ;segment for type 1 commands type2loc dw 0 ;offset for type 2 commands type2seg dw 0 ;segment for type 2 commands usermax rw 1 userloc2 rw 1 userseg2 rw 1 ; ; memory control block declarations ; mcb rs 0 ;used in reading/writing file mcbbase dw 0 ;segment of memory block mcblen dw 0 ;length of memory block mcbext db 0 ;returned value from bdos memory functions ; sysif rb 1 ;system interrupt flag numreq rb 1 ;number required or optional wmode rb 1 ;set for DW, FW and SW commands mode db 'I' ;last disk access with 'R' or 'E' command savevecflag db 0 ;save/restore bp and ss vectors, or not COL40 DB 0 ;PATCHED TO 1 FOR 40 COLUMN CONSOLE ERRMODE DB 0 ;SET IF BDOS RETURN ERR MODE SET (V3.0) ; basepagesave rb 48 ;copy of user's base page ; ; parsing declarations ; delims db ' ', '=', '.', ',', ':', ';', '[', ']', '<', '>', eol ndelims equ offset $ - offset delims lastchar db 0 fcbadr dw 0 ;temp storage for fcb address ; rs stsize ;stack size stackp rs 0 ;top of stack ; if debug ; biosentryoff dw 0a00h ;empty part of ccp (hopefully) biosentryseg dw 0 ;same as bdos segment ; endif ; end