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

📄 queues.s

📁 Frank s MP3 Player Source Files
💻 S
📖 第 1 页 / 共 2 页
字号:
;***************************************************************************
;*
;* Title:				Queueing Routines
;* Version:				1.0
;* Last updated:		6 Oct 2003
;*
;*
;* DESCRIPTION:
;* This file contains routines for handling queues. Queues are also known
;* as FIFOs or circular buffers or ring buffers.
;*
;* Data space for ALL the various queues used by the system are defined in
;* this file, and the Q_init_all function initializes all of them.
;*
;* The functions used to read data from, and write data to, the queues
;* are in this file.
;*
;* The structure of a queue is: (with byte offsets)
;*
;*		0		read pointer high byte
;*		1		read pointer low byte
;*		2		write pointer high byte
;*		3		write pointer low byte
;*		4		end-of-queue+1 pointer high byte
;*		5		end-of-queue+1 pointer low byte
;*		6		first data byte location	
;*		7		second data byte location
;*						...
;*				last data byte location
;*
;* The read pointer points to the address of the next location to be read from.
;* The write pointer points to the next location to be written into.
;* The end pointer points to the next byte after the end of the queue, ie, 
;* if you reach that address it's time to loop back to the beginning of the 
;* data area.
;*
;* At initialization both the read & write pointers point to the first data
;* byte location. An empty queue is when the read & write pointers are
;* the same. A full queue is when the write pointer is one byte behind
;* the read pointer, ie, if writing one more byte would make the pointers
;* identical. Note this means that one byte in the buffer is always empty
;* (to prevent the write pointer from catching the read pointer). So if you
;* want a queue to contain 100 data bytes for example, you need to allocate 107 
;* bytes in memory for it: 100 for data, 6 for header, and the 1 extra.
;*
;* A queue can be of any length; it is not limited to powers of 2. This
;* makes it an efficient use of limited memory.
;*
;***************************************************************************



/* include the definition files we need */
#include		"frankmp3.h"			
#include		"frankasm.h"


#define ACD		7
#define ACSR	0x08					/* bit & register address for AVR analog comparator */



/* Make the routines in this file available to other files */
		.global Q_init_all
		.global Q_clear
		.global Q_read
		.global Q_write
		.global Q_CheckEmpty
		.global Q_CheckEmptyC
		.global Q_query
		.global Q_HowMuchData
		.global Q_HowMuchDataC
		.global PrintMP3Q
		.global PrintQdata
		.global General_init
		.global Q_read_C
		.global Q_clear_C
		.global Q_Read_FILO_C
		.global EEPROM_ReadC
		
		
/* Make some variables allocated in this file visible to other files */
		.global MP3DATAQ
		.global ReadQstatus


		.comm	ReadQstatus,	1				; status of Q_read_C is placed in this location 
		
; define SRAM space for the queues themselves

/* size for this queue defined in frankmp3.h */
		.comm	MP3DATAQ,		MP3DATAQ_size	; data space for the MP3 data queue

; This queue is no longer used. In frankasm.h it's defined that FindFile now uses the MP3data queue
; #define			FINDFILEQ_size  50		
;		.comm	FINDFILEQ,		FINDFILEQ_size  ; data space for the FindFile queue
		
		
		.text
				



;**********************************************************************************
;*
;* General_init
;* 
;* Just does some general initializations. Not really part of the queues per-se,
;* this is just a convenient place to keep this routine.
;*
;*
;* Accepts: Nothing
;* Returns: Nothing
;* Uses:	flags. 
;*
;**********************************************************************************
General_init:
		sbi		ACSR,ACD				; turn off the analog comparator; it's not reqd.
		
		ret





;**********************************************************************************
;*
;* Q_init_all
;* Initializes all the queues in the system, defined above.
;* 
;* For each of the queues, write the write pointer,
;* read pointer & end+1 pointer values into the queue header.
;*
;* Note that this routine MUST be called BEFORE any queue operations can take place
;* (including Q_clear), as this is the ONLY routine that initializes the queue's
;* read, write & end pointers.
;*
;* Accepts: Nothing
;* Returns: Nothing
;* Uses:	flags. 
;*
;**********************************************************************************

Q_init_all:
		push	ZH
		push	ZL
		push	temp

; Init the MP3 Data Q
		ldi		ZL,lo8(MP3DATAQ)
		ldi		ZH,hi8(MP3DATAQ)				; point Z to the Q head
		ldi		temp,hi8(MP3DATAQ+6)
		st		Z+,temp							; write high byte of read pointer
		ldi		temp,lo8(MP3DATAQ+6)
		st		Z+,temp							; write low byte of read pointer
		ldi		temp,hi8(MP3DATAQ+6)
		st		Z+,temp							; write high byte of write pointer
		ldi		temp,lo8(MP3DATAQ+6)
		st		Z+,temp							; write low byte of write pointer
		ldi		temp,hi8(MP3DATAQ+MP3DATAQ_size)
		st		Z+,temp							; write high byte of end+1 pointer
		ldi		temp,lo8(MP3DATAQ+MP3DATAQ_size)
		st		Z,temp							; write low byte of end+1 pointer

; Init the FindFile Q
		ldi		ZL,lo8(FINDFILEQ)
		ldi		ZH,hi8(FINDFILEQ)				; point Z to the Q head
		ldi		temp,hi8(FINDFILEQ+6)
		st		Z+,temp							; write high byte of read pointer
		ldi		temp,lo8(FINDFILEQ+6)
		st		Z+,temp							; write low byte of read pointer
		ldi		temp,hi8(FINDFILEQ+6)
		st		Z+,temp							; write high byte of write pointer
		ldi		temp,lo8(FINDFILEQ+6)
		st		Z+,temp							; write low byte of write pointer
		ldi		temp,hi8(FINDFILEQ+FINDFILEQ_size)
		st		Z+,temp							; write high byte of end+1 pointer
		ldi		temp,lo8(FINDFILEQ+FINDFILEQ_size)
		st		Z,temp							; write low byte of end+1 pointer
		
		; clr	r1								; zero r1 (for the C compiler)
		pop		temp
		pop		ZL
		pop		ZH
		ret





;**********************************************************************************
;*
;* Q_clear_C
;* Clears the specified queue, C callable version
;* 
;*
;* Accepts: Pointer to the queue in r25:24
;* Returns: Nothing
;* Uses:	flags
;*
;**********************************************************************************

Q_clear_C:
		push	temp
		push	ZL
		push	ZH
		mov		ZL,r24
		mov		ZH,r25							; pointer to Q arrives in r25:r24
		rcall	Q_clear
		pop		ZH		
		pop		ZL
		pop		temp
		ret
		





;**********************************************************************************
;*
;* Q_clear
;* Clears the specified queue, ie, makes it empty
;* 
;* An empty queue is defined as one where the read & write pointers are the
;* same. So this routine copies the read pointer into the write pointer, so
;* that they are identical.
;*
;* Accepts: Pointer to the queue in Z
;* Returns: Nothing
;* Uses:	Z, temp, flags. 
;*			Z is left unchanged
;*
;**********************************************************************************

Q_clear:
		ld		temp,Z							; read the *read high byte
		std		Z+2,temp						; store in *write high byte
		ldd		temp,Z+1						; read the *read low byte
		std		Z+3,temp						; store in *write low byte
		ret

		




;**********************************************************************************
;*
;* Q_read_C
;*
;* Similar to Q_read below, but registers saved and rearranged to make it C-callable.
;* Data byte read from Q is returned via the function call. Return code (pass or fail) 
;* is returned in ReadQstatus SRAM location.
;*		
;**********************************************************************************
Q_read_C:
		push	temp
		push	param1
		push	param2
		push	XL
		push	XH
		push	ZL
		push	ZH
		mov		ZL,r24
		mov		ZH,r25							; pointer to Q arrives in r25:r24
		rcall	Q_read
		mov		r24,param2						; data byte read returned to C code in r24		
		sts		ReadQstatus,param1				; place Q_read status in SRAM for later access
		pop		ZH								
		pop		ZL
		pop		XH
		pop		XL
		pop		param2
		pop		param1
		pop		temp
		ret
		



;**********************************************************************************
;*
;* Q_read
;* Reads a single byte from the queue
;* 
;* This routine reads a single byte from the queue pointed to by Z. It functions
;* according to the following pseudo-code:
;*
;* (Note the definition of an empty queue: *read==*write. We need to check
;* for this before we attempt to read from the queue.)
;*
;* if (*read == *write)
;*		return (Q empty)
;* else
;*		data byte = *read
;*		*read = *read+1
;*		if (*read == *end) then *read=Z+6		; wrap *read to start of data buffer
;*		write *read back into queue header
;*		return (OK, data byte)
;*
;*
;* Accepts: pointer to queue in Z
;* Returns: result code in param1, data byte read from queue in param2
;* Uses:	X, temp, param1, param2, flags. 
;*			Z is unchanged		
;*
;**********************************************************************************

Q_read:
		ld		XH,Z
		ldd		XL,Z+1							; read pointer in X

		ldd		temp,Z+3
		sub		temp,XL							; compare *read & *write low bytes
		brne	Q_read1							; branch if not the same
		ldd		temp,Z+2
		sub		temp,XH							; compare *read & *write high bytes
		brne	Q_read1							; branch if not the same

; execute this code if *read==*write, ie, queue is empty

; debug - print message on debug screen.
;		ldi		param1,' '
;		call	UART_TxCharWait			
;		ldi		param1,'Q'
;		call	UART_TxCharWait 
;		ldi		param1,'R'
;		call	UART_TxCharWait
;		ldi		param1,'Q'
;		call	UART_TxCharWait 
;		ldi		param1,'E'
;		call	UART_TxCharWait
;		ldi		param1,':'
;		call	UART_TxCharWait			
;		ldi		param1,'$'
;		call	UART_TxCharWait 
;		pop		XH
;		pop		XL
;		mov		param1,XH
;		call	UART_PutHexWait
;		mov		param1,XL
;		call	UART_PutHexWait					; print address of calling function
;		push	XL
;		push	XH
;		ldi		param1,' '
;		call	UART_TxCharWait			
; end debug

		ldi		param1,Q_empty
		ret										; return with "queue empty" response


; execute this code if *read != *write. Remember that *read is in X
Q_read1:
		ld		param2,X						; read data byte from queue

		adiw	XL,1							; increment read pointer
		
		ldd		temp,Z+5
		sub		temp,XL							; compare *read & *end low bytes
		brne	Q_read2							; branch if not the same
		ldd		temp,Z+4
		sub		temp,XH							; compare *read & *end high bytes
		brne	Q_read2							; branch if not the same
; execute this code if we've read to the end of the data buffer area & so we need
; to wrap the read pointer to the start of the data buffer area
		mov		XH,ZH
		mov		XL,ZL							; X points to head of queue
		adiw	XL,6							; now X is pointing to the buffer start 

Q_read2:
		st		Z,XH
		std		Z+1,XL							; write updated *read into Q header
		ldi		param1,Q_OK
		ret										; return with OK in param1, data in param2
		
		




;**********************************************************************************
;*
;* Q_Read_FILO_C
;*
;* Similar to Q_Read_FILO below, but registers saved and rearranged to make it C-callable.
;* Data byte read from Q is returned via the function call. Return code (pass or fail) 
;* is returned in ReadQstatus SRAM location.
;*		
;**********************************************************************************
Q_Read_FILO_C:
		push	param1
		push	param2
		push	XL
		push	XH
		push	ZL
		push	ZH
		mov		ZL,r24
		mov		ZH,r25							; pointer to Q arrives in r25:r24
		rcall	Q_Read_FILO
		mov		r24,param2						; data byte read returned to C code in r24		
		sts		ReadQstatus,param1				; place Q_read status in SRAM for later access
		pop		ZH								
		pop		ZL
		pop		XH
		pop		XL
		pop		param2
		pop		param1
		ret
		





;**********************************************************************************
;*
;* Q_Read_FILO
;*
;* This routine does a "reverse read" out of the specified queue. The other queueing routines 
;* are FIFO routines - first in first out. This queue read routine is a FILO - first in last out.
;* This routine reads the MOST RECENT byte out of the queue, in effect reversing the most recent
;* queue write operation. Put another way, this routine reads data out the queue backwards; in the
;* reverse order to which the data was entered into the queue.
;*
;* This routine functions as follows:
;*
;*		if queue empty then return saying queue empty
;*		get queue write pointer & decrement it
;*		if pointer before start of queue space then wrap it to end of queue space
;*		store new pointer value in write pointer location
;*		read data value pointed to by new write pointer
;*		return with data value & read successful
;*
;* This is a little wierd compared to the normal queue routines; we're reading from the
;* queue but changing the write pointer, ignoring the read pointer. It's easier to think
;* of this routine as "reversing the last write".
;*
;* Accepts: pointer to queue in Z
;* Returns: result code in param1, data byte read from queue in param2
;* Uses:	X, param1, param2, flags. 
;*			Z is unchanged
;*
;**********************************************************************************
 
Q_Read_FILO:

		ldd		XH,Z+2
		ldd		XL,Z+3							; write pointer in X

		ldd		param1,Z+1
		cp		param1,XL						; compare *read & *write low bytes
		brne	Q_read_F1						; branch if not the same
		ld		param1,Z
		cp		param1,XH						; compare *read & *write high bytes
		brne	Q_read_F1						; branch if not the same

; execute this code if *read==*write, ie, queue is empty
		ldi		param1,Q_empty
		ret										; return with "queue empty" response


; execute this code if *read != *write, ie queue not empty. Remember that *write is in X
; now decrement the write pointer and then determine if it's dec'd to before the queue data space
Q_read_F1:
		sbiw	XL,1							; decrement write pointer
		adiw	ZL,5							; make Z point to the byte before the queue data space
		
		cp		XL,ZL
		brne	Q_read_F2						; branch forward if *write not before q data space
		cp		XH,ZH					
		brne	Q_read_F2						; ditto
		
; execute this code if the write pointer has decremented out of the data space - reset to end of data space

⌨️ 快捷键说明

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