From 7bf244072606ef8798508cf2fc1f5dfc0a2dc70f Mon Sep 17 00:00:00 2001
From: Hunter Hedges <h.hedges@live.com>
Date: Sat, 28 Apr 2018 19:32:53 -0500
Subject: [PATCH] Fix stalling and add more samples

---
 css/styles.min.css        |  1 -
 index.html                |  7 ++++--
 js/mipsInstructions.js    | 53 +++++++++++++++++++++++++++++++--------
 js/mipsSimulator.min.js   |  1 -
 js/simulate.js            | 53 ++++++++++++++++++++++++++++++++++++---
 sampleinputs/sample_1.txt |  2 +-
 sampleinputs/sample_3.txt | 12 +++++++++
 sampleinputs/sample_4.txt | 16 ++++++++++++
 sampleinputs/sample_5.txt | 29 +++++++++++++++++++++
 9 files changed, 155 insertions(+), 19 deletions(-)
 delete mode 100644 css/styles.min.css
 delete mode 100644 js/mipsSimulator.min.js
 create mode 100644 sampleinputs/sample_3.txt
 create mode 100644 sampleinputs/sample_4.txt
 create mode 100644 sampleinputs/sample_5.txt

diff --git a/css/styles.min.css b/css/styles.min.css
deleted file mode 100644
index ae24edb..0000000
--- a/css/styles.min.css
+++ /dev/null
@@ -1 +0,0 @@
-.navbar,.navbar a{color:#ecf0f1}body,html{height:100%}a:hover{text-decoration:none}#content-wrap{min-height:100%}#main{overflow:auto;padding:5px 5px 75px}.navbar{background:url(https://github.com/hunterhedges/mipsSimulator/blob/master/images/overlay.png?raw=true) #041942;font-family:'Open Sans',sans-serif}.navbar a:hover{color:#95a5a6}.navbar-toggler{border:1px solid #fff}.navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 1)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 8h24M4 16h24M4 24h24'/%3E%3C/svg%3E")}footer{position:relative;clear:both;background:url(https://github.com/hunterhedges/mipsSimulator/blob/master/images/overlay.png?raw=true) #041942;height:75px;margin-top:-75px}.decoded-instructions-container,.simulation-results-container{border:3px dotted #000;padding:10px;margin-top:20px;margin-bottom:20px}.upload-container{min-height:500px;display:flex;border:3px dotted #000;font-size:22px}.file-input{display:none}.upload-icon{max-width:100%;width:50%}.file-hover{background-color:#e6e6e6}.demo-link{position:absolute;top:10px;right:20px;font-size:16px}.decoded-instructions-container{display:none;font-size:22px}.decoded-instructions-container h4{margin-bottom:20px}.decoded-instructions-container p{text-align:left;font-size:16px}.simulation-results-container{display:none}@media(max-width:320px){.navbar-brand{font-size:18px}}@media (min-width:992px){.upload-icon{width:35%}.upload-container{margin-top:20px;margin-bottom:20px}}
diff --git a/index.html b/index.html
index cfeb02f..578e64a 100644
--- a/index.html
+++ b/index.html
@@ -9,7 +9,7 @@
   <!-- Bootstrap CSS -->
   <link href="depends/bootstrap-4.0.0/css/bootstrap.min.css" rel="stylesheet" />
   <!-- Site CSS -->
-  <link href="css/styles.min.css" rel="stylesheet" />
+  <link href="css/styles.css" rel="stylesheet" />
   <!-- jQuery -->
   <script src="depends/jquery-3.3.1.min.js"></script>
   <!-- Bootstrap JS -->
@@ -202,7 +202,10 @@ <h5 class="modal-title" id="modalTitle"><!-- Modal Title --></h5>
   </div>
   <!-- End Error Modal -->
 
-  <script src="js/mipsSimulator.min.js"></script>
+  <script src="js/extensions.js"></script>
+  <script src="js/parseInputFile.js"></script>
+  <script src="js/mipsInstructions.js"></script>
+  <script src="js/simulate.js"></script>
 
 </body>
 </html>
diff --git a/js/mipsInstructions.js b/js/mipsInstructions.js
index 61efeca..b13c391 100644
--- a/js/mipsInstructions.js
+++ b/js/mipsInstructions.js
@@ -1,6 +1,7 @@
 const ACTIONS = {
 	DECODE: "decode",
-	EXECUTE: "execute"
+	EXECUTE: "execute",
+	SHOULD_STALL: "stall"
 }
 
 // ExecutionResult object returned by MIPS instruction on execute action.
@@ -10,8 +11,9 @@ const ACTIONS = {
 //	Memory location and value object affected if applicable
 //	Bool if the instruction causes a branch
 //	Integer of branch offset if shouldBranch = true
-function ExecutionResult(stallAmount, registerState, memoryState, shouldBranch, branchOffset) {
+function ExecutionResult(stallLocation, stallAmount, registerState, memoryState, shouldBranch, branchOffset) {
 
+	this.stallLocation = stallLocation;
 	this.stallAmount = stallAmount;
 	this.registerState = registerState;
 	this.memoryState = memoryState;
@@ -196,13 +198,17 @@ function add(binaryInstructionString, action) {
 		setRegisterDefault(rs);
 		setRegisterDefault(rt);
 
+		var stallLocation = rd;
 		var stallAmount = 2;
 		var registerState = { register: rd, value: registers[rs] + registers[rt] };
 		var memoryState = null;
 		var shouldBranch = false;
 		var branchOffset = 0;
 
-		return new ExecutionResult(stallAmount, registerState, memoryState, shouldBranch, branchOffset);
+		return new ExecutionResult(stallLocation, stallAmount, registerState, memoryState, shouldBranch, branchOffset);
+	}
+	else if(action == ACTIONS.SHOULD_STALL) {
+		return [rs, rt];
 	}
 
 }
@@ -222,13 +228,17 @@ function addi(binaryInstructionString, action) {
 	else if(action == ACTIONS.EXECUTE) {
 		setRegisterDefault(rs);
 
+		var stallLocation = rt;
 		var stallAmount = 2;
 		var registerState = { register: rt, value: registers[rs] + imm };
 		var memoryState = null;
 		var shouldBranch = false;
 		var branchOffset = 0;
 
-		return new ExecutionResult(stallAmount, registerState, memoryState, shouldBranch, branchOffset);
+		return new ExecutionResult(stallLocation, stallAmount, registerState, memoryState, shouldBranch, branchOffset);
+	}
+	else if(action == ACTIONS.SHOULD_STALL) {
+		return [rs];
 	}
 
 }
@@ -260,7 +270,10 @@ function branchOnEqual(binaryInstructionString, action) {
 			branchOffset = offset;
 		}
 
-		return new ExecutionResult(stallAmount, registerState, memoryState, shouldBranch, branchOffset);
+		return new ExecutionResult(null, stallAmount, registerState, memoryState, shouldBranch, branchOffset);
+	}
+	else if(action == ACTIONS.SHOULD_STALL) {
+		return [rs, rt];
 	}
 
 }
@@ -292,7 +305,10 @@ function branchNotEqual(binaryInstructionString, action) {
 			branchOffset = offset;
 		}
 
-		return new ExecutionResult(stallAmount, registerState, memoryState, shouldBranch, branchOffset);
+		return new ExecutionResult(null, stallAmount, registerState, memoryState, shouldBranch, branchOffset);
+	}
+	else if(action == ACTIONS.SHOULD_STALL) {
+		return [rs, rt];
 	}
 
 }
@@ -314,14 +330,17 @@ function loadWord(binaryInstructionString, action) {
 		setRegisterDefault(rs);
 		setMemoryDefault(rs + offset);
 
+		var stallLocation = rt;
 		var stallAmount = 2;
 		var registerState = { register: rt, value: memory[registers[rs] + offset] };
 		var memoryState = null;
 		var shouldBranch = false;
 		var branchOffset = 0;
 
-		return new ExecutionResult(stallAmount, registerState, memoryState, shouldBranch, branchOffset);
-
+		return new ExecutionResult(stallLocation, stallAmount, registerState, memoryState, shouldBranch, branchOffset);
+	}
+	else if(action == ACTIONS.SHOULD_STALL) {
+		return [rs];
 	}
 
 }
@@ -349,7 +368,10 @@ function storeWord(binaryInstructionString, action) {
 		var shouldBranch = false;
 		var branchOffset = 0;
 
-		return new ExecutionResult(stallAmount, registerState, memoryState, shouldBranch, branchOffset);
+		return new ExecutionResult(null, stallAmount, registerState, memoryState, shouldBranch, branchOffset);
+	}
+	else if(action == ACTIONS.SHOULD_STALL) {
+		return [rs, rt];
 	}
 
 }
@@ -380,11 +402,16 @@ function setOnLessThan(binaryInstructionString, action) {
 			registerState = { register: rd, value: 0 };
 		}
 
