📄 mypaulm2.asm
字号:
;;we'll start timer #1 in 16 bit mode at the transition between the;start bit and the LSB and stop it between the MBS and stop bit.;That will give approx the number of cpu cycles for 8 bits. Divide;by 8 for one bit and by 16 since the built-in UART takes 16 timer;overflows for each bit. We need to be careful about roundoff during;division and the result has to be inverted since timer #1 counts up. Of;course, timer #1 gets used in 8-bit auto reload mode for generating the;built-in UART's baud rate once we know what the reload value should be.autobaud: mov a, #baud_const ;skip if user supplied baud rate constant jnz autoend_jmp mov a, baud_save+3 ;is there a value from a previous boot? xrl baud_save+2, #01010101b xrl baud_save+1, #11001100b xrl baud_save+0, #00011101b cjne a, baud_save+2, autob1 cjne a, baud_save+1, autob1 cjne a, baud_save+0, autob1autoend_jmp: ajmp autoendautob1: ;wait for inactivity mov pcon, #0x80 ;configure uart, fast baud mov scon, #0x42 ;configure uart, but receive disabled mov tmod, #0x11 ;get timers ready for action (16 bit mode) clr a mov tcon, a mov tl0, a mov th0, a mov tl1, a mov th1, a ;make sure there is no activity on the line ;before we actually begin looking for the carriage return mov r0, #200autob1b:mov r1, #30autob1c:jnb p3.0, autob1 djnz r1, autob1c djnz r0, autob1bautob2: ;look for the bits of the carriage return jb p3.0, autob2 ;wait for start bit jb p3.0, autob2 jb p3.0, autob2 ; check it a few more times to make jb p3.0, autob2 ; sure we don't trigger on some noise jb p3.0, autob2autob2b:jnb p3.0, autob2b ;wait for bit #0 to begin setb tr1 ;and now we're timing itautob2c:jb tf1, autob1 ;check for timeout while waiting jb p3.0, autob2c ;wait for bit #1 to beginautob2d:jb tf1, autob1 ;check for timeout while waiting jnb p3.0, autob2d ;wait for bit #2 to beginautob2e:jb tf1, autob1 ;check for timeout while waiting jb p3.0, autob2e ;wait for bit #4 to begin setb tr0 ;start timing last 4 bitsautob2f:jb tf1, autob1 ;check for timeout while waiting jnb p3.0, autob2f ;wait for stop bit to begin clr tr1 ;stop timing (both timers) clr tr0 jb tf1, autob1 ;check for timeout one last time ;compute the baud rate based on timer1 mov a, tl1 rlc a mov b, a mov a, th1 rlc a jc autob1 ;error if timer0 > 32767 mov c, b.7 addc a, #0 cpl a inc a ;now a has the value to load into th1 jz autob1 ;error if baud rate too fast ;after we get the carriage return, we need to make sure there ;isn't any "crap" on the serial line, as there is in the case ;were we get the letter E (and conclude the wrong baud rate). ;unfortunately the simple approach of just looking at the line ;for silence doesn't work, because we have to accept the case ;where the user's terminal emulation is configured to send a ;line feed after the carriage return. The best thing to do is ;use the uart and look see if it receives anythingautob3: mov th1, a ;config timer1 mov tl1, #255 ;start asap! mov tmod, #0x21 ;autoreload mode setb ren ;turn on the uart setb tr1 ;turn on timer1 for its clock mov a, th1 cpl a inc a mov r1, aautob3b:mov r0, #255autob3c:djnz r0, autob3c djnz r1, autob3b jnb ri, autob4 ;if we got here, there was some stuff after the carriage ;return, so we'll read it and see if it was the line feed clr ri mov a, sbuf anl a, #01111111b add a, #246 jz autob4 ;ok if 0A, the line feed character add a, #5 jz autob4 ;of if 05, since we may have missed start bitautob1_jmp: ljmp autob1autob4: ;compute the baud rate based on timer0, check against timer1 value mov a, tl0 rlc a mov r0, a mov a, th0 rlc a mov r1, a jc autob1_jmp ;error if timer0 > 32767 mov a, r0 rlc a mov b, a mov a, r1 rlc a mov c, b.7 addc a, #0 jz autob1_jmp ;error if baud too fast! cpl a inc a cjne a, th1, autob1_jmp ;acc has th1 value at this pointautoend:mov baud_save+3, a mov baud_save+2, a ;store the baud rate for next warm boot. mov baud_save+1, a mov baud_save+0, a xrl baud_save+2, #01010101b xrl baud_save+1, #11001100b xrl baud_save+0, #00011101b mov th1, a mov tl1, a mov tmod, #0x21 ;set timer #1 for 8 bit auto-reload mov pcon, #0x80 ;configure built-in uart mov scon, #0x52 setb tr1 ;start the baud rate timer ret;---------------------------------------------------------;; ;; More subroutines, but less frequent used, so ;; they're down here in the second 2k page. ;; ;;---------------------------------------------------------;;this twisted bit of code looks for escape sequences for;up, down, left, right, pageup, and pagedown, as well;as ordinary escape and ordinary characters. Escape;sequences are required to arrive with each character;nearly back-to-back to the others, otherwise the characters;are treated as ordinary user keystroaks. cin_filter;returns a single byte when it sees the multi-byte escape;sequence, as shown here.; return value key escape sequence; 11 (^K) up 1B 5B 41; 10 (^J) down 1B 5B 42; 21 (^U) right 1B 5B 43; 8 (^H) left 1B 5B 44; 25 (^Y) page up 1B 5B 35 7E; 26 (^Z) page down 1B 5B 36 7E.equ esc_char, 27cin_filter: jnb ri, cinf1 lcall cin cjne a, #esc_char, cinf_end ;if esc was already in sbuf, just ignore itcinf1: lcall cin cjne a, #esc_char, cinf_endcinf2: acall cinf_wait jb ri, cinf4 mov a, #esc_char ret ;an ordinary ESCcinf4: ;if we get here, it's a control code, since a character ;was received shortly after receiving an ESC character lcall cin cjne a, #'[', cinf_consume acall cinf_wait jnb ri, cin_filter lcall cincinf5a: cjne a, #'A', cinf5b mov a, #11 retcinf5b: cjne a, #'B', cinf5c mov a, #10 retcinf5c: cjne a, #'C', cinf5d mov a, #21 retcinf5d: cjne a, #'D', cinf5e mov a, #8 retcinf5e: cjne a, #0x35, cinf5f sjmp cinf8cinf5f: cjne a, #0x36, cinf5g sjmp cinf8cinf5g: sjmp cinf_consume ;unknown escape sequencecinf8: ;when we get here, we've got the sequence for pageup/pagedown ;but there's one more incoming byte to check... push acc acall cinf_wait jnb ri, cinf_restart lcall cin cjne a, #0x7E, cinf_notpg pop acc add a, #228cinf_end: retcinf_restart: pop acc sjmp cin_filtercinf_notpg: pop acc;unrecognized escape... eat up everything that's left coming in;quickly, then begin looking againcinf_consume: acall cinf_wait jnb ri, cin_filter lcall cin cjne a, #esc_char, cinf_consume sjmp cinf2;this thing waits for a character to be received for approx;4 character transmit time periods. It returns immedately;or after the entire wait time. It does not remove the character;from the buffer, so ri should be checked to see if something;actually did show up while it was waiting .equ char_delay, 4 ;number of char xmit times to waitcinf_wait: mov a, r2 push acc mov r2, #char_delay*5cinfw2: mov a, th0cinfw3: jb ri, cinfw4 inc a jnz cinfw3 djnz r2, cinfw2cinfw4: pop acc mov r2, a retpint8u: ;prints the unsigned 8 bit value in Acc in base 10 push b push acc sjmp pint8bpint8: ;prints the signed 8 bit value in Acc in base 10 push b push acc jnb acc.7, pint8b mov a, #'-' lcall cout pop acc push acc cpl a add a, #1pint8b: mov b, #100 div ab setb f0 jz pint8c clr f0 add a, #'0' lcall coutpint8c: mov a, b mov b, #10 div ab jnb f0, pint8d jz pint8epint8d: add a, #'0' lcall coutpint8e: mov a, b add a, #'0' lcall cout pop acc pop b ret ;print 16 bit unsigned integer in DPTR, using base 10.pint16u: ;warning, destroys r2, r3, r4, r5, psw.5 push acc mov a, r0 push acc clr psw.5 mov r2, dpl mov r3, dphpint16a:mov r4, #16 ;ten-thousands digit mov r5, #39 acall pint16x jz pint16b add a, #'0' lcall cout setb psw.5pint16b:mov r4, #232 ;thousands digit mov r5, #3 acall pint16x jnz pint16c jnb psw.5, pint16dpint16c:add a, #'0' lcall cout setb psw.5pint16d:mov r4, #100 ;hundreds digit mov r5, #0 acall pint16x jnz pint16e jnb psw.5, pint16fpint16e:add a, #'0' lcall cout setb psw.5pint16f:mov a, r2 ;tens digit mov r3, b mov b, #10 div ab jnz pint16g jnb psw.5, pint16hpint16g:add a, #'0' lcall coutpint16h:mov a, b ;and finally the ones digit mov b, r3 add a, #'0' lcall cout pop acc mov r0, a pop acc ret;ok, it's a cpu hog and a nasty way to divide, but this code;requires only 21 bytes! Divides r2-r3 by r4-r5 and leaves;quotient in r2-r3 and returns remainder in acc. If Intel;had made a proper divide, then this would be much easier.pint16x:mov r0, #0pint16y:inc r0 clr c mov a, r2 subb a, r4 mov r2, a mov a, r3 subb a, r5 mov r3, a jnc pint16y dec r0 mov a, r2 add a, r4 mov r2, a mov a, r3 addc a, r5 mov r3, a mov a, r0 ret;pcstr prints the compressed strings. A dictionary of 128 words is;stored in 4 bit packed binary format. When pcstr finds a byte in;a string with the high bit set, it prints the word from the dictionary.;A few bytes have special functions and everything else prints as if;it were an ordinary string.; special codes for pcstr:; 0 = end of string; 13 = CR/LF; 14 = CR/LF and end of string; 31 = next word code should be capitalizedpcstr: push acc mov a, r0 push acc mov a, r1 push acc mov a, r4 push acc setb psw.1 setb psw.5pcstr1: clr a movc a, @a+dptr inc dptr jz pcstr2 jb acc.7, decomp anl a, #0x7Fpcstrs1:cjne a, #13, pcstrs2 lcall newline setb psw.1 sjmp pcstr1pcstrs2:cjne a, #31, pcstrs3 clr psw.5 sjmp pcstr1pcstrs3:cjne a, #14, pcstrs4 lcall newline sjmp pcstr2pcstrs4: clr psw.1 lcall cout sjmp pcstr1pcstr2: pop acc mov r4, a pop acc mov r1, a pop acc mov r0, a pop acc ret;dcomp actually takes care of printing a word from the dictionary; dptr = position in packed words table; r4=0 if next nibble is low, r4=255 if next nibble is highdecomp: anl a, #0x7F mov r0, a ;r0 counts which word jb psw.1, decomp1 ;avoid leading space if first word lcall spacedecomp1:clr psw.1 push dpl push dph mov dptr, #words mov r4, #0 mov a, r0 jz dcomp3 ;here we must seek past all the words in the table ;that come before the one we're supposed to print mov r1, adcomp2: acall get_next_nibble jnz dcomp2 ;when we get here, a word has been skipped... keep doing ;this until we're pointing to the correct one djnz r1, dcomp2dcomp3: ;now we're pointing to the correct word, so all we have ;to do is print it out acall get_next_nibble jz dcomp_end cjne a, #15, dcomp4 ;the character is one of the 12 least commonly used acall get_next_nibble inc a movc a, @a+pc sjmp dcomp5 .db "hfwgybxvkqjz"dcomp4: ;the character is one of the 14 most commonly used inc a movc a, @a+pc sjmp dcomp5 .db "etarnisolumpdc"dcomp5: ;decide if it should be uppercase or lowercase mov c, psw.5 mov acc.5, c setb psw.5 cjne r0, #20, dcomp6 clr acc.5dcomp6: cjne r0, #12, dcomp7 clr acc.5dcomp7: lcall cout sjmp dcomp3dcomp_end: pop dph pop dpl ajmp pcstr1get_next_nibble: ;...and update dptr and r4, of course clr a movc a, @a+dptr cjne r4, #0, gnn2 mov r4, #255 anl a, #00001111b retgnn2: mov r4, #0 inc dptr swap a anl a, #00001111b ret;---------------------------------------------------------;; ;; Here begins the data tables and strings ;; ;;---------------------------------------------------------;;this is the dictionary of 128 words used by pcstr.words: .db 0x82, 0x90, 0xE8, 0x23, 0x86, 0x05, 0x4C, 0xF8 .db 0x44, 0xB3, 0xB0, 0xB1, 0x48, 0x5F, 0xF0, 0x11 .db 0x7F, 0xA0, 0x15, 0x7F, 0x1C, 0x2E, 0xD1, 0x40 .db 0x5A, 0x50, 0xF1, 0x03, 0xBF, 0xBA, 0x0C, 0x2F .db 0x96, 0x01, 0x8D, 0x3F, 0x95, 0x38, 0x0D, 0x6F .db 0x5F, 0x12, 0x07, 0x71, 0x0E, 0x56, 0x2F, 0x48 .db 0x3B, 0x62, 0x58, 0x20, 0x1F, 0x76, 0x70, 0x32 .db 0x24, 0x40, 0xB8, 0x40, 0xE1, 0x61, 0x8F, 0x01 .db 0x34, 0x0B, 0xCA, 0x89, 0xD3, 0xC0, 0xA3, 0xB9 .db 0x58, 0x80, 0x04, 0xF8, 0x02, 0x85, 0x60, 0x25 .db 0x91, 0xF0, 0x92, 0x73, 0x1F, 0x10, 0x7F, 0x12 .db 0x54, 0x93, 0x10, 0x44, 0x48, 0x07, 0xD1, 0x26 .db 0x56, 0x4F, 0xD0, 0xF6, 0x64, 0x72, 0xE0, 0xB8 .db 0x3B, 0xD5, 0xF0, 0x16, 0x4F, 0x56, 0x30, 0x6F .db 0x48, 0x02, 0x5F, 0xA8, 0x20, 0x1F, 0x01, 0x76 .db 0x30, 0xD5, 0x60, 0x25, 0x41, 0xA4, 0x2C, 0x60 .db 0x05, 0x6F, 0x01, 0x3F, 0x26, 0x1F, 0x30, 0x07 .db 0x8E, 0x1D, 0xF0, 0x63, 0x99, 0xF0, 0x42, 0xB8 .db 0x20, 0x1F, 0x23, 0x30, 0x02, 0x7A, 0xD1, 0x60 .db 0x2F, 0xF0, 0xF6, 0x05, 0x8F, 0x93, 0x1A, 0x50 .db 0x28, 0xF0, 0x82, 0x04, 0x6F, 0xA3, 0x0D, 0x3F .db 0x1F, 0x51, 0x40, 0x23, 0x01, 0x3E, 0x05, 0x43 .db 0x01, 0x7A, 0x01, 0x17, 0x64, 0x93, 0x30, 0x2A .db 0x08, 0x8C, 0x24, 0x30, 0x99, 0xB0, 0xF3, 0x19 .db 0x60, 0x25, 0x41, 0x35, 0x09, 0x8E, 0xCB, 0x19 .db 0x12, 0x30, 0x05, 0x1F, 0x31, 0x1D, 0x04, 0x14 .db 0x4F, 0x76, 0x12, 0x04, 0xAB, 0x27, 0x90, 0x56 .db 0x01, 0x2F, 0xA8, 0xD5, 0xF0, 0xAA, 0x26, 0x20 .db 0x5F, 0x1C, 0xF0, 0xF3, 0x61, 0xFE, 0x01, 0x41 .db 0x73, 0x01, 0x27, 0xC1, 0xC0, 0x84, 0x8F, 0xD6 .db 0x01, 0x87, 0x70, 0x56, 0x4F, 0x19, 0x70, 0x1F .db 0xA8, 0xD9, 0x90, 0x76, 0x02, 0x17, 0x43, 0xFE .db 0x01, 0xC1, 0x84, 0x0B, 0x15, 0x7F, 0x02, 0x8B .db 0x14, 0x30, 0x8F, 0x63, 0x39, 0x6F, 0x19, 0xF0 .db 0x11, 0xC9, 0x10, 0x6D, 0x02, 0x3F, 0x91, 0x09 .db 0x7A, 0x41, 0xD0, 0xBA, 0x0C, 0x1D, 0x39, 0x5F .db 0x07, 0xF2, 0x11, 0x17, 0x20, 0x41, 0x6B, 0x35 .db 0x09, 0xF7, 0x75, 0x12, 0x0B, 0xA7, 0xCC, 0x48 .db 0x02, 0x3F, 0x64, 0x12, 0xA0, 0x0C, 0x27, 0xE3 .db 0x9F, 0xC0, 0x14, 0x77, 0x70, 0x11, 0x40, 0x71 .db 0x21, 0xC0, 0x68, 0x25, 0x41, 0xF0, 0x62, 0x7F .db 0xD1, 0xD0, 0x21, 0xE1, 0x62, 0x58, 0xB0, 0xF3 .db 0x05, 0x1F, 0x73, 0x30, 0x77, 0xB1, 0x6F, 0x19 .db 0xE0, 0x19, 0x43, 0xE0, 0x58, 0x2F, 0xF6, 0xA4 .db 0x14, 0xD0, 0x23, 0x03, 0xFE, 0x31, 0xF5, 0x14 .db 0x30, 0x99, 0xF8, 0x03, 0x3F, 0x64, 0x22, 0x51 .db 0x60, 0x25, 0x41, 0x2F, 0xE3, 0x01, 0x56, 0x27 .db 0x93, 0x09, 0xFE, 0x11, 0xFE, 0x79, 0xBA, 0x60 .db 0x75, 0x42, 0xEA, 0x62, 0x58, 0xA0, 0xE5, 0x1F .db 0x53, 0x4F, 0xD1, 0xC0, 0xA3, 0x09, 0x42, 0x53 .db 0xF7, 0x12, 0x04, 0x62, 0x1B, 0x30, 0xF5, 0x05 .db 0xF7, 0x69, 0x0C, 0x35, 0x1B, 0x70, 0x82, 0x2F .db 0x2F, 0x14, 0x4F, 0x51, 0xC0, 0x64, 0x25, 0x00;STRlogon1: .db "Welcome",128,148,"2, by",31,248,31,254,13,14logon2: .db 32,32,"See",148,"2.DOC,",148,"2.EQU",164 .db 148,"2.HDR",180,213,141,".",14abort: .db " ",31,158,31,160,"!",13,14prompt1:.db 148,"2 Loc:",0prompt2:.db " >", 160 ;must follow after prompt1prompt3:.db 134,202,130,'(',0prompt4:.db "),",149,140,128,200,": ",0prompt5:.db 31,151,130,195,"s",199,166,131,"," .db 186," JUMP",128,134,161,"r",130,13,14prompt6:.db 13,13,31,135,131,129,": ",0prompt7:.db 31,228,251," key: ",0prompt8:.db 13,13,31,136,128,131,129," (",0prompt9:.db 13,13,31,130,31,253,0prompt9b:.db 31,129,32,32,32,32,32,31,201,14 ;must follow prompt9prompt10:.db ") ",31,135,31,178,": ",0beg_str:.db "First",31,129,": ",0end_str:.db "Last",31,129,":",32,32,0sure: .db 31,185,161," sure?",0edits1: .db 13,13,"Address> ",0 ;31,156,154,146,",",140,128,200,14edits2: .db " ",31,156,193,",",142,129,247,13,14dnlds1: .db 13,13,31,159," ascii",249,150,31,152,132,137 .db ",",149,140,128,160,13,14dnlds2: .db 13,31,138,160,"ed",13,14dnlds3: .db 13,31,138,193,"d",13,14dnlds4: .db "Summary:",14dnlds5: .db " ",198,"s",145,"d",14dnlds6a:.db " ",139,145,"d",14dnlds6b:.db " ",139," written",14dnlds7: .db 31,155,":",14dnlds8: .db " ",139," unable",128," write",14dnlds9: .db 32,32,"bad",245,"s",14dnlds10:.db " ",133,159,150,198,14dnlds11:.db " ",133,132,157,14dnlds12:.db " ",133," non",132,157,14dnlds13:.db 31,151,155," detected",13,14runs1: .db 13,134,"ning",130,":",13,14uplds3: .db 13,13,"Sending",31,152,132,137,172,32,32,0uplds4: .db " ",128,32,32,0 ;must follow uplds3help1txt:.db 13,13,"Standard",31,158,"s",14help2txt:.db 31,218,31,244,"ed",31,158,"s",14type1: .db 31,154,158,0type2: .db 31,130,0type4: .db 31,143,31,226,31,170,0type5: .db "???",0help_cmd2:.db 31,215,0help_cmd: .db 31,142,215,209,0 ;these 11 _cmd string must be in orderdir_cmd: .db 31,209,130,"s",0run_cmd: .db 31,134,130,0dnld_cmd: .db 31,138,0upld_cmd: .db 31,147,0nloc_cmd: .db 31,135,129,0jump_cmd: .db 31,136,128,131,129,0dump_cmd: .db 31,132,219,154,131,0intm_cmd: .db 31,132,219,192,131,0edit_cmd: .db 31,156,154,146,0clrm_cmd: .db 31,237,131,0erfr_cmd: .db 31,203,153,144,0erfr_ok: .db 31,153,144,203,'d',13,14erfr_err: .db 31,133,155,13,14
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -