300 likes | 584 Views
Stacks & Queues. Computer Organization and Assembly Language: Module 7. Stacks. Last-In-First-Out (LIFO) Stacks are often used in programming when data will need to be used in the reverse order A stack has two operations: push (places a new item at the top of the stack)
E N D
Stacks & Queues Computer Organization and Assembly Language: Module 7
Stacks • Last-In-First-Out (LIFO) • Stacks are often used in programming when data will need to be used in the reverse order • A stack has two operations: • push (places a new item at the top of the stack) • pop (retrieves the top item from the stack)
Stack Implementation • A stack can be implemented in several ways • array • linked list • In the array implementation, a stack pointer is a container that holds the address of the next item to be placed onto the stack (the address of the space “above” the stack) stack pointer
Declaring a Stack stack: .space 64 stackp: .word stack or stack: .space 64 stackp: .space 4 . . . la $t0, stack sw $t0, stackp stackp uses the address bound to the label stack as the initial value (static initialization) dynamic initialization
Some variations to the implementation • In our sample implementation, the stack pointer points to the next available space • In some implementations, a stack pointer points to the top of the stack • A stack can be grown upward or downward, i.e., we can either add a value to the stack pointer or subtract a value from it when pushing an element
Pushing an element onto the top of the stack Here, push is implemented with a memory resident stack pointer. lw $t0, stackp lw $t1, x #x labels a word sw $t1, 0($t0) add $t0,$t0,4 #this stack grows up sw $t0, stackp
sp sp Pushing an element onto the top of the stack initially 20 Push 20
sp sp Pushing an element onto the top of the stack 20 5 Push 5 Push 10 20 5 10
Taking an item off the top of the stack This operation is called pop. lw $t0, stackp lw $t1, -4($t0) add $t0,$t0,-4 sw $t1, x #x labels a word sw $t0, stackp
sp sp Popping an element off of the top of the stack initially 20 5 10 20 5 10 Pop Note: popping the stack means moving back the pointer to the next available space. There is no need to explicitly delete the data. It will get overwritten in the next push.
sp sp Popping an element off of the top of the stack initially 20 5 10 20 5 10 Pop Note: popping the stack means moving back the pointer to the next available space. There is no need to explicitly delete the data. It could be overwritten on the next push.
Full and Empty Stack • MAL does not provide any form of boundary check • there is no automatic feature that detects whether an element is “pushed” beyond the stack’s capacity • A robust program must • check on a push whether the stack is full • What code needs to be added to push for this pupose? • check whether the stack is empty on a pop • What code needs to be added to pop for this pupose?
The system stack • The system stack is used to implement procedure calls and expression evaluation • The system stack is a particular example of the stack data type. It is not the only one • The MIPS architecture provides a special register, the $sp register, for pointing to the top of the system stack • The $sp register should never be used to point to the top of a user created stack 0xffffffff 0x7fffeffc $sp 0x00000000
Queues • A queue is a data structure that maintains a “first-in first-out” (FIFO) ordering. • In contrast, a stack maintains a “last-in first-out” (LIFO) ordering. • A queue adds new elements at the end. An element can only be removed at the front. • This is an abstraction of the “first-come first-served” practice.
Queue operations • A queue has two operations: • enqueue • dequeue • An enqueue operation adds new elements at the end of the queue or its tail. This is similar to the stack operation push; only that push now is done at the end of the queue instead of at the front (or top) of the stack. • A dequeue operation removes an element from the front of the queue or its head.
head tail Implementation • A queue can be implemented using an array. • A naïve implementation will allow the enqueued data to “walk” through the array.
head tail A circular queue • An array can be reused by allowing the enqueued data to “walk around” the array. This type of implementation is called a circular queue.
A circular queue • The particular implementation that will be illustrated here uses an empty element. This will simplify the check for a full or empty queue. • If the queue is empty, the dequeue operation must not return an invalid element. • If the queue is full, the enqueue operation must not destroy an element already in the queue.
Declaring a queue • Space must be allocated for the head, tail, and the array itself • Here a 64 element queue of integers is declared queue: .space 256 head: .word 0 tail: .word 0 • Note that head and tail hold offsets, not absolute addresses. This differs from the implementation of the stack discussed previously
0 1 head tail 0 1 2 Adding elements (enqueue) • To add one element, we simply add <size> to the the current value of the tail, then access memory lw $t0, tail lw $t1, x add $t0, $t0, 4 sw $t1, queue($t0) sw $t0, tail B = blank cell B
0 1 2 B head tail 0 1 2 B Removing elements (dequeue) • To remove one element, add <size> to the current value of head and read from the array lw $t0, head add $t0, $t0, 4 lw $t1, queue($t0) sw $t1, x sw $t0, head
0 1 2 B head tail 0 1 2 B Detecting an empty queue • During a dequeue, the first thing that is done is to check whether (head == tail). If this is true, then the queue is empty. not empty empty
head tail 0 1 2 B Detecting a full queue • Before an enqueue is done, the tail is incremented. If after the increment (head == tail) then the queue is full. before increment 0 1 2 B after increment full queue detected
Enqueue and dequeue with checks enqueue: lw $t0, tail lw $t1, head lw $t2, x add $t0, $t0, 4 beq $t0, $t1, full_queue sw $t2, queue($t0) sw $t0, tail dequeue: lw $t0, tail lw $t1, head beq $t0, $t1, empty_queue add $t1, $t1, 4 lw $t2, queue($t1) sw $t1, head sw $t2, x
Making the address circular • Suppose we have the array • To make the address 4 equal to the address 0 we simply use modulo arithmetic, i.e., 4 modulo 4 = 0. 0 1 2 3 4
Modulo arithmetic • Using modulo arithmetic maps any address to an address within the allocated space, thus preventing access to out-of-the-range addresses • Also, the modulo conveniently gives us the offset from the base address. • We need the offset from the base address to access specific elements in the queue. • Is this expensive in performance? • Use powers of 2, masking
What is masking? • Masking is the extraction of bits from a memory cell by ANDing with a bit pattern, called the mask • For example, to implement modulo 256 arithmetic, we can use a mask of 0xff after each addition. add $s0, $s0, 1 and $s0, $s0, 0xff • To determine if a number is odd… and $t0, $s0, 1 beq $t0, 0, isEven
Using a mask • How could a mask be used to determine whether the contents of register $a0 are divisible by four? • Only the 2 least significant bits matter • If they are both zero, the number is divisible by four • We can ignore the other 30 bits in the register and $t0, $a0, 0x3 beq $t0, 0, isDivisibleByFour
Enqueue and dequeue circular enqueue: lw $t0, tail lw $t1, head lw $t2, x add $t0, $t0, 4 and $t0, $t0, 0xff beq $t0, $t1, full_queue sw $t2, queue($t0) sw $t0, tail dequeue: lw $t0, tail lw $t1, head beq $t0, $t1, empty_queue add $t1, $t1, 4 and $t1, $t1, 0xff lw $t2, queue($t1) sw $t1, head sw $t2, x