;user installable disassembler and single-step run for paulmon2 .equ locat, 0x1000 ;location for these commands (usually 1000) .equ paulmon2, 0x0000 ;location where paulmon2 is at (usually 0000) .equ phex1, 0x2E+paulmon2 .equ cout, 0x30+paulmon2 ;send acc to uart .equ cin, 0x32+paulmon2 ;getchar() .equ phex, 0x34+paulmon2 ;print acc in hex .equ phex16, 0x36+paulmon2 ;print dptr in hex .equ pstr, 0x38+paulmon2 ;print string @dptr .equ ghex, 0x3A+paulmon2 ;get two-digit hex (acc) .equ ghex16, 0x3C+paulmon2 ;get four-digit hex (dptr) .equ upper, 0x40+paulmon2 ;convert acc to uppercase .equ newline, 0x48+paulmon2 .equ pcstr, 0x45+paulmon2 .equ pint, 0x50+paulmon2 .equ smart_wr, 0x56+paulmon2 .equ cin_filter, 0x62+paulmon2 .equ asc2hex, 0x65+paulmon2 .equ list_key, 'L' ;list (disassemble) .equ step_key, 'S' ;single step run .equ vtedit_key, 'E' ;memory editor ;for testing in ram ;.equ list_key, 'K' ;list (disassemble) ;.equ step_key, 'W' ;single step run ;.equ vtedit_key, 'E' ;memory editor ;location of two bytes used by single-step in internal ram which we ;hope the user's program won't write over while it's running. These ;two bytes hold the address of the previous instruction, so we can ;show the last executed instruction with the current value of the ;registers, which is much more intuitive than displaying the next ;instruction by grabbing the program counter from the stack as was ;done in PAULMON1's single step. .equ lastpc, 0x7C ;don't forget to update the docs below ;DIS ;---------------------------------------------------------; ; ; ; list command ; ; ; ;---------------------------------------------------------; .org locat .db 0xA5,0xE5,0xE0,0xA5 ;signiture .db 254,list_key,0,0 ;id (254=user installed command) .db 0,0,0,0 ;prompt code vector .dB 0,0,0,0 ;reserved .db 0,0,0,0 ;reserved .db 0,0,0,0 ;reserved .db 0,0,0,0 ;user defined .db 255,255,255,255 ;length and checksum (255=unused) .db "List",0 newline_h:ljmp newline .org locat+64 ;executable code begins here ; disassembler register usage ; r0 = temporary storage ; r1 = temporart storage ; r2 = first instruction byte ; r3 = second instruction byte ; r4 = third instruction byte ; r5 = line count ; r6 = program counter (lsb) ; r7 = program counter (msb) list: acall newline_h mov r5, #20 clr psw.1 ;use ordinary long format list2: acall disasm djnz r5, list2 ajmp newline_h disasm: ;print out the memory location and fetch the next three bytes mov a, r7 mov dph, a acall phex_h mov a, r6 mov dpl, a acall phex_h clr a movc a, @a+dptr mov r2, a inc dptr clr a movc a, @a+dptr mov r3, a inc dptr clr a movc a, @a+dptr mov r4, a mov a, r2 anl a, #00001000b jnz lookup2 ;fetch constants for instructions not using R0-R7 lookup1: mov a, r2 rr a anl a, #01111000b ;grab upper 4 bits mov r0, a ;keep in r0 for a moment mov a, r2 anl a, #00000111b ;get lower 3 bits orl a, r0 ;combine in upper 4 mov dptr, #opot1 ;opot=operand offset table movc a, @a+dptr sjmp unpack ;fetch constants for R0-R7 instructions lookup2: mov a, r2 swap a anl a, #00001111b mov dptr, #opot2 movc a, @a+dptr ;now we'll unpack the operand code (# bytes and addr mode) unpack: anl a, #00000011b mov r0, a ;increment the r7/r6 pointer add a, r6 mov r6, a mov a, r7 addc a, #0 mov r7, a ;now print the bytes and spaces (r0 has # of bytes to print) pbytes: mov a, #':' acall cout_h acall space_h jb psw.1, pmnu ;skip bytes if running single-step mov a, r2 acall phex_h acall space_h cjne r0, #1, pbytes2 mov r1, #11 sjmp pbytes4 pbytes2:mov a, r3 acall phex_h acall space_h cjne r0, #2, pbytes3 mov r1, #8 sjmp pbytes4 pbytes3:mov a, r4 acall phex_h mov r1, #6 pbytes4:acall space_h djnz r1, pbytes4 ;prints the mnunonic name and spaces pmnu: mov a, r2 anl a, #00001000b jnz pmnu_lookup2 pmnu_lookup1: mov dptr, #mnot1 ;mnot=mnunonic offset table mov a, r2 rr a anl a, #01111000b ;grab upper 4 bits mov r0, a ;keep in r0 for a moment mov a, r2 anl a, #00000111b ;get lower 3 bits orl a, r0 ;combine in upper 4 movc a, @a+dptr mov r1, a sjmp pmnu0 pmnu_lookup2: mov dptr, #mnot2 ;16 byte table for r0-r7 instructions mov a, r2 swap a anl a, #00001111b movc a, @a+dptr mov r1, a pmnu0: mov dptr, #mnu_tbl mov r0, #8 clr c pmnu1: mov a, #' ' jc pmnu2 mov a, r1 movc a, @a+dptr inc r1 mov c, acc.7 anl a, #0x7F pmnu2: acall cout_h djnz r0, pmnu1 ;print the operands mov a, #dasm2 & 255 ;(low) push acc mov a, #dasm2 >> 8 ;(high) push acc am_lookup0: mov a, r2 anl a, #00001000b jnz am_lookup2 ;fetch constants for instructions not using R0-R7 am_lookup1: mov a, r2 rr a anl a, #01111000b ;grab upper 4 bits mov r0, a ;keep in r0 for a moment mov a, r2 anl a, #00000111b ;get lower 3 bits orl a, r0 ;combine in upper 4 mov dptr, #opot1 ;opot=operand offset table movc a, @a+dptr sjmp am_unpack ;fetch constants for R0-R7 instructions am_lookup2: mov a, r2 swap a anl a, #00001111b mov dptr, #opot2 movc a, @a+dptr am_unpack: anl a, #11111100b rr a rr a dec a mov dptr, #oprt ;oprt=operand routine table rl a add a, dpl mov dpl, a clr a addc a, dph mov dph, a clr a jmp @a+dptr dasm2: ajmp newline_h oprt: ajmp opcd1 ;addr11 ajmp opcd2 ;A,Rn ajmp opcd3 ;A,direct ajmp opcd4 ;A,@Ri ajmp opcd5 ;A,#data ajmp opcd6 ;direct,A ajmp opcd7 ;direct,#data ajmp opcd8 ;C,bit ajmp opcd9 ;C,/bit ajmp opcd10 ;A,direct,rel ajmp opcd11 ;A,#data,rel ajmp opcd12 ;Rn,#data,rel ajmp opcd13 ;@Ri,#data,rel ajmp pa ;A ajmp prc ;C ajmp pbit ;bit ajmp pdirect ;direct ajmp p_reg_i ;@Ri ajmp opcd19 ;AB ajmp opcd20 ;Rn,rel ajmp opcd21 ;direct,rel ajmp p_reg_n ;Rn ajmp pdptr ;DPTR ajmp opcd24 ;bit,rel ajmp prel ;rel ajmp opcd26 ;@A+DPTR ajmp opcd27 ;addr16 ajmp opcd28 ;Rn,A ajmp opcd29 ;Rn,direct ajmp opcd30 ;Rn,#data ajmp opcd31 ;direct,Rn ajmp opcd32 ;direct,direct ajmp opcd33 ;direct,@Ri ajmp opcd34 ;@Ri,A ajmp opcd35 ;@Ri,direct ajmp opcd36 ;@Ri,#data ajmp opcd37 ;bit,C ajmp opcd38 ;DPTR,#data16 ajmp opcd39 ;A,@A+DPTR ajmp opcd40 ;A,@A+PC ajmp opcd41 ;A,@DPTR ajmp opcd42 ;@DPTR,A ret ; opcd4: ;A,@Ri done acall pac p_reg_i:mov a,#'@' acall cout_h mov a,#'R' acall cout_h mov a, r2 anl a,#00000001b ajmp phex1_h opcd3: ;A,direct done acall pac pdirect: mov a, r3 jb acc.7,pdir1 pdir0: mov a, r3 ajmp phex_h pdir1: mov dptr,#sfrmnu pdir2: clr a movc a,@a+dptr inc dptr jz pdir0 mov r0,a clr c subb a, r3 jnz pdir3 pstr_h: ljmp pstr pdir3: clr a movc a,@a+dptr inc dptr jnb acc.7,pdir3 sjmp pdir2 opcd9: ;C,/bit done acall prc acall pcomma mov a, #'/' acall cout_h pbit: mov a, r3 anl a,#01111000b rl a swap a mov r0,a mov a, r3 anl a,#10000000b jz pbit1 mov dptr,#bitptr ;it's a Special Function Reg. mov a,r0 movc a,@a+dptr mov dptr,#bitmnu addc a,dpl mov dpl,a jnc pbit0 inc dph pbit0: acall pstr_h sjmp pbit2 pbit1: mov a,r0 ;it's between 20h and 2Fh add a,#20h acall phex_h pbit2: mov a,#'.' acall cout_h mov a, r3 anl a,#00000111b ajmp phex1_h opcd10: ;A,direct,rel done acall pac acall pdirect opcd10a:acall pcomma mov a, r4 mov r3, a prel: mov a, r3 add a, r6 mov dpl, a mov a, r3 jb acc.7, prel2 clr a sjmp prel3 prel2: clr a cpl a prel3: addc a, r7 mov dph, a ljmp phex16 pat: ;prints the '@' symbol mov a,#'@' ajmp cout_h pac: ;print "A," acall pa pcomma: ;prints a comma mov a,#',' acall cout_h pspace: mov a, #' ' ajmp cout_h plb: ;prints the '#' symbol mov a,#'#' ajmp cout_h opcd6: ;direct,A done acall pdirect acall pcomma pa: ;prints 'A' mov a,#'A' ajmp cout_h opcd37: ;bit,C done acall pbit acall pcomma prc: ;prints 'C' mov a,#'C' ajmp cout_h opcd26: ;@A+DPTR done acall pat acall pa mov a,#'+' acall cout_h pdptr: ;prints DPTR mov a, #'D' acall cout_h mov a, #'P' acall cout_h mov a, #'T' acall cout_h mov a, #'R' cout_h: ljmp cout opcd1: mov a, r7 ;addr11 done anl a, #11111000b mov r0, a mov a, r2 swap a rr a anl a, #00000111b orl a, r0 acall phex_h mov a, r3 ajmp phex_h opcd2: ;A,Rn done acall pac p_reg_n:mov a,#'R' acall cout_h mov a, r2 anl a,#00000111b phex1_h: ljmp phex1 opcd5: ;A,#data done acall pa pdata: acall pcomma acall plb mov a, r3 phex_h: ljmp phex opcd7: ;direct,#data done acall pdirect mov a, r4 mov r3, a ajmp pdata opcd8: ;C,bit done acall prc acall pcomma ajmp pbit opcd11: ;A,#data,rel done acall pa opcd11a:acall pcomma acall plb mov a, r3 acall phex_h ajmp opcd10a opcd12: ;Rn,#data,rel done acall p_reg_n ajmp opcd11a opcd13: ;@Ri,#data,rel done acall p_reg_i ajmp opcd11a opcd19: ;AB done acall pa mov a, #'B' ajmp cout_h opcd20: ;Rn,rel done acall p_reg_n acall pcomma ajmp prel opcd21: ;direct,rel done acall pdirect ajmp opcd10a opcd24: ;bit,rel done acall pbit ajmp opcd10a opcd28: ;Rn,A done acall p_reg_n acall pcomma ajmp pa opcd29: ;Rn,direct done acall p_reg_n acall pcomma ajmp pdirect opcd30: ;Rn,#data done acall p_reg_n ajmp pdata opcd31: ;direct,Rn done acall pdirect acall pcomma ajmp p_reg_n opcd32: ;direct,direct done mov a, r3 push acc mov a, r4 mov r3, a acall pdirect acall pcomma pop acc mov r3, a ajmp pdirect opcd33: ;direct,@Ri done acall pdirect acall pcomma ajmp p_reg_i opcd34: ;@Ri,A done acall p_reg_i acall pcomma ajmp pa opcd35: ;@Ri,direct done acall p_reg_i acall pcomma ajmp pdirect opcd36: ;@Ri,#data done acall p_reg_i ajmp pdata opcd38: ;DPTR,#data16 done acall pdptr acall pcomma acall plb opcd27: mov a, r3 ;addr16 done acall phex_h mov a, r4 ajmp phex_h opcd39: ;A,@A+DPTR done acall pac acall pat acall pa mov a,#'+' acall cout_h ajmp pdptr opcd40: ;A,@A+PC done acall pac acall pat acall pa mov a,#'+' acall cout_h mov a,#'P' acall cout_h ajmp prc opcd41: ;A,@DPTR done acall pac acall pat ajmp pdptr opcd42: ;@DPTR,A done acall pat acall pdptr acall pcomma ajmp pa sfrmnu: .db 0xE0,"AC",'C'+128 .db 0x81,'S','P'+128 .db 0x82,"DP",'L'+128 .db 0x83,"DP",'H'+128 .db 0x80,'P','0'+128 .db 0x90,'P','1'+128 .db 0xA0,'P','2'+128 .db 0xB0,'P','3'+128 .db 0x99,"SBU",'F'+128 .db 0xCD,"TH",'2'+128 .db 0xC8,"T2CO",'N'+128 .db 0xCC,"TL",'2'+128 .db 0xCB,"RCAP2",'H'+128 .db 0xCA,"RCAP2",'L'+128 .db 0x8C,"TH",'0'+128 .db 0x8A,"TL",'0'+128 .db 0x8D,"TH",'1'+128 .db 0x8B,"TL",'1'+128 sfr1: .db 0xF0,'B'+128 ;5 sfr2: .db 0xD0,"PS",'W'+128 ;7 sfr3: .db 0xA8,'I','E'+128 sfr4: .db 0xB8,'I','P'+128 sfr5: .db 0x89,"TMO",'D'+128 ;8 sfr6: .db 0x88,"TCO",'N'+128 ;8 sfr7: .db 0x98,"SCO",'N'+128 ;8 sfr8: .db 0x87,"PCO",'N'+128 ;8 .db 0 ;just in case opot2: .db 0x59, 0x59, 0x09, 0x09 ;inc, dec, add, addc .db 0x09, 0x09, 0x09, 0x7A ;orl, anl, xrl, mov .db 0x7E, 0x09, 0x76, 0x33 ;mov, subb, mov, cjne .db 0x09, 0x52, 0x09, 0x71 ;xch, djnz, mov, mov bitptr: .db 0x00, 0x02, 0x06, 0x08, 0x0C, 0x0E, 0x10, 0x12 .db 0x14, 0x16, 0x1B, 0x1E, 0x20, 0x23, 0x24, 0x25 ;some stuff used by single step... it's here to fill up some of ;the unused space from the end of the disassembler code and the ;beginning of the single-step header (which must begin on a 256 ;byte page boundry) wr_check: ;write to memory and check that it worked. ;acc=0 if it worked, nonzero if it didn't write mov r0, a ;keep a copy of the data in r0 movx @dptr, a clr a movc a, @a+dptr clr c subb a, r0 ret ;delay for approx 1 character transmit time chardly:mov r1, #80 chdly2: mov a, th1 cpl a inc a mov r0, a djnz r0, * djnz r1, chdly2 ret prcolon:acall phex_h mov a, #':' ajmp cout_h phexsp: acall phex_h space_h: mov a, #' ' ajmp cout_h ;SINGLE ;---------------------------------------------------------; ; ; ; single step command ; ; ; ;---------------------------------------------------------; .org locat+0x400 .db 0xA5,0xE5,0xE0,0xA5 ;signiture .db 254,step_key,0,0 ;id (254=user installed command) .db 0,0,0,0 ;prompt code vector .dB 0,0,0,0 ;reserved .db 0,0,0,0 ;reserved .db 0,0,0,0 ;reserved .db 0,0,0,0 ;user defined .db 255,255,255,255 ;length and checksum (255=unused) .db "Single-Step",0 .org locat+0x440 ;executable code begins here ssrun: ;first check to make sure they connect int1 low jnb p3.3, ssrun2 mov dptr, #sserr1 ;give error msg if int1 not grounded pcstr_h: ljmp pcstr ssrun2: ;make sure there's a ljmp at the int1 vector location mov dptr, #0x0013 clr a movc a, @a+dptr add a, #254 jz ssrun3 mov dptr, #sserr2 ;give error that paulmon2 was not found. ajmp pcstr_h ssrun3: ;now write an ljmp to "step" in the ram and check it. inc dptr movc a, @a+dptr mov r0, a clr a inc dptr movc a, @a+dptr mov dpl, a mov dph, r0 ;now data pointer points to int1 target mov a, #2 acall wr_check jnz ssrun4 inc dptr mov a, #(step >> 8) acall wr_check jnz ssrun4 inc dptr mov a, #(step & 255) acall wr_check jz ssrun5 ssrun4: mov r0, dpl mov r1, dph mov dptr, #sserr3 ;error: couldn't write to memory @xxxx acall pcstr_h mov a, r1 acall phex_h mov a, r0 acall phex_h ajmp newline_h ssrun5: mov a, ip ;set to high priority interrupt anl a, #00000100b mov ip, a ;let's not beat around the bush (like paulmon1), all ;we need to know is where to jump into memory. mov dptr, #prompt8 acall pcstr_h mov a, r7 acall phex_h mov a, r6 acall phex_h mov dptr,#prompt4 acall pcstr_h lcall ghex16 ;ask for the jump location jb psw.5, ssrun7 jnc ssrun6 mov dptr,#abort acall pstr_h ajmp newline_h ssrun6: mov r6, dpl ;where we'll begin executing mov r7, dph ssrun7: clr tcon.2 ;need low-level triggered int1 mov dptr,#ssmsg ;tell 'em we're starting acall pcstr_h mov dptr,#ssnames acall pstr_h clr a mov sp, #8 ;just like after a reset push acc ;unlike a 8051 start-up, push return addr push acc ;of 0000, just in case they end w/ ret mov dpl, r6 ;load the program's address into dptr mov dph, r7 mov psw, a ;and clear everything to zero mov r0, a mov r1, a mov r2, a mov r3, a mov r4, a mov r5, a mov r6, a mov r7, a mov b, a mov lastpc, #ssstart & 255 mov (lastpc+1), #ssstart >> 8 setb ie.2 setb ea ;turn on the interrupt ssstart:jmp @a+dptr done: acall chardly pop acc mov r1, a pop acc mov r0, a pop dpl pop dph pop psw pop acc reti step: ;this is the single step interrupt service code... push acc push psw ;Stack Contents: (in this order) push dph ;PC_L PC_H ACC PSW DPH DPL R0 R1 push dpl mov a, r0 push acc mov a, r1 push acc ;in case the previous instruction was "clr ti", we ;must wait for a character transmit time "in case it ;was a move to SBUF) and then set ti so that our cout ;doesn't hang when we transmit the first character! acall chardly setb ti ;now print out a line that looks like this: ;ACC B C DPTR R0 R1 R2 R3 R4 R5 R6 R7 SP PC Instruction ;00 00 0 3F00 00:00:00:00:00:00:00:00 00 - 0000: LJMP 0825 acall space_h acall space_h mov a, sp add a, #251 mov r0, a ;r0 points to user's acc on stack mov a, @r0 acall phexsp ;print acc mov a, b acall phexsp ;print b register inc r0 mov a, @r0 rl a anl a, #1 acall phex1_h ;print carry bit acall space_h inc r0 mov a, @r0 acall phex_h ;print dptr (msb) inc r0 mov a, @r0 acall phexsp ;print dptr (lsb) acall space_h inc r0 mov a, @r0 acall prcolon ;print r0 inc r0 mov a, @r0 acall prcolon ;print r1 mov a, r2 acall prcolon ;print r2 mov a, r3 acall prcolon ;print r3 mov a, r4 acall prcolon ;print r4 mov a, r5 acall prcolon ;print r5 mov a, r6 acall prcolon ;print r6 mov a, r7 acall phexsp ;print r7 acall space_h mov a, r0 add a, #248 acall phexsp ;print stack pointer acall space_h acall space_h ;now the trick is to disassemble the instruction... this isn't ;easy, since the user wants to see the last instruction that ;just executed, but program counter on the stack points to the ;next instruction to be executed. The dirty trick is to grab ;the program counter from last time where we stashed it in some ;memory that hopefully the user's program hasn't overwritten. mov a, lastpc mov lastpc, r6 mov r6, a mov a, (lastpc+1) mov (lastpc+1), r7 mov r7, a mov a, r2 push acc mov a, r3 push acc mov a, r4 push acc setb psw.1 ;tell it to use a compact format ;the disassembler uses quite a bit of stack space... if the ;user didn't leave enough room for the stack to grow with ;all this overhead, it will likely crash somewhere in the ;disassembler... oh well, not much I can do about it. The ;worst case stack usage for disasm is 9 bytes. We just ;pushed 5 and 6 at the beginning of step. With the two ;bytes for the interrupt, a total of 22 bytes of free stack ;space must be available to use the single-step feature. acall disasm pop acc mov r4, a pop acc mov r3, a pop acc mov r2, a mov r7, (lastpc+1) mov r6, lastpc ;now grab the user's PC value to keep it for next time mov a, sp add a, #249 mov r0, a ;r0 points to user's acc on stack mov a, @r0 mov lastpc, a inc r0 mov a, @r0 mov (lastpc+1), a ;SINGLE STEP step1: lcall cin_filter lcall upper step2: cjne a, #13, step7 ajmp done step7: cjne a, #' ', step8 ;check space ajmp done step8: cjne a,#'?',step10 ;check '?' mov dptr,#help5txt acall pcstr_h ajmp step1 step10: cjne a,#'Q',step11 ;check 'Q'=quit and run normal mov dptr, #squit acall pstr_h clr ie.2 acall chardly mov 8, #0 ;force return to 0000 mov 9, #0 mov sp, #9 reti step11: cjne a,#'H',step12 ;check 'H'=hex dump internal ram ajmp ssdmp step12: cjne a,#'R',step13 ;check 'R'=print out registers ajmp ssreg step13: cjne a,#'S',step14 ;check 'S'=skip next inst ajmp ssskip step14: cjne a,#'A',step15 ;check 'A'=change acc value ajmp sschacc step15: cjne a,#'.',step20 mov dptr, #ssnames acall pstr_h ajmp step1 step20: ajmp step1 pequal: ; prints '=' mov a,#'=' ajmp cout_h ssdmp: mov dptr, #ssdmps1 acall pstr_h clr a acall prcolon acall space_h mov r0, sp dec r0 mov a, @r0 acall phexsp inc r0 mov a, @r0 acall phex_h mov r0, #2 mov r1, #14 ajmp ssdmp2 ssdmp1: mov a, r0 acall prcolon mov r1, #16 ssdmp2: acall space_h mov a, @r0 acall phex_h inc r0 djnz r1, ssdmp2 acall newline_h cjne r0, #0x80, ssdmp1 acall newline_h ajmp step1 ssreg: mov dptr, #sfr2+1 acall pstr_h acall pequal mov a, sp add a, #252 mov r0, a mov a, @r0 acall phexsp ;print psw mov dptr,#sfr3+1 mov r0, 0xA8 acall psfr ;print ie mov dptr,#sfr4+1 mov r0, 0xB8 acall psfr ;print ip mov dptr,#sfr5+1 mov r0, 0x89 acall psfr ;print tmod mov dptr,#sfr6+1 mov r0, 0x88 acall psfr ;print tcon mov dptr,#sfr7+1 mov r0, 0x98 acall psfr ;print smod mov dptr,#sfr8+1 mov r0, 0x87 acall psfr ;print pcon mov a, #'T' acall cout_h mov a, #'0' acall cout_h acall pequal mov a, 8Ch acall phex_h ;print Timer 0 mov a, 8Ah acall phex_h acall space_h mov a, #'T' acall cout_h mov a, #'1' acall cout_h acall pequal mov a, 8Dh ;print Timer 1 acall phex_h mov a, 8Bh acall phex_h acall newline_h ajmp step1 psfr: acall pstr_h acall pequal mov a, r0 ajmp phexsp ;skip the next instruction ssskip: mov r0, #23 ssskip2:acall space_h djnz r0, ssskip2 mov dptr,#sskip1 acall pstr_h mov a, sp add a, #249 mov r0, a ;set r0 to point to pc on stack mov a, @r0 mov lastpc, r6 ;keep r6/r7 safe in lastpc mov r6, a ;put user's pc into r6/r7 inc r0 mov a, @r0 mov (lastpc+1), r7 mov r7, a mov a, r2 push acc mov a, r3 push acc mov a, r4 push acc setb psw.1 ;tell it to use a compact format acall disasm ;run disasm to show 'em what was skipped pop acc mov r4, a pop acc mov r3, a pop acc mov r2, a mov a, sp add a, #249 mov r0, a ;set r0 to point to pc on stack mov a, r6 mov r6, lastpc ;restore r6/r7 mov lastpc, a ;update lastpc with next inst addr mov @r0, a ;also update user's pc!! inc r0 mov a, r7 mov r7, (lastpc+1) mov (lastpc+1), a mov @r0, a ajmp step1 sschacc: mov a, sp add a, #251 mov r0, a ;r0 points to acc on stack mov dptr, #chaccs1 acall pstr_h lcall ghex jc chacc2 jb psw.5, chacc2 mov @r0, a acall newline_h ajmp step1 chacc2: mov dptr, #abort acall pstr_h ajmp step1 ;stuff some of the disassembler tables, strings, etc since we have a ;bit of space before the beginning of the editor command code ;opcode offset table (gives #bytes for the instruction ;and the number of the routine to print the operands) opot1: .db 0xAD, 0x06, 0x6F, 0x39, 0x39, 0x46, 0x49, 0x49 ;0 .db 0x63, 0x06, 0x6F, 0x39, 0x39, 0x46, 0x49, 0x49 ;1 .db 0x63, 0x06, 0xAD, 0x39, 0x16, 0x0E, 0x11, 0x11 ;2 .db 0x63, 0x06, 0xAD, 0x39, 0x16, 0x0E, 0x11, 0x11 ;3 .db 0x66, 0x06, 0x1A, 0x1F, 0x16, 0x0E, 0x11, 0x11 ;4 .db 0x66, 0x06, 0x1A, 0x1F, 0x16, 0x0E, 0x11, 0x11 ;5 .db 0x66, 0x06, 0x1A, 0x1F, 0x16, 0x0E, 0x11, 0x11 ;6 .db 0x66, 0x06, 0x22, 0x69, 0x16, 0x1F, 0x92, 0x92 ;7 .db 0x66, 0x06, 0x22, 0xA1, 0x4D, 0x83, 0x86, 0x86 ;8 .db 0x9B, 0x06, 0x96, 0x9D, 0x16, 0x0E, 0x11, 0x11 ;9 .db 0x26, 0x06, 0x22, 0x5D, 0x4D, 0xAD, 0x8E, 0x8E ;A .db 0x26, 0x06, 0x42, 0x3D, 0x2F, 0x2B, 0x37, 0x37 ;B .db 0x46, 0x06, 0x42, 0x3D, 0x39, 0x0E, 0x11, 0x11 ;C .db 0x46, 0x06, 0x42, 0x3D, 0x39, 0x57, 0x11, 0x11 ;D .db 0xA5, 0x06, 0x11, 0x11, 0x39, 0x0E, 0x11, 0x11 ;E .db 0xA9, 0x06, 0x89, 0x89, 0x39, 0x1A, 0x89, 0x89 ;F mnot1: ;mnunonic offset table (gives offset into above table) .db 0x5A, 0x0E, 0x48, 0x73 ;nop, ajmp, ljmp, rr .db 0x2B, 0x2B, 0x2B, 0x2B ;inc, inc, inc, inc .db 0x30, 0x00, 0x43, 0x75 ;jbc, acall, lcall rrc .db 0x21, 0x21, 0x21, 0x21 ; .db 0x2E, 0x0E, 0x67, 0x6E ; etc... .db 0x06, 0x06, 0x06, 0x06 ; .db 0x38, 0x00, 0x6A, 0x70 ; .db 0x0A, 0x0A, 0x0A, 0x0A ; .db 0x33, 0x0E, 0x5D, 0x5D ; .db 0x5D, 0x5D, 0x5D, 0x5D ; .db 0x3B, 0x00, 0x12, 0x12 ; .db 0x12, 0x12, 0x12, 0x12 ; .db 0x41, 0x0E, 0x8F, 0x8F ; .db 0x8F, 0x8F, 0x8F, 0x8F ; .db 0x3E, 0x00, 0x5D, 0x35 ; .db 0x4C, 0x4C, 0x4C, 0x4C ; .db 0x7C, 0x0E, 0x12, 0x4F ; .db 0x24, 0x4C, 0x4C, 0x4C ; .db 0x4C, 0x00, 0x4C, 0x4F ; .db 0x80, 0x80, 0x80, 0x80 ; .db 0x5D, 0x0E, 0x4C, 0x2B ; .db 0x57, 0x92, 0x4C, 0x4C ; .db 0x12, 0x00, 0x1C, 0x1C ; .db 0x15, 0x15, 0x15, 0x15 ; .db 0x63, 0x0E, 0x19, 0x19 ; .db 0x84, 0x88, 0x88, 0x88 ; .db 0x60, 0x00, 0x78, 0x78 ; .db 0x1F, 0x27, 0x8B, 0x8B ; .db 0x53, 0x0E, 0x53, 0x53 ; .db 0x19, 0x4C, 0x4C, 0x4C ; .db 0x53, 0x00, 0x53, 0x53 ; .db 0x1C, 0x4C, 0x4C, 0x4C ; mnot2: .db 0x2B, 0x21, 0x06, 0x0A ;inc, dec, add, addc .db 0x5D, 0x12, 0x8F, 0x4C ;orl, anl, xlr, mov .db 0x4C, 0x80, 0x4C, 0x15 ;mov, subb, mov, cjne .db 0x88, 0x27, 0x4C, 0x4C ;xch, djnz, mov, mov ;---------------------------------------------------------; ; ; ; About PAULMON2 ; ; ; ;---------------------------------------------------------; ;register usage: ; R4, Flags: ; bit0: 0=display CODE memory, 1=display DATA memory ; bit1: 0=editing disabled, 1=editing enabled ; bit2: 0=editing in hex, 1=editing in ascii ; bit3: 0=normal, 1=in middle of hex entry (value in r5) ; R6/R7, current memory location ; .org locat+0x800 .db 0xA5,0xE5,0xE0,0xA5 ;signiture .db 254,'A',0,0 ;id (254=user installed command) .db 0,0,0,0 ;prompt code vector .dB 0,0,0,0 ;reserved .db 0,0,0,0 ;reserved .db 0,0,0,0 ;reserved .db 0,0,0,0 ;user defined .db 255,255,255,255 ;length and checksum (255=unused) .db "About PAULMON2",0 .org locat+0x0840 ;executable code begins here mov dptr,#about lcall pstr ljmp newline_h about: .db 13,10," PAULMON2 by Paul Stoffregen paul@ece.orst.edu" .db 13,10," modified by Wichit Sirichote July 25,'99" .db 13,10," * add return path to monitor & print ACC & PSW" .db 13,10," * use 9600 fixed baud rate",13,10,0 ; change Fix_baud to 9600 ;this little program is an example of how to use the "init" type ;of startup program to initialize the baud rate and the other ;related memory locations, so that PAULMON2 will *not* attempt ;to do automatic baud rate detection, even if it configured to ;do automatic baud rate detection by default. For boards with ;flash rom, this allows the board to used for a dedicated purpose ;without having to do automatic baud rate detection every time ;the power is cycled. Startup programs other than hardware ;initialization should usually used type 253 instead of 249. ;.equ baud_const, 255 ;57600 baud w/ 11.0592 MHz ;.equ baud_const, 253 ;19200 baud w/ 11.0592 MHz ;.equ baud_const, 252 ;19200 baud w/ 14.7456 MHz ;.equ baud_const, 243 ;4808 baud w/ 12 MHz .equ baud_const, 250 ; 9600 baud w/11.0592 MHz .org locat+0x900 ; i.e., 1900h .db 0xA5,0xE5,0xE0,0xA5 ;signiture bytes .db 249,255,0,0 ;id (35=prog, 249=init, 253=startup, 254=cmd) .db 0,0,0,0 ;prompt code vector .db 0,0,0,0 ;reserved .db 0,0,0,0 ;reserved .db 0,0,0,0 ;reserved .db 0,0,0,0 ;user defined .db 255,255,255,255 ;length and checksum (255=unused) .db "Fixed Baud Rate",0 .org locat+0x940 ;executable code begins here mov a, #baud_const mov 0x7B, a mov 0x7A, a ;store the baud rate for next warm boot. mov 0x79, a mov 0x78, a xrl 0x7A, #01010101b xrl 0x79, #11001100b xrl 0x78, #00011101b ret ;------------------------- my code ------------------------------ ; back to monitor program path with printout accumulator and ; psw's content ; W.Sirichote 25 July 1999 monitor: push psw push acc lcall newline mov dptr, #accumulator lcall pstr pop acc lcall phex lcall newline mov dptr, #PSW_REG lcall pstr pop psw mov a,psw lcall phex lcall newline ljmp 0 ; go to reset condition accumulator: .db "Accumulator = ",0 PSW_REG: .db "PSW = ",0 ;---------------------------------------------------------- ; getnum() and _atoi() ; W.Sirichote 16 August 1999 ; 16 bit multiply of AB by R3-4, result in AB ; mul16: MOV R6,A ; Save LO1 MOV A,R3 ; Get LO2 MUL AB ; Multiply HI1 * LO2 MOV R5,A ; Save partial product MOV B,R6 ; Get LO1 MOV A,R4 ; Get HI2 MUL AB ; Multiply LO1 * HI2 MOV R4,A ; Save partial product MOV A,R3 ; Get LO2 MOV B,R6 ; Get LO1 MUL AB ; Multiply LO2 * LO1 XCH A,B ; Save low & get high ADD A,R4 ; Add in carry from LO1 * HI2 ADD A,R5 ; Add in carry from HI1 * LO2 XCH A,B ; Restore proper order RET ; Convert ASCII string to number: int _atoi(string) ; r1 string pointer _atoi: CLR A ; Get ZERO MOV R3,A ; Set LOW MOV R4,A ; Set HIGH MOV R7,A ; Assume positive A1: MOV A,@R1 ; Get char INC R1 ; Advance CJNE A,#'-',A3 ; Not minus INC R7 ; Set negative flag A2: MOV A,@R1 ; Get char INC R1 ; Advance A3: CLR C ; Insure no carry SUBB A,#'0' ; Convert to binary CJNE A,#10,*+3 ; Non-destructive compare JNC A4 ; End of number MOV R2,A ; Save for later MOV A,#10 ; *10 MOV B,#0 ; Zero high LCALL mul16 ; Multiply result ADD A,R2 ; Include digit MOV R3,A ; Save LOW MOV A,B ; Swap ADDC A,#0 ; Insure high incs MOV R4,A ; Save high SJMP A2 ; And go again A4: MOV A,R3 ; Get LOW result MOV B,R4 ; Get HIGH result DJNZ R7,A5 ; Negative sign? ; LJMP neg ; Yes, convert A5: RET ; int getnum() return integer in BA ; get decimal string then convert to int ; use 6-byte RAM at f0h-f5h, eg. '65535' 0 _getnum: mov r1,#0xf0 _getnum2: lcall cin cjne a,#0dh,check_BS mov @r1,#0 ; put terminator mov r1,#0xf0 lcall _atoi ret ; return BA as an integer check_BS: cjne a,#8,check_FF lcall cout dec r1 sjmp _getnum2 check_FF: cjne a,#0x0c,save_char lcall cout inc r1 sjmp _getnum2 save_char: lcall cout mov @r1,a inc r1 sjmp _getnum2 ;---------------------------------------------------------; ; ; ; single step strings ; ; ; ;---------------------------------------------------------; prompt4:.db "), or to exit: ",0 prompt8:.db 13,31,136,128,131,129," (",0 abort: .db " Command Aborted.",13,10,0 sserr1: .db 13,161,197," connect INT1 (pin 13) low" .db 128,186,207,204,13,0 sserr2: .db 148,"2",179,199,174,129," 0013",13,0 sserr3: .db 31,184,179,255,165," vector",174," ",0 ssmsg: .db 13,"Now",134,"ning",166,207,204," mode: " .db "=",204,", ?= Help",13,13,0 sskip1: .db "Skipping Instruction-> ",0 ssdmps1:.db 13,10,"Loc: Int RAM Memory Contents",13,10,0 chaccs1:.db "New Acc Value: ",0 help5txt:.db 13 .db 31,207,31,204,31,158,":",13 .db " ",134,212,246,13 .db " ",134,212,246,13 .db " '?' ",255,142,215,13 .db " '.' ",255,196,253,"s",13 .db " 'R' ",255," special function",196,"s",13 .db " 'H' ",132,219,192,146,13 .db " 'S' ",252,212,246,13 .db " 'A' ",240,162," Acc value",13 .db " 'Q' ",200,207,204,13,14 squit: .db "Quit",13,10,0 ssnames:.db " ACC B C DPTR R0 R1 R2 R3 R4 R5 R6 R7 SP" .db " Addr Instruction",13,10,0 ;---------------------------------------------------------; ; ; ; disassembler data ; ; ; ;---------------------------------------------------------; mnu_tbl:.db "ACAL",'L'+128 .db 0 .db "AD",'D'+128 .db 0 .db "ADD",'C'+128 .db "AJM",'P'+128 .db "AN",'L'+128 .db "CJN",'E'+128 .db "CL",'R'+128 .db "CP",'L'+128 .db "D",'A'+128 .db "DE",'C'+128 .db "DI",'V'+128 .db "DJN",'Z'+128 .db "IN",'C'+128 .db "J",'B'+128 .db "JB",'C'+128 .db "J",'C'+128 .db "JM",'P'+128 .db "JN",'B'+128 .db "JN",'C'+128 .db "JN",'Z'+128 .db "J",'Z'+128 .db "LCAL",'L'+128 .db "LJM",'P'+128 .db "MO",'V'+128 .db "MOV",'C'+128 .db "MOV",'X'+128 .db "MU",'L'+128 .db "NO",'P'+128 .db "OR",'L'+128 .db "PO",'P'+128 .db "PUS",'H'+128 .db "RE",'T'+128 .db "RET",'I'+128 .db "R",'L'+128 .db "RL",'C'+128 .db "R",'R'+128 .db "RR",'C'+128 .db "SET",'B'+128 .db "SJM",'P'+128 .db "SUB",'B'+128 .db "SWA",'P'+128 .db "XC",'H'+128 .db "XCH",'D'+128 .db "XR",'L'+128 .db "??",'?'+128 bitmnu: .db 'P','0'+128 .db "TCO",'N'+128 .db 'P','1'+128 .db "SCO",'N'+128 .db 'P','2'+128 .db 'I','E'+128 .db 'P','3'+128 .db 'I','P'+128 .db 'C','0'+128 .db "T2CO",'N'+128 .db "PS",'W'+128 .db 'D','8'+128 .db "AC",'C'+128 .db 'E'+'8'+128 .db 'B'+128 .db 'F'+'8'+128