Files
Digital-Research-Source-Code/CPM OPERATING SYSTEMS/CPM 86/CONCURRENT/CCPM-86 3.1 SOURCE/D7/DDT86.A86
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

2663 lines
57 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

title 'DDT86 1.2 8/20/82'
;
; *****************************************
; * *
; * D D T 8 0 8 6 - 8 0 8 8 *
; * *
; *****************************************
;
ddt_org equ 100h ;origin of this module
lasmorg equ ddt_org+1400h ;origin of disassembler
asmorg equ ddt_org+2300h ;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.','2'
;
date db ' 08/20/82',' ' or 80h
;
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:
mov si,offset signon ;get sign on message
call printm ;and print it
CALL GETDATAPAGEADDR
CMP BX,0FFFFH ;SEE IF FUNCTION IS IMPLEMENTED
JZ D15 ;SKIP COLUMN CHECK IF THERE IS NO DATA PAGE
CMP ES:BYTE PTR 64[BX],80 ;CHECK FOR 80-COLUMN CONSOLE
JNC D15 ;IF >= 80, NO FURTHER ACTION
MOV COL40,1 ;IF < 80, SET 40-COLUMN MODE
D15:
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:
CMP FILEOPEN,0 ;SEE IF A FILE WAS LEFT OPEN
JZ STRT00 ;IF NOT, SKIP CLOSE
MOV DX,OFFSET FCB
CALL CLOSE ;CLOSE FILE
STRT00:
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 QUERY ;QUERY I/O PORT
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
;
consin:
mov cl,1
call bdos
ret
;
conout:
mov cl,2
mov dl,al
call bdos
ret
;
rdconbuff:
mov cl,10
call bdos
ret
;
constat:
mov cl,11
call bdos
ret
;
version:
mov cl,12
jmp bdos
;
open:
mov cl,15
call bdos
inc al ;test for 0ffh returned
jz openerr
MOV FILEOPEN,1
ret
openerr:
mov si,offset openm
jmps errm
;
close:
mov cl,16
call bdos
inc al
jz closeerr
MOV FILEOPEN,0
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
;
COMPUTEFILESIZE:
MOV CL,35
JMP BDOS
;
seterrmode:
mov cl,45
jmp bdos
;
GETDATAPAGEADDR:
MOV CL,49
JMP BDOS
;
setdmab:
mov cl,51
jmp bdos
;
errm:
call printm
jmp start
;
getmaxmem:
PUSH DX
mov cl,53
call bdos
POP DX
inc al
jz memerr
CALL ALLOCABSNOCHECK
ret
;
GETABSMAX:
PUSH DX
MOV CL,54
CALL BDOS
POP DX
INC AL
JZ MEMERR
CALL ALLOCABSNOCHECK
RET
;
ALLOCMEM:
MOV CL,55
CALL BDOS
INC AL
JZ MEMERR
RET
;
ALLOCABSNOCHECK:
MOV CL,56
JMP BDOS
;
allocabsmem:
CALL ALLOCABSNOCHECK
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
jmps errm
;
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 *
; * *
; ****************************************************
;
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
;
RAWCONIN:
mov si,offset conbuff
add si,conptr
lods al
inc conptr
RET
;
CONIN:
CALL RAWCONIN ;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
;
DEBLANK:
CALL CONIN
MOV LASTCHAR,AL
CMP AL,' '
JZ DEBLANK ;DEBLANK INPUT
RET
;
setupdisk: ;set byte 0 of fcb according to char in fcb (1)
CALL DEBLANK
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 PR1
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
JMPS PR1
pr0:
call testregcl ;see if reg should be printed
jnb pr2 ;don't print if carry not set
push cx
CALL BLANK
POP CX
PR1:
PUSH CX
CALL PRINTREGVAL
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,8
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
MOV NREG,13
JMPS PRH05
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
mov cx,3
call tabs
POP CX
PRH05:
PUSH CX
CALL PRINTREGNAME
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 SETDONE
mov useres,ax ;set it if there was one
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
MOV AX,USERDS
MOV TYPE2SEG,AX ;SEG TYPE2SEG
RET
;
breakaddr: ;print address where break occurred
call crlf
mov al,'*'
call conout
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:
OR TRACECOUNT,0 ;IF COUNT IS 0, MUST HAVE GOT HERE
;BY TRACING THRU A PUSHF INSTRUCTION, AND
;LATER POPPING THE FLAGS AFTER A G COMMAND.
JZ RSTORE ;IF SO, SIMPLY CONTINUE WITH G COMMAND
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 - <sr>:
;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:
;<empty>
;nnnn
;sr:nnnn
;mmmm:nnnn
;if numreq set, <empty> is invalid
;called with:
;di = offset of 4 byte area containing <offset><segment>
;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 <offset>
mov 2[di],dx ;first number (or sr) goes to <segment>
ret
gets2:
mov [di],dx ;only one number, put it in <offset>
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,STARTREADSEG
MOV ENDREADSEG,AX
MOV AX,STARTREADOFF
MOV ENDREADOFF,AX
rf0:
MOV DX,MCBBASE
call setdmab ;set dma base
MOV DX,0
CALL SETDMA ;DMA OFFSET WILL ALWAYS BE 0
cmp mcblen,8 ;8 paragraphs per sector
JB NOMEM ;NO MORE MEMORY, CHECK FOR END OF FILE
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,ENDREADOFF
MOV BX,80H
ADD BX,AX ;COMPUTE NEW END OFFSET
CMP BX,AX ;CHECK FOR WRAPAROUND
JNC RF1
ADD ENDREADSEG,1000H ;INCREMENT SEGMENT IF WRAP OCCURRED
RF1:
MOV ENDREADOFF,BX ;UPDATE END READ OFFSET
JMPS RF0 ;CONTINUE READING
readdone:
MOV AX,ENDREADOFF
DEC ENDREADOFF ;TO POINT TO LAST BYTE ACTUALLY READ
OR AX,AX ;WERE WE ON A 64K BOUNDARY?
JNZ RF2
SUB ENDREADSEG,1000H ;SINCE ONE TOO MANY WAS ADDED IN READ LOOP
RF2:
MOV DX,OFFSET FCB
CALL CLOSE
ret
NOMEM:
MOV DX,CS
CALL SETDMAB
MOV DX,80H
CALL SETDMA ;POINT TO DEFAULT BUFFER IN SID86 BASEPAGE
MOV DX,OFFSET FCB
CALL READSEC ;JUST TO SEE IF WE ARE AT THE END OF THE FILE
CMP AL,1 ;TEST FOR EOF ERROR
JZ READDONE ;IF NO MORE FILE, SIMPLE RETURN
;ELSE FALL THRU TO ERROR
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
CMP AL,EOL
JNZ ASMERR ;ONLY 1 PARAMETER ALLOWED
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'
;
eerr:
jmp err
execute:
CALL DEBLANK
cmp al,eol ;check for no filename
JZ FREE ;NO FILENAME MEANS FREE ALL MEMORY
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
CALL FREE
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
FREE:
mov mcbext,0ffh ;free all allocations below DDT86
mov dx,offset mcb
call freemem ;free all memory previously allocated under DDT
RET
;
; ***************************
; * *
; * 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
;
; *************************
; * *
; * Q - QUERY I/O *
; * *
; *************************
;
QUERY:
CALL CONIN ;CHECK FOR INPUT OR OUTPUT
CMP AL,'I'
JZ QINPUT
CMP AL,'O'
JZ QOUTPUT
QERR:
JMP ERR
;
QINPUT:
CALL CHECKWORD ;CHECK FOR 16-BIT INPUT
CALL GETLASTOFFSET ;GET PORT #
PUSH BX ;SAVE PORT ADDR
CALL CRLF
POP DX ;SET UP FOR IN INSTRUCTION
TEST WMODE,0FFH
JZ INBYTE ;IF WMODE = 0, INPUT A BYTE
IN AX,DX ;OTHERWISE, INPUT A WORD
CALL PRINTWORD ;AND PRINT THE VALUE
RET
INBYTE:
IN AL,DX ;INPUT A BYTE
CALL PRINTBYTE ;AND PRINT IT
RET
;
QOUTPUT:
CALL CHECKWORD ;CHECK FOR 16-BIT OUTPUT
CALL GETOFFSET ;GET PORT #
PUSH BX ;SAVE PORT #
CMP AL,EOL
JZ QERR ;REQUIRES 2 ARGUMENTS
CALL GETLASTOFFSET ;GET VALUE TO OUTPUT
MOV AX,BX ;PREPARE FOR OUT INSTRUCTION
POP DX ;RESTORE PORT #
TEST WMODE,0FFH ;CHECK FOR 8 OR 16-BIT OUTPUT
JZ OUTBYTE
OUT DX,AX ;OUTPUT 16-BIT VALUE
RET
OUTBYTE:
OR AH,AH ;TEST FOR VALUE > 255
JNZ QERR ;VALUE MUST BE <= 255 FOR 8-BIT OUTPUT
OUT DX,AL ;OUTPUT 8-BIT VALUE
RET
;
; *************************
; * *
; * r - read file *
; * *
; *************************
;
rerr:
jmp err
read:
MOV ABSREADFLAG,0 ;DEFAULT TO NOT ABSOLUTE
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
JZ READ1 ;1 PARAMETER ALLOWED - ABSOLUTE LOCATION
MOV AX,TYPE1SEG
MOV STARTREADSEG,AX ;DEFAULT TO TYPE1 SEG VALUE
MOV DI,OFFSET STARTREADOFF
CALL GETSEGANDOFF ;GET READ ADDRESS
CMP AL,EOL
JNZ RERR ;NO MORE PARAMETERS ALLOWED
AND STARTREADOFF,0FFF0H ;MASK TO PARAGRAPH BOUNDARY
MOV AX,STARTREADOFF
MOV CL,4
SHR AX,CL ;GET # PARAGRAPHS IN OFFSET
ADD AX,STARTREADSEG ;COMPUTE ACTUAL PARAGRAPH # FOR READ
MOV MCBBASE,AX ;SET UP MCB FOR ABSOLUTE REQUEST
MOV ABSREADFLAG,1 ;SET SO ALLOC ABS IS USED LATER
READ1:
mov dx,offset fcb
call open
MOV DX,OFFSET FCB
CALL COMPUTEFILESIZE
CMP BYTE PTR FCB+35,0 ;CHECK R2 BYTE IN FCB
JNZ TOOBIG ;FILE TOO BIG IF OVER FFFF RECORDS
MOV AX,WORD PTR FCB+33 ;GET FILE SIZE (IN RECORDS)
CMP AX,2000H ;1FFFH RECORDS = FFF0 PARAGRAPHS, WHICH IS MAX
JNC TOOBIG
MOV CL,3
SHL AX,CL ;* 8 TO CONVERT RECORDS TO PARAGRAPHS
MOV MCBLEN,AX ;SET MEMORY REQUEST SIZE
mov dx,offset mcb
TEST ABSREADFLAG,0FFH
JNZ READ2 ;USE ALLOC ABS IF ADDRESS SPECIFIED
CALL ALLOCMEM ;GET CHUNK REQUIRED FOR FILE
JMPS READ3
READ2:
CALL ALLOCABSMEM
JMPS READ3
READ3:
TEST ABSREADFLAG,0FFH
JNZ READ4 ;IF ABS READ - START, END ALREADY SET UP
MOV AX,MCBBASE
MOV STARTREADSEG,AX
MOV ENDREADSEG,AX
MOV STARTREADOFF,0
READ4:
call readfile ;read file into memory block
mov ax,startreadseg
mov type2seg,ax ;set default type2 segment to file just read
mov type1seg,ax ;also type1 segment
MOV AX,STARTREADOFF
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
TOOBIG:
JMP MEMERR
;
; **************************
; * *
; * s - set memory *
; * *
; **************************
;
setmem:
CALL CONIN
CMP AL,'R' ;'SR' IS SEARCH COMMAND
JZ SEARCH
DEC CONPTR ;TO RESCAN THE CHAR READ ABOVE
call checkword ;check for 'SW'
mov di,offset type2loc
call getsegandoff
CMP AL,EOL
JNZ SETERR ;ONLY 1 ARGUMENT ALLOWED
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
;
; ***********************
; * *
; * SR - SEARCH *
; * *
; ***********************
;
SRERR:
JMP ERR
;
SEARCH:
MOV DI,OFFSET TYPE2LOC
CALL GETSEGANDOFF ;GET ADDRESS OF START OF SEARCH BLOCK
CALL GETOFFSET ;GET OFFSET OF END OF SEARCH BLOCK
PUSH BX ;SAVE END OFFSET
MOV STRINGLEN,0 ;CLEAR SEARCH STRING LENGTH
SRLOOP1:
CALL CONIN
CMP AL,'"' ;CHECK FOR START OF ASCII STRING
JZ GETSTRING ;IF SO, COLLECT STRING THRU " OR EOL
DEC CONPTR ;IF NOT A STRING, RESCAN FIRST CHAR
CALL GETOFFSET ;GET NUMERIC VALUE
PUSH AX ;SAVE DELIMITER
OR BH,BH ;TEST VALUE FOR < 256
JNZ SRERR ;DON'T ALLOW VALUES OVER 255
MOV AL,BL
CALL PUTSTRING ;PUT VALUE INTO STRING BUFFER
POP AX ;RESTORE DELIMITER
CHKEND:
CMP AL,EOL ;CHECK FOR DONE
JZ SRCH ;IF EOL FOUND, PROCEED WITH SEARCH
JMPS SRLOOP1 ;ELSE GO BACK FOR MORE VALUES
;
GETSTRING: ;COLLECT STRING THRU '"' OR EOL
CALL RAWCONIN
CMP AL,EOL
JZ SRCH ;EOL MEANS END OF SEARCH STRING
CMP AL,'"'
JNZ NOTQUOTE
CALL CONIN ;IF WE FOUND A QUOTE, CHECK FOR DOUBLE QUOTE
CMP AL,'"'
JNZ CHKEND ;NOT " MEANS END OF STRING; COULD BE MORE ON LINE
NOTQUOTE:
CALL PUTSTRING ;PUT ASCII CHAR IN SEARCH BUFFER
JMPS GETSTRING ;KEEP COLLECTING STRING
;
PUTSTRING: ;PUT CHAR IN AL INTO SEARCH BUFFER
MOV BL,STRINGLEN
MOV BH,0
MOV STRINGBUFF[BX],AL
INC STRINGLEN
RET
;
SRCH:
POP BX ;GET END ADDRESS
LES DI,DWORD PTR TYPE2LOC ;SET UP DEST OF SEARCH
CMP BX,DI ;CHECK FOR END < START
JC SRERR ;ERROR IF END < START
MOV CL,STRINGLEN
MOV CH,0
JCXZ SRERR ;DON'T ALLOW NULL SEARCH STRING
SUB BX,CX
INC BX ;BX HAS LAST LOC TO TEST
SRLOOP3:
MOV SI,STRINGBUFF ;SET UP SOURCE OF SEARCH
CMP BX,DI ;CHECK FOR DONE
JC SRDONE
PUSH CX
PUSH BX ;SAVE SOME VALUES
PUSH DI
REP CMPSB ;DO COMPARE
JNZ NOMATCH ;ZERO FLAG UNSET MEANS BAD COMPARE
PUSH ES ;SAVE FOR PRINTDWORD
CALL CRLFCHK ;ELSE CRLF AND CHECK FOR KB INTERRUPT
POP ES ;RESTORE FOR PRINTDWORD
POP DI ;GET ADDRESS OF START OF STRING
PUSH DI ;AND PUT IT BACK ON THE STACK
PUSH ES ;SAVE FOR SEARCHING
CALL PRINTDWORD ;AND PRINT MATCH ADDRESS
POP ES ;RESTORE FOR SEARCHING
NOMATCH:
POP DI
POP BX
POP CX ;RESTORE THE REGS
INC DI ;POINT TO NEXT LOCATION TO COMPARE
JMPS SRLOOP3 ;KEEP LOOKING
SRDONE:
RET
;
; ***************************************
; * *
; * 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
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 BLANK
JMPS XRET2 ;PRINT INSTRUCTION AND RETURN
;
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
XRET2:
call printinstr
XRET1:
CALL SETDEFSEG ;SET UP DEFAULT SEGMENTS
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 XRET1 ;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
call setreg
xnext:
inc regnum
cmp regnum,totreg
jb x0
JMPS XRET1 ;SET UP DEFAULT SEGMENTS AND RETURN
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
ABSREADFLAG DB 0 ;SET IF READING INTO ABSOLUTE SEGMENT
;
; SR COMMAND DECLARATIONS
;
STRINGLEN DB 0 ;LENGTH OF SEARCH STRING
STRINGBUFF EQU 80H ;USE DEFAULT DMA BUFFER
;
; 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)
FILEOPEN DB 0 ;SET WHEN FILE IS OPEN
;
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
;
end