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

📄 queues.s

📁 Frank s MP3 Player Source Files
💻 S
📖 第 1 页 / 共 2 页
字号:
		sbiw	ZL,5							; return Z to point to start of queue
		ldd		XH,Z+4
		ldd		XL,Z+5							; *write in X pointing to end of dataspace + 1
		sbiw	XL,1							; now X points to end of dataspace
		adiw	ZL,5							; add 5 to Z because we're about to subtract 5 again  :-)
		
; execute here once X the write pointer is correct  (note that Z is still 5 too high)
Q_read_F2:
		sbiw	ZL,5							; return Z to point to start of queue	
		std		Z+2,XH
		std		Z+3,XL							; write updated *write into Q header
		ld		param2,X						; read data byte from queue
		ldi		param1,Q_OK
		ret										; return with OK in param1, data in param2
		









;**********************************************************************************
;*
;* Q_write
;* Writes a single byte into the queue
;* 
;* This routine writes a single byte into the queue pointed to by Z. It functions
;* according to the following pseudo-code:
;*
;* (Note the definition of a full queue: if writing into the queue would result
;* in the write pointer catching the read pointer (ie *write+1==*read) then the
;* queue is full. We need to test for a full queue before we attempt the write.)
;*
;* *writeinc = *write +1
;* if (*writeinc == *end) then *writeinc = Z+6  ; wrap to start of data buffer
;* if (*writeinc == *read)
;*		return (Q full)
;* else
;*		write data byte (param1) into *write
;*		write *writeinc back into queue header (*write location)
;*		return (OK)
;*
;* If this code is not obvious, the reason that *writeinc is calculated up
;* front is so that it can be used twice: to test if the Q is full, and then
;* later after the Q write to update the write pointer in the Q header.
;* *writeinc is simply *write+1, with provision for wrapping around the
;* buffer if necessary.
;*
;* Accepts: pointer to queue in Z, data to write in param1
;* Returns: result code in param1
;* Uses:	X, Y, temp, param1, flags. 
;*			Z is unchanged		
;*
;**********************************************************************************

Q_write:
		ldd		XH,Z+2							; X is going to be *writeinc...
		ldd		XL,Z+3							; *writeinc = *write
		adiw	XL,1							; *writeinc = *write+1
		
		ldd		temp,Z+5
		sub		temp,XL							; compare *writeinc & *end low bytes
		brne	Q_write1						; branch if not the same
		ldd		temp,Z+4
		sub		temp,XH							; compare *writeinc & *end high bytes
		brne	Q_write1						; branch if not the same
		
; execute this code if *writeinc is pointing past the end of the data buffer area & so 
; we need to wrap the *writeinc to the start of the data buffer area
		mov		XH,ZH
		mov		XL,ZL							; *writeinc points to head of queue
		adiw	XL,6							; now *writeinc is pointing to the buffer start 
		
; Now that we've calculated *writeinc it's time to see if the queue is full
Q_write1:
		ldd		temp,Z+1
		sub		temp,XL							; compare *writeinc & *read low bytes
		brne	Q_write2						; branch if not the same
		ld		temp,Z
		sub		temp,XH							; compare *writeinc & *read high bytes
		brne	Q_write2						; branch if not the same
		
; execute here if our calculations show that the queue is full

; debug - print error message.
		ldi		param1,'Q'
		call	UART_TxCharWait 
		ldi		param1,'W'
		call	UART_TxCharWait
		ldi		param1,'Q'
		call	UART_TxCharWait 
		ldi		param1,'F'
		call	UART_TxCharWait
; end debug

		ldi		param1,Q_full
		ret										; return with queue full response
		
; execute here if our calculations show the queue has a free space to write into.
; write the data byte, update the write pointer, and return ok.
Q_write2:
		ldd		YH,Z+2
		ldd		YL,Z+3							; *write is in Y
		st		Y,param1						; Store the data byte into the queue buffer
		std		Z+2,XH							; Store the incremented *write (ie *writeinc)
		std		Z+3,XL							;	 in the queue header
		ldi		param1,Q_OK						; return parameter is OK
		ret		
		


		


;**********************************************************************************
;*
;* Q_CheckEmptyC
;*
;* Similar to Q_CheckEmpty below, but registers saved and rearranged to make 
;* it C-callable. Return value is returned via the function call. 
;*		
;**********************************************************************************
Q_CheckEmptyC:
		push	temp
		push	param1
		push	XL
		push	XH
		push	ZL
		push	ZH
		mov		ZL,r24
		mov		ZH,r25							; pointer to Q arrives in r25:r24
		rcall	Q_CheckEmpty
		mov		r24,param1						; result code returned to C code in r24 
		pop		ZH								
		pop		ZL
		pop		XH
		pop		XL
		pop		param1
		pop		temp
		ret

		

