⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pm2_mp3.asm

📁 A MP3 Player Source Code, Enjoy it!
💻 ASM
📖 第 1 页 / 共 5 页
字号:
; PAULMON2, a user-friendly 8051 monitor, by Paul Stoffregen
; Please email comments, suggestions, bugs to paul@pjrc.com

; Modified version for the MP3 Player project.

; PAULMON2 is in the public domain. PAULMON2 is distributed in
; the hope that it will be useful, but without any warranty;
; without even the implied warranty of merchantability or fitness
; for a particular purpose. 

.equ	base, 0x0000		;location for PAULMON2
.equ	vector, 0x2000		;location to LJMP interrupt vectors

; These three parameters tell PAULMON2 where the user's memory is
; installed.  "bmem" and "emem" define the space that will be searched
; for program headers, user installed commands, start-up programs, etc.
; "bmem" and "emem" should be use so they exclude memory areas where
; perphreal devices may be mapped, as reading memory from an io chip
; may reconfigure it unexpectedly.  If flash rom is used, "bmem" and "emem"
; should also include the space where the flash rom is mapped.

.equ	pgm, 0x2000		;default location for the user program
.equ	bmem, 0x1000		;where is the beginning of memory
.equ	emem, 0xFFFF		;end of the memory

; To set the baud rate, use this formula
; baud_const = 256 - (crystal / (12 * 16 * baud))

.equ	baud_const, 254		;19200 baud w/ 7.3728 MHz

.equ	line_delay, 6		;num of char times to pause during uploads


.equ	selected_bank_bit, 0x00	;stored at memory location 0x20
.equ	selected_bank_byte, 0x20 ;byte where selected_bank_bit is stored


.equ    scl_pin, 0x90
.equ    sda_pin, 0x91
.equ    reset_pin, 0x92
.equ    hc165_load_pin, 0x93
.equ    unused_pin, 0x94
.equ    xilinx_cclk_pin, 0x95
.equ    hc165_clk_pin, 0x95
.equ    hc165_data_pin, 0x96
.equ    xilinx_din_pin, 0x97
.equ    flash_a16_pin, 0xB4
.equ    shutdown_pin, 0xB5



; Flash ROM parameters.	 If "has_flash" is set to zero, all flash rom
; features are turned off, otherwise "bflash" and "eflash" should specify
; the memory range which is flash rom.	Though AMD doesn't suggest it,
; you may be able to map only a part of the flash rom with your address
; decoder logic (and not use the rest), but you should be careful that
; "bflash" and "eflash" don't include and memory which is NOT flash rom
; so that the erase algorithm won't keep applying erase pulses until it
; finally gives up (which will stress the thin oxide and degrade the
; flash rom's life and reliability).  "erase_pin" allows you to specify
; the bit address for a pin which (if held low) will tell PAULMON2 to
; erase the flash rom chip when it starts up.  This is useful if you
; download programs with the "start-up" headers on them and the code you've
; put in the flash rom crashes!

.equ	has_flash, 1		;set to non-zero value if flash installed
.equ	bflash, 0x2000		;first memory location of Flash ROM
.equ	eflash, 0xFFFF		;last memory location of Flash ROM
.equ	erase_pin, 0		;00 = disable erase pin feature
.equ	dram_disable, 0xFFC0	;write to here disables writes to DRAM
.equ	dram_enable, 0xFFC1	;write to here enables writes to DRAM

; mp3 player address bus wiring:
;Flash: A15 A14 A13 A12 A11 A10  A9  A8  A7  A6  A5  A4  A3  A2  A1  A0
;8051:  A14 A13 A15 A12 A11  A9  A8 A10  A4  A2  A6  A5  A7  A0  A1  A3
;
;0x5555  0   1   0   1   0   1   0   1   0   1   0   1   0   1   0   1
;0x362D  0   0   1   1   0   1   1   0   0   0   1   0   1   1   0   1 
;
;0x2AAA  0   0   1   0   1   0   1   0   1   0   1   0   1   0   1   0
;0x89D2  1   0   0   0   1   0   0   1   1   1   0   1   0   0   1   0   

; mp3 player data bus wiring:

;Flash:  D7  D6  D5  D4  D3  D2  D1  D0
;8051:   D6  D4  D5  D2  D7  D0  D1  D3

;0xAA     1   0   1   0   1   0   1   0
;0xE2     1   1   1   0   0   0   1   0

;0x55     0   1   0   1   0   1   0   1
;0x1D     0   0   0   1   1   1   0   1

;0xA0     1   0   1   0   0   0   0   0
;0x60     0   1   1   0   0   0   0   0

;0x80     1   0   0   0   0   0   0   0
;0x40     0   1   0   0   0   0   0   0

;0x10     0   0   0   1   0   0   0   0
;0x04     0   0   0   0   0   1   0   0




;sets the base address to add to the flash memory register addresses.
.equ    flash_base, 0

;.equ   flash_en1_addr, 0x5555 + flash_base
.equ    flash_en1_addr, 0x362D + flash_base
;.equ   flash_en1_data, 0xAA
.equ    flash_en1_data, 0xE2

;.equ   flash_en2_addr, 0x2AAA + flash_base
.equ    flash_en2_addr, 0x89D2 + flash_base
;.equ   flash_en2_data, 0x55
.equ    flash_en2_data, 0x1D

;.equ   flash_wr_addr, 0x5555 + flash_base
.equ    flash_wr_addr, 0x362D + flash_base
;.equ   flash_wr_data, 0xA0
.equ    flash_wr_data, 0x60

;.equ   flash_er1_addr, 0x5555 + flash_base
.equ    flash_er1_addr, 0x362D + flash_base
;.equ   flash_er1_data, 0x80
.equ    flash_er1_data, 0x40

;.equ   flash_er2_addr, 0x5555 + flash_base
.equ    flash_er2_addr, 0x362D + flash_base
;.equ   flash_er2_data, 0x10
.equ    flash_er2_data, 0x04


; Please note... much of the memory management code only looks at the
; upper 8 bits of an address, so it's not a good idea to somehow map
; your memory chips (with complex address decoding logic) into chunks
; less than 256 bytes.	In other words, only using a piece of a flash
; rom chip and mapping it between C43A to F91B would confuse PAULMON2
; (as well as require quit a bit of address decoding logic circuitry)

; Several people didn't like the key definations in PAULMON1.
; Actually, I didn't like 'em either, but I never took the time
; to change it.	 Eventually I got used to them, but now it's
; really easy to change which keys do what in PAULMON2.	 You
; can guess what to do below, but don't use lowercase.

.equ	help_key, '?'		;help screen
.equ	dir_key,  'M'		;directory
.equ	run_key,  'R'		;run program
.equ	dnld_key, 'D'		;download
.equ	upld_key, 'U'		;upload
.equ	nloc_key, 'N'		;new memory location
.equ	jump_key, 'J'		;jump to memory location
.equ	dump_key, 'H'		;hex dump memory
.equ	intm_key, 'I'		;hex dump internal memory
.equ	edit_key, 'E'		;edit memory
.equ	clrm_key, 'C'		;clear memory
.equ	erfr_key, 'Z'		;erase flash rom

; timing parameters for AMD Flash ROM 28F256.  These parameters
; and pretty conservative and they seem to work with crystals
; between 6 MHz to 24 MHz... (tested with AMD 28F256 chips only)
; unless you know this is a problem, it is probably not a good
; idea to fiddle with these.

;.equ	pgmwait, 10		;22.1184 MHz crystal assumed
.equ	pgmwait, 19		;11.0592 MHz
.equ	verwait, 5
;.equ	erwait1, 40		;fourty delays @22.1184
.equ	erwait1, 20		;twenty delays for 11.0592 MHz
.equ	erwait2, 229		;each delay .5 ms @22.1184MHz



; These symbols configure paulmon2's internal memory usage.
; It is usually not a good idea to change these unless you
; know that you really have to.

.equ	psw_init, 0		;value for psw (which reg bank to use)
.equ	dnld_parm, 0x10		;block of 16 bytes for download
.equ	stack, 0x80		;location of the stack

;---------------------------------------------------------;
;							  ;
;		     Interrupt Vectors			  ;
;  (and little bits of code crammed in the empty spaces)  ;
;							  ;
;---------------------------------------------------------;

	.org	base
	ljmp	poweron		;reset vector

	.org	base+3
	ljmp	vector+3	;ext int0 vector

r6r7todptr:
	mov	dpl, r6
	mov	dph, r7
	ret

	.org	base+11
	ljmp	vector+11	;timer0 vector

dptrtor6r7:
	mov	r6, dpl
	mov	r7, dph
	ret

	.org	base+19
	ljmp	vector+19	;ext int1 vector

dash:	mov	a, #'-'		;seems kinda trivial, but each time
	ajmp	cout		;this appears in code, it takes 4
	nop			;bytes, but an acall takes only 2

	.org	base+27
	ljmp	vector+27	;timer1 vector

cout_sp:acall	cout
	ajmp	space
	nop

	.org	base+35
	ljmp	vector+35	;uart vector

dash_sp:acall	dash
	ajmp	space
	nop

	.org	base+43
	ljmp	vector+43	;timer2 vector (8052)


;---------------------------------------------------------;
;							  ;
;	The jump table for user programs to call	  ;
;	      subroutines within PAULMON		  ;
;							  ;
;---------------------------------------------------------;

.org	base+46		;never change this line!!  Other
			;programs depend on these locations
			;to access paulmon2 functions

	ajmp	phex1		;2E
	ajmp	cout		;30
	ajmp	cin		;32
	ajmp	phex		;34
	ajmp	phex16		;36
	ajmp	pstr		;38
	ajmp	ghex		;3A
	ajmp	ghex16		;3C
	ajmp	esc		;4E
	ajmp	upper		;40
	nop
	nop
	nop
pcstr_h:ljmp	pcstr		;45
	ajmp	newline		;48
	ljmp	lenstr		;4A
	ljmp	pint8u		;4D
	ljmp	pint8		;50
	ljmp	pint16u		;53
	ljmp	smart_wr	;56
	ljmp	prgm		;59
	ljmp	erall		;5C
	ljmp	find		;5F
cin_filter_h:
	ljmp	cin_filter	;62
	ajmp	asc2hex		;65
	ljmp	erblock		;67
	ljmp	rst_devices	;6A
	ljmp	warm_boot	;6D

;---------------------------------------------------------;
;							  ;
;	       Subroutines for serial I/O		  ;
;							  ;
;---------------------------------------------------------;


cin:	jnb	ri, cin
	clr	ri
	mov	a, sbuf
	ret

dspace: acall	space
space:	mov	a, #' '
cout:	jnb	ti, cout
	clr	ti		;clr ti before the mov to sbuf!
	mov	sbuf, a
	ret

;clearing ti before reading sbuf takes care of the case where
;interrupts may be enabled... if an interrupt were to happen
;between those two instructions, the serial port will just
;wait a while, but in the other order and the character could
;finish transmitting (during the interrupt routine) and then
;ti would be cleared and never set again by the hardware, causing
;the next call to cout to hang forever!

newline2:			;print two newlines
	acall	newline
newline:push	acc		;print one newline
	mov	a, #13
	acall	cout
	mov	a, #10
	acall	cout
	pop	acc
	ret

	;get 2 digit hex number from serial port
	; c = set if ESC pressed, clear otherwise
	; psw.5 = set if return w/ no input, clear otherwise
ghex:
ghex8:	clr	psw.5
ghex8c:
	acall	cin_filter_h	;get first digit
	acall	upper
	cjne	a, #27, ghex8f
ghex8d: setb	c
	clr	a
	ret
ghex8f: cjne	a, #13, ghex8h
	setb	psw.5
	clr	c
	clr	a
	ret
ghex8h: mov	r2, a
	acall	asc2hex
	jc	ghex8c
	xch	a, r2		;r2 will hold hex value of 1st digit
	acall	cout
ghex8j:
	acall	cin_filter_h	;get second digit
	acall	upper
	cjne	a, #27, ghex8k
	sjmp	ghex8d
ghex8k: cjne	a, #13, ghex8m
	mov	a, r2
	clr	c
	ret
ghex8m: cjne	a, #8, ghex8p
ghex8n: acall	cout
	sjmp	ghex8c
ghex8p: cjne	a, #21, ghex8q
	sjmp	ghex8n
ghex8q: mov	r3, a
	acall	asc2hex
	jc	ghex8j
	xch	a, r3
	acall	cout
	mov	a, r2
	swap	a
	orl	a, r3
	clr	c
	ret




	;carry set if esc pressed
	;psw.5 set if return pressed w/ no input
ghex16:
	mov	r2, #0		;start out with 0
	mov	r3, #0
	mov	r4, #4		;number of digits left
	clr	psw.5

ghex16c:
	acall	cin_filter_h
	acall	upper
	cjne	a, #27, ghex16d
	setb	c		;handle esc key
	clr	a
	mov	dph, a
	mov	dpl, a
	ret
ghex16d:cjne	a, #8, ghex16f
	sjmp	ghex16k
ghex16f:cjne	a, #127, ghex16g  ;handle backspace
ghex16k:cjne	r4, #4, ghex16e	  ;have they entered anything yet?
	sjmp	ghex16c
ghex16e:acall	cout
	acall	ghex16y
	inc	r4
	sjmp	ghex16c
ghex16g:cjne	a, #13, ghex16i	  ;return key
	mov	dph, r3
	mov	dpl, r2
	cjne	r4, #4, ghex16h
	clr	a
	mov	dph, a
	mov	dpl, a
	setb	psw.5
ghex16h:clr	c
	ret
ghex16i:mov	r5, a		  ;keep copy of original keystroke
	acall	asc2hex
	jc	ghex16c
	xch	a, r5
	lcall	cout
	mov	a, r5
	push	acc
	acall	ghex16x
	pop	acc
	add	a, r2
	mov	r2, a
	clr	a
	addc	a, r3
	mov	r3, a
	djnz	r4, ghex16c
	clr	c
	mov	dpl, r2
	mov	dph, r3
	ret

ghex16x:  ;multiply r3-r2 by 16 (shift left by 4)
	mov	a, r3
	swap	a
	anl	a, #11110000b
	mov	r3, a
	mov	a, r2
	swap	a
	anl	a, #00001111b
	orl	a, r3
	mov	r3, a
	mov	a, r2
	swap	a
	anl	a, #11110000b
	mov	r2, a
	ret

ghex16y:  ;divide r3-r2 by 16 (shift right by 4)
	mov	a, r2
	swap	a
	anl	a, #00001111b
	mov	r2, a
	mov	a, r3
	swap	a
	anl	a, #11110000b
	orl	a, r2
	mov	r2, a
	mov	a, r3
	swap	a
	anl	a, #00001111b
	mov	r3, a
	ret


	;carry set if invalid input
asc2hex:
	add	a, #208
	jnc	hex_not
	add	a, #246
	jc	hex_maybe
	add	a, #10
	clr	c
	ret
hex_maybe:
	add	a, #249
	jnc	hex_not
	add	a, #250
	jc	hex_not
	add	a, #16
	clr	c
	ret
hex_not:setb	c
	ret


; Highly code efficient resursive call phex contributed
; by Alexander B. Alexandrov <abalex@cbr.spb.ru>

phex:
phex8:
	acall	phex_b
phex_b:	swap	a		;SWAP A will be twice => A unchanged
phex1:	push	acc
	anl	a, #15
	add	a, #0x90	; acc is 0x9X, where X is hex digit
	da	a		; if A to F, C=1 and lower four bits are 0..5
	addc	a, #0x40
	da	a
	acall	cout
	pop	acc
	ret

; the old code... easier to understand
;	push	acc
;	swap	a
;	anl	a, #15
;	add	a, #246
;	jnc	phex_b
;	add	a, #7
;phex_b:add	a, #58
;	acall	cout
;	pop	acc
;phex1:	push	acc
;	anl	a, #15
;	add	a, #246
;	jnc	phex_c
;	add	a, #7
;phex_c:add	a, #58
;	acall	cout
;	pop	acc
;	ret


phex16:
	push	acc
	mov	a, dph
	acall	phex
	mov	a, dpl
	acall	phex
	pop	acc
	ret


;a not so well documented feature of pstr is that you can print
;multiple consecutive strings without needing to reload dptr
;(which takes 3 bytes of code!)... this is useful for inserting
;numbers or spaces between strings.

pstr:	push	acc
pstr1:	clr	a
	movc	a, @a+dptr
	inc	dptr
	jz	pstr2
	mov	c, acc.7
	anl	a, #0x7F
	acall	cout
	jc	pstr2
	sjmp	pstr1
pstr2:	pop	acc
	ret

;converts the ascii code in Acc to uppercase, if it is lowercase

; Code efficient (saves 6 byes) upper contributed
; by Alexander B. Alexandrov <abalex@cbr.spb.ru>

upper:
	cjne	a, #97, upper2
upper2:	jc	upper4		;end if acc < 97
	cjne	a, #123, upper3
upper3:	jnc	upper4		;end if acc >= 123
	add	a, #224		;convert to uppercase
upper4:	ret



lenstr: mov	r0, #0	  ;returns length of a string in r0
	push	acc
lenstr1:clr	a
	movc	a,@a+dptr
	jz	lenstr2
	mov	c,acc.7
	inc	r0
	Jc	lenstr2
	inc	dptr
	sjmp	lenstr1
lenstr2:pop	acc
	ret


esc:  ;checks to see if <ESC> is waiting on serial port
      ;C=clear if no <ESC>, C=set if <ESC> pressed
      ;buffer is flushed
	push	acc
	clr	c
	jnb	ri,esc2
	mov	a,sbuf
	cjne	a,#27,esc1

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -