;user installable disassembler and single-step run for paulmon2 .equ pgm, 0x8000 ;default location for the user program .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 getnum, 0x19D2 .equ pint16u, 0x53+paulmon2 .equ list_key, 'D' ; 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 "Disassemble",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, #0x00, ssdmp1 ; modified for 256 bytes RAM 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 ;---------------------------------------------------------; ; ; ; EEPROM Boot Loader ; ; detect P3.5 if P3.5 == 0 then run EEPROM Booting ; ;---------------------------------------------------------; ; detect gpio2 bit0, if low then run eeprom booting ;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 253,255,0,0 ;id (253= startup) .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 "EEPROM booting",0 .org locat+0x0840 ;executable code begins here MOV DPTR,#200H MOVX A,@DPTR JNB ACC.0,boot ret boot: acall boot_eeprom ; 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 ;.equ baud_const, 246 ; 9600 baud w/18.432 MHz (smod = 1) ;.equ baud_const, 251 ; 38400 baud w/18.432MHz (smod = 1) .org locat+0x900 ; i.e., 1900h .db 0xA5,0xE5,0xE0,0xA5 ;signiture bytes .db 254,'Q',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 "Quick home",0 .org locat+0x940 ;executable code begins here mov r6, #(pgm & 255) mov r7, #(pgm >> 8) ljmp newline_h .org locat+0x954 ;------------------------- 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 ; modify it to be 70h-75h _getnum: mov r1,#0x70 _getnum2: lcall cin cjne a,#0dh,check_BS mov @r1,#0 ; put terminator mov r1,#0x70 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 ;========================================================== ; ZAP eeprom service routines ; ; W.Sirichote Feb 5, 2002 ;========================================================== .org locat+0xA00 ; i.e. 0x1A00 .db 0xA5,0xE5,0xE0,0xA5 ;signiture .db 254,'Z',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 "ZAP EEPROM",0 .org locat+0x0A40 ;executable code begins here loop_eeprom: mov dptr,#eeprom_menu lcall pstr mov a,#'>' lcall cout lcall cin cjne a,#'1',next2 acall save_pgm sjmp loop_eeprom next2: cjne a,#'2',next3 acall eeprom_dump sjmp loop_eeprom next3: cjne a,#'3',next4 acall boot_eeprom sjmp loop_eeprom next4: mov r6,#0x00 mov r7,#0x80 ; return to start address of SRAM 0x8000 ljmp newline_h eeprom_menu: .db 13,10,"24LC256 EEPROM functions 1 SAVE, 2 DUMP, 3 LOAD",13,10,0 ;==================== eeprom drivers ========================= ; Generate a START condition & TX char in A ICstrt: SETB P3.4 ;SDA = 1 SETB P1.0 ;SCL = 1 NOP NOP CLR P3.4 ;SDA = 0 - START NOP NOP CLR P1.0 ;SCL = 0 - Ready for first bit RET ; Send 8 bit character in A ICsend: MOV R7,#8 ;8 bits ber byte send1: RLC A ; Get next bit to send MOV P3.4,C ;Write bit to data line MOV P1.7,C ; use P1.7 as a I2C functioning SETB P1.0 ;Toggle CLOCK high NOP NOP NOP NOP CLR P1.0 ;Toggle CLOCK low DJNZ R7,send1 ;Send all bits SETB P3.4 ;Release DATA line SETB P1.0 ;9'th clock NOP NOP NOP NOP MOV C,P3.4 ;Get ACK bit CLR P1.0 ;Return clock LOW RET ; ; Read 8 bits of data into ACC ; ICread: MOV R7,#8 read_bit: SETB P1.0 NOP NOP NOP NOP MOV C,P3.4 MOV P1.7,C ; also for reading I2C indicator RLC A CLR P1.0 DJNZ R7,read_bit RET ; ; Send an ACK to the remote ; ICack: CLR P3.4 ; Zero DATA SETB P1.0 ; Raise CLOCK NOP NOP NOP NOP CLR P1.0 ; Lower CLOCK SETB P3.4 ; Release DATA RET ; Send the STOP condition to the remote ; ICstop: CLR P3.4 ;Zero DATA SETB P1.0 ;Raise CLOCK NOP NOP NOP NOP NOP SETB P3.4 ;Raise DATA RET ; Write complete polling ; exit when complete complete_poll: ACALL ICstrt MOV A,#device_addressWR ACALL ICsend JC complete_poll ret .equ device_addressWR, 0xA0 .equ device_addressRD, 0xA1 ; Read byte from EEPROM ; Entry: DPTR holds address to be accessed ; Exit: ACC ; eeread: ACALL ICstrt ; Start transfer MOV A,#device_addressWR ACALL ICsend ; Write MOV A,DPH ACALL ICsend MOV A,DPL ACALL ICsend acall ICstrt mov a,#device_addressRD acall ICsend ACALL ICread ; Get data byte acall ICstop ret ; Write byte to eeprom ; Entry: DPTR address to be written ; ACC byte to be written ; eewrite: mov b,a acall ICstrt mov a,#device_addressWR acall ICsend mov a,dph acall ICsend mov a,dpl acall ICsend mov a,b acall ICsend acall ICstop acall complete_poll ret ; hex dump from external eeprom address 0000H-7FFFH ; DPTR: start address to be displayed eeprom_dump: mov dptr,#read_location lcall pstr lcall ghex16 lcall newline mov r2, #16 ;number of lines to print eedump1: lcall newline lcall phex16 ;tell 'em the memory location mov a,#' ' lcall cout mov r3, #16 ;r3 counts # of bytes to print eedump2: acall eeread inc dptr lcall phex ;print each byte in hex mov a,#' ' lcall cout djnz r3,eedump2 djnz r2,eedump1 lcall newline ret read_location: .db 13,10,"eeprom address [0000-7FFF] > ",0 ; increment ptr ; entry: r0 inc_ptr: mov a,#1 add a,@r0 mov @r0,a inc r0 mov a,#0 addc a,@r0 mov @r0,a ret ; get DPTR get_dptr: mov a,@r0 mov dpl,a inc r0 mov a,@r0 mov dph,a ret ; save program ; save code from 8000H to eeprom ; the number of byte to be saved was input by user ; ; test with 9000H..... ; ; eeprom address content ; 0000H start address low ; 0001H start address high ; 0002H number of byte low ; 0003H number of byte high ; 0004H XX reserved for future ; 0005H XX ; ..... .. ; 0010H first byte ; 0011H .. ; 7FFFH nn .equ ptr2,0x7C ; 16-bit eeprom address pointer .equ ptr1,0x7E ; 16-bit SRAM address pointer save_pgm: mov dptr,#save lcall pstr lcall ghex16 jnc no_esc1 ret no_esc1: mov a,dpl mov r2,dph push dph push dpl mov dptr,#0 acall eewrite mov dptr,#1 mov a,r2 acall eewrite ; save start address to 0000-0001 pop dpl pop dph mov r0,#ptr1 mov a,dpl mov @r0,a inc r0 mov a,dph mov @r0,a mov dptr,#save2 lcall pstr lcall getnum ; get number of byte to be saved cpl a mov dpl,a mov a,b cpl a mov dph,a inc dptr ; got two's complement of number of bytes lcall newline push dph push dpl mov a,dpl mov r2,dph mov dptr,#2 acall eewrite mov dptr,#3 mov a,r2 acall eewrite ; save number of byte to 0002-0003 pop dpl pop dph mov r0,#ptr2 mov a,#0x10 mov @r0,a ; eeprom start address is 0010H inc r0 mov a,#0 mov @r0,a loop_write: push dph push dpl ;----------------------- mov r0,#ptr1 acall get_dptr movx a,@dptr ; read from 32K SRAM mov r3,a ; save to r3 mov r0,#ptr2 acall get_dptr mov a,r3 acall eewrite ; save to eeprom mov r0,#ptr1 acall inc_ptr ; next source mov r0,#ptr2 acall inc_ptr ; next destination ;---------------------- pop dpl pop dph mov a,#13 lcall cout lcall pint16u inc dptr mov a,dph orl a,dpl jnz loop_write mov dptr,#done2 lcall pstr ret save: .db 13,10,"Save Program start address> ",0 save2: .db 13,10,"Number of bytes [0-32768] > ",0 save3: .db 13,10,"Saving...",0 done2: .db 13,"Done..",0 ;========================================================================= ; load program from eeprom, write to RAM and jump to start address in SRAM boot_eeprom: mov dptr,#loading lcall pstr ; get start address from eeprom 0000H and 0001H save to ptr1 mov dptr,#0 acall eeread mov r0,#ptr1 mov @r0,a mov dptr,#1 acall eeread mov r0,#ptr1+1 mov @r0,a ; initialize address counter for eeprom to ptr2 mov a,#0x10 mov r0,#ptr2 mov @r0,a inc r0 mov a,#0 mov @r0,a ; get number of byte from eeprom 0002H-0003H mov dptr,#2 acall eeread mov r2,a ; save acc mov dptr,#3 acall eeread mov dph,a mov dpl,r2 loop_read: push dph ; save counter push dpl ;========loop body===================== mov r0,#ptr2 acall get_dptr ; get eeprom address acall eeread mov r3,a ; save to r3 mov r0,#ptr1 acall get_dptr mov a,r3 movx @dptr,a ; write to SRAM mov r0,#ptr1 acall inc_ptr ; next destination mov r0,#ptr2 acall inc_ptr ; next source ;---------------------------------------- pop dpl pop dph inc dptr mov a,dph orl a,dpl jnz loop_read mov dptr,#0 acall eeread mov r2,a mov dptr,#1 acall eeread mov dph,a mov dpl,r2 ; call phex16 push dpl push dph ret ; run application program loading: .db 13,10,"Loading...",0 ;---------------------------------------------------------; ; ; ; 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