public AddressSetView addInstructions(InstructionSet instructionSet, boolean overwrite) {
		AddressSet set = new AddressSet();
		lock.acquire();
		creatingInstruction = true;
		try {

			HashSet<Address> skipDelaySlots = new HashSet<>();

			if (overwrite) {
				// Clear memory which corresponds to all code blocks.  No need to remove context
				// since this will happen when instruction is added
				for (AddressRange range : instructionSet.getAddressSet()) {
					clearCodeUnits(range.getMinAddress(), range.getMaxAddress(), false,
						TaskMonitor.DUMMY);
				}
			}
			else {
				// Check for conflicts with existing instructions, clear locations where 
				// delay-slots will be replacing non-delay slot.  The skipDelaySlots set will be 
				// filled-in with any existing delay slot locations which should not be overwritten
				checkInstructionSet(instructionSet, skipDelaySlots);
			}

			// Add instruction blocks to program listing
			for (InstructionBlock block : instructionSet) {

				InstructionError conflict = block.getInstructionConflict();
				Address errorAddr = null;
				CodeUnit conflictCodeUnit = null;
				if (conflict != null) {
					errorAddr = conflict.getInstructionAddress();
					if (errorAddr == null) {
						continue; // skip block if block error has no instruction address
					}
					if (conflict.getInstructionErrorType().isConflict) {
						conflictCodeUnit = getCodeUnitAt(conflict.getConflictAddress());
						if ((conflictCodeUnit instanceof Data) &&
							!((Data) conflictCodeUnit).isDefined()) {
							conflictCodeUnit = null; // undefined code unit
						}
					}
				}

				// Delay Slot Note: delay slot group is added in reverse order to ensure that pcode
				// can be generated for delay-slotted instruction immediately after it is created

				Instruction protoInstr;
				boolean deferDS;
				int count = 0;
				Instruction lastInstruction = null;
				Iterator<Instruction> instructionIterator = block.iterator();
				Stack<Instruction> delaySlotStack = null;
				while (delaySlotStack != null || instructionIterator.hasNext()) {

					if (delaySlotStack != null) {
						protoInstr = delaySlotStack.pop();
						deferDS = false;
						if (delaySlotStack.isEmpty()) {
							delaySlotStack = null;
						}
					}
					else {
						protoInstr = instructionIterator.next();
						deferDS = true;
					}

					InstructionPrototype prototype = protoInstr.getPrototype();
					Address startAddr = protoInstr.getMinAddress();
					Address endAddr = protoInstr.getMaxAddress();

					if (prototype.hasDelaySlots()) {
						// perform bounds check on entire delay slot instruction group
						try {
							int fallThruOffset =
								prototype.getFallThroughOffset(protoInstr.getInstructionContext());
							endAddr = startAddr.addNoWrap(fallThruOffset - 1);
						}
						catch (AddressOverflowException e) {
							break;
						}
					}

					if (conflictCodeUnit != null && (endAddr.compareTo(errorAddr) >= 0 &&
						startAddr.compareTo(conflictCodeUnit.getMaxAddress()) <= 0)) {
						if (errorAddr.compareTo(protoInstr.getMaxAddress()) > 0) {
							Address flowFromAddr =
								(lastInstruction != null) ? lastInstruction.getAddress()
										: block.getFlowFromAddress();
							block.setCodeUnitConflict(conflict.getConflictAddress(), startAddr,
								flowFromAddr, conflict.isInstructionConflict(), false);
						}
						break; // terminate block prior to adding conflicted code unit
					}

					// skip instruction if we are attempting to lay down a non-delay slot prototype
					// onto an existing delay slot instruction although we need to continue
					// processing subsequent instructions
					if (!skipDelaySlots.contains(startAddr)) {

						if (!program.getMemory().contains(startAddr, endAddr)) {
							block.setInstructionError(InstructionErrorType.MEMORY, startAddr,
								startAddr, null, "Not enough bytes available for instruction");
							break;
						}

						if (deferDS && prototype.hasDelaySlots()) {
							if (delaySlotStack != null) {
								throw new AssertException();
							}
							delaySlotStack = new Stack<>();
							delaySlotStack.push(protoInstr);
							int dsCount = protoInstr.getDelaySlotDepth();
							while (dsCount-- != 0 && instructionIterator.hasNext()) {
								Instruction dsProtoInstr = instructionIterator.next();
								if (!dsProtoInstr.isInDelaySlot()) {
									break; // throw new AssertException();
								}
								if (skipDelaySlots.contains(dsProtoInstr.getAddress())) {
									break;
								}
								delaySlotStack.push(dsProtoInstr);
							}
							continue; // process delaySlotStack
						}

						lastInstruction =
							addInstruction(startAddr, endAddr, prototype, protoInstr, protoInstr);

						++count;

						if (protoInstr.isFallThroughOverridden()) {
							// copy fall-through override
							lastInstruction.setFallThrough(protoInstr.getFallThrough());
						}

						FlowOverride flowOverride = protoInstr.getFlowOverride();
						if (flowOverride != FlowOverride.NONE) {
							lastInstruction.setFlowOverride(flowOverride);
						}

						try {
							if (protoInstr.isLengthOverridden()) {
								lastInstruction.setLengthOverride(protoInstr.getLength());
							}
						}
						catch (CodeUnitInsertionException e) {
							// unexpected - should have been caught previously
							throw new RuntimeException(e);
						}
					}

					if (errorAddr != null && conflictCodeUnit == null &&
						errorAddr.compareTo(startAddr) <= 0) {
						break; // skip remainder of block if disassembler conflict address encountered
					}
				}
				block.setInstructionsAddedCount(count);

				// fire event
				if (lastInstruction != null) {
					Address maxAddr = lastInstruction.getMaxAddress();
					InstructionPrototype prototype = lastInstruction.getPrototype();
					if (prototype.hasDelaySlots()) {
						try {
							int fallThruOffset = prototype
									.getFallThroughOffset(lastInstruction.getInstructionContext());
							maxAddr = lastInstruction.getAddress().addNoWrap(fallThruOffset - 1);
						}
						catch (AddressOverflowException e) {
							// ignore
						}
					}
					set.addRange(block.getStartAddress(), maxAddr);
					program.setChanged(ProgramEvent.CODE_ADDED, block.getStartAddress(), maxAddr,
						null, null);
				}
			}

		}
		catch (IOException e) {
			program.dbError(e);
		}
		catch (CancelledException e) {
			throw new AssertException(); // unexpected - no monitor
		}
		finally {
			creatingInstruction = false;
			lock.release();
		}
		return set;
	}
Creates a complete set of instructions.  A preliminary pass will be made checking for code 
unit conflicts which will be marked within the instructionSet causing dependent blocks to 
get pruned.
@param instructionSet the set of instructions to be added. All code unit conflicts will be
marked within the instructionSet and associated blocks.
@param overwrite if true, overwrites existing code units.
@return the set of addresses over which instructions were actually added to the program. 
This may differ from the InstructionSet address set if conflict errors occurred. Such 
conflict errors will be recorded within the InstructionSet and its InstructionBlocks.
Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/code/CodeManager.java