private void followCode(TaskMonitor monitor, AddressSet flowAddressSet, CodeUnit codeUnit,
			Address dataAddr) {

		if (codeUnit == null) {
			return;
		}
		Stack<CodeUnit> instructionStack = new Stack<CodeUnit>();
		if (codeUnit instanceof Data) {
			followData(instructionStack, flowAddressSet, (Data) codeUnit, dataAddr);
		}
		else {
			instructionStack.push(codeUnit);
		}
		Address start_addr = codeUnit.getMinAddress();

		if (!followIntoFunction) {
			try {
				nextSymbolAddr = getNextSymbolAddress(start_addr.add(1), nextSymbolAddr);
			}
			catch (AddressOutOfBoundsException e) {
				nextSymbolAddr = null;
			}
		}
		
		// Delay adding instructions in delay slots to the functions body
		// until the end.  This allows for branches into the delay slot to be handled correctly.
		AddressSet delaySlotSet = new AddressSet();

		while (!monitor.isCancelled() && !instructionStack.isEmpty()) {

			codeUnit = instructionStack.pop();
			if (!(codeUnit instanceof Instruction)) {
				// Probably undefined data which should be disassembled
				if (includeData) {
					flowAddressSet.addRange(codeUnit.getMinAddress(), codeUnit.getMaxAddress());
				}
				continue;
			}

			Instruction currentInstr = (Instruction) codeUnit;
			Address currentAddress = currentInstr.getMinAddress();

			// Return if code unit already encountered
			if (flowAddressSet.contains(currentAddress)) {
				continue;
			}
  	
			Instruction instr = currentInstr;

			// handle instruction with delay slot instructions
			Address end = instr.getMaxAddress();
			int delaySlotDepth = instr.getDelaySlotDepth();
			for (int i = 0; i < delaySlotDepth; i++) {
				instr = instr.getNext();
				if (instr == null)
					break;
				delaySlotSet.add(instr.getMinAddress(),instr.getMaxAddress());
			}
			flowAddressSet.addRange(currentInstr.getMinAddress(), end);
			followInstruction(instructionStack, flowAddressSet, currentInstr);

		}
		
		// add in any instructions that were in a delayslot
		flowAddressSet.add(delaySlotSet);
	}
followCode follows the program's code unit (instruction or data) flow and
adds addresses to the address set for the flow from the current location.
The plugin's properties indicate which flow types should be followed for
instruction code units.
@param monitor a cancellable task monitor
@param flowAddressSet the address set to be added to
@param codeUnit the code unit to flow from.
    Appropriate flows out of this code unit will be traversed.
@param dataAddr null or the address to flow from within the currentCodeUnit for Data.
Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/block/FollowFlow.java