/****************************************************** * CALL: bool ok = addrIdxToUpdate(Bit12, out byte); * TASK: Handles indexing of STORE, CALL and RETURN * instructions. *****************************************************/ public bool addrIdxToUpdate(Bit12 command, out byte idx) { byte val = (byte)extractVal(command.value()); Operations opr = Operations.LOAD; if (!extractOperation(command.value(), out opr)) { idx = 0; return(false); } switch (opr) { case Operations.STORE: { idx = (byte)(val); return(true); } case Operations.CALL: { idx = (byte)(255 - _memoryStack.size()); return(true); } case Operations.RETURN: { idx = (byte)(255 - _memoryStack.size() - 1); return(true); } default: { idx = 0; return(false); } } }
/****************************************************** * CALL: programTick(); * TASK: Progresses the execution of the program * one instruction. *****************************************************/ private void programTick() { Bit12 currentAddr = _assemblerModel.getAddr(_assemblerModel.instructionPtr()); Operations opr; byte val = (byte)_assemblerModel.extractVal(currentAddr.value()); _assemblerModel.extractOperation(currentAddr.value(), out opr); if (opr == Operations.RETURN && _assemblerModel.stack().size() == 0) { errorCode("Attempted Return on an empty stack."); pauseProgram(); return; } if (!_assemblerModel.processCurrentAddr()) { errorCode("Invalid operation."); pauseProgram(); return; } // Mark current row markRow(getMMRowOfPosition(255 - _assemblerModel.instructionPtr())); // Update graphics of changed memory byte index; if (_assemblerModel.addrIdxToUpdate(currentAddr, out index)) { if (opr != Operations.STORE) { index++; } MemoryRow row = getMMRowOfPosition(255 - index); row.ShowMemoryAdress(_assemblerModel.getAddr(index)); if (index > 250) { MemoryRow stackRow = getStackRowOfPosition(255 - index); stackRow.ShowMemoryAdress(_assemblerModel.getAddr(index)); } } ValueRow_WorkingRegister.ShowMemoryAdress(_assemblerModel.workingRegister()); ValueRow_Output.ShowMemoryAdress(_assemblerModel.output()); ValueRow_InstructionPointer.ShowMemoryAdress(new Bit12(_assemblerModel.instructionPtr())); //First bit on output sets the light lightIfOutputIsOn(); }
/****************************************************** * CALL: Clicking the step back button. * TASK: Rolls back the program one step i.e. undo the * previous operation. *****************************************************/ private void Button_StepBack_Click(object sender, RoutedEventArgs e) { if (_runTimer.IsEnabled) { errorCode("Cannot undo while running the application."); return; } if (_assemblerModel.undoStack().size() == 0) { errorCode("Nothing to undo."); return; } if (_assemblerModel.undoStack().size() == 1) { Keyboard.ClearFocus(); _currentTextBox.Foreground = (Brush)FindResource("TextBoxForegroundOff"); clearUserMsg(); _currentTextBox.IsReadOnly = false; showButtonAsEnabled(ButtonType.Stop); } UndoStorage undoValues = _assemblerModel.undo(); Bit12 currentAddr = _assemblerModel.getAddr(_assemblerModel.instructionPtr()); Operations opr = Operations.LOAD; _assemblerModel.extractOperation(currentAddr.value(), out opr); // Mark current row markRow(getMMRowOfPosition(255 - _assemblerModel.instructionPtr())); // Update graphics of changed memory byte index; if (_assemblerModel.addrIdxToUpdate(currentAddr, out index)) { if (opr == Operations.RETURN) { index += 2; } MemoryRow row = getMMRowOfPosition(255 - index); row.ShowMemoryAdress(_assemblerModel.getAddr(index)); if (index > 250) { MemoryRow stackRow = getStackRowOfPosition(255 - index); stackRow.ShowMemoryAdress(_assemblerModel.getAddr(index)); } } ValueRow_WorkingRegister.ShowMemoryAdress(_assemblerModel.workingRegister()); ValueRow_Output.ShowMemoryAdress(_assemblerModel.output()); lightIfOutputIsOn(); ValueRow_InstructionPointer.ShowMemoryAdress(new Bit12(_assemblerModel.instructionPtr())); }
/****************************************************** * CALL: bool ok = machineToAssembly(Bit12, out string); * TASK: Returns true if conversion from machine code * to assembly code was done successfully. * NOTE: Returns false if the inputted Bit12 doesn't * contain any (or unapproved) assembly instruction. *****************************************************/ public bool machineToAssembly(Bit12 bits, out string assemblyCode) { Operations opr; if (!extractOperation(bits.value(), out opr)) { assemblyCode = ""; return(false); } assemblyCode = opr.ToString(); // Special case if (assemblyCode == "IN" || assemblyCode == "OUT" || assemblyCode == "RETURN") { return(true); } // Otherwise read the value aswell byte addr = extractVal(bits.value()); assemblyCode += " " + addr; return(true); }
/****************************************************** * CALL: ShowMemoryAdress(); * TASK: Prints a row of ones and zeros in the memory. *****************************************************/ public void ShowMemoryAdress(Bit12 val) { UniformGrid memoryGrid = this.BinaryMemoryAdress as UniformGrid; string str = Convert.ToString(val.value(), 2).PadLeft(12, '0'); if (str.Length > 12) { str = str.Substring(str.Length - 12); } for (int i = 0; i < str.Length && i < memoryGrid.Children.Count; i++) { Label lab = memoryGrid.Children[i] as Label; if (str[i] == '0' || str[i] == '1') { lab.Content = str[i]; } } }
/****************************************************** * CALL: processCurrentAddr(); * TASK: Interprets the current address and runs the * corresponding function. *****************************************************/ public bool processCurrentAddr() { Bit12 current = _memory[_instructionPtr]; Operations opr = Operations.LOAD; byte addr = (byte)extractVal(current.value()); if (!extractOperation(current.value(), out opr)) { return(false); } _undoStack.push(new UndoStorage(_memory, _memoryStack, _instructionPtr, _workingRegister, _input, _output)); switch (opr) { case Operations.LOAD: { _workingRegister = _memory[addr]; _instructionPtr = (byte)(++_instructionPtr % _size); } break; case Operations.STORE: { _memory[addr] = _workingRegister; _instructionPtr = (byte)(++_instructionPtr % _size); } break; case Operations.ADD: { _workingRegister += _memory[addr]; _instructionPtr = (byte)(++_instructionPtr % _size); } break; case Operations.SUB: { _workingRegister -= _memory[addr]; _instructionPtr = (byte)(++_instructionPtr % _size); } break; case Operations.MUL: { _workingRegister *= _memory[addr]; _instructionPtr = (byte)(++_instructionPtr % _size); } break; case Operations.JUMP: { _instructionPtr = addr; } break; case Operations.PJUMP: { if (_workingRegister > new Bit12(0)) { _instructionPtr = addr; } else { _instructionPtr++; } } break; case Operations.IN: { _workingRegister = _input; _instructionPtr = (byte)(++_instructionPtr % _size); } break; case Operations.OUT: { _output = _workingRegister; _instructionPtr = (byte)(++_instructionPtr % _size); } break; case Operations.CALL: { _instructionPtr++; _memoryStack.push(new Bit12(_instructionPtr)); _instructionPtr = addr; } break; case Operations.RETURN: { _instructionPtr = (byte)_memoryStack.top().value(); _memoryStack.pop(); } break; } return(true); }
/****************************************************** * CALL: bool ok = assemblyToMachine(string, out Bit12); * TASK: Converts the inputted assembly string to Bit12 * machine code. *****************************************************/ public bool assemblyToMachine(string assemblyString, out Bit12 machineCode) { if (isBinary(assemblyString) && assemblyString.Length == 12) { machineCode = new Bit12(0); return(false); } string label = ""; if (containsLabel(assemblyString, out label) == LabelStatus.Success) { label = ":" + label; assemblyString = assemblyString.Replace(label, ""); if (assemblyString.Length != 0) { assemblyString = assemblyString.TrimStart(' '); } } // Empty lines to create space are fine if (assemblyString == "\r\n" || assemblyString == "\r" || assemblyString == "\n" || string.IsNullOrWhiteSpace(assemblyString)) { machineCode = new Bit12(0); return(true); } char[] trimChars = new char[3] { '\r', '\n', ' ' }; assemblyString = assemblyString.TrimEnd(trimChars); string[] splitString = assemblyString.Split(' '); // Special case where length is 1 and is a constant(number) if (splitString.Length == 1) { short val = 0; if (short.TryParse(splitString[0], out val)) { if (val < -2048 || val > 2047) { machineCode = new Bit12(0); return(false); } machineCode = new Bit12(val); return(true); } } Operations opr = Operations.LOAD; byte addr = 0; label = ""; if (splitString.Length == 2 && Enum.TryParse(splitString[0], false, out opr) && (byte.TryParse(splitString[1], out addr) || referencesLabel(assemblyString, out label)) && !(splitString[0] == "IN" || splitString[0] == "OUT" || splitString[0] == "RETURN")) { if (label.Length > 0) { addr = _labels[label]; } machineCode = new Bit12((short)opr); machineCode = new Bit12((short)(machineCode.value() << Constants.StartOprBit)); machineCode += new Bit12(addr); return(true); } if (splitString.Length == 1 && (splitString[0] == "IN" || splitString[0] == "OUT" || splitString[0] == "RETURN") && Enum.TryParse(splitString[0], false, out opr)) { machineCode = new Bit12((short)((short)opr << Constants.StartOprBit)); return(true); } machineCode = new Bit12(0); return(false); }