mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-26 18:04:07 +00:00
2553 lines
53 KiB
Plaintext
2553 lines
53 KiB
Plaintext
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 - <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,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
|