;**********************************************************************************
;*
;* Q_CheckEmpty
;* Determines if queue is empty or not
;* 
;* 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. )
;*
;* if (*read == *write)
;*		return (Q empty)
;* else
;*		return (Q not empty)
;*
;*
;* Accepts: pointer to queue in Z
;* Returns: result code in param1
;* Uses:	X, temp, flags. 
;*			Z is unchanged		
;*
;**********************************************************************************

Q_CheckEmpty:
		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_Cempty1								; branch if not the same
		ldd		temp,Z+2
		sub		temp,XH							; compare *read & *write high bytes
		brne	Q_Cempty1								; branch if not the same

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

; execute this code if *read != *write, ie, queue is not empty
Q_Cempty1:
		ldi		temp,Q_notempty
		mov		param1,temp
		ret										; return with "queue not empty" response		




;**********************************************************************************
;*
;* Q_query
;* Returns the number of free bytes in the queue
;* 
;* This routine calculates the number of free bytes in the queue pointed to by Z. 
;* It functions according to the following pseudo-code:
;*
;* if (*read > *write)
;*		space free = *read - *write - 1
;*		return (space free)
;* else	  (*write >= *read)
;*		space free = (*end-of-queue+1) - (*queue-start) - 7 - *write + *read
;*		return (space free)
;*
;*
;* Note the -1 or -7 (-6 -1). There is always one unused byte in the queue buffer.
;* Note also that if the write pointer is greater than the read pointer, the
;* calculation has to take into account wrapping around the end of the buffer,
;* which greatly increases the complexity of the calculation.
;*
;* Accepts: pointer to queue in Z
;* Returns: high byte of result in param1, low byte in param2
;* Uses:	r0, r1, r2, r3, temp, Z
;*			Z is not altered
;*
;**********************************************************************************

Q_query:
		ld		r1,Z					; read pointer high byte
		ldd		r0,Z+1					; read pointer low byte
		ldd		r3,Z+2					; write pointer high byte
		ldd		r2,Z+3					; write pointer low byte
		
		cp		r2,r0
		cpc		r3,r1
		brsh	Q_query1				; branch if *write >= *read

		
; execute here if *read > *write  (ie *write < *read)
; space free = *read - *write - 1
		sub		r0,r2					; *read(lowbyte) - *write(lowbyte)
		sbc		r1,r3					; *read(highbyte) - *write(highbyte)
		ldi		temp,1
		sub		r0,temp					; subract 1 from the lowbyte
		ldi		temp,0					; ldi does not affect the carry flag
		sbc		r1,temp					; subtract carry flag from the highbyte
		mov		param1,r1
		mov		param2,r0				; result in param1:param2
		ret
		


; execute here if *write >= *read
; space free = (*end-of-queue+1) - (*queue-start) - 7 - *write + *read
Q_query1:
		ldd		param1,Z+4				; param1 has *end-of-queue+1 highbyte
		ldd		param2,Z+5				; param2 has *end-of-queue+1 lowbyte
		
		sub		param2,ZL
		sbc		param1,ZH				; (*end-of-queue+1) - (*queue-start)
		
		subi	param2,7
		sbci	param1,0				; (*end-of-queue+1) - (*queue-start) - 7
		
		add		param2,r0
		adc		param1,r1				; (*end-of-queue+1) - (*queue-start) - 7 + *read
		
		sub		param2,r2
		sbc		param1,r3				; (*end-of-queue+1) - (*queue-start) - 7 + *read - *write
		ret



;**********************************************************************************
;*
;* u16 Q_HowMuchDataC (*pointer_to_queue)
;*
;* Same as Q_HowMuchData below, but C-callable. 
;*
;**********************************************************************************

Q_HowMuchDataC:
		push	r0
		push	r1
		push	r2
		push	r3
		push	temp
		push	ZL
		push	ZH
		mov		ZL,r24
		mov		ZH,r25							; pointer to Q arrives in r25:r24
		rcall	Q_HowMuchData
		mov		r25,param1
		mov		r24,param2						; return the result in r25:r24
		pop		ZH
		pop		ZL
		pop		temp
		pop		r3
		pop		r2
		pop		r1
		pop		r0
		ret




;**********************************************************************************
;*
;* Q_HowMuchData
;* 
;* Returns the number of bytes of data in the specified queue.
;*
;* This routine uses Q_query (above) plus a simple calculation to determine how
;* much data is in the queue. The amount of data in the queue is equal to:
;*		Total space in queue - free space in queue
;*
;* Total space in queue is equal to:
;*		(Q end +1) - (Q start) - 7
;* Free space in the queue is found by calling Q_query.
;*
;* Accepts: pointer to Q in Z
;* Returns: high byte of result in param1, low byte in param2
;* Uses:	r0, r1, r2, r3, temp, Z, flags 
;*			
;*
;**********************************************************************************

Q_HowMuchData:
		rcall	Q_query					; free space now in param1:param2
		
		ldd		r1,Z+4					; r1 has *end-of-queue+1 highbyte
		ldd		r0,Z+5					; r0 has *end-of-queue+1 lowbyte
		
		sub		r0,ZL
		sbc		r1,ZH					; (*end-of-queue+1) - (*queue-start)
		
		ldi		temp,7
		sub		r0,temp
		ldi		temp,0
		sbc		r1,temp					; (*end-of-queue+1) - (*queue-start) - 7
				
		sub		r0,param2
		sbc		r1,param1				; then subtract free space from the above

		mov		param2,r0
		mov		param1,r1				; put result in param1:param2
		
		ret




;**********************************************************************************
;*
;* PrintMP3Q
;* Test routine
;* 
;* Prints 16 bytes of hex data (if possible) out of the MP3 data queue
;*
;*
;* Accepts: nothing
;* Returns: nothing
;* Uses:	param1, param2, temp, temp2, r15, X, Z, flags
;*			
;*
;**********************************************************************************

PrintMP3Q:
		ldi		ZL,lo8(MP3DATAQ)
		ldi		ZH,hi8(MP3DATAQ)				; Z points to the MP3 Data Queue
		rcall	PrintQdata
		ret





;**********************************************************************************
;*
;* PrintQdata
;* Test routine
;* 
;* Given a pointer to a queue in Z, this routine prints out 16 hex bytes
;* from that queue (or less if the Q contains less) followed by a CR LF.
;* Printing happens slowly out the UART 0 (debug port)
;*
;*
;* Accepts: pointer to queue in Z
;* Returns: nothing
;* Uses:	param1, param2, temp, temp2, r20, X, flags
;*			Z is unchanged
;*
;**********************************************************************************

PrintQdata:

; try to read data from data queue (pointed to by Z), and return if that Q is empty
		rcall	Q_read
		cpi		param1,Q_empty
		brne	PrintQdata_2					; branch forward if Q not empty
		ret										; return if Q empty
		
PrintQdata_2:
		mov		param1,param2
		rcall	UART_PutHexWait					; print the data byte as hex
		ldi		param1,' '
		rcall	UART_TxCharWait					; print a space
		
		ldi		r20,15							; 15 bytes left to print
		
PrintQdata_3:
		rcall	Q_read
		cpi		param1,Q_empty
		breq	PrintQdata_4					; branch out if Q empty
		mov		param1,param2
		rcall	UART_PutHexWait					; print the data byte as hex
		ldi		param1,' '
		rcall	UART_TxCharWait					; print a space 
		dec		r20
		brne	PrintQdata_3					; loop until all bytes done
		
PrintQdata_4:
		ldi		param1,13
		rcall	UART_TxCharWait					; print a CR
		ldi		param1,10
		rcall	UART_TxCharWait					; print a LF
		ret






;**********************************************************************************
;*
;* u08 EEPROM_ReadC (u16 eeprom_address)
;*
;* C callable routine. Given an eeprom location, this routine reads that location
;* and returns the contents. Uses the eeprom read algorithm from the Mega128
;* datasheet, namely:
;*
;* while (EECR & 0x02);					// wait until any eeprom writes completed
;* EEARx = eeprom_address;				// write 16-bit address to EEARH:EEARL
;* EECR |= 0x01;						// command read to occur
;* return (EEDR);						// return with the read result
;*
;*
;* Accepts: eeprom address to read in r25:24
;* Returns: byte read from eeprom in r24
;* Uses:	flags
;*
;**********************************************************************************

EEPROM_ReadC:
		sbic	0x1c,2
		rjmp	EEPROM_ReadC			; wait until write bit in eeprom ctl register clear

		out		0x1f,r25				; high byte of eeprom address to read
		out		0x1e,r24				; low byte of eeprom address to read

;		method 1 - set bit 0 in control register - works
;		 in		 r24,0x1c				 ; read control register
;		 ori	 r24,0x01				 ; set the read bit
;		 out	 0x1c,r24				 ; and write it back

;		method 2 - set bit 0 in control register - works
		sbi		0x1c,0					; set read bit in the control register

;		method 3 - set bit 0 in control register - does not work, resets device
;		 in		 r24,0x1c				 ; read control register
;		 ori	 r24,0x01				 ; set the read bit
;		 sts	 0x1c+0x20,r24			 ; and write it back

		in		r24,0x1d				; read result of eeprom read into r24
		ret								; and we're done		



⌨️ 快捷键说明

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