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