def SFSTOR(self, hardware=False): """ This is a more complicated instruction. This instruction will compare the source value with the value located at the address contained in $A. If the resulting flags matches the source value is then copied at $A. Of importance, source register can't be $A. 2 possibilities: SFSTOR <FLAGS> imm SFSTOR <FLAGS> reg :return: The flags are affected by this instruction and can be used to check if the value has been copied """ sourceValue = 0 destinationPointer = 0 condition = self.ci.flags sfstorInstruction = self.ci # This will be saved back in the register at the end of the operation destinationPointer = self.eu.getRegisterValue(registerCode=REGISTER_A) if self.ci.sourceImmediate is None: sourceValue = self.eu.getRegisterValue( registerCode=self.ci.sourceRegister) else: sourceValue = self.ci.sourceImmediate # Now first step is to read the data widthAndDestination = 0b01000000 # width = 4, destination = reg A memrInstruction = Instruction(binaryInstruction=(0b00000001 << 8 * 5) | (widthAndDestination << 8 * 4) | destinationPointer, form=formDescription["InsWidthImmReg"]) self.executeInstruction(memrInstruction) # Second step is to compare the data cmpInstruction = Instruction(binaryInstruction=(0b01101000 << 8 * 5) | (sourceValue << 8 * 1) | REGISTER_A, form=formDescription["InsImmReg"]) # This will cause a modification of the live Flags register self.executeInstruction(cmpInstruction) # Need to make $A be the initial $A again self.eu.setRegisterValue(REGISTER_A, destinationPointer) # Flags after cmp instruction cmpFlags = self.eu.FLAGS # if this succeeds, we can move forward with the memory write # As strange as the next conditional looks, the second part is for # unconditional set detection. if ((condition & self.eu.FLAGS) > 0) or (condition == self.eu.FLAGS): memwInstruction = Instruction( binaryInstruction=(0b00000000 << 8 * 5) | (widthAndDestination << 8 * 4) | sourceValue, form=formDescription["InsWidthImmReg"]) self.executeInstruction(memwInstruction) self.ci = sfstorInstruction # Need to return the current FLAGS as these would be overwritten upon return of this method. return cmpFlags
def test_extractValueFromBinaryField(self): """ Validates good working of the _extractValueFromBinaryField method for Instruction _extractValueFromBinaryField(self, mask, field) """ ins = Instruction(0b10010000 << 8 * 1, formDescription["InsRegReg"]) self.assertEqual(0b10, ins._extractValueFromBinaryField(0b00011000, 0b11110111)) self.assertEqual(0b10, ins._extractValueFromBinaryField(0b00000011, 0b11111110)) self.assertEqual(0b00, ins._extractValueFromBinaryField(0b00000000, 0b11111110))
def test_extractValueFromBinaryField(self): """ Validates good working of the _extractValueFromBinaryField method for Instruction _extractValueFromBinaryField(self, mask, field) """ ins = Instruction(0b10010000 << 8 * 1, formDescription["InsRegReg"]) self.assertEqual( 0b10, ins._extractValueFromBinaryField(0b00011000, 0b11110111)) self.assertEqual( 0b10, ins._extractValueFromBinaryField(0b00000011, 0b11111110)) self.assertEqual( 0b00, ins._extractValueFromBinaryField(0b00000000, 0b11111110))
def INT(self, hardware=False): """ This method is a bit more complex. If interrupt are deactivated, simply return. Otherwise the correct interrupt handler address needs to be fetched from the interrupt vector. Also the return address needs to be pushed on the stack. Interrupt handler number is given either in a register or as an immediate value. 2 possibilities: INT sReg int sImm :param: bool, optional, hardware, This indicates if the interrupt has been hardware generated :return: """ sourceValue = 0 # Interrupts are deactivated by the execution unit when handling a hardware interrupt # Since the hardware interrupt reuse this code, a check needs to happen here in order # to allow interrupt execution if generated in hardware. if hardware or self.eu.IS != 0b0: intInstruction = self.ci if hardware: # If this is an hardware generated interrupt, we NEED to save the flags flags = self.eu.FLAGS pushInstruction = Instruction( binaryInstruction=(0b10000001 << 8 * 4) | flags, form=formDescription["InsImm"]) self.executeInstruction(pushInstruction, hardware=True) # Bring the correct instruction!!! self.ci = intInstruction if self.ci.sourceImmediate is None: sourceValue = self.eu.getRegisterValue(self.ci.sourceRegister) else: sourceValue = self.ci.sourceImmediate # At this moment, sourceValue hold the vector number # we need sourceValue * 4 since the system uses 32 bits pointers sourceValue *= 4 # Here, we read the vector data into source value sourceValue = self.eu.mioc.memoryReadAtAddressForLength( self.eu.IVR + sourceValue, 4) # Now int can be managed like a call callInstruction = Instruction( binaryInstruction=(0b10000010 << 8 * 4) | sourceValue, form=formDescription["InsImm"]) self.executeInstruction(callInstruction, hardware=True) self.ci = intInstruction return 0
def _fetchInstructionAtAddressUsingForm(self, address=MEMORY_START_AT, form=None): """ This will fetch the complete instruction information and build an instruction instance using the extracted data. The instruction instance is returned to calling method :param address: Address of the instruction that needs to be fetched :param form: The form of the instruction that requires fetching :return: An instance of the Instruction class """ instruction = None # First, we get the memory bits that we need! memorySlice = self._memoryArray.extractMemory(address, form["length"]) # Now, build a big number (as in real big) with the extracted memory binaryInstruction = 0 for mc in memorySlice: binaryInstruction <<= 8 binaryInstruction |= mc.executeValue() # Using executeValue makes sure we have execute permission # binaryInstruction is now a big number representing the instruction # Time to create the instruction using this big number! # Parsing of the details of the instruction will happen in the Instruction class instruction = Instruction(binaryInstruction, form) return instruction
def HIRET(self, hardware=False): """ This instruction is used to return from a hardware interrupt. It will reactivate the interrupts on the core, restore the flags and will then return. :param hardware: bool, optional, hardware, This indicates if the instruction executed was hardware generated :return: 0, this method does not affect the flags register """ currentInstruction = self.ci oldAValue = self.eu.A # First save the return address popInstruction = Instruction(binaryInstruction=(0b01110100 << 8) | REGISTER_A, form=formDescription["InsReg"]) self.executeInstruction(popInstruction, hardware=True) returnAddress = self.eu.A self.executeInstruction(popInstruction, hardware=True) flagsToBeRestored = self.eu.A self.eu.A = oldAValue self.eu.I = returnAddress self.ci = currentInstruction # This absolutely needs to happen last since the core plays with registers. Would that happen # before, there would be a big risk for the core to be in an inconsistent state. self.eu.interruptSignalLock.acquire() self.eu.IS = 0b1 self.eu.interruptSignalLock.release() # Flags are restored in the return value other wise it will be overwritten return flagsToBeRestored
def _parseCodeLine(self, line: list=None): """ This will parse an extracted line of code and build an instruction from that code line Parsing a line of code requires many steps. 1- Find the possible codes for the mnemonic from OperationDescription 2- Based on the possible codes and parts of the lines, find the correct form 3- Based on the form, build the instruction 4- Return the instruction If the instruction returned has a string as instruction mnemonic, this means that the instruction simply represent a label in the code. It will be removed from the final program. :param line: :return: """ lineInstruction = None buildInstruction = Instruction(skipValidation=True) # This is used as model in early instruction building finalCode = 0x00 form = None possibleCodes = None self._evaluateAndExtractInfoFromLine(line, buildInstruction) if type(buildInstruction.instructionCode) is not str: # Instruction is real not just memory address or comment possibleCodes = self._findPossibleCodesForInstruction(buildInstruction) instructionCode, instructionForm = self._getInstructionCodeAndFormUsingPossibleCodes(buildInstruction, possibleCodes) if instructionForm is None or instructionCode is None: raise ValueError("Assembler general error") else: buildInstruction.instructionCode = instructionCode buildInstruction.instructionLength = formDescription[instructionForm]["length"] lineInstruction = self._generateBinaryInstructionFromInstruction(buildInstruction, formDescription[instructionForm]) else: if COMMENT_INDICATORS in buildInstruction.instructionCode: # Simply ignore a comment line buildInstruction = None lineInstruction = None elif DATA_ALPHA_INDICATOR in buildInstruction.instructionCode: # This is a bunch of alpha data lineInstruction = buildInstruction.sourceImmediate buildInstruction.instructionCode = 0 # Calling code expect this to be non STR for non mem ref elif DATA_NUMERIC_INDICATOR in buildInstruction.instructionCode: # This is a numeric data field lineInstruction = struct.pack(">I", buildInstruction.sourceImmediate) buildInstruction.instructionCode = 0 # Calling code expect this to be non STR for non mem ref elif DATA_MEMORY_REFERENCE in buildInstruction.instructionCode: lineInstruction = buildInstruction.sourceImmediate buildInstruction.instructionCode = 0 else: lineInstruction = None return buildInstruction, lineInstruction
def _handleHardwareInterrupt(self): """ This will handle an hardwareInterrupt. It will deactivate the interrupts on a given core and attempt at jumping into the code handling the latest successfully signaled interrupt. :return: Nothing """ self.interruptSignalLock.acquire() self.IS = 0 # Interrupts are now deactivated across the core intInstruction = Instruction(binaryInstruction=(0b10000011 << 8 * 4) | self._interruptSignal, form=formDescription["InsImm"]) self.lu.executeInstruction(instruction=intInstruction, hardware=True) self._interruptSignal = None # Interrupt has been handled, we need to reset this self.interruptSignalLock.release()
def _parseCodeLine(self, line: list=None, rawLine: str=None): """ This will parse an extracted line of code and build an instruction from that code line Parsing a line of code requires many steps. 1- Find the possible codes for the mnemonic from OperationDescription 2- Based on the possible codes and parts of the lines, find the correct form 3- Based on the form, build the instruction 4- Return the instruction If the instruction returned has a string as instruction mnemonic, this means that the instruction simply represent a label in the code. It will be removed from the final program. :param line: line split into individual arguments :param rawLine: raw line as we originally read it from the file, used to preserve spaces in .dataAlpha fields :return: The instruction object with all info about arguments, and the line's binary instruction """ lineInstruction = None buildInstruction = Instruction(skipValidation=True) # This is used as a model in early instruction building finalCode = 0x00 form = None possibleCodes = None # We evaluate the line and extract any bits of relevant info to build the appropriate instruction self._evaluateAndExtractInfoFromLine(line, buildInstruction, rawLine) if type(buildInstruction.instructionCode) is not str: # We assume it's an instruction (integer), since memory references or comments would be strings # Parser will verify all possible codes, and generate the appropriate instruction based on its form possibleCodes = self._findPossibleCodesForInstruction(buildInstruction) instructionCode, instructionForm = self._getInstructionCodeAndFormUsingPossibleCodes(buildInstruction, possibleCodes) if instructionForm is None or instructionCode is None: raise ValueError("Assembler general error") else: # Code is valid, fetch the instruction's form based on the arguments, then generate the instruction buildInstruction.instructionCode = instructionCode buildInstruction.instructionLength = formDescription[instructionForm]["length"] lineInstruction = self._generateBinaryInstructionFromInstruction(buildInstruction, formDescription[instructionForm]) else: # In this case, there were no instructions. Thus, we look at other possibilities if COMMENT_INDICATORS in buildInstruction.instructionCode: # Simply ignore a comment line buildInstruction = None lineInstruction = None # In these next cases, we can treat them as "data" variables with no real instructions. # We store the data as the instruction's source immediate value, and set instruction code to 0 elif DATA_ALPHA_INDICATOR in buildInstruction.instructionCode: # This is a bunch of alpha data (String) lineInstruction = buildInstruction.sourceImmediate buildInstruction.instructionCode = 0 elif DATA_NUMERIC_INDICATOR in buildInstruction.instructionCode: # This is a numeric data field (Integer) lineInstruction = struct.pack(">I", buildInstruction.sourceImmediate) buildInstruction.instructionCode = 0 elif DATA_MEMORY_REFERENCE in buildInstruction.instructionCode: # This is a data memory reference (dataMemref) lineInstruction = buildInstruction.sourceImmediate buildInstruction.instructionCode = 0 else: # Having exhausted all options, we assume there was nothing else on this line. lineInstruction = None return buildInstruction, lineInstruction
def test_init(self): """ Validates good working of the __init__ method for Instruction __init__(self, binaryInstruction=0b000000, form=None) """ ins = Instruction(0b11111111, formDescription["Ins"]) self.assertIsNotNone(ins.instructionCode) self.assertIsNone(ins.sourceRegister) self.assertIsNone(ins.destinationRegister) self.assertIsNone(ins.sourceImmediate) self.assertIsNone(ins.destinationImmediate) self.assertIsNone(ins.width) self.assertIsNone(ins.flags) self.assertEqual(ins.instructionLength, 1) self.assertEqual(ins.operationMnemonic, "NOP") ins = Instruction(0b01110000 << 8 * 1, formDescription["InsReg"]) self.assertIsNotNone(ins.instructionCode) self.assertIsNotNone(ins.sourceRegister) self.assertIsNone(ins.destinationRegister) self.assertIsNone(ins.sourceImmediate) self.assertIsNone(ins.destinationImmediate) self.assertIsNone(ins.width) self.assertIsNone(ins.flags) self.assertEqual(ins.instructionLength, 2) self.assertEqual(ins.operationMnemonic, "NOT") ins = Instruction(0b10000000 << 8 * 4, formDescription["InsImm"]) self.assertIsNotNone(ins.instructionCode) self.assertIsNone(ins.sourceRegister) self.assertIsNone(ins.destinationRegister) self.assertIsNotNone(ins.sourceImmediate) self.assertIsNone(ins.destinationImmediate) self.assertIsNone(ins.width) self.assertIsNone(ins.flags) self.assertEqual(ins.instructionLength, 5) self.assertEqual(ins.operationMnemonic, "SNT") ins = Instruction(0b01100000 << 8 * 5, formDescription["InsImmReg"]) self.assertIsNotNone(ins.instructionCode) self.assertIsNone(ins.sourceRegister) self.assertIsNotNone(ins.destinationRegister) self.assertIsNotNone(ins.sourceImmediate) self.assertIsNone(ins.destinationImmediate) self.assertIsNone(ins.width) self.assertIsNone(ins.flags) self.assertEqual(ins.instructionLength, 6) self.assertEqual(ins.operationMnemonic, "MOV") ins = Instruction(0b00000000 << 8 * 5, formDescription["InsWidthImmReg"]) self.assertIsNotNone(ins.instructionCode) self.assertIsNone(ins.sourceRegister) self.assertIsNotNone(ins.destinationRegister) self.assertIsNotNone(ins.sourceImmediate) self.assertIsNone(ins.destinationImmediate) self.assertIsNotNone(ins.width) self.assertIsNone(ins.flags) self.assertEqual(ins.instructionLength, 6) self.assertEqual(ins.operationMnemonic, "MEMW") ins = Instruction(0b00010000 << 16 * 1, formDescription["InsWidthRegReg"]) self.assertIsNotNone(ins.instructionCode) self.assertIsNotNone(ins.sourceRegister) self.assertIsNotNone(ins.destinationRegister) self.assertIsNone(ins.sourceImmediate) self.assertIsNone(ins.destinationImmediate) self.assertIsNotNone(ins.width) self.assertIsNone(ins.flags) self.assertEqual(ins.instructionLength, 3) self.assertEqual(ins.operationMnemonic, "MEMR") ins = Instruction(0b00100000 << 8 * 5, formDescription["InsWidthRegImm"]) self.assertIsNotNone(ins.instructionCode) self.assertIsNotNone(ins.sourceRegister) self.assertIsNone(ins.destinationRegister) self.assertIsNone(ins.sourceImmediate) self.assertIsNotNone(ins.destinationImmediate) self.assertIsNotNone(ins.width) self.assertIsNone(ins.flags) self.assertEqual(ins.instructionLength, 6) self.assertEqual(ins.operationMnemonic, "MEMW") ins = Instruction(0b00110000 << 8 * 9, formDescription["InsWidthImmImm"]) self.assertIsNotNone(ins.instructionCode) self.assertIsNone(ins.sourceRegister) self.assertIsNone(ins.destinationRegister) self.assertIsNotNone(ins.sourceImmediate) self.assertIsNotNone(ins.destinationImmediate) self.assertIsNotNone(ins.width) self.assertIsNone(ins.flags) self.assertEqual(ins.instructionLength, 10) self.assertEqual(ins.operationMnemonic, "MEMW") ins = Instruction(0b01000000 << 8 * 5, formDescription["InsFlagImm"]) self.assertIsNotNone(ins.instructionCode) self.assertIsNone(ins.sourceRegister) self.assertIsNone(ins.destinationRegister) self.assertIsNotNone(ins.sourceImmediate) self.assertIsNone(ins.destinationImmediate) self.assertIsNone(ins.width) self.assertIsNotNone(ins.flags) self.assertEqual(ins.instructionLength, 6) self.assertEqual(ins.operationMnemonic, "JMPR") ins = Instruction(0b01010000 << 8 * 1, formDescription["InsFlagReg"]) self.assertIsNotNone(ins.instructionCode) self.assertIsNotNone(ins.sourceRegister) self.assertIsNone(ins.destinationRegister) self.assertIsNone(ins.sourceImmediate) self.assertIsNone(ins.destinationImmediate) self.assertIsNone(ins.width) self.assertIsNotNone(ins.flags) self.assertEqual(ins.instructionLength, 2) self.assertEqual(ins.operationMnemonic, "JMPR") ins = Instruction(0b10010000 << 8 * 1, formDescription["InsRegReg"]) self.assertIsNotNone(ins.instructionCode) self.assertIsNotNone(ins.sourceRegister) self.assertIsNotNone(ins.destinationRegister) self.assertIsNone(ins.sourceImmediate) self.assertIsNone(ins.destinationImmediate) self.assertIsNone(ins.width) self.assertIsNone(ins.flags) self.assertEqual(ins.instructionLength, 2) self.assertEqual(ins.operationMnemonic, "XOR") self.assertIsNotNone(Instruction(skipValidation=True))