; -------------------------------------------------------- ; DDT.COM is a part of the collection of programs which ; one receives when buying CP/M from Digital Research. Of ; all the programs in the CP/M package, it is one of the ; weakest, and seems to have been mainly intended to use ; to insert the custom part of BIOS into CP/M when it is ; desired to generate a new system. Its strongest point is ; its single step facility and its suppression during the ; execution of BDOS. Its most frustrating point may be its ; lack of transparency to the command line of programs to ; which it is to be applied. ; ; The present program was based on a disassembly of the ; Digital Research version, which has now been very ; extensively rearranged, even though vestiges of that ; original program still remain. Several minor errors ; have been corrected, but the important changes consist ; in the greatly expanded capabilities of most of the ; options, besides a complete replacement of both the ; assembler and the disassembler. Many commands now admit ; a repeat factor, examination of registers and memory is ; much more extensive, and a bitmap can generated to mark ; significant memory locations. Other modifications or ; extensions may be deduced from the change log below. ; ; Since DDT will be coresident with the program it will ; examine, it is convenient to relocate it to high memory ; and adjust the BDOS call to reflect less free space. If ; an origin for the relocated DDT can be assigned, a small ; translation program is included to move it once loaded. ; It has been disabled by commenting it out. It would have ; to be assembled by Microsoft's M80 or a similar assembler ; allowing phasing and dephasing. It is much more general ; to generate a bitmap for a page relocator, for which the ; following script will serve as a guide. It assumes that ; the utilities LOHD.COM, GENBIM.COM, and PAGREL.COM are ; available; also that two separate copies of DDT were ; prepared: NDDT at origin 100H, and ZDDT at origin 000H, ; but otherwise identical. ; ; A>ASM NDDT.AAZ ; A>ASM ZDDT.AAZ ; A>LOHD NDDT ; A>LOHD ZDDT ; A>GENBIM ZDDT NDDT ; A>NDDT PAGREL [NEXT = 180] ; -IZDDT.COM ; -R100 [NEXT = 1600] ; -IZDDT.BIM ; -R1500 [NEXT = 1900] ; -S103 ; . 0103 BB 00 ; . 0104 BB 02 ; . 0105 EE 00 ; . 0106 EE 16 ; h 0107 68 . ; -^C ; A>SAVE 24 NDDT.COM ; ; NDDT.ASM -- Copyright (C) 1983 ; Universidad Autonoma de Puebla ; 20 November 1983 ; ; ---------------: B generates a bitmap, L shows X's. ; ---------------: V is a T which ignores CALLs. ; 24 October 1982: R sets 007C to zero before starting. ; 24 October 1982: I will read an entire command line. ; 06 November 1982 - preliminary circulation copies. ; 12 December 1982 - XA shows both HEX, ASCII values. ; 12 December 1982 - X confirms register changes. ; 13 December 1982 - 007C zeroed while opening file. ; 13 December 1982 - I when leaving HEX option. ; 13 December 1982 - taken as .COM ; 13 December 1982 - P "Peek" added. ; 16 December 1982 - E "Execute" added. ; 18 December 1982 - S accepts quoted character. ; 20 December 1982 - edition for Assembler II. ; 7 August 1983 - correct overwrite of b in G. ; 7 August 1983 - zero 7C after initial program load. ; 20 August 1983 - clear memory before loading. ; 20 August 1983 - decimal prefix to all commands. ; 22 August 1983 - new format for display line. ; 22 August 1983 - En,xxxx superseded by nG,xxxx. ; 23 August 1983 - nV/, nT/, nU/ suppress display lines. ; 23 August 1983 - X=xxxx displays a window around xxxx. ; 23 August 1983 - nU superseded by nT/. ; 23 August 1983 - P incorporated into X. ; 26 August 1983 - M moves overlapping interval backwards. ; 26 August 1983 - A does not leave 3 0D's on exit. ; 28 August 1983 - General rearrangement and revision. ; 30 August 1983 - Edition for Languages II. ; 20 November 1983 - X - jz for jnz refused flag changes. ; 20 November 1983 - ASM - assembly of RST N was wrong. ; 20 November 1983 - stor - xra a to avoid false signals. ; [Harold V. McIntosh, 20 December 1982] ; [Harold V. McIntosh, 30 August 1983] ; -------------------------------------------------------- HT equ 09H ;tab LF equ 0AH ;line feed CR equ 0DH ;carriage return KZ equ 1AH ;^Z RO equ 7FH ;rubout ;ddtorg equ 09000H ;absolute DDT origin ; ; ;; Move DDT up to higher memory. ; ;X0100: lxi b,enddt-begn ;X013D: lxi sp,begn ; lxi d,ddtorg ; lxi h,X0165 ;X0158: mov a,b ; ora c ; jz ddtorg ; dcx b ; mov a,m ; stax d ; inx d ; inx h ; jmp X0158 ;X0165: ds 0 ; ;; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ; ; .phase ddtorg org 0100H begn: jmp init ;initialize DDT ; ======================================================== ; Assembler for the INTEL 8080. As a "small" assembler, ; it is subject to the following restraints: ; 1) only hexadecimal numbers are accepted ; 2) opcode identification is merely sufficient ; 3) source code is not confined to a single line ; 4) error detection only for an unintelligible ; opcode or field; then three zero bytes are ; deposited to allow patches, assembler line ; is abandoned ; 5) implausible combinations are not rejected ; ; Register pair HL points to the byte in which the ; assembled opcode will be stored. If necessary, hex ; data or address fields will be read and HL will be ; incremented by 1, 2, or 3 as required. Flags are valid ; on return; zero means no error. ; ; No RAM memory is used directly by the program, so that ; it may be inscribed in its entirity in a PROM. All its ; requirements for temporary storage are met from the ; internal registers of the 8080 or the stack. ; ======================================================== assm: push h lxi h,stor push h call alfa jmp aopco ; Read an alpha field by ignoring leading separators, ; storing letters in registers C,D,E, and terminating ; reading when a separator is again encountered. All ; fields are held to three letters, so that the only ; letters in a chain that are stored are the first, ; second, and last. alfa: lxi d,' ' ala: call relc call sepa jz ala mov c,a call relc call sepa rz call term rz mov d,a alb: call relc call sepa rz call term rz mov e,a jmp alb ; Read an alpha field with the intention of keeping only ; the last letter in the field. Otherwise the same rules ; apply as in the subroutine alfa: leading separators are ; ignored, trailing separators terminate. beta: call relc call sepa jz beta bet: mov b,a call relc call sepa jz bta call term jnz bet bta: mov a,b ret ; Locate the operation codes. A simple linear search is ; made of some sixty mnemonics, grouping them mostly in ; sets of eight because their position within an octet ; translates directly into a source or destination field ; in the 2-3-3 decomposition of INTEL 8080 opcodes. aopco: mvi b,0CH lxi H,AT4 ;Quadrant 0 with minor modifications call mnem jp AQ0 mvi b,01H lxi h,AT0 ;Quadrant 1: interregister movements call mnem jp AQ1 mvi b,08H lxi h,AT1 ;Quadrant 3: arithmetic-logical call mnem jp AQ2 mvi b,08H lxi h,AT2 ;Quadrant 2, column 6: immediate call mnem jp AB6 mvi b,11H lxi h,AT5 ;All the sporadic opcodes call mnem jp qq mvi b,08H lxi h,AT3 ;Quadrant 0, column 7: accumulator call mnem jp AA7 mov a,c cpi 'r' jz AB0 ;Quadrant 3, column 0: returns cpi 'j' jz AB2 ;Quadrant 3, column 2: jumps cpi 'c' jz AB4 ;Quadrant 3, column 4: calls mvi b,05H lxi h,AT7 ;Assembler directives call mnem jp QD jmp hexb ; Quadrant zero - memory to register - and some others. AQ0: mov c,a call juta dw X0 ;pop pair dw AA1 ;lxi pair,addr dw AA0 ;stax pair - beware - only b, d legal dw AA0 ;inx pair dw AA4 ;inr register dw AA4 ;dcr register dw AA6 ;mvi register,data dw AB7 ;rst digit in opcode dw Y0 ;push pair dw AA0 ;dad pair dw AA0 ;ldax pair - beware - only b, d legal dw AA0 ;dcx pair X0: mvi c,0C1H jmp AA0 Y0: mvi c,0C5H AA0: call beta call apair ora c ret AA1: call AA0 jmp addq AA4: call rdst ora c ret AA6: call AA4 jmp datq AA7: add a add a add a ori 07H ret AQ1: call rdst mov c,a call rsrc ora c ori 040H ret AQ2: add a add a add a mov c,a call rsrc ora c ori 080H ret qq: cpi 09H jc ss lxi h,adata cpi 0BH jc rr lxi h,aaddr rr: xthl ss: lxi h,AT8 jmp reta ; Quadrant 3 - mostly program counter modification AB0: mvi a,0C0H jmp abb AB2: mvi a,0C2H call abb jmp addq AB4: mvi a,0C4H call abb jmp addq abb: push psw mvi c,' ' mvi b,08H lxi h,AT6 call mnem pop b jm error add a add a add a ora b ret ; Immediates. AB6: add a add a add a ori 0C6H jmp datq ; Restarts. AB7: call beta rlc rlc rlc ani 038H ori 0C7H ret ; Assembler directives. QD: call juta dw D0 ;data byte dw D1 ;data word dw D2 ;data space dw D3 ;origin dw D4 ;end D0: inx sp ;data byte inx sp pop d call hxar mov l,a mvi a,0FDH ;error rnz inr a ;(org) xchg mov m,e inx h ret D1: inx sp ;data word inx sp pop d call hexf mvi a,0FDH ;error rnc inr a ;(org) xchg mov m,e inx h mov m,d inx h ret D2: inx sp ;data space inx sp pop d call hexf mvi a,0FDH ;error rnc inr a ;org dad d ret D3: inx sp ;origin inx sp inx sp inx sp call hexf mvi a,0FEH ;org rc dcr a ret D4: inx sp ;end inx sp inx sp inx sp mvi a,0FFH ;done ret ; If the operation field did not hold a valid opcode or ; assembler directive, try it out for a one-byte, two ; nibble hexadecimal byte. hexb: lxi h,error push h mov a,e cpi ' ' rz mov a,c call cnh rc add a add a add a add a mov b,a mov a,d call cnh rc add b inx sp inx sp ret ; Read and deposit a hexadecimal address field. addq: inx sp inx sp aaddr: mov b,a call onar xchg pop h mov m,b inx h mov m,e inx h mov m,d inx h ret ; Read and deposit a one-byte hexadecimal data field. datq: inx sp inx sp adata: mov b,a call hxar jnz error ; xchg pop h mov m,b inx h mov m,e inx h ret ; Deposit the assembled operation code stor: pop h mov m,a inx h xra a ;don't return the wrong signal ret ; Load accumulator with nth item in the list whose ; origin is contained in register pair HL, when n ; lies in the accumulator. reta: add l mov l,a mov a,h aci 00H mov h,a mov a,m ret ; Find numerical equivalents for register designations. ; Source registers are reported at their true value, but ; destination registers are multiplied by eight to have ; their value positioned correctly for its field. rsrc: call beta srce: mvi b,08H lxi h,atr call regi jm error ret rdst: call beta dest: call srce add a add a add a ret ; Find numerical equivalents for register pair symbols. ; They always left-pack their destination field. apair: mvi b,05H lxi h,atp call regi jm error cpi 04H cmc sbi 00H mov b,a add a add a add a add a ret ; Search a list of bytes whose origin is contained in ; in HL to find the one, if any, which matches the ; accumulator. The length of the list in is B on entry; ; on exit A contains either the position or FF if no ; match was found. regi: dcx h cmp m jz reg dcr b jnz regi reg: xra a dcr b ora b ret ; Search a table of three-letter mnemonics to find the ; code contained in registers C,D,E. Enter with the ; table origin in pair HL, the table size N in the ; accumulator. On exit the accumulator will contain ; either the position, ranging between 0 and N-1, of ; the item in the table, or else FF(hex) if it was not ; found. mnem: dcx h mov a,m cmp e jnz mnb dcx h mov a,m cmp d jnz mnc dcx h mov a,m sub c jnz mnd mna: dcr b ora b ret mnb: dcx h mnc: dcx h mnd: dcr b jnz mnem jmp mna ; Table of mnemonics grouped by octets and dodecuplets. dtr: db 'bcdehlma' atr: db 'bdhpw' atp: db 'mov' AT0: db 'add','adc','sub','sbb' db 'ana','xra','ora','cmp' AT1: db 'adi','aci','sui','sbi' db 'ani','xri','ori','cpi' AT2: db 'rlc','rrc','ral','rar' db 'daa','cma','stc','cmc' AT3: db 'pop','lxi','stx','inx' db 'inr','dcr','mvi','rst' db 'puh','dad','ldx','dcx' AT4: db 'nop','ret','pcl','spl' db 'xtl','xcg','di ','ei ' db 'hlt','out','in ','jmp' db 'cal','shd','lhd','sta','lda' AT5: db ' nz',' z ',' nc',' c ' db ' po',' pe',' p ',' m ' AT6: db 'db ','dw ','ds ','org','end' AT7: db nop db ret db pchl db sphl db xthl db xchg db di db ei db hlt db 0D3H ;(out) db 0DBH ;(in) db 0C3H ;(jmp) db 0CDH ;(call) db 022H ;(shld) db 02AH ;(lhld) db 032H ;(sta) db 03AH ;(lda) ; T7 is the end of one table, T8 is the beginning of another. AT8 equ AT7 ; ===================================================== ; Disassembler for the INTEL 8080. Register pair HL ; points to the byte to be disassembled. HL will be ; incremented by 1, 2, or 3 according to the type of ; instruction encountered. No RAM storage is used ; within the program, which may therefore be entirely ; resident in ROM. ; ===================================================== dism: mov a,m push h lxi h,done push h cpi 76H jnz split halt: lxi h,td jmp three ; separate the instruction field into groups of 2,3,3 ; bits and then continue according to quadrants. split: push psw push psw ani 07H mov c,a pop psw rrc rrc rrc ani 07H mov b,a pop psw rlc rlc ani 03H lxi h,jq jump: call bndx mov e,m inx h mov d,m xchg pchl ; Indexing subroutines which add corresponding multiples ; [3,4,2,1] of A to the register pair HL. tndx: mov e,a add a add e jmp indx qndx: add a bndx: add a indx: add l mov l,a mov a,h aci 00H mov h,a ret ; ------------------------------------------------------- ; Quadrant 0 contains accumulator operations, increments, ; decrements, loads, stores and immediate moves, all of ; which must be detailled further. ; ------------------------------------------------------- DQ0: mov a,c lxi h,ja jmp jump ; Column 0 contains NOP together with seven unused codes DA0: mov a,b ora a jnz node noop: lxi h,tc jmp trey ; Column 1 alternates lxi to a register pair with dad ; from a register pair. The lxi's require data words, ; but not the dad's. DA1: mov a,b ani 01H call aa mov a,b ani 01H rnz call sngl jmp daddr ; Column 2 alternates storing and loading instructions. ; The first six refer to register pairs, the last two to ; the accumulator; the last four require addresses. DA2: mov a,b lxi h,DT5 call vier mov a,b ani 04H jz putp jmp daddr ; Column 3 alternates inx of a register pair with dcx of ; the same pair. DA3: mov a,b ani 01H adi 02H aa: lxi h,DT4 call drei jmp putp ; Column 4 contains inr, 5 containd dcr, both modified ; by the register list. DA4: mov a,c lxi h,DT4 call drei mov a,b lxi h,dtr jmp ein ; Column 6 contains the mvi's, which require a data byte. DA6: call DA4 call sngl jmp ddata ; Column 7 contains the accumulator operations. DA7: mov a,b lxi h,AT2 call tndx jmp trey ; ---------------------------------------------------------- ; Quadrant 1 consists of interregister movements. ; ---------------------------------------------------------- DQ1: lxi h,tb call three mov a,b lxi h,dtr call ein call sngl mov a,c lxi h,dtr jmp ein ; ---------------------------------------------------------- ; Quadrant 2 consists of arithmetic operations ; ---------------------------------------------------------- DQ2: mov a,b lxi h,AT0 call drei mov a,c lxi h,dtr jmp ein ; --------------------------------------------------------- ; Quadrant 3 has returns, calls, jumps, pushes, pops, ; and a variety of miscellania needing a detailed study. ; --------------------------------------------------------- DQ3: mov a,c lxi h,jb jmp jump ; Column 0 contains all the conditional returns DB0: mvi a,'r' bb: call aout ;A to console mov a,b lxi h,AT5 call tndx inx h jmp two ; Column 1 contains the pops, together with the unconditional ; return, pchl, sphl, and an undefined code. DB1: mov a,b lxi h,DT7 call vier mov a,b cpi 03H jz dopco ani 01H rnz jmp putq ; Column 2 contains all the conditional jumps. DB2: mvi a,'j' call bb jmp daddr ; Columnn 3 is an assortment, requiring many distinctions. DB3: mov a,b lxi h,DT8 call vier mov a,b cpi 04H rnc cpi 01H jz dopco jc daddr jmp ddata ; Column 4 contains all the conditional calls. DB4: mvi a,'c' call bb jmp daddr ; Column 5 contains the pushes, simple call, 3 undefined. DB5: mov a,b ani 01H jnz xx lxi h,tf call four jmp putq xx: mov a,b cpi 01H jnz node lxi h,te call four jmp daddr ; Column 6 holds all the arithmetic immediates. DB6: mov a,b lxi h,AT1 call drei jmp ddata ; Column 7 contains all the restarts. DB7: lxi h,DT4+21 call three mov a,b adi '0' jmp aout ;A to console ; ------------------------------------------------------ ; a collection of copying and spacing routines. ; ------------------------------------------------------ vier: call qndx jmp four drei: call tndx jmp three ein: call indx jmp one four: call quad jmp sngl three: call trey jmp dubl two: call dpair jmp dubl quad: mov a,m call aout ;A to console inx h trey: mov a,m call aout ;A to console inx h dpair: mov a,m call aout ;A to console inx h one: mov a,m jmp aout ;A to console ; ------------------------------------------------------- ; Commonly used transferrence and conversion routines. ; ------------------------------------------------------- putp: mov a,b ani 06H lxi h,dtp call indx jmp dpair putq: mov a,b ani 06H rrc lxi h,tq call tndx jmp trey done: pop h inx h ret daddr: inx sp inx sp pop h inx h mov e,m inx h mov d,m push h call word jmp done node: lxi h,ta call three dopco: inx sp inx sp pop h jmp goby ddata: inx sp inx sp pop h inx h goby: mov a,m push h call byte jmp done ; -------------------------------------------------------- ; Jump tables ; -------------------------------------------------------- jq: dw DQ0,DQ1,DQ2,DQ3 ja: dw DA0,DA1,DA2,DA3,DA4,DA4,DA6,DA7 jb: dw DB0,DB1,DB2,DB3,DB4,DB5,DB6,DB7 ; -------------------------------------------------------- ; Tables of mnemonics for the 8080 instructions ; -------------------------------------------------------- ta: db 'db ' tb: db 'mov' tc: db 'nop' td: db 'hlt' te: db 'call' tf: db 'push' dtp: db 'b d h sp' tq: db 'b ' db 'd ' db 'h ' db 'psw' DT4: db 'lxi','dad','inx','dcx' db 'inr','dcr','mvi','rst' DT5: db 'stax','ldax','stax','ldax' db 'shld','lhld','sta ','lda ' DT7: db 'pop ','ret ','pop ','db ' db 'pop ','pchl','pop ','sphl' DT8: db 'jmp ','db ','out ','in ' db 'xthl','xchg','di ','ei ' ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- DP equ 16 ;paragraph length for D NL equ 12 ;default lines in L NR equ 12 ;number of registers to examine in X WW equ 5 ;window halfwidth in register display BDOS equ 0005H ;jump to BDOS RST7 equ 0038H ;DDT breakpoint handler TFCB equ 005CH ;DDT's file control block TBUF equ 0080H ;DDT's sector buffer TORG equ 0100H ;program origin bsiz equ 2000H ;8K = size of bitmap XDOS: xthl ;<> shld sica ;site of call to BDOS xthl GDOS: jmp 0000 ;BDOS address ; Initialize DDT init: lhld BDOS+1 shld GDOS+1 ;BDOS address lxi h,XDOS ;DDT analogue of 0005 shld begn+1 lxi h,begn shld BDOS+1 xra a sta bkpt ;breakpoint data lxi h,TORG ;CP/M transient origin shld lorg ;origin for L shld dorg ;origin for D shld pmax ;program high limit shld savpc ;PC at breakpoint shld savmr ;memory reference lxi sp,savhl ;breakpoint push h lxi h,0002 push h dcx h dcx h shld savhl ;HL at breakpoint push h push h mvi a,0C3H ;(jmp) sta RST7 ;RST 7 destination lxi h,rtbk ;return from breakpoint shld RST7+1 lxi b,begn ;top of memory lxi h,TORG ;bottom of memory mov a,c sub l mov c,a mov a,b sbb h mov b,a zero: mov a,c ora b jz zerd mvi m,00 inx h dcx b jmp zero zerd: lxi h,logo ;"DDT/UAP" call mssg mvi c,25 ;(19) read logged in disk call XDOS sta ldsk ;logged disk mvi b,80H lxi d,TBUF lxi h,ctex shld cptr ;pointer to command buffer lxi h,clen muve: ldax d mov m,a inx h inx d dcr b jnz muve mov m,b lxi h,loop ;DDT loop push h lda TFCB+1 ;file name cpi ' ' rz lxi h,TFCB+9 ;extension mov a,m cpi ' ' jnz scom mvi m,'C' inx h mvi m,'O' inx h mvi m,'M' scom: lxi h,0000 ;zero offset call opra ;R with implicit argument jmp opia ;I after discarding program name ; ---------------------------------------------- ; DDT loop: waits for commands and executes them ; ---------------------------------------------- loop: lxi sp,savde ;DDT's private stack lxi h,loop ;DDT loop push h call past ;check limit transgression jc looq lxi h,XDOS ;link to BDOS shld 0006H looq: call crlf ;type CR,LF mvi a,'-' call aout ;A to console call incl ;fetch a command line call decf ;read decimal field cpi CR rz shld rept call alta ;alternate table db 14 db 'A' dw opta ;A = assemble db 'B' dw bmap ;B = bitmap db 'D' dw optd ;D = display db 'F' dw optf ;F = fill db 'G' dw optg ;G = go db 'H' dw opth ;H = hex sum, difference db 'I' dw opti ;I = initialize CCP command line db 'L' dw optl ;L = list program db 'M' dw optm ;M = move db 'R' dw optr ;R = read file db 'S' dw opts ;S = store db 'T' dw optt ;T = type registers db 'V' dw optv ;V = single step w/ call as 1 step db 'X' dw optx ;X = examine registers ; (A) Assemble 8080 code. will assemble n lines ; of code beginning at address x. Defaults are x=lorg, ; while no limit is set if n is missing or zero. opta: call past ;check limit transgression jnc error ; lhld lorg ;origin for L call hef opaa: shld lorg ;origin for L call dubl call tyhl ;type HL as four nibbles call dubl call incl ;fetch a command line jz opac call assm inr a ;FF means done rz inr a ;FE means new origin jnz opab call crlf jmp opaa opab: call ctlx lhld lorg ;origin for L inr a ;FD means error - retry jz opaa opac: call dubl ;otherwise confirm & advance call tyhl ;type HL as four nibbles call dubl call dism call crlf call drnz ;decrement retn if nonzero jnz opaa shld lorg ;origin for L ret ; (B) Generate a bitmap of all bytes in the range ; 100H - (pmax) which could possibly be the address ; of an instruction. bmap: lhld pmax xchg lxi h,begn lxi b,-bsiz dad b mov a,l sub e mov a,h sbb d jc error ; lxi b,bsiz bzer: mvi m,00H inx h dcx b mov a,c ora b jnz bzer lhld pmax ;program high limit xchg lxi h,TORG ;CP/M transient origin mov a,e sub l mov c,a mov a,d sbb h mov b,a bbit: push b mov a,m call twob jnc bbjt push h inx h mov e,m inx h mov d,m xchg call wrib pop h bbjt: inx h pop b dcx b mov a,c ora b jnz bbit ret ; Decide if opcode has one-byte sequel. oneb: cpi 0D3H jz oney cpi 0DBH jz oney ani 0C7H cpi 006H jz oney cpi 0C6H jz oney stc cmc ret oney: stc ret ; decide if opcode has two-byte address twob: push b cpi 0C3H jz twoy cpi 0CDH jz twoy mov b,a ani 0C7H cpi 0C2H jz twoy cpi 0C4H jz twoy mov a,b ani 0CFH cpi 001H jz twoy mov a,b ani 0E7H cpi 022H jz twoy stc cmc pop b ret twoy: stc pop b ret ; read bit corresponding to address HL reab: push h call biby ;addr = byte + bit mov a,m rea: rrc dcr c jnz rea pop h ret ; define bit corresponding to address HL wrib: push psw call biby ;addr = byte + bit push b mov a,m wra: rrc dcr c jnz wra mov m,a pop b pop psw mov a,m ral rrc wrb: rlc dcr c jnz wrb mov m,a ret ; reduce an address to byte (HL), bit (C). biby: mov a,l ani 07H inr a mov c,a mvi b,3 bib: mov a,h rar mov h,a mov a,l rar mov l,a dcr b jnz bib mov a,h ani 1FH mov h,a lxi d,begn dad d lxi d,-bsiz dad d ret ; (D) Display the memory in groups of 16 bytes, both as ; pairs of hexadecimal nibbles and as ASCII characters, ; when the latter is appropriate. The command ; will display n lines, or else the interval between ; hexadecimal addresses a and b; the interval takes ; precedence but if a or b or both are null, the line ; count helps determine the interval. When a is null the ; display will usually continue from where it last ended, ; but nD,b will display b-n up to b. In general: ; nDa,b a through b-1, n lines of 16 bytes ; Da,b a through b-1, DP lines of 16 bytes ; nDa, a through a+n ; nD,b b-n through b ; nD, PC through PC+n ; Da, a to the end ; Da just line containing a ; D,b PC through b ; D, PC to the end ; D just line beginning at PC optd: lxi h,pinc ;paragraph length mvi m,DP lhld rept mov a,l ora h sui 1 sbb a ani 01H mov b,a ;1 means n=0 dad h dad h dad h dad h shld rept ;1 line is worth 16 bytes lhld dorg ;default is dorg call hef ;read mov c,a mov a,b ral mov b,a ;0 means null xchg lhld rept dad d ; is default mov a,c sui CR jz opda lxi h,0FFF0H opda: sui 1 mov c,a ;FF means CR mov a,b ral mov b,a ;1 means CR call hef ;read mov a,b ral mov b,a inr c jnz opdb ;z means CR lhld rept dad d opdb: shld dorg ; At this point, DE=, HL=, B defines case, ; but a few anomalies still have to be resolved. mov a,b cpi 01H jnz opdc lhld dorg xchg lhld rept mov a,e sub l mov l,a mov a,d sbb h mov h,a xchg ;else a=b-n opdc: cpi 05H jz opdd cpi 04H jz opdd cpi 00H jnz opde opdd: lhld rept dad h dad h dad h dad h mov a,h sta pinc ;paragraph length ; The parameters are now ready to start typing. opde: lhld dorg xchg mov a,e sub l mov a,d sbb h jc error ; lda pinc ;paragraph length mov b,a opdf: call crlf ;type CR,LF call inst ;read console status jz opdg shld dorg ;mark stopping point ret opdg: call tyhl ;type HL as four nibbles push h call dubl call hebl call sngl ;type space pop h mvi c,10H call ascl dcr b jnz opdh lda pinc ;paragraph length mov b,a call crlf opdh: mov a,l sub e mov a,h sbb d jc opdf ret hebl: call oobl oobl: call fobl fobl: call tetr jmp sngl tetr: call duce duce: call once once: mov a,m call byte inx h jmp sngl ; (F) Fill an interval. will fill the interval ; from x to y with the hexadecimal value a. optf: call onar push h call onar xchg call hxar jnz error ; mov b,a pop h opfa: mov a,l ;cmp(HL,DE) sub e mov a,h sbb d rnc mov m,b inx h jmp opfa ; (G) Go to the program for execution. The form ; allows the insertion of up to two breakpoints, b and c, ; before jumping to the address a. If a count n is also ; included, the breakpoints will be traversed n times ; before control is t returned to DDT. If the field a is ; null, the program will continue from the point where ; control was surrendered to DDT (or 100H if it is an ; initial call. optg: call crlf ;type CR,LF xra a sta swtv ;T/V = z/nz sta swgt ;G/T = z/nz lhld rept dad h shld rept lhld savpc ;PC at breakpoint call hef ;fetch a shld savpc push h cpi CR mvi a,1 jz opga call hexf ;fetch b jnc gnex shld gbrk ;nG's breakpoint xchg call hexf ;fetch c mvi a,2 jnc opga shld gbrl inr a mov b,h mov c,l opga: pop h sta gbrn ora a jmp gprg ;G without arguments ; G without arguments ; z unconditional go (savsp) ; c ignore HL, but set breakpoints ; A number of arguments - 0,1,2,3 ; HL explicit destination ; DE first breakpoint ; BC second breakpoint gnex: call step gprg: di jz gnez ;no arg, unconditional go jc gney ;comma, set breakpoint & go shld savpc ;PC at breakpoint gney: dcr a sta bkpt jz gnez ;one arg already noted xchg mov e,a mov a,m sta brkx mvi m,0FFH ;RST 7 shld brkp dcr e jz gnez ;unless 2nd breakpoint mov l,c mov h,b mov a,m sta brky mvi m,0FFH ;RST 7 shld brkq ; Restore registers and return to program. gnez: lxi sp,savde ;DDT's private stack pop d pop b pop psw pop h sphl lhld savpc ;PC at breakpoint push h lhld savhl ;HL at breakpoint NOP ret ; (H) Display a hexadecimal sum and difference. ; will result in typing '+'x+y '-'x-y. Mainly used to ; help patch CP/M during system generation. opth: call onar xchg call onar xra a sub l mov c,a sbb h sub c mov b,a call crlf ;type CR,LF dad d mvi a,'s' ;"sum" call aout call tyhl ;type HL as four nibbles call sngl ;type space xchg dad b mvi a,'d' ;"difference" call aout jmp tyhl ;type HL as four nibbles ; (I) Input a command line, according to the same ; criteria used by CCP; in other words a parameter ; list can follow the file name. opia: call fico opti: lxi d,TBUF lhld cptr ;pointer to command buffer lda clen mov b,a inr b moov: stax d mov a,m call lcfo inx d inx h dcr b jnz moov mvi a,00 stax d lxi h,TBUF+1 shld cptr ;pointer to command buffer call fico lxi h,adsk ;active disk push h mov a,m sta TFCB ;CP/M default FCB mvi a,10H call fica pop h mov a,m sta TFCB+16 xra a sta TFCB+32 jmp crlf zsep: ora a rz cpi CR rz cpi ' ' jc error ; rz cpi '=' rz cpi '_' rz cpi '.' rz cpi ':' rz cpi ';' rz cpi '<' rz cpi '>' ret fsep: call zsep rz call rech ;read one character jmp fsep ret ; Advance to a non blank character in the console ; buffer unless there is none, indicated by a 00. zonb: call rech ;read one character ora a rz cpi ' ' jz zonb ;zero or non-blank ret ; Generate a file control block in the manner of CCP. fico: mvi a,00 fica: lxi h,TFCB add l mov l,a mov a,h aci 00 mov h,a xra a sta adsk ;active disk call zonb ;zero or non-blank push psw jz ficb sbi '@' mov b,a push h lhld cptr ;pointer to command buffer mov a,m pop h cpi ':' jz ficc ficb: lda ldsk ;logged disk jmp ficd ficc: call rech ;read one character pop psw call rech ;read one character push psw mov a,b sta adsk ;active disk ficd: mov m,a inx h mvi b,08 pop psw call ffil call fsep mvi b,03 cpi '.' jnz ficp call rech ;read one character call ffil call fsep jmp ficq ficp: call bfil ficq: mvi b,03 mvi c,00 jmp kfil ; Fill a field ffil: call zsep jz bfil cpi '*' jz qfil mov m,a inx h dcr b rz call rech ;read one character jmp ffil ; Block fill qfil: mvi c,'?' jmp kfil bfil: mvi c,' ' kfil: mov m,c inx h dcr b jnz kfil ret ; (L) List the memory as 8080 operation codes. The ; command will list n lines of code between ; the hexadecimal addresses a and b, with the interval ; taking precedence over the number of lines, unless ; either a or b is missing. optl: call past ;check limit transgression jnc error ; lhld rept mov a,l sta pinc ;paragraph length ora h jnz opla lxi h,NL ;default length opla: inx h shld rept ;line counter for L xra a sta pctr ;paragraph counter lhld lorg ;origin for L call hef ;read shld lorg ;origin for L mov b,a xchg lxi h,begn ;bottom DDT = top memory call hef ;read shld llim ;limit for L jc oplc ;c means not null mov a,b cpi CR jz opld oplc: lxi h,0000H shld rept ;line counter for L lda pinc ;paragraph length sta pctr ;paragraph counter ; The parameters have been established, start typing. opld: call inst ;read console status rnz lhld rept ;line counter for L mov a,l ora h jnz oplf ;nz means counter working lda pctr ;paragraph counter ora a jz oplg ;z means no paragraphing dcr a jnz ople call crlf lda pinc ;paragraph length ople: sta pctr ;paragraph counter jmp oplg oplf: dcx h mov a,l ora h rz shld rept ;line counter for L oplg: call dubl lhld lorg ;origin for L call reab jnc nox mvi a,'X' call aout ;A to console nox: call tyhl ;type HL as four nibbles call dubl lhld llim ;upper limit for "L" xchg lhld lorg ;origin for L mov a,e ;cmp(DE,HL) sub l mov a,d sbb h rc call dism shld lorg ;origin for L call crlf jmp opld ; (M) Move part of the memory from one place to another. ; will move the interval x,y to begin at z. The ; direction of movement compensates for possible overlap. optm: call onar mov c,l mov b,h call onar xchg call onar mov a,e ;cmp(DE,BC) sub c mov a,d sbb b jc error ; mov a,e ;cmp(DE,HL) sub l mov a,d sbb h jc opmb mov a,c ;cmp(BC,HL) sub l mov a,b sbb h jnc opmb mov a,e ;BC=DE-BC sub c mov c,a mov a,d sbb b mov b,a dad b ;HL=HL+(DE-BC) opma: mov a,c ora b rz ldax d mov m,a dcx h dcx d dcx b jmp opma opmb: mov a,e ;cmp(DE,BC) sub c mov a,d sbb b rc ldax b mov m,a inx b inx h jmp opmb ; (R) Read into memory the file specified by TFCB. ; It was probably defined by a preceding I command, ; but might still be the program defined in the DDT ; command line. will start loading at TORG+x. optr: call hexf ;with zero default opra: push h call openf ;open file cpi 0FFH jz error ; call chex ;check for .HEX jz ihex ;load INTEL HEX file pop h lxi d,TORG ;CP/M transient origin dad d shld savpc ;PC at breakpoint oprb: push h lxi d,TFCB ;CP/M default FCB mvi c,20 ;(14) read one record call XDOS ;DDT analogue of 0005 pop h ora a jnz efil ;EOF lxi d,TBUF ;CP/M default FCB mvi c,80H ;size of one record oprc: ldax d inx d mov m,a inx h dcr c jnz oprc ;move to memory call rmax ;record upper limit jmp oprb ;read another record ; Test whether HL beyond previous maximum. tmax: xchg lhld pmax ;program high limit mov a,l ;cmp(HL,DE) sub e mov a,h sbb d xchg ret ; Record maximum program length. rmax: call tmax rnc shld pmax ;program high limit ret ; Test for limit transgression. past: push h lxi h,begn ;lower DDT limit call tmax pop h ret ; Check for the extension 'HEX' chex: lxi h,TFCB+9 ;extension mov a,m ani 07FH cpi 'H' rnz inx h mov a,m ani 07FH cpi 'E' rnz inx h mov a,m ani 07FH cpi 'X' ret ; Load INTEL HEX file, whose records have the form: ; :NNAAAA00DDDDDDDDDD....DDXX ; : start of line ; NN number of bytes in line ; AAAA first address of line ; 00 class of line (zero in CP/M) ; DD byte of data - NNH altogether ; XX checksum - full bytesum w/XX = 00 ; :00AAAA - end of file, start address AAAA. ihex: call renb ;next byte from CP/M buffer cpi 01AH ;^Z jz error ; sbi ':' ;line begins with colon jnz ihex ;load INTEL HEX file mov d,a ;start checksum w/zero pop h push h call nbyt ;next byte w/checksum mov e,a call nbyt ;next byte w/checksum push psw call nbyt ;next byte w/checksum pop b mov c,a dad b mov a,e ora a jnz ihxx ;read non-null line mov h,b mov l,c shld savpc ;PC at breakpoint pop h ;displacement not added to AAAA <<--- jmp efil ;EOF ihxx: call nbyt ;next byte w/checksum hlin: call nbyt ;next byte w/checksum mov m,a inx h dcr e jnz hlin ;read the full line call nbyt ;next byte w/checksum push psw call rmax ;record upper limit pop psw jnz error ; jmp ihex ;load INTEL HEX file ; Form next byte, add to checksum nbyt: push b push h push d call renb ;next byte from CP/M buffer call cnh jc error ; add a add a add a add a push psw call renb ;next byte from CP/M buffer call cnh jc error ; pop b ora b mov b,a pop d add d mov d,a mov a,b pop h pop b ret ; EOF after reading file efil: mvi c,12 ;(0C) lift disk head call XDOS ;DDT analogue of 0005 lxi h,rmsg ;header: 'NEXT PC' call mssg call crlf ;type CR,LF lhld pmax ;program high limit call tyhl ;type HL as four nibbles call sngl ;type space lhld savpc ;PC at breakpoint shld dorg ;origin for D shld lorg ;origin for L jmp tyhl ;type HL as four nibbles rmsg: db CR,LF,'NEXT PC',00 ; (S) Store hexadecimal bytes. will store ; n bytes starting at address x, read one by one ; from the console. Missing n means indefinite ; repetition, missing x means TORG. Confirmation ; and progression is automatic while hexadecimal ; bytes are being received; however, for ; - go back one byte, ; 'x deposit ASCII x, ; ^x deposit ctl x, ; CR go on to next byte. ; Any other input terminates the cycle. opts: lxi h,TORG call hef ;read hex field xchg opsa: call crlf ;type CR,LF call typs ;verify the line call incl ;fetch a command line jz opsc ;null buffer, go next line call hxar ;read one-byte arg jz opsb ; cpi '-' ;go back rnz ;leave the cycle dcx d jmp opsa opsb: stax d call ctlx call typs ;verify the line opsc: inx d call drnz jnz opsa ret ; Type the format line for S. typs: ldax d call prip ;type printable or . call sngl call word ;type DE as four nibbles call sngl ;type space ldax d call byte ;type A as two nibbles jmp sngl ;type space ; (T) Type the register status line while single-stepping ; through the program. runs through n steps typing ; each one, while executes without typing. The option ; V, with the same alternatives and treats a ; call or a conditional call as a single step, avoiding a ; detailled examination of the interior contents of each ; subroutine. optt: xra a oooa: sta swtv ;T/V = z/nz mvi a,0FFH sta swgt ;G/T = z/nz call reuc cpi '/' jnz ooob xra a ooob: sta swtu ;T/U = nz/z lhld rept mov a,l ora h jz oooc dcx h oooc: shld rept ;repetition counter call line ;type display line jmp gnex ; (V) A variant of T. optv: mvi a,0FFH jmp oooa ; (X) Examine registers. Any one of the registers or ; register pairs A, BC, HL, DE, SP, PC may be examined, ; or one of the five flag bits C, Z, M, E, I, by typing ; Xr, with r = czmeiabhdsp*, or =xxxx with a hexadecimal ; address xxxx. The latter defines the register * at ; first. A display line is typed, of the form ; r=xxxx xx ... xx ... xx +++++ + +++++ ooo ooooo ; where xxxx is the contents of register r, xx etc is ; a window of hexadecimal bytes centered on xxxx, ++ etc ; is a similar window of ASCII characters, and finally ; ooo ooooo is the instruction, if meaningful, at xxxx. ; ; Once an examination is underway, the window may be ; moved by various operators: ; * indirect from window ; ^ indirect from instruction address ; excl save value ; ? recover value ; / next instruction ; + 1 byte forward ; - 1 byte backward ; # forward, stop at nonzero ; @ backward, stop at nonzero ; =xx search for byte xx ('x or ^x also) ; |xxxx search for pair xxxx ; > forward half-window ; < backward half-window ; . type crlf - make new line optx: call relc ;char to A from buffer cpi CR jz ljne ;type display line cpi '=' jnz opxa call hexf shld savmr ;save memory reference mvi a,'*' opxa: lxi b,NR ;B=0, C=# registers lxi h,regs ;register list opxb: cmp m jz opxc ;modify given register inx h inr b dcr c jnz opxb ;repeat for all jmp error ; opxc: push h mov a,b call gesr ;fetch saved register shld savxx ;?/! cell call reuc ;char to A from buffer cpi CR jnz error ; push b opxd: pop b pop h push h push b call ctlx ;type ^X call tyfr ;type flag or register call sngl ;type space call incl ;fetch a command line call hexf pop b jnc opxg ;nc means null hex field push b opxe: mov a,b cpi 05 jnc uacc ;update register mov a,h ora a jnz error ; mov a,l cpi 02 jnc error ; call fmaf ;fetch mask & flags mov h,a mov b,c mvi a,0FEH ;-2 call shla ;shl(A,B) ana h mov b,c mov h,a mov a,l call shla ;shl(A,B) ora h stax d jmp opxd ; Window modifiers are possible with a null hex field. opxg: push psw mov a,b call gesr ;fetch saved register pop psw cpi CR jnz opxh shld dorg shld lorg pop h ret opxh: push b lxi d,opxe push d call alta db 14 db '*' ;indirect address from window dw opxv db '^' ;indirect address from instruction dw opxu db '!' ;save address dw opxw db '?' ;restore address dw opxx db '/' ;next instruction dw opxy db '+' ;advance 1 byte dw opxz db '-' ;return 1 byte dw opxt db '#' ;advance to nonzero byte dw opxs db '.' ;type crlf dw crlf db '=' ;=x: search for xx, 'x, ^x dw opxr db '|' ;|xxxx: search for pair xxxx dw opxm db '>' ;advance halfwindow dw opxp db '<' ;return halfwindow dw opxo db '@' ;return to nonzero dw opxn opxu: inx h ;^ opxv: mov e,m ;* inx h mov d,m xchg ret opxw: shld savxx ;excl ret opxx: lhld savxx ;? ret opxy: mov a,m ;/ inx h inx h inx h call twob rc dcx h call oneb rc opxt: dcx h ;- (beware - it's part of opxy) ret opxz: inx h ;+ ret opxs: xra a ;# oxs: inx h cmp m jz oxs ret opxr: xchg ;= lhld rept call hxr ;hex argument w/default shld rept ;be sure to find it again mov a,l xchg oxr: inx h cmp m jnz oxr ret opxp: lxi d,WW+1 ;> dad d ret opxo: lxi d,-WW-1 ;< dad d ret opxn: xra a ;@ oxn: dcx h cmp m jz oxn ret opxm: xchg ;| lhld rept call hef shld rept ;be sure we'll find the pair xchg inx h oxm: mov a,e call oxr inx h mov a,d cmp m dcx h jnz oxm dcx h ret ; shl(A,B) shla: dcr b rz rlc jmp shla ;shl(A,B) ; Decrement REPT if it is non-zero. drnz: push h lhld rept mov a,h ora l sui 1 sbb a jnz dnz dcx h shld rept mov a,h ora l dnz: pop h ret ; Update register uacc: jnz ureg mov a,h ora a jnz error ; mov a,l sta sava ;save A jmp opxd ureg: push h call gasr ;get address of saved register pop d mov m,e inx h mov m,d jmp opxd ; Open file openf: push h push d push b xra a sta TFCB-1 sta TFCB+32 mvi c,15 ;(0F) open file lxi d,TFCB ;CP/M default FCB call XDOS ;DDT analogue of 0005 pop b pop d pop h ret ; Read next byte from CP/M buffer, ; replenish when exhausted. renb: push h push d push b lda TFCB-1 ani 07FH jz ror ;read one record rnb: mvi d,00 mov e,a lxi h,TBUF ;CP/M default FCB dad d mov a,m cpi 01AH ;^Z jz reen ;end of record lxi h,TFCB-1 inr m ora a jmp reex ;return ror: mvi c,20 ;(14) read one record lxi d,TFCB ;CP/M default FCB call XDOS ;DDT analogue of 0005 ora a jnz reen ;end of record sta TFCB-1 jmp rnb reen: stc ;end of record reex: pop b ;return pop d pop h ret ; Error error: mvi a,'?' call aout ;A to console jmp loop ;clear out the stack ; Read console status. inst: push b push d push h mvi c,11 ;(0B) console status call XDOS ;DDT analogue of 0005 ani 01 pop h pop d pop b ret ; Fill command line buffer from console. The z flag ; on return indicates whether a null line was read. incl: push h push d push b mvi c,10 ;(0A) read buffer lxi d,cbuf ;command buffer call XDOS ;DDT analogue of 0005 lxi h,ctex ;command text shld cptr ;pointer to command buffer lda clen pop b pop d pop h ora a ret ; Read a one-byte argument, which may be hexadecimal, ; 'x or ^x. Blatant errors are rejected, but nz at ; return means null field not terminated by CR, ', or^. hxar: lxi h,0000 hxr: call hef jnc har mov a,h ora a jnz error ; mov a,l ret har: cpi '''' jnz has call rech cpi ' ' jc error ; jmp hat has: cpi '^' rnz call rech sui '@' jc error ; cpi ' ' jc hat sui ' ' cpi ' ' jnc error ; hat: mov l,a call rech cpi CR jnz error ; mov a,l ret ; Read a hexadecimal field; error if null. onar: call hexf jnc error ; ret ; Type CR,LF. crlf: mvi a,CR call aout ;A to console mvi a,LF jmp aout ;A to console ; Type ^X [erase line] ctlx: mvi a,18H ;^X jmp aout ;A to console ; Type one or two spaces. dubl: call sngl sngl: mvi a,' ' ; A to console aout: push h push d push b mov e,a mvi c,02 call XDOS ;DDT analogue of 0005 pop b pop d pop h ret ; Lower case fold excepting rubout reuc: call rech ;read one character lcfo: cpi 'a' rc cpi '{' rnc ani 5FH ret ; Upper case fold relc: call rech ;read one character ucfo: cpi '[' rnc cpi 'A' rc ori 20H ret ; Fetch a character into A from command line rech: push h lxi h,clen ;command string length mov a,m ora a mvi a,CR ;fake CR from empty buffer jz recx dcr m lhld cptr ;pointer to command buffer mov a,m inx h shld cptr ;pointer to command buffer recx: pop h ret ; Type A as two nibbles word: mov a,d call byte mov a,e byte: push psw rar rar rar rar call nybl pop psw nybl: ani 0FH adi 90H daa aci 40H daa jmp aout ;A to console ; Type HL as four nibbles tyhl: xchg call word xchg ret ; Message terminated by zero to console mssg: mov a,m ora a rz call aout ;A to console inx h jmp mssg ; Print printables, put dot for the rest prip: cpi RO jnc priq cpi ' ' jnc aout ;A to console priq: mvi a,'.' jmp aout ;A to console ; Type minus or B, according to sign. morb: rlc push psw mvi a,'-' jnc morc mov a,b morc: call aout pop psw ret ; Type 5 flags as letter (1) or minus (0). feql: lda savf mvi b,'s' call morb mvi b,'z' call morb rlc mvi b,'i' call morb rlc mvi b,'p' call morb rlc mvi b,'c' call morb jmp sngl ; Type to display a register. reql: push psw mov a,b call aout mvi a,'=' call aout pop psw push psw call byte call sngl pop psw call prip jmp sngl ; Type to display a register pair. peql: mov a,b call aout mvi a,'=' call aout call tyhl jmp sngl ; Test for separators, which are characters which can ; be passed over at the beginning of a field, but which ; terminate it when found at the end. The character to ; be tested is in the accumulator, where it remains. sepa: cpi ' ' rz cpi HT ret ; Test for terminators, which mean that a field must ; end, even if it is null. term: cpi ',' rz cpi CR ret ; Test whether the character in the accumulator is a ; decimal digit. If so, it is replaced by its binary ; value, otherwise remaining unchanged. The carry ; flag distinguishes the cases - carry if not decimal. cnd: cpi '0' rc cpi ':' cmc rc sui '0' ret ; Read a decimal field, leaving the last four ; digits read in HL, with leading zeros for fewer ; digits. BC, DE remain unchanged. A null field ; is zero. Leading separators are passed by, but ; trailing separators terminate. A null field is ; marked by the carry flag, which is 0 for a null ; field delimited by a terminator, 1 otherwise. ; A non-zero default value can be given to a null ; field using rather than . decf: lxi h,0000 def: call reuc call sepa jz def call cnd cmc rnc lxi h,0000 push d dec: mov e,l mov d,h dad h dad h dad d dad h mov e,a mvi d,0 dad d call reuc call cnd jnc dec pop d ret ; Test whether the character in the accumulator is a ; hexadecimal digit. If so, it is replaced by its ; binary value, otherwise remaining unchanged. The ; carry flag distinguishes the cases - carry if not ; hexadecimal. cnh: cpi '0' rc cpi ':' jc cni cpi 'A' rc cpi 'G' jnc cnj sui 07 cni: sui '0' stc cnj: cmc ret ; Read a hexadecimal field, leaving the last four ; digits read in HL, with leading zeros for fewer ; digits. BC, DE remain unchanged. A null field ; is zero. Leading separators are passed by, but ; trailing separators terminate. A null field is ; marked by the carry flag, which is 0 for a null ; field delimited by a terminator, 1 otherwise. ; A non-zero default value can be given to a null ; field using rather than . hexf: lxi h,0000 hef: call reuc call sepa jz hef call cnh cmc rnc lxi h,0000 hex: dad h dad h dad h dad h ora l mov l,a call reuc call cnh jnc hex ret ; Fetch mask and saved flags fmaf: push h lxi h,fmsk ;flag masks mov e,b mvi d,00 dad d mov c,m lxi h,savf ;save AF mov a,m xchg pop h ret ; Get value of saved flag fval: call fmaf ;fetch mask & flags val: dcr c jz vam ;ani a,01 rar jmp val vam: ani 01 ret ; Get address of saved register gasr: sui 06 lxi h,rdsp ;list of displacements mov e,a mvi d,00 dad d dad d mov e,m inx h mov d,m lxi h,savmr ;save memory reference dad d ret ; Fetch saved register gesr: call gasr ;get address of saved register mov e,m inx h mov d,m xchg ret ; Type flag or register tyfr: mov a,b cpi 05 jnc tyra mov a,m call aout ;A to console call fval ;get saved flag jmp nybl ;type A as DEC or HEX tyra: mov b,m jnz tyre ;type saved register lda sava ;save A jmp reql ; Type register and the memory pointed to in the format: ; r=value, window, ASCII window, dism tyre: call gesr ;get saved register call peql call sngl push h lxi d,-WW ;go back window halfwidth dad d push h call tyrg call sngl pop h call tyrj call dubl pop h jmp dism ; Type 2*WW+1 bytes centered on pointer, as nibble pairs. tyrg: call tyrh call sngl mov a,m call byte call dubl inx h tyrh: mvi c,WW tyri: mov a,m call byte call sngl inx h dcr c jnz tyri ret ; Then type the same window using ASCII characters or points. tyrj: call tyrk call sngl mov a,m call prip ;type printable or . inx h call sngl tyrk: mvi c,WW ascl: mov a,m call prip ;type printable or . inx h dcr c jnz ascl ret ; Type display line. line: call ljne jmp crlf ljne: mvi b,'b' lhld savbc call peql mvi b,'d' lhld savde call peql mvi b,'h' lhld savhl push h call peql pop h mvi b,'m' mov a,m call reql mvi b,'a' lda sava call reql call feql mvi b,'s' lhld savsp call peql mvi b,'p' lhld savpc call peql call sngl jmp dism regs: db 'czmeiabdhsp*' rdsp: dw -10,-12,-4,-6,-2,0 fmsk: db 1,7,8,3,5 ; Jump guided by a table of alternatves. The table ; should have the form: ; call alta ; db n ; db 'x' ; dw xxxx ; The last two lines are to be repeated n times, for ; each of which xxxx is the jump address corresponding ; to the alternative x. The table is used by jumping ; to its heading with the alternative in A. Registers ; C, D, and E are lost in the process. alta: xthl mov c,m alt: inx h cmp m inx h jnz alu mov e,m inx h mov d,m xchg xthl ret alu: dcr c inx h jnz alt jmp error ; ; Indexed jump through a table. juta: pop h mov e,a mvi d,00 dad d dad d mov e,m inx h mov d,m xchg pchl ; Return from breakpoint rtbk: di shld savhl; HL at breakpoint pop h dcx h shld savpc ;PC at breakpoint push psw lxi h,0002 dad sp pop psw lxi sp,savhl ;HL at breakpoint push h push psw push b push d lhld savpc ;PC at breakpoint mov a,m cpi 0FFH ;RST 7 push psw push h lxi h,bkpt ;breakpoint data mov a,m mvi m,00 ora a jz rtbb dcr a jz rtba lda brky lhld brkq mov m,a rtba: lda brkx lhld brkp mov m,a rtbb: pop h pop psw jz rtbc ;if RST 7 inx h shld savpc ;PC at breakpoint xchg lxi h,GDOS+1 ;BDOS address mov c,m inx h mov b,m mov a,e ;cmp(DE,BC) sub c mov a,d sbb b jc rtbc ;if RST 7 lxi h,0000 shld rept lhld sica ;site of call to BDOS xchg mvi a,02H ora a stc jmp gprg ;G without arguments ; If RST 7 brought us to the breakpoint. rtbc: NOP lhld rept ;repetition counter mov a,h ora l jz rtbd ;we won't continue dcx h shld rept ;repetition counter lda swgt ;G/T = z/nz ora a jz rtbf call inst ;read console status jnz rtbd ;we won't continue lda swtu ;T/U = nz/z ora a cnz line ;type display line jmp gnex ; Return to DDT rather than program. rtbd: mvi a,'*' call aout ;A to console lhld savpc ;PC at breakpoint shld dorg ;origin for D call past ;check limit transgression jnc rtbe ;can't count on using L shld lorg ;origin for L rtbe: call tyhl ;type HL as four nibbles jmp loop ;DDT loop - cannot be rtbf: mov a,l ani 01H jnz gnex lhld gbrl mov c,l mov b,h lhld gbrk xchg lda gbrn ora a stc jmp gprg ;G without arguments ; Surround instruction by breakpoints for single-step. type: lxi d,000DH lxi h,mtbl ;table of type codes tyqe: mov a,m ana b inx h cmp m inx h jz tyse inr d dcr e jnz tyqe tyse: mov a,d ret step: lhld savpc ;PC at breakpoint mov b,m inx h push h call type call juta dw xjmp ;jump dw xcju ;conditional jump dw ding ;call dw dong ;conditional call dw xret ;return dw xrst ;restart dw xpch ;pchl dw xmvi ;immediate move dw xmvi ;immediate arithmetic dw xlxi ;lxi dw xlxi ;lhld dw xcrt ;conditional return dw xmvi ;in, out dw xoth ;others ding: lda swtv ;T/V = z/nz inr a jz xlxi ;lxi, lhld jmp xjmp ;jump, call dong: lda swtv ;T/V = z/nz inr a jz xlxi ;lxi, lhld jmp xcju ;cndl jmp, cndl call ; Jump or call xjmp: call idos jnz xtwo ; Return xret: call xrtn jmp xtwo ; qdos - check whether DE = BDOS ; idos - check whether (DE) = BDOS idos: pop b pop h mov e,m inx h mov d,m inx h push h push b qdos: lda GDOS+1 ;BDOS address cmp e rnz lda GDOS+2 ;BDOS address cmp d ret xrtn: lhld savsp ;SP at breakpoint mov e,m inx h mov d,m ret ; Conditional jump or call xcju: call idos jz zdos pop b push b mvi a,02 jmp xone zdos: pop d push d jmp xtwo ; Restart xrst: mov a,b cpi 0FFH jnz xsvn xra a jmp xzer xsvn: ani 38H mov e,a mvi d,00 jmp xtwo ; PCHL xpch: lhld savhl ;HL at breakpoint xchg call qdos ;does DE = BDOS? jnz xtwo jmp xret jtwo: jmp xtwo ; Other. xoth: pop d push d jmp xtwo ; Conditional return. xcrt: call xrtn pop b push b mvi a,02 jmp xone ; LXI, LHLD xlxi: pop d inx d push d ; Immediate move or arithmetic, in, out. xmvi: pop d inx d push d xtwo: mvi a,01 xone: inr a stc xzer: pop h ret mtbl: db 0FFH,0C3H,0C7H,0C2H ;jump, conditional jump db 0FFH,0CDH,0C7H,0C4H ;call, conditional call db 0FFH,0C9H,0C7H,0C7H ;return, restart db 0FFH,0E9H,0C7H,006H ;pchl, immediate moves db 0C7H,0C6H,0CFH,001H ;immediate arithmetc, lxi db 0E7H,022H,0C7H,0C0H ;lhlf, conditional return db 0F7H,0D3H ;in, out ; --------------------------------------------------------- logo: db ' DDT(8080)/ICUAP',CR,LF db 'Universidad Autonoma de Puebla',CR,LF db ' November 20, 1983',00 dw 00,00,00,00,00,00,00;can't overwrite logo yet savde: dw 0000 ;save DE, tail of DDT stack 1 savbc: dw 0000 ;save BC 2 savf: db 00 ;save F 3 sava: db 00 ;save A 4 savsp: dw 0000 ;SP at breakpoint 5 savhl: dw 0000 ;HL at breakpoint 6 savpc: dw 0000 ;PC at breakpoint 7 savmr: dw 0000 ;save memory reference 8 savxx: dw 0000 ;storage for optx 9 sica: dw 0000 ;site of call to BDOS swtv: db 00 ;T/V = z/nz swtu: db 00 ;T/U = nz/z swgt: db 00 ;G/T = z/nz rept: dw 0000 ;counter for commands gbrk: dw 0000 ;nG's breakpoint gbrl: dw 0000 ;nG's second breakpoint gbrn: db 00 ;nG's # of breakpoints bkpt: db 00 ;number of breakpoints brkp: dw 0000 ;first breakpoint brkx: db 00 ;first opcode brkq: dw 0000 ;second breakpoint brky: db 00 ;second opcode pinc: db 00 ;paragraph length pctr: db 00 ;paragraph counter dorg: dw 0000 ;origin for D lorg: dw 0000 ;origin for L llim: dw 0000 ;upper limit for "L" pmax: dw 0000 ;program high limit ldsk: db 00 ;logged disk adsk: db 00 ;active disk cptr: dw 0000 ;pointer to command buffer cbuf: db 80H ;command buffer clen: db 00 ;command string length ctex: ds 80H ;command text enddt: ds 0 ; .dephase end