; queue.asm ; Author: Mark Mraz ; ; The routines in this module are used to add and remove entries from ; a queue. ; These routines are designed to be small and fast, especially the enq ; operation. No checking is performed on enq, and the only check ; on deq is if the queue is already empty, in which case it returns 0. ; There is no way to tell whether deq is returning 0 because of an empty ; queue or if the queue value was 0. However, since there is a call ; to get the number of entries in the queue, the caller can avoid ; that problem by checking the count before calling deq. ; ; To save time and code space, the queue is not circular. Instead, ; when deq is called, and this causes it to remove the last item ; from the queue, the head and tail pointers get set back to the ; initial values. This means that the queue must be emptied periodically. ; If it is not, it will overflow its allocated memory and write to ; memory it should not write to (remember, enq has no bounds checking). ; The typical use is to let an ISR add to the queue while the program is ; busy doing something else, then periodically process the data in the ; queue non-stop until it is empty. Specifically, these routines were ; designed to receive UART data asynchronously and allow for processing ; of the received data in chunks rather than a byte at a time. ; ; It is assumed that the caller has disabled interrupts while inside ; enq and deq, or at least, if an ISR *does* fire, it is guaranteed to ; not call enq or deq. ; Define SAVE_FSR if the value of FSR needs to be saved before ; it is modified by these routines. These routines set FSR ; to the value needed, so it doesn't matter to this code if ; other code modifies FSR. #define NSAVE_FSR INCLUDE "include.inc" ; This is the starting memory location for the queue. Queue entries ; are added starting here and increases as more entries are added. ; We'll allocate 40 bytes for the queue. This takes us to the ; end of the available memory in bank 1 on a 16F628. ; These numbers may need to be tweaked for other processors. ; QUEUE_DATA_START EQU 200 QUEUE_SIZE EQU 40 UDATA head RES 1 ; The head of the queue (data removed here) tail RES 1 ; The tail of the queue (data added here) count RES 1 ; Number of entries in the queue INNERMOST_DATA UDATA_OVR value RES 1 ; The value enqueued or dequeued ifdef SAVE_FSR fsr_save RES 1 ; Location to save FSR endif QUEUE_DATA UDATA QUEUE_DATA_START queue_data RES QUEUE_SIZE ; The queue itself QUEUE_CODE CODE ; ; Initialize the queue variables. Must be called before any other ; routine in this module is called. ; No parameters ; No return value ; init_queue global init_queue clrf count movlw QUEUE_DATA_START movwf head movwf tail return ; ; Add an entry (the value of W, to be specific) to the tail of the queue. ; Parameters: The value to be added is passed in in W. ; No return value ; enq global enq movwf value ifdef SAVE_FSR movf FSR, w movwf fsr_save endif movf tail, w movwf FSR movf value, w movwf INDF incf tail, f incf count, f ifdef SAVE_FSR movf fsr_save, w movwf FSR endif return ; ; Removes the value at the head of the queue and returns it in W. ; If doing this makes the queue empty, the head and tail of the ; queue get reset to their starting values. ; If the queue is empty before deq is called, 0 is returned in W. ; No parameters. ; The dequeued value is returned in W. ; deq global deq ifdef SAVE_FSR movf FSR, w movwf fsr_save endif clrf value ; Clear the value in case the queue is empty movf count, w ; Check to see if the queue is empty btfsc STATUS, Z goto end_of_deq ; It is, so we'll return value, which is zero movf head, w ; Set FSR to the head of the queue movwf FSR movf INDF, w ; Get the value from the queue and movwf value ; store it in value for now incf head, f ; Move the head to the next position decfsz count, f ; Decrement the queue count. If not zero goto end_of_deq ; we're done. movlw QUEUE_DATA_START ; The count is zero, so reset the queue. movwf head movwf tail end_of_deq ifdef SAVE_FSR movf fsr_save, w movwf FSR endif movf value, w ; Load the return value return ; ; Returns the queue count in W ; get_queue_count global get_queue_count movf count, w return end