📄 queues.s
字号:
;***************************************************************************
;*
;* 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 + -