diff -Nur a/core/hw/sh4/dyna/blockmanager.cpp b/core/hw/sh4/dyna/blockmanager.cpp
--- a/core/hw/sh4/dyna/blockmanager.cpp	2015-10-06 21:43:53.030336315 -0300
+++ b/core/hw/sh4/dyna/blockmanager.cpp	2015-10-06 21:58:25.685653822 -0300
@@ -122,7 +122,11 @@
 	}
 	else
 	{
-		printf("bm_GetBlock(%08X) failed ..\n",dynarec_code);
+		for (iter = blkmap.begin(); iter != blkmap.end(); iter++) {
+			if ((*iter)->contains_code((u8*)dynarec_code))
+				return *iter;
+		}
+		//printf("bm_GetBlock(%p, %p) failed ..\n",dynarec_code, ngen_FailedToFindBlock);
 		return 0;
 	}
 }
@@ -158,6 +162,8 @@
 	verify((void*)bm_GetCode(blk->addr)==(void*)ngen_FailedToFindBlock);
 	FPCA(blk->addr)=blk->code;
 
+	verify(bm_GetBlock(blk->addr) == blk);
+
 #ifdef DYNA_OPROF
 	if (oprofHandle)
 	{
diff -Nur a/core/hw/sh4/dyna/blockmanager.h b/core/hw/sh4/dyna/blockmanager.h
--- a/core/hw/sh4/dyna/blockmanager.h	2015-10-06 21:43:53.030336315 -0300
+++ b/core/hw/sh4/dyna/blockmanager.h	2015-10-06 21:58:25.685653822 -0300
@@ -71,6 +71,7 @@
 
 	u32 memops;
 	u32 linkedmemops;
+	bool entry_block;
 };
 
 struct CachedBlockInfo: RuntimeBlockInfo_Core
diff -Nur a/core/hw/sh4/dyna/decoder.cpp b/core/hw/sh4/dyna/decoder.cpp
--- a/core/hw/sh4/dyna/decoder.cpp	2015-10-06 21:43:53.030336315 -0300
+++ b/core/hw/sh4/dyna/decoder.cpp	2015-10-06 21:58:25.685653822 -0300
@@ -14,6 +14,7 @@
 #include "hw/sh4/sh4_core.h"
 #include "hw/sh4/sh4_mem.h"
 #include "decoder_opcodes.h"
+#include "../interpr/sh4_opcodes.h"
 
 #define BLOCK_MAX_SH_OPS_SOFT 500
 #define BLOCK_MAX_SH_OPS_HARD 511
@@ -1098,6 +1099,13 @@
 						else
 							blk->guest_cycles+=CPU_RATIO;
 
+						if ((state.cpu.is_delayslot && OpDesc[op]->SetPC()) ||
+							OpDesc[op]->oph == iNotImplemented) {
+							blk->addr = -1;
+							return;
+						}
+
+
 						verify(!(state.cpu.is_delayslot && OpDesc[op]->SetPC()));
 						if (state.ngen.OnlyDynamicEnds || !OpDesc[op]->rec_oph)
 						{
@@ -1168,6 +1176,8 @@
 	if (settings.dynarec.idleskip)
 	{
 		//Experimental hash-id based idle skip
+		if (blk->addr == 0x8C0B926A)
+			blk->guest_cycles *= 100;
 		if (strstr(idle_hash,blk->hash(false,true)))
 		{
 			//printf("IDLESKIP: %08X reloc match %s\n",blk->addr,blk->hash(false,true));
diff -Nur a/core/hw/sh4/dyna/driver.cpp b/core/hw/sh4/dyna/driver.cpp
--- a/core/hw/sh4/dyna/driver.cpp	2015-10-06 21:43:53.030336315 -0300
+++ b/core/hw/sh4/dyna/driver.cpp	2015-10-06 21:58:25.685653822 -0300
@@ -72,11 +72,24 @@
 	LastAddr=LastAddr_min;
 	memset(emit_GetCCPtr(),0xCC,emit_FreeSpace());
 }
+
+#include <map>
+#include <algorithm>
+#include <set>
+
+typedef map<u32, RuntimeBlockInfo*> BlockGraph;
+
+vector<BlockGraph*> graphs;
+map<u32, BlockGraph*> blockgraphs;
+
 void recSh4_ClearCache()
 {
 	LastAddr=LastAddr_min;
 	bm_Reset();
 
+	graphs.clear();
+	blockgraphs.clear();
+
 	printf("recSh4:Dynarec Cache clear at %08X\n",curr_pc);
 }
 
@@ -212,9 +225,145 @@
 	AnalyseBlock(this);
 }
 
+void merge_graphs(BlockGraph* one, BlockGraph* two) {
+	for (BlockGraph::iterator it = two->begin(); it != two->end(); it++) {
+		blockgraphs[it->second->addr] = one;
+		(*one)[it->second->addr] = it->second;
+	}
+	graphs.erase(find(graphs.begin(), graphs.end(), two));
+}
+
+void discover_graph(u32 bootstrap) {
+	BlockGraph* graph;
+	set<u32> resolved;
+	vector<u32> unresolved;
+
+	if (blockgraphs.count(bootstrap)) {
+		graph = blockgraphs[bootstrap];
+		(*graph)[bootstrap]->entry_block = true;
+		return;
+	} else {
+		graph = new BlockGraph();
+
+		graphs.push_back(graph);
+	}
+
+	unresolved.push_back(bootstrap);
+
+	while (unresolved.size()) {
+		u32 pc = unresolved[unresolved.size()-1];
+		unresolved.pop_back();
+
+		if (resolved.count(pc))
+			continue;
+
+		if (graph->count(pc))
+			continue;
+
+		if (blockgraphs.count(pc)) {
+			verify(blockgraphs[pc] != graph);
+			merge_graphs(blockgraphs[pc], graph);
+			graph = blockgraphs[pc];
+			resolved.clear();
+			continue;
+		}
+
+		resolved.insert(pc);
+		//printf("resolving %08X\n", pc);
+
+		RuntimeBlockInfo* rbi = ngen_AllocateBlock();
+		rbi->Setup(pc,fpscr);
+		rbi->entry_block = pc == bootstrap;
+
+		if (rbi->addr == -1)
+			continue;
+
+		(*graph)[pc] = rbi;
+		blockgraphs[pc] = graph;
+
+		if (rbi->BranchBlock !=-1 && rbi->BlockType != BET_StaticCall)
+			unresolved.push_back(rbi->BranchBlock);
+
+		if (rbi->NextBlock != -1)
+			unresolved.push_back(rbi->NextBlock);
+	}
+
+	int entrypoints = 0;
+	
+	for (BlockGraph::iterator it = graph->begin(); it != graph->end(); it++) {
+		entrypoints += it->second->entry_block;
+	}
+
+	//printf("Graph: %d blocks w/ %d entrypoints, %d graphs\n", graph->size(), entrypoints, graphs.size());
+}
+
+void print_graphs() {
+	int top_runs = 0;
+	int total_runs = 0;
+	map<BlockGraph*, u32> graph_runs;
+
+	for (size_t i = 0; i < graphs.size(); i++) {
+		BlockGraph* graph = graphs[i];
+		for (BlockGraph::iterator it = graphs[i]->begin(); it != graphs[i]->end(); it++) {
+
+			RuntimeBlockInfo* natblock = bm_GetBlock(it->first);
+			if (!natblock || natblock->runs == 0)
+				continue;
+
+			if (natblock->runs > top_runs)
+				top_runs = natblock->runs;
+
+			total_runs += natblock->runs;
+
+			graph_runs[graph] += natblock->runs;
+		}
+	}
+
+	int baseline = top_runs / 100;
+
+	printf("<Graphdump\n");
+	for (size_t i = 0; i < graphs.size(); i++) {
+		BlockGraph* graph = graphs[i];
+		if (graph_runs[graph] < baseline)
+			continue;
+		printf("\tGraph: %p\n", graphs[i]);
+		
+		int cnt = 0;
+		int cnt2 = 0;
+		for (BlockGraph::iterator it = graphs[i]->begin(); it != graphs[i]->end(); it++) {
+			
+			RuntimeBlockInfo* natblock = bm_GetBlock(it->first);
+			if (!natblock || natblock->runs == 0 || natblock->runs < baseline) {
+				if (natblock) {
+					cnt2++;
+					natblock->runs = 0;
+				} else {
+					cnt++;
+				}
+				continue;
+			}
+			printf("\t\tBlock %08X, compiled: %d, entrypoint: %d, type: %d, len: %d, cycles: %d, runs %d, loop %d\n", 
+					it->first, natblock != 0, it->second->entry_block, it->second->BlockType, it->second->oplist.size(),
+					it->second->guest_cycles, natblock ? natblock->runs : 0, 
+					(it->second->BlockType == BET_Cond_0 || it->second->BlockType == BET_Cond_1) && graph->count(it->second->BranchBlock) );
+
+			if (natblock)
+				natblock->runs = 0;
+		}
+		if (cnt2) {
+			printf("\t\t and %d more not worth mentioning\n", cnt2);
+		}
+		if (cnt) {
+			printf("\t\t and %d more that never run\n", cnt);
+		}
+	}
+	printf("Graphdump>\n");
+}
+
 DynarecCodeEntryPtr rdv_CompilePC()
 {
 	u32 pc=next_pc;
+	discover_graph(pc);
 
 	if (emit_FreeSpace()<16*1024 || pc==0x8c0000e0 || pc==0xac010000 || pc==0xac008300)
 		recSh4_ClearCache();
@@ -232,6 +381,7 @@
 		rbi->staging_runs=do_opts?100:-100;
 		ngen_Compile(rbi,DoCheck(rbi->addr),(pc&0xFFFFFF)==0x08300 || (pc&0xFFFFFF)==0x10000,false,do_opts);
 		verify(rbi->code!=0);
+		verify(rbi->host_code_size!=0);
 
 		bm_AddBlock(rbi);
 
diff -Nur a/core/linux-dist/main.cpp b/core/linux-dist/main.cpp
--- a/core/linux-dist/main.cpp	2015-10-06 21:43:53.042336401 -0300
+++ b/core/linux-dist/main.cpp	2015-10-06 21:58:25.685653822 -0300
@@ -189,6 +189,18 @@
 	#if defined(USE_SDL)
 		input_sdl_handle(port);
 	#endif
+	
+	//Whatever happened to these?
+#if FEAT_SHREC != DYNAREC_NONE
+	/*
+		void print_graphs();
+		if ('b' == key)	emit_WriteCodeCache();
+		if ('n' == key)	bm_Reset();
+		if ('m' == key)	bm_Sort();
+		if (',' == key)	{ emit_WriteCodeCache(); bm_Sort(); }
+		if ('q' == key)	print_graphs();
+	*/
+#endif
 }
 
 void os_DoEvents()
diff -Nur a/core/rec-x64/rec_x64.cpp b/core/rec-x64/rec_x64.cpp
--- a/core/rec-x64/rec_x64.cpp	2015-10-06 21:43:53.045336422 -0300
+++ b/core/rec-x64/rec_x64.cpp	2015-10-06 21:58:25.685653822 -0300
@@ -162,6 +162,10 @@
 
 		sub(dword[rax], block->guest_cycles);
 
+		mov(rax, (size_t)&block->runs);
+		add(dword[rax], 1);
+
+
 		sub(rsp, 0x28);
 
 		for (size_t i = 0; i < block->oplist.size(); i++) {
@@ -355,6 +359,7 @@
 
 		block->code = (DynarecCodeEntryPtr)getCode();
 
+		block->host_code_size = getSize();
 		emit_Skip(getSize());
 	}