📄 paulmon2.asm
字号:
;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, autob1
autoend_jmp:
ajmp autoend
autob1: ;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, #200
autob1b:mov r1, #30
autob1c:jnb p3.0, autob1
djnz r1, autob1c
djnz r0, autob1b
autob2: ;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, autob2
autob2b:jnb p3.0, autob2b ;wait for bit #0 to begin
setb tr1 ;and now we're timing it
autob2c:jb tf1, autob1 ;check for timeout while waiting
jb p3.0, autob2c ;wait for bit #1 to begin
autob2d:jb tf1, autob1 ;check for timeout while waiting
jnb p3.0, autob2d ;wait for bit #2 to begin
autob2e:jb tf1, autob1 ;check for timeout while waiting
jb p3.0, autob2e ;wait for bit #4 to begin
setb tr0 ;start timing last 4 bits
autob2f: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 anything
autob3: 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, a
autob3b:mov r0, #255
autob3c: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 bit
autob1_jmp:
ljmp autob1
autob4:
;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 point
autoend: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, 27
cin_filter:
jnb ri, cinf1
lcall cin
cjne a, #esc_char, cinf_end
;if esc was already in sbuf, just ignore it
cinf1: lcall cin
cjne a, #esc_char, cinf_end
cinf2: acall cinf_wait
jb ri, cinf4
mov a, #esc_char
ret ;an ordinary ESC
cinf4: ;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 cin
cinf5a: cjne a, #'A', cinf5b
mov a, #11
ret
cinf5b: cjne a, #'B', cinf5c
mov a, #10
ret
cinf5c: cjne a, #'C', cinf5d
mov a, #21
ret
cinf5d: cjne a, #'D', cinf5e
mov a, #8
ret
cinf5e: cjne a, #0x35, cinf5f
sjmp cinf8
cinf5f: cjne a, #0x36, cinf5g
sjmp cinf8
cinf5g: sjmp cinf_consume ;unknown escape sequence
cinf8: ;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, #228
cinf_end: ret
cinf_restart:
pop acc
sjmp cin_filter
cinf_notpg:
pop acc
;unrecognized escape... eat up everything that's left coming in
;quickly, then begin looking again
cinf_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 wait
cinf_wait:
mov a, r2
push acc
mov r2, #char_delay*5
cinfw2: mov a, th0
cinfw3: jb ri, cinfw4
inc a
jnz cinfw3
djnz r2, cinfw2
cinfw4: pop acc
mov r2, a
ret
pint8u: ;prints the unsigned 8 bit value in Acc in base 10
push b
push acc
sjmp pint8b
pint8: ;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, #1
pint8b: mov b, #100
div ab
setb f0
jz pint8c
clr f0
add a, #'0'
lcall cout
pint8c: mov a, b
mov b, #10
div ab
jnb f0, pint8d
jz pint8e
pint8d: add a, #'0'
lcall cout
pint8e: 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, dph
pint16a:mov r4, #16 ;ten-thousands digit
mov r5, #39
acall pint16x
jz pint16b
add a, #'0'
lcall cout
setb psw.5
pint16b:mov r4, #232 ;thousands digit
mov r5, #3
acall pint16x
jnz pint16c
jnb psw.5, pint16d
pint16c:add a, #'0'
lcall cout
setb psw.5
pint16d:mov r4, #100 ;hundreds digit
mov r5, #0
acall pint16x
jnz pint16e
jnb psw.5, pint16f
pint16e:add a, #'0'
lcall cout
setb psw.5
pint16f:mov a, r2 ;tens digit
mov r3, b
mov b, #10
div ab
jnz pint16g
jnb psw.5, pint16h
pint16g:add a, #'0'
lcall cout
pint16h: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, #0
pint16y: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 capitalized
pcstr: push acc
mov a, r0
push acc
mov a, r1
push acc
mov a, r4
push acc
setb psw.1
setb psw.5
pcstr1: clr a
movc a, @a+dptr
inc dptr
jz pcstr2
jb acc.7, decomp
anl a, #0x7F
pcstrs1:cjne a, #13, pcstrs2
lcall newline
setb psw.1
sjmp pcstr1
pcstrs2:cjne a, #31, pcstrs3
clr psw.5
sjmp pcstr1
pcstrs3:cjne a, #14, pcstrs4
lcall newline
sjmp pcstr2
pcstrs4:
clr psw.1
lcall cout
sjmp pcstr1
pcstr2: 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 high
decomp: anl a, #0x7F
mov r0, a ;r0 counts which word
jb psw.1, decomp1 ;avoid leading space if first word
lcall space
decomp1: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, a
dcomp2: 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, dcomp2
dcomp3: ;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.5
dcomp6: cjne r0, #12, dcomp7
clr acc.5
dcomp7: lcall cout
sjmp dcomp3
dcomp_end:
pop dph
pop dpl
ajmp pcstr1
get_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
ret
gnn2: 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
;STR
logon1: .db "Welcome",128,148,"2, by",31,248,31,254,13,14
logon2: .db 32,32,"See",148,"2.DOC,",148,"2.EQU",164
.db 148,"2.HDR",180,213,141,".",14
abort: .db " ",31,158,31,160,"!",13,14
prompt1:.db 148,"2 Loc:",0
prompt2:.db " >", 160 ;must follow after prompt1
prompt3:.db 134,202,130,'(',0
prompt4:.db "),",149,140,128,200,": ",0
prompt5:.db 31,151,130,195,"s",199,166,131,","
.db 186," JUMP",128,134,161,"r",130,13,14
prompt6:.db 13,13,31,135,131,129,": ",0
prompt7:.db 31,228,251," key: ",0
prompt8:.db 13,13,31,136,128,131,129," (",0
prompt9:.db 13,13,31,130,31,253,0
prompt9b:.db 31,129,32,32,32,32,32,31,201,14 ;must follow prompt9
prompt10:.db ") ",31,135,31,178,": ",0
beg_str:.db "First",31,129,": ",0
end_str:.db "Last",31,129,":",32,32,0
sure: .db 31,185,161," sure?",0
edits1: .db 13,13,31,156,154,146,",",140,128,200,14
edits2: .db " ",31,156,193,",",142,129,247,13,14
dnlds1: .db 13,13,31,159," ascii",249,150,31,152,132,137
.db ",",149,140,128,160,13,14
dnlds2: .db 13,31,138,160,"ed",13,14
dnlds3: .db 13,31,138,193,"d",13,14
dnlds4: .db "Summary:",14
dnlds5: .db " ",198,"s",145,"d",14
dnlds6a:.db " ",139,145,"d",14
dnlds6b:.db " ",139," written",14
dnlds7: .db 31,155,":",14
dnlds8: .db " ",139," unable",128," write",14
dnlds9: .db 32,32,"bad",245,"s",14
dnlds10:.db " ",133,159,150,198,14
dnlds11:.db " ",133,132,157,14
dnlds12:.db " ",133," non",132,157,14
dnlds13:.db 31,151,155," detected",13,14
runs1: .db 13,134,"ning",130,":",13,14
uplds3: .db 13,13,"Sending",31,152,132,137,172,32,32,0
uplds4: .db " ",128,32,32,0 ;must follow uplds3
help1txt:.db 13,13,"Standard",31,158,"s",14
help2txt:.db 31,218,31,244,"ed",31,158,"s",14
type1: .db 31,154,158,0
type2: .db 31,130,0
type4: .db 31,143,31,226,31,170,0
type5: .db "???",0
help_cmd2:.db 31,215,0
help_cmd: .db 31,142,215,209,0 ;these 11 _cmd string must be in order
dir_cmd: .db 31,209,130,"s",0
run_cmd: .db 31,134,130,0
dnld_cmd: .db 31,138,0
upld_cmd: .db 31,147,0
nloc_cmd: .db 31,135,129,0
jump_cmd: .db 31,136,128,131,129,0
dump_cmd: .db 31,132,219,154,131,0
intm_cmd: .db 31,132,219,192,131,0
edit_cmd: .db 31,156,154,146,0
clrm_cmd: .db 31,237,131,0
erfr_cmd: .db 31,203,153,144,0
erfr_ok: .db 31,153,144,203,'d',13,14
erfr_err: .db 31,133,155,13,14
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -