📄 pm2_mp3.asm
字号:
mov a, #(((eflash+1) >> 8) & 255)
cjne a, dph, erall2
clr c
ret
erall_err:
setb c
ret
;finds the next header in the external memory.
; Input DPTR=point to start search (only MSB used)
; Output DPTR=location of next module
; C=set if a header found, C=clear if no more headers
find: mov dpl, #0
clr a
movc a, @a+dptr
cjne a, #0xA5, find3
inc dptr
clr a
movc a, @a+dptr
cjne a, #0xE5, find3
inc dptr
clr a
movc a, @a+dptr
cjne a, #0xE0, find3
inc dptr
clr a
movc a, @a+dptr
cjne a, #0xA5, find3
mov dpl, #0 ;found one here!
setb c
ret
find3: mov a, #(emem >> 8)
cjne a, dph, find4 ;did we just check the end
clr c
ret
find4: inc dph ;keep on searching
sjmp find
;************************************
;To make PAULMON2 able to write to other
;types of memory than RAM and flash rom,
;modify this "smart_wr" routine. This
;code doesn't accept any inputs other
;that the address (dptr) and value (acc),
;so this routine must know which types
;of memory are in what address ranges
;************************************
;Write to Flash ROM or ordinary RAM. Carry bit will indicate
;if the value was successfully written, C=1 if not written.
smart_wr:
push acc
push b
mov b, a
;there is a flash rom, but is this address in it?
mov a, dph
cjne a, #(eflash >> 8), isfl3
sjmp wr_flash
isfl3: jnc wr_ram
cjne a, #(bflash >> 8), isfl4
sjmp wr_flash
isfl4: jnc wr_flash
;sjmp wr_ram
wr_ram: mov a, b
movx @dptr, a ;write the value to memory
clr a
movc a, @a+dptr ;read it back from code memory
clr c
subb a, b
jz smwrok
movx a, @dptr ;read it back from data memory
clr c
subb a, b
jz smwrok
smwrbad:setb c
sjmp smwrxit
smwrok: clr c
smwrxit:pop b
pop acc
ret
wr_flash:
mov a, b
lcall prgm
pop b
pop acc
ret
;---------------------------------------------------------;
; ;
; Power-On initialization code and such... ;
; ;
;---------------------------------------------------------;
;first the hardware has to get initialized.
intr_return:
reti
poweron:
;set low power OTP eprom mode for philips 87C52
mov 0xA2, #255
clr a
mov ie, a ;all interrupts off
mov ip, a
mov psw, #psw_init
;clear any interrupt status, just in case the user put
;"ljmp 0" inside their interrupt service code.
acall intr_return
acall intr_return
cpl a
mov p0, a
mov p1, a
mov p2, a
mov p3, a
mov sp, #stack
acall set_bank0
acall rst_devices
;initialize the serial port
mov a, #baud_const
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
;now print out the nice welcome message
welcome:
mov r0, #24
welcm2: lcall newline
djnz r0, welcm2
mov dptr, #logon1
lcall pcstr
lcall dir
;check for the user to press "S" to avoid auto-startup.
;allow a 1/2 second timeout, and accept and 'S' that's
;already in sbuf
; 0.5 seconds is 307200 instruction cycles at 7.3728 MHz
; 307200 = 256 * 240 * 5
aabort0:
mov r0, #0
aabort1:
mov r1, #240
aabort2:
jnb ri, aabort3
clr ri
mov a, sbuf
lcall upper
cjne a, #'S', aabort0 ;begin another 1/2 wait if not 'S'
sjmp stcode5 ;don't do startup code if 'S'
aabort3:nop
djnz r1, aabort2
djnz r0, aabort1
stcode: mov dptr, #bmem ;search for startup routines
stcode2:lcall find
jnc stcode5
mov dpl, #4
clr a
movc a, @a+dptr
cjne a, #253, stcode4 ;only startup code if matches B
push dph
mov a, #(stcode3 & 255)
push acc
mov a, #(stcode3 >> 8)
push acc
mov dpl, #64
clr a
jmp @a+dptr ;jump to the startup code
stcode3:pop dph ;hopefully it'll return to here
stcode4:inc dph
mov a, dph
cjne a, #((emem+1) >> 8) & 255, stcode2
stcode5: ;now we've executed all of 'em
warm_boot:
clr a
mov ie, a ;all interrupts off
mov ip, a
acall intr_return
acall intr_return
mov psw, #psw_init
mov sp, #stack
acall set_bank0
mov r0, #250
wb_ti: jb ti, wb_ti2
nop
djnz r0, wb_ti
wb_ti2:
mov a, #baud_const ;initialize the serial port
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
mov r6, #(pgm & 255)
mov r7, #(pgm >> 8)
ljmp menu
;---------------------------------------------------------;
; ;
; 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -