diff --git a/mm.c b/mm.c
index 7eb6cc32fb3c71a9610831d8f826a729533ba94f..980a784ceccb6835dfada8c1c28d7cabffa4f2e0 100644
--- a/mm.c
+++ b/mm.c
@@ -1,30 +1,46 @@
 /* 
- * mm-handout.c -  Simple allocator based on implicit free lists and 
- *                 first fit placement (similar to lecture4.pptx). 
- *                 It does not use boundary tags and does not perform
- *                 coalescing. Thus, it tends to run out of memory 
- *                 when used to allocate objects in large traces  
- *                 due to external fragmentation.
+ * mm.c  -  Simple allocator based on explicit free lists and 
+ *         	first fit placement. It uses boundary tags and
+ * 			a circular doubly linked list to keep track of
+ * 			free blocks.
  *
- * Each block has a header of the form:
+ * Each block has a header and footer of the form:
  * 
  *      31                     3  2  1  0 
  *      -----------------------------------
  *     | s  s  s  s  ... s  s  s  0  0  a/f
  *      ----------------------------------- 
  * 
- * where s are the meaningful size bits and a/f is set 
- * iff the block is allocated. The list has the following form:
+ * where s are the meaningful size bits and a/f is set iff the
+ * block is allocated (0=a/1=f). Every block follows the form:
+ * 
+ *      31             0
+ *      ----------------
+ *     | Header
+ *      ------------------
+ *     | prev_free_block  \
+ *      ----------------   | - Payload when not free
+ *     | next_free_block  /
+ *      ------------------
+ *     | Footer
+ *      ----------------
+ * 
+ * Due to the size of the header and the bytes required to store
+ * the next and previous pointers, the minsize of a free block MUST
+ * be 4 words, or 2 DWORDS (16 bytes)
+ * 
+ * The list has the following form:
  *
  * begin                                                         end
  * heap                                                          heap  
  *  -----------------------------------------------------------------   
- * |  pad   | hdr(8:a) |   pad   | zero or more usr blks | hdr(8:a) |
+ * |  key   | hdr(8:a) |   pad   | zero or more usr blks | hdr(8:a) |
  *  -----------------------------------------------------------------
  *    four  | prologue |  four   |                       | epilogue |
  *    bytes | block    |  bytes  |                       | block    |
  *
  */
+
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
@@ -53,8 +69,9 @@ team_t team = {
 #define DSIZE       8       /* doubleword size (bytes) */
 #define CHUNKSIZE  (1<<12)  /* initial heap size (bytes) */
 #define OVERHEAD    8       /* overhead of headers (bytes) */
+#define MINSIZE		16		/* min size of block for overhead + explicit list */
 
-#define MAX(x, y)		((x) > (y)? (x) : (y))  
+#define MAX(x, y)		((x) > (y) ? (x) : (y))  
 
 /* Pack a size and allocated bit into a word */
 #define PACK(size, alloc)	((size) | (alloc))
@@ -75,21 +92,19 @@ team_t team = {
 #define NEXT_BLKP(bp)	((char *)(bp) + GET_SIZE((char *)(bp) - WSIZE))
 #define PREV_BLKP(bp)	((char *)(bp) - GET_SIZE((char *)(bp) - DSIZE))
 
-/* $end mallocmacros */
+/* Gets next/previous free list pointers in free area of a free block (bp) */
+#define GET_NEXT_FREE(bp)		(*(char **)(bp))
+#define GET_PREV_FREE(bp)		(*(char **)(bp + WSIZE))
 
+/* Puts next/previous free list pointers (fp) in free area of a free block (bp) */
+#define SET_NEXT_FREE(bp, fp)	(GET_NEXT_FREE(bp) = (fp))
+#define SET_PREV_FREE(bp, fp)	(GET_PREV_FREE(bp) = (fp))
+
+/* $end mallocmacros */
 
 /* Global variables */
 static char *heap_listp;  /* pointer to first block */  
-// static char *free_listp;  /* pointer to free list */
-
-// typedef struct Node
-// {
-// 	char * prev;
-// 	char * next;
-// }Node;
-
-
-
+static char *free_listp;  /* pointer to free list */
 
 /* function prototypes for internal helper routines */
 static void *extend_heap(size_t words);
@@ -98,6 +113,8 @@ static void *find_fit(size_t asize);
 static void printblock(void *bp);
 static int mm_coalesce(void *bp);
 static void mm_memcpy(void * dest, void * src);
+static void add_to_list(void* bp);
+static void remove_from_list(void* bp);
 
 /* 
  * mm_init - Initialize the memory manager 
@@ -105,20 +122,25 @@ static void mm_memcpy(void * dest, void * src);
 /* $begin mminit */
 int mm_init(void) 
 {
-   /* create the initial empty heap */
-   if ((heap_listp = mem_sbrk(4*WSIZE)) == NULL)
+	/* create the initial empty heap */
+	if ((heap_listp = mem_sbrk(4*WSIZE)) == NULL){
 		return -1;
-   PUT(heap_listp, KEY);               /* alignment padding */
-   PUT(heap_listp+WSIZE, PACK(DSIZE, 0));  /* prologue header */ 
-   PUT(heap_listp+DSIZE, PACK(0, 0));  /* empty word*/ 
-   PUT(heap_listp+DSIZE+WSIZE, PACK(0, 0));   /* epilogue header */
-   heap_listp += (DSIZE);
-
-
-   /* Extend the empty heap with a free block of CHUNKSIZE bytes */
-   if (extend_heap(CHUNKSIZE/WSIZE) == NULL)
+	}
+	PUT(heap_listp, KEY);						/* alignment padding */
+	PUT(heap_listp+WSIZE, PACK(DSIZE, 0));		/* prologue header */ 
+	PUT(heap_listp+DSIZE, PACK(0, 0));			/* empty word*/ 
+	PUT(heap_listp+DSIZE+WSIZE, PACK(0, 0));	/* epilogue header */
+	heap_listp += (DSIZE);						/* move pointer to user blocks */
+	free_listp = NULL;							/* clear free list */
+
+	/* Extend the empty heap with a free block of CHUNKSIZE bytes 
+	 * point free list at the returned block
+	*/
+	if (extend_heap(CHUNKSIZE/WSIZE) == NULL){
 		return -1;
-   return (int) heap_listp;
+	}
+
+	return (int) heap_listp;
 }
 /* $end mminit */
 
@@ -130,21 +152,19 @@ void *mm_malloc(size_t size)
 {
 	size_t asize;      /* adjusted block size */
 	size_t extendsize; /* amount to extend heap if no fit */
-	char *bp;      
-	
-	//printf("call mm_malloc\n");
+	char *bp;
 
 	/* Ignore spurious requests */
-	if (size <= 0)
+	if (size <= 0){
 		return NULL;
+	}
 
 	/* Adjust block size to include overhead and alignment reqs. */
-	if (size <= WSIZE)
-		asize = WSIZE + OVERHEAD;
-	else
+	if (size <= DSIZE){
+		asize = MINSIZE;
+	} else{
 		asize = DSIZE * ((size + (OVERHEAD) + (DSIZE-1)) / DSIZE);
-	
-	//printf("asize = %d\n", asize);
+	}
 
 	/* Search the free list for a fit */
 	if ((bp = find_fit(asize)) != NULL) {
@@ -154,18 +174,13 @@ void *mm_malloc(size_t size)
 
 	/* No fit found. Get more memory and place the block */
 	extendsize = MAX(asize,CHUNKSIZE);
-	//printf("extendsize = %d\n", extendsize);
 	if ((bp = extend_heap(extendsize/WSIZE)) == NULL) {
 		printf("mm_malloc = NULL\n");
 		return NULL;
 	}
 
-	//printf("return address = %p\n", bp);
-
 	place(bp, asize);
 
-	mm_checkheap(0);
-
 	return bp;
 } 
 /* $end mmmalloc */
@@ -181,20 +196,23 @@ void *mm_malloc(size_t size)
 void mm_free(void *bp)
 {
 	if(bp == NULL){
-		fprintf(stderr, "Error: memory not alloced or corrupted");
+		fprintf(stderr, "mm_free(): null pointer");
 		return;
 	}
 
+	// If allocated...
 	if(!GET_ALLOC(HDRP(bp))){
+		// try to coalesce...
 		if(mm_coalesce(bp)){
+			// else free
 			*HDRP(bp) |= 1;
 			*FTRP(bp) |= 1;
+			add_to_list(bp);
 		}
 	} else {
-		fprintf(stderr, "Error: memory not alloced or corrupted");
+		fprintf(stderr, "mm_free(): memory not alloced or corrupted");
 		return;
 	}
-	mm_checkheap(0);
 		
 }
 
@@ -211,6 +229,8 @@ void mm_free(void *bp)
  */
 static int mm_coalesce(void *bp)
 {	
+	return 1;
+
 	size_t nextBlock = GET_ALLOC(HDRP(NEXT_BLKP(bp)));
 	size_t prevBlock = GET_ALLOC(HDRP(PREV_BLKP(bp)));
 	size_t size = GET_SIZE(HDRP(bp));
@@ -263,6 +283,8 @@ void *mm_realloc(void *ptr, size_t size)
 	 * contents of the new block are identical to the first 4 bytes of the old block.
 	 */
 
+	return NULL;
+
 	if(ptr == NULL && size > 0){
 		return mm_malloc(size);
 	} else if(ptr != NULL && size == 0) {
@@ -355,25 +377,181 @@ void mm_memcpy(void * dest, void * src)
  */
 void mm_checkheap(int verbose) 
 {
+	printf("\n");
+
 	char *bp = heap_listp;
 
-	if (verbose)
+	if (verbose){
 		printf("Heap (%p):\n", heap_listp);
-	if ((GET_SIZE(HDRP(heap_listp)) != DSIZE) || GET_ALLOC(HDRP(heap_listp)))
+	}
+
+	// Check if prologue header is good
+	if ((GET_SIZE(HDRP(heap_listp)) != DSIZE) || GET_ALLOC(HDRP(heap_listp))){
 		printf("Bad prologue header\n");
+	}
+	
+	// check if every block in free list is actaully free
+	char * node = free_listp;
+	int freeCount = 0;
+
+	do
+	{
+		if(node == NULL){
+			break;
+		}
+		if(!GET_ALLOC(HDRP(node))){
+			printf("%p not free but is in list!\n", node);
+		}
+		freeCount++;
+		node = GET_NEXT_FREE(node);
+	} while (node != free_listp);
+	
 
 	for (bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = NEXT_BLKP(bp)) {
-		if (verbose)
+		//if free, see if it can be found in the free list
+		if(GET_ALLOC(HDRP(bp))){
+			node = free_listp;
+			do
+			{	
+				if(node == bp){
+					break;
+				}else{
+					node = GET_NEXT_FREE(node);
+				}
+			} while (node != free_listp);
+			if(node != bp){
+				printf("%p is free but not in list!\n", bp);
+			}
+		}
+		if (verbose){
 			printblock(bp);
+		}
 	}
 
-	if (verbose)
+	if (verbose){
 		printblock(bp);
-	if ((GET_SIZE(HDRP(bp)) != 0) || (GET_ALLOC(HDRP(bp))))
+	}
+	if ((GET_SIZE(HDRP(bp)) != 0) || (GET_ALLOC(HDRP(bp)))){
 		printf("Bad epilogue header\n");
+	}
+}
+
+/**
+ * add_to_list - Adds free block to list
+ * 
+ * Will try to add block in address order
+ */
+static void add_to_list(void* bp){
+
+	// case for nothing to add or empty list
+	if(bp == NULL || !GET_ALLOC(HDRP(bp))){
+		fprintf(stderr, "add_to_list(): Pointer is null or not free\n");
+		return;
+	}
+
+	/**
+	 * If list is empty, set head to free bp,
+	 * then add next and prev pointers.
+	 */ 
+	if(free_listp == NULL){
+		free_listp = bp;
+		SET_NEXT_FREE(free_listp, free_listp);
+		SET_PREV_FREE(free_listp, free_listp);
+		return;
+	}
+	
+	// case for 1 node in list.
+	if(free_listp == GET_NEXT_FREE(free_listp)){
+		// Set head next to new
+		SET_NEXT_FREE(free_listp, bp);
+		// Set pre prev as new
+		SET_PREV_FREE(free_listp, bp);
+		// Set new next as head
+		SET_NEXT_FREE(bp, free_listp);
+		// Set new prev as head
+		SET_PREV_FREE(bp, free_listp);
+		return;
+	}
+
+	/**
+	 * If previous cases don't apply, move head through list until
+	 * the new bp is in between two addresses.
+	 */ 
+	char * node = free_listp;
+	do
+	{	
+		if((char *) bp > node){
+			if((char *) bp < GET_NEXT_FREE(node) || node > GET_NEXT_FREE(node)){
+				//printf("Adding %p between %p -> %p\n\n", bp, node, GET_NEXT_FREE(node));
+				/* bp inserted after node */
+				// Set new next as current next
+				SET_NEXT_FREE(bp, GET_NEXT_FREE(node));
+				// Set current next as new
+				SET_NEXT_FREE(node, bp);
+				// Set new prev as current
+				SET_PREV_FREE(bp, node);
+				// Set new next's prev as new
+				SET_PREV_FREE(GET_NEXT_FREE(bp), bp);
+				// Move head to the inserted node to keep it closer to new inserts
+				free_listp = node;
+				return;
+			}
+			node = GET_NEXT_FREE(node);
+		}
+		else if((char *) bp < node){
+			if((char *) bp > GET_PREV_FREE(node) || node < GET_PREV_FREE(node)){
+				//printf("Adding %p between %p -> %p\n\n", bp, GET_PREV_FREE(node), node);
+				/* bp inserted before node */
+				// Set new next to node
+				SET_NEXT_FREE(bp, node);
+				// Set new prev as node's prev
+				SET_PREV_FREE(bp, GET_PREV_FREE(node));
+				// Set prev as new
+				SET_NEXT_FREE(GET_PREV_FREE(bp), bp);
+				// set node prev as new
+				SET_PREV_FREE(node, bp);
+				// Move head to the inserted node to keep it closer to new inserts
+				free_listp = node;
+				return;
+			}
+			node = GET_PREV_FREE(node);
+		} else if(node == (char *) bp){
+			fprintf(stderr, "add_to_list(): %p is a duplicate\n", bp);
+			return;
+		}
+	} while (node != free_listp);
+
+	fprintf(stderr, "add_to_list(): failed to add %p\n", bp);
+
+	return;
 }
 
-/* The remaining routines are internal helper routines */
+/**
+ * remove_from_list - Removes free block from list
+ * 
+ */
+static void remove_from_list(void* bp){
+
+	// case for nothing to remove or empty list
+	if(bp == NULL || free_listp == NULL){
+		fprintf(stderr, "remove_from_list(): List is free or memory is corrupt\n");
+		return;
+	}
+
+	if(free_listp == GET_NEXT_FREE(free_listp)){ /* case for 1 item */
+		free_listp = NULL;
+	} else {
+		/* case for head being removed */
+		if(free_listp == bp){
+			free_listp = GET_NEXT_FREE(free_listp);
+		}
+		// Set next previous to current previous
+		SET_PREV_FREE(GET_NEXT_FREE(bp), GET_PREV_FREE(bp));
+		// Set previous next to current next
+		SET_NEXT_FREE(GET_PREV_FREE(bp), GET_NEXT_FREE(bp));
+	}
+	return;
+}
 
 /* 
  * extend_heap - Extend heap with free block and return its block pointer
@@ -389,13 +567,16 @@ static void *extend_heap(size_t words)
     if ((bp = mem_sbrk(size)) == (void *)-1) 
 		return NULL;
 
-    /* Initialize free block header and the epilogue header */
-    PUT(HDRP(bp), PACK(size, 1));         /* free block header */
-    PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 0)); /* new epilogue header */
+    /* Initialize free block and the epilogue header */
+    PUT(HDRP(bp), PACK(size, 1));			/* free block header */
+	PUT(FTRP(bp), PACK(size, 1));			/* free block footer */
+	add_to_list(bp);
+    PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 0));	/* new epilogue header */
     return bp;
 }
 /* $end mmextendheap */
 
+
 /* 
  * place - Place block of asize bytes at start of free block bp 
  *         and split if remainder would be at least minimum block size
@@ -405,19 +586,21 @@ static void *extend_heap(size_t words)
 static void place(void *bp, size_t asize)
 /* $end mmplace-proto */
 {
-	size_t csize = GET_SIZE(HDRP(bp));   
-	// printf("csize = %d\n", csize);
+	size_t csize = GET_SIZE(HDRP(bp));
 
-	if ((csize - asize) >= (DSIZE)) {
+	if ((csize - asize) >= MINSIZE) {
 		PUT(HDRP(bp), PACK(asize, 0));
 		PUT(FTRP(bp), PACK(asize, 0));
+		remove_from_list(bp);
 		bp = NEXT_BLKP(bp);
 		PUT(HDRP(bp), PACK(csize-asize, 1));
 		PUT(FTRP(bp), PACK(csize-asize, 1));
+		add_to_list(bp);
 	}
 	else { 
 		PUT(HDRP(bp), PACK(csize, 0));
 		PUT(FTRP(bp), PACK(csize, 0));
+		remove_from_list(bp);
 	}
 }
 /* $end mmplace */
@@ -427,16 +610,24 @@ static void place(void *bp, size_t asize)
  */
 static void *find_fit(size_t asize)
 {
-    /* first fit search */
-    void *bp;
+	// No more free blocks
+	if(free_listp == NULL){
+		return NULL;
+	}
 
-    for (bp = heap_listp; GET_SIZE(bp-WSIZE) > 0; bp = NEXT_BLKP(bp)) {
-		if (GET_ALLOC(HDRP(bp)) && (asize <= GET_SIZE(HDRP(bp)))) {
+    /* first fit search */
+	void *bp = free_listp;
+	do {
+		if (asize <= GET_SIZE(HDRP(bp))) {
 	    	return bp;
 		}
-    }
+		if((bp = GET_NEXT_FREE(bp)) == NULL){
+			return NULL;
+		}
+	} while(bp != free_listp);
     return NULL; /* no fit */
 }
+
 static void printblock(void *bp)
 {
 	    size_t hsize, halloc;