+		var stallLocation = rd;
+		var stallAmount = 2;
 		var memoryState = null;
 		var shouldBranch = false;
 		var branchOffset = 0;
 
-		return new ExecutionResult(stallAmount, registerState, memoryState, shouldBranch, branchOffset);
+		return new ExecutionResult(stallLocation, stallAmount, registerState, memoryState, shouldBranch, branchOffset);
+	}
+	else if(action == ACTIONS.SHOULD_STALL) {
+		return [rs, rt];
 	}
 
 }
@@ -405,13 +432,17 @@ function sub(binaryInstructionString, action) {
 		setRegisterDefault(rs);
 		setRegisterDefault(rt);
 
+		var stallLocation = rd;
 		var stallAmount = 2;
 		var registerState = { register: rd, value: registers[rs] - registers[rt] };
 		var memoryState = null;
 		var shouldBranch = false;
 		var branchOffset = 0;
 
-		return new ExecutionResult(stallAmount, registerState, memoryState, shouldBranch, branchOffset);
+		return new ExecutionResult(stallLocation, stallAmount, registerState, memoryState, shouldBranch, branchOffset);
+	}
+	else if(action == ACTIONS.SHOULD_STALL) {
+		return [rs, rt];
 	}
 
 }
diff --git a/js/mipsSimulator.min.js b/js/mipsSimulator.min.js
deleted file mode 100644
index 9a3c18e..0000000
--- a/js/mipsSimulator.min.js
+++ /dev/null
@@ -1 +0,0 @@
-var SECTIONS={REGISTERS:{sectionName:"registers",stopCharacters:["m","c"]},MEMORY:{sectionName:"memory",stopCharacters:["r","c"]},CODE:{sectionName:"code",stopCharacters:["r","m"]}},registers={},memory={},decodedCode=[],warnings=[];function canDoDragAndDrop(){var e=document.createElement("div");return("draggable"in e||"ondragstart"in e&&"ondrop"in e)&&"FormData"in window&&"FileReader"in window}function readDemoFile(){$.get("https://raw.githubusercontent.com/hunterhedges/mipsSimulator/master/sampleinputs/sample_1.txt",function(e){parseInputFile(e)})}function readFileOnUpload(e){var t;if("drop"==e.type?t=e.originalEvent.dataTransfer.files[0]:"change"==e.type&&(t=$("#file")[0].files[0]),t.type.includes("text")){var r=new FileReader;r.onload=function(e){var t=e.target.result;t.isNullOrEmpty()?showModal("Error Uploading File","File is empty"):parseInputFile(t)},r.readAsText(t)}else showModal("Error Uploading File","Incorrect file type")}function parseInputFile(e){reset(),loadRegisters(parseSection(e=e.toLowerCase(),SECTIONS.REGISTERS)),loadMemory(parseSection(e,SECTIONS.MEMORY)),loadDecodedCode(parseSection(e,SECTIONS.CODE)),displayDecodedInstructions(),displayWarnings()}function parseSection(e,t){var r,n="",s=0;if(e.includes(t.sectionName)){for(s=e.indexOf(t.sectionName)+t.sectionName.length;!t.stopCharacters.includes(e.charAt(s))&&s<e.length;)n+=e.charAt(s),s++;r=(r=n.split("\n")).removeEmptyElements()}else warnings.push("<strong>"+t.sectionName.toUpperCase()+"</strong> section not found in file.");return r}function loadRegisters(e){if(e)for(var t=0;t<e.length;t++){for(var r=0,n="",s="";" "!=e[t].charAt(r)&&r<e[t].length;)n+=e[t].charAt(r),r++;for(r+=1;r<e[t].length;r++)s+=e[t].charAt(r);"r"==n.charAt(0)&&(n=n.replace("r","")),isValidRegister(n)&&isValidValue(s)&&(s=parseInt(s),registers[n]=s)}}function isValidRegister(e){var t,r=!1;return(t=parseInt(e))||0==t?t>0&&t<32?r=!0:warnings.push("Register <strong>"+e+"</strong> must be between 1 and 31 inclusive."):warnings.push("Register <strong>"+e+"</strong> could not be parsed."),r}function loadMemory(e){if(e)for(var t=0;t<e.length;t++){for(var r=0,n="",s="";" "!=e[t].charAt(r)&&r<e[t].length;)n+=e[t].charAt(r),r++;for(r+=1;r<e[t].length;r++)s+=e[t].charAt(r);"m"==n.charAt(0)&&(n=n.replace("m","")),isValidMemoryLocation(n)&&isValidValue(s)&&(s=parseInt(s),memory[n]=s)}}function isValidMemoryLocation(e){var t,r=!1;return(t=parseInt(e))?t>=0&&t<65280&&t%4==0?r=!0:warnings.push("Memory location <strong>"+e+"</strong> must be greater than 0, less than 65280, and divisible by 4."):warnings.push("Memory location <strong>"+e+"</strong> could not be parsed."),r}function loadDecodedCode(e){if(e)for(var t=0;t<e.length;t++){e[t]=e[t].replace(/ /g,"");var r=findInstruction(e[t],ACTIONS.DECODE);r?(decodedCode.push(r),instructions.push(e[t])):warnings.push("Code <strong>"+e[t]+"</strong> is not a valid instruction.")}}function isValidValue(e){var t=!1;return(e=parseInt(e,10))||0==e?e<=4294967295&&e>=-2147483648?t=!0:warnings.push("Value <strong>"+e+"</strong> will result in overflow."):warnings.push("Value <strong>"+e+"</strong> could not be parsed."),t}function displayDecodedInstructions(){for(var e in $("#decodedInstructionsContainer").show(),$("#decodedInstructions").append("REGISTERS<br />"),registers)$("#decodedInstructions").append("R"+e+" "+registers[e]+"<br />");for(var e in 0==registers.length&&$("#decodedInstructions").append("All registers set to 0<br />"),$("#decodedInstructions").append("<br />"),$("#decodedInstructions").append("MEMORY<br />"),memory)$("#decodedInstructions").append(e+" "+memory[e]+"<br />");0==memory.length&&$("#decodedInstructions").append("All memory locations set to 0<br />"),$("#decodedInstructions").append("<br />"),$("#decodedInstructions").append("CODE<br />");for(var t=0;t<decodedCode.length;t++)$("#decodedInstructions").append(decodedCode[t]+"<br />");0==decodedCode.length&&$("#decodedInstructions").append("No code detected"),$("html, body").animate({scrollTop:$("#decodedInstructionsContainer").offset().top-20},500)}function displayWarnings(){if(0!=warnings.length){for(var e="",t=0;t<warnings.length;t++)e+=t+1+". "+warnings[t]+"<br />";showModal("Warnings",e)}}function showModal(e,t){$("#modalTitle").html(e),$("#modalBody").html(t),$("#modal").modal("show")}function reset(){$("#decodedInstructionsContainer").hide(),$("#decodedInstructions").html(""),$("#simulationResultsContainer").hide(),$("#simulationInstructions").html(""),$("#simulationRegisters").html(""),$("#simulationMemory").html(""),$("#simulationCycleData").html(""),registers={},memory={},decodedCode=[],warnings=[],instructions=[],registerStates=[],memoryStates=[],cycleData=[],pcCounter=0,cycleCounter=1,$("html, body").animate({scrollTop:0},500)}$(function(){canDoDragAndDrop||$("#dragDropAvailable").hide(),$("#uploadContainer").on("drag dragstart dragend dragover dragenter dragleave drop",function(e){e.preventDefault(),e.stopPropagation()}),$("#uploadContainer").on("dragenter dragover",function(){$("#uploadContainer").addClass("file-hover")}),$("#uploadContainer").on("dragleave dragend drop",function(){$("#uploadContainer").removeClass("file-hover")}),$("#uploadContainer").on("drop",readFileOnUpload),$("input[type='file']").change(readFileOnUpload),$("#uploadLink").on("click",function(e){e.preventDefault(),$("#file:hidden").trigger("click")})});var ACTIONS={DECODE:"decode",EXECUTE:"execute"};function ExecutionResult(e,t,r,n,s){this.stallAmount=e,this.registerState=t,this.memoryState=r,this.shouldBranch=n,this.branchOffset=s}function findInstruction(e,t){var r;switch((e=e.trim()).substring(0,6)){case"000000":var n=e.substring(26);"100000"==n?r=add(e,t):"100010"==n?r=sub(e,t):"101010"==n&&(r=setOnLessThan(e,t));break;case"001000":r=addi(e,t);break;case"000100":r=branchOnEqual(e,t);break;case"000101":r=branchNotEqual(e,t);break;case"100011":r=loadWord(e,t);break;case"101011":r=storeWord(e,t)}return r}function parseRs(e){var t=e.substring(6,11);return parseInt(t,2)}function parseRt(e){var t=e.substring(11,16);return parseInt(t,2)}function parseRd(e){var t=e.substring(16,21);return parseInt(t,2)}function parseOffset(e){var t=e.substring(16);return parseInt(t,2)}function parseImm(e){var t=e.substring(16);return t=uintToInt(t=parseInt(t,2),10)}function setRegisterDefault(e){registers[e]||(registers[e]=0)}function setMemoryDefault(e){memory[e]||(memory[e]=0)}function add(e,t){var r=parseRs(e),n=parseRt(e),s=parseRd(e);if(t==ACTIONS.DECODE)return"ADD R"+s+", R"+r+", R"+n;if(t==ACTIONS.EXECUTE){setRegisterDefault(r),setRegisterDefault(n);return new ExecutionResult(2,{register:s,value:registers[r]+registers[n]},null,!1,0)}}function addi(e,t){var r=parseRs(e),n=parseRt(e),s=parseImm(e);if(t==ACTIONS.DECODE)return"ADDI R"+n+", R"+r+", "+s;if(t==ACTIONS.EXECUTE){setRegisterDefault(r);return new ExecutionResult(2,{register:n,value:registers[r]+s},null,!1,0)}}function branchOnEqual(e,t){var r=parseRs(e),n=parseRt(e),s=parseOffset(e);if(t==ACTIONS.DECODE)return"BEQ R"+r+", R"+n+", "+s;if(t==ACTIONS.EXECUTE){setRegisterDefault(r),setRegisterDefault(n);var a=!1,o=0;return registers[r]==registers[n]&&(a=!0,o=s),new ExecutionResult(0,null,null,a,o)}}function branchNotEqual(e,t){var r=parseRs(e),n=parseRt(e),s=parseOffset(e);if(t==ACTIONS.DECODE)return"BNE R"+r+", R"+n+", "+s;if(t==ACTIONS.EXECUTE){setRegisterDefault(r),setRegisterDefault(n);var a=!1,o=0;return registers[r]!=registers[n]&&(a=!0,o=s),new ExecutionResult(0,null,null,a,o)}}function loadWord(e,t){var r=parseRs(e),n=parseRt(e),s=parseOffset(e);if(t==ACTIONS.DECODE)return"LW R"+n+", "+s+"(R"+r+")";if(t==ACTIONS.EXECUTE){setRegisterDefault(n),setRegisterDefault(r),setMemoryDefault(r+s);return new ExecutionResult(2,{register:n,value:memory[registers[r]+s]},null,!1,0)}}function storeWord(e,t){var r=parseRs(e),n=parseRt(e),s=parseOffset(e);if(t==ACTIONS.DECODE)return"SW R"+n+", "+s+"(R"+r+")";if(t==ACTIONS.EXECUTE){setRegisterDefault(n),setRegisterDefault(r),setMemoryDefault(r+s);return new ExecutionResult(0,null,{memoryLocation:registers[r]+s,value:registers[n]},!1,0)}}function setOnLessThan(e,t){var r=parseRs(e),n=parseRt(e),s=parseRd(e);if(t==ACTIONS.DECODE)return"SLT R"+s+", R"+r+", R"+n;if(t==ACTIONS.EXECUTE){setRegisterDefault(r),setRegisterDefault(n);return new ExecutionResult(2,registers[r]<registers[n]?{register:s,value:1}:{register:s,value:0},null,!1,0)}}function sub(e,t){var r=parseRs(e),n=parseRt(e),s=parseRd(e);if(t==ACTIONS.DECODE)return"SUB R"+s+", R"+r+", R"+n;if(t==ACTIONS.EXECUTE){setRegisterDefault(r),setRegisterDefault(n);return new ExecutionResult(2,{register:s,value:registers[r]-registers[n]},null,!1,0)}}var previousExecutionResult,instructions=[],registerStates=[],memoryStates=[],cycleData=[],currentStep=0,pcCounter=0,cycleCounter=1;function stepThrough(){"END"!=decodedCode[decodedCode.length-1]&&decodedCode.push("END"),simulationReset(),simulate(),$("#simulationResultsContainer").show(),displayInstructions(0),displayRegisters(0),displayMemory(0),displayCycleData(0),setDownloadLink(),$("#prevStepBtn").attr("disabled","disabled"),$("#nextStepBtn").removeAttr("disabled"),$("html, body").animate({scrollTop:$("#simulationResultsContainer").offset().top-20},500)}function nextStep(){displayInstructions(++currentStep),displayRegisters(currentStep),displayMemory(currentStep),displayCycleData(currentStep),currentStep==decodedCode.length-1&&$("#nextStepBtn").attr("disabled","disabled"),0!=currentStep&&$("#prevStepBtn").removeAttr("disabled")}function previousStep(){displayInstructions(--currentStep),displayRegisters(currentStep),displayMemory(currentStep),displayCycleData(currentStep),0==currentStep&&$("#prevStepBtn").attr("disabled","disabled"),currentStep!=decodedCode.length-1&&$("#nextStepBtn").removeAttr("disabled")}function executeAll(){"END"!=decodedCode[decodedCode.length-1]&&decodedCode.push("END"),simulationReset(),currentStep=decodedCode.length-1,simulate(),$("#simulationResultsContainer").show(),displayInstructions(decodedCode.length-1),displayRegisters(registerStates.length-1),displayMemory(memoryStates.length-1),displayCycleData(cycleData.length),setDownloadLink(),$("#nextStepBtn").attr("disabled","disabled"),$("#prevStepBtn").removeAttr("disabled"),$("html, body").animate({scrollTop:$("#simulationResultsContainer").offset().top-20},500)}function displayInstructions(e){$("#simulationInstructions").html("");for(var t=0;t<decodedCode.length;t++)t==e?$("#simulationInstructions").append("<tr><td>&rarr;</td><td>"+decodedCode[t]+"</td></tr>"):$("#simulationInstructions").append("<tr><td></td><td>"+decodedCode[t]+"</td></tr>")}function displayRegisters(e){for(var t in $("#simulationRegisters").html(""),registerStates[e])registerStates[e][t]&&$("#simulationRegisters").append("<tr><td>R"+t+"</td><td>"+registerStates[e][t]+"</td></tr>")}function displayMemory(e){for(var t in $("#simulationMemory").html(""),memoryStates[e])memoryStates[e][t]&&$("#simulationMemory").append("<tr><td>"+t+"</td><td>"+memoryStates[e][t]+"</td></tr>")}function displayCycleData(e){$("#simulationCycleNumber").html(""),$("#simulationCycleData").html(""),$("#clockCycleTitle").attr("colspan",cycleCounter);for(var t=1;t<cycleCounter;t++)$("#simulationCycleNumber").append("<td>"+t+"</td>");for(t=0;t<e;t++){$("#simulationCycleData").append("<tr>");for(var r=1;r<cycleCounter;r++)r<cycleData[t].length&&cycleData[t][r]?$("#simulationCycleData").append("<td>"+cycleData[t][r]+"</td>"):$("#simulationCycleData").append("<td></td>");$("#simulationCycleData").append("</tr>")}}function simulate(){for(registerStates.push(Object.assign({},registers)),memoryStates.push(Object.assign({},memory));pcCounter<instructions.length;){var e=decodeAndExecute(instructionFetch());e?(previousExecutionResult=e,writeMemory(e),writeBack(e),pcCounter++,cycleCounter-=4):previousExecutionResult=null}cycleCounter+=4}function instructionFetch(){return cycleData.push([]),cycleData[pcCounter][cycleCounter]="I"+(pcCounter+1)+"-IF",cycleCounter++,instructions[pcCounter]}function decodeAndExecute(e){if(previousExecutionResult&&(stall(previousExecutionResult.stallAmount),previousExecutionResult.shouldBranch))return pcCounter+=previousExecutionResult.branchOffset,cycleCounter++,memoryStates.push(Object.assign({},memoryStates[memoryStates.length-1])),void registerStates.push(Object.assign({},registerStates[registerStates.length-1]));cycleData[pcCounter][cycleCounter]="I"+(pcCounter+1)+"-ID",cycleCounter++;var t=findInstruction(e,ACTIONS.EXECUTE);return cycleData[pcCounter][cycleCounter]="I"+(pcCounter+1)+"-EX",cycleCounter++,t}function writeMemory(e){if(e.memoryState){var t=Object.assign({},memory),r=e.memoryState.memoryLocation,n=e.memoryState.value;t[r]=n,memoryStates.push(t),memory[r]=n}else memoryStates.push(Object.assign({},memoryStates[memoryStates.length-1]));cycleData[pcCounter][cycleCounter]="I"+(pcCounter+1)+"-MEM",cycleCounter++}function writeBack(e){if(e.registerState){var t=Object.assign({},registers),r=e.registerState.register,n=e.registerState.value;t[r]=n,registerStates.push(t),registers[r]=n}else registerStates.push(Object.assign({},registerStates[registerStates.length-1]));cycleData[pcCounter][cycleCounter]="I"+(pcCounter+1)+"-WB",cycleCounter++}function stall(e){for(var t=0;t<e;t++)cycleData[pcCounter][cycleCounter]="I"+(pcCounter+1)+"-stall",cycleCounter++}function simulationReset(){0!=registerStates.length&&(registers=registerStates[0]),0!=memoryStates.length&&(memory=memoryStates[0]),registerStates=[],memoryStates=[],cycleData=[],currentStep=0,pcCounter=0,cycleCounter=1,previousExecutionResult=null}function setDownloadLink(){for(var e="",t=1;t<cycleCounter;t++){e+="c#"+t;for(var r=0;r<cycleData.length;r++)cycleData[r][t]&&(e+=" "+cycleData[r][t]);e+="\n"}for(var n in e+="REGISTERS\n",registerStates[registerStates.length-1])0!=registerStates[registerStates.length-1][n]&&(e+="R"+n+" "+registerStates[registerStates.length-1][n]+"\n");for(var n in e+="MEMORY\n",memoryStates[memoryStates.length-1])0!=memoryStates[memoryStates.length-1][n]&&(e+=n+" "+memoryStates[memoryStates.length-1][n]+"\n");var s="data:application/octet-stream;charset=utf-8;base64,"+btoa(e);$("#downloadLink").attr("href",s)}function uintToInt(e,t){return e<<=32-(t=+t||32),e>>=32-t}Array.prototype.removeEmptyElements=function(){for(var e=[],t=0;t<this.length;t++)this[t].isNullOrEmpty()||e.push(this[t]);return e},String.prototype.isNullOrEmpty=function(){return!this||/^\s*$/.test(this)};
diff --git a/js/simulate.js b/js/simulate.js
index bb058e0..4509407 100644
--- a/js/simulate.js
+++ b/js/simulate.js
@@ -9,6 +9,8 @@ var pcCounter = 0;
 var cycleCounter = 1;
 
 var previousExecutionResult;
+var secondPreviousResult;
+var didPreviousStall = false;
 
 // Initiate the step through. Get simulation data, then show
 // it starting with the initial conditions. Disable previous
@@ -249,6 +251,9 @@ function simulate() {
 		var executionResult = decodeAndExecute(instruction);
 
 		if(executionResult) {
+
+			secondPreviousResult = previousExecutionResult;
+
 			previousExecutionResult = executionResult;
 
 			writeMemory(executionResult);
@@ -257,7 +262,7 @@ function simulate() {
 
 			pcCounter++;
 
-			cycleCounter = cycleCounter - 4;
+			cycleCounter -= 4;
 		}
 		else {
 			previousExecutionResult = null;
@@ -278,7 +283,10 @@ function simulate() {
 //	String of 32-bit binary instruction corresponding to pcCounter
 function instructionFetch() {
 
-	cycleData.push([]);
+	while(!cycleData[pcCounter]) {
+		cycleData.push([]);
+	}
+
 	cycleData[pcCounter][cycleCounter] = "I" + (pcCounter + 1) + "-IF";
 	cycleCounter++;
 
@@ -297,8 +305,27 @@ function instructionFetch() {
 // 	case of previousExecutionResult being a branch
 function decodeAndExecute(instructionBinary) {
 
+	var shouldStall = false;
+	var stallLocations = findInstruction(instructionBinary, ACTIONS.SHOULD_STALL);
+
 	if(previousExecutionResult) {
-		stall(previousExecutionResult.stallAmount);
+
+		if(previousExecutionResult.stallLocation) {		
+
+			for(var i = 0; i < stallLocations.length; i++) {
+				if(stallLocations[i] == previousExecutionResult.stallLocation) {
+					shouldStall = true;
+				}
+			}
+
+			if(shouldStall) {
+				stall(previousExecutionResult.stallAmount);
+				didPreviousStall = true;
+			}
+			else {
+				didPreviousStall = false;
+			}
+		}
 
 		if(previousExecutionResult.shouldBranch) {
 			pcCounter += previousExecutionResult.branchOffset;
@@ -309,6 +336,26 @@ function decodeAndExecute(instructionBinary) {
 
 			return;
 		}
+
+	}
+
+	if(secondPreviousResult && !didPreviousStall) {
+
+		if(secondPreviousResult.stallLocation) {
+
+			var shouldStallSecond = false;
+
+			for(var i = 0; i < stallLocations.length; i++) {
+				if(stallLocations[i] == secondPreviousResult.stallLocation) {
+					shouldStallSecond = true;
+				}
+			}
+
+			if(shouldStallSecond) {
+				stall(secondPreviousResult.stallAmount - 1);
+			}
+
+		}
 	}
 
 	cycleData[pcCounter][cycleCounter] = "I" + (pcCounter + 1) + "-ID";
diff --git a/sampleinputs/sample_1.txt b/sampleinputs/sample_1.txt
index fb965e2..3c2ca3a 100644
--- a/sampleinputs/sample_1.txt
+++ b/sampleinputs/sample_1.txt
@@ -9,6 +9,6 @@ CODE
 10001100001000100000000000000000
 00000000010000110010000000100000
 10101100001001000000000000000000
-00010100000001000000000000000001
+00010100000001000000000000000010
 00100000010000011111111111110111
 00000000001000110000100000100000
diff --git a/sampleinputs/sample_3.txt b/sampleinputs/sample_3.txt
new file mode 100644
index 0000000..1c4636d
--- /dev/null
+++ b/sampleinputs/sample_3.txt
@@ -0,0 +1,12 @@
+// This sample demonstrates a data hazard stall
+
+// add r3, r1, r2
+// add r4, r3, r2
+
+REGISTERS
+R1 10
+R2 20
+
+CODE
+0000 0000 0010 0010 0001 1000 0010 0000
+0000 0000 0110 0010 0010 0000 0010 0000
\ No newline at end of file
diff --git a/sampleinputs/sample_4.txt b/sampleinputs/sample_4.txt
new file mode 100644
index 0000000..1352ea6
--- /dev/null
+++ b/sampleinputs/sample_4.txt
@@ -0,0 +1,16 @@
+// This sample should not stall
+
+// add rd, rs, rt
+// rd = rs + rt
+// 0000 00ss ssst tttt dddd d000 0010 0000
+
+// add r3, r1, r2
+// add r4, r1, r2
+
+REGISTERS
+R1 10
+R2 20
+
+CODE
+0000 0000 0010 0010 0001 1000 0010 0000
+0000 0000 0010 0010 0010 0000 0010 0000
\ No newline at end of file
diff --git a/sampleinputs/sample_5.txt b/sampleinputs/sample_5.txt
new file mode 100644
index 0000000..48fe36d
--- /dev/null
+++ b/sampleinputs/sample_5.txt
@@ -0,0 +1,29 @@
+// lw rt, offset(rs)
+// rt = MEM[rs + offset]
+// 1000 11ss ssst tttt iiii iiii iiii iiii
+
+// addi rs, rt, imm
+// rt = rs + imm
+// 0010 00ss ssst tttt iiii iiii iiii iiii
+
+// bne rs, rt, offset
+// if(rs != rt) advance pc offset << 2
+// 0001 01ss ssst tttt iiii iiii iiii iiii
+
+//LW R2, 0(R1)
+//ADDI R5, R2, 1
+//BNE R5, R1, 2
+
+REGISTERS
+R1 4
+
+MEMORY
+M4 12
+
+CODE
+1000 1100 0010 0010 0000 0000 0000 0000
+0010 0000 0100 0101 0000 0000 0000 0001
+0001 0100 1010 0001 0000 0000 0000 0010
+0010 0000 0100 0101 0000 0000 0000 0001
+0010 0000 0100 0101 0000 0000 0000 0001
+0010 0000 0100 0101 0000 0000 0000 0001
\ No newline at end of file