Example #1
0
    def pushUal(self,
                lineNumber: int,
                label: Optional[Label],
                operator: str,
                destination: int,
                regOperands: Tuple[int, ...],
                littOperand: Optional[Litteral] = None) -> None:
        """
        Ajoute une commande de calcul UAL dans l'assembleur.

        :param lineNumber: numéro de la ligne d'origine
        :type lineNumber: int
        :param label: label de l'instruction
        :type label: Optional[Label]
        :param destination: registre destination
        :type destination: int
        :param operator: opérateur
        :type operator: string
        :param regOperands: opérandes de type registre
        :type regOperands: tuple[int]
        :param littOperand: opérande de type littéral
        :type littOperand: Optional[Litteral]
        """
        for ope in regOperands:
            assert isinstance(ope, int)
        if destination != 0 and not self.__engine.ualOutputIsFree():
            raise CompilationError(
                f"Calcul {operator} stocké dans le registre {destination}.",
                {"lineNumber": lineNumber})
        if self.__engine.ualOutputIsFree():
            regOperands = (destination, ) + regOperands
        if isinstance(littOperand, Litteral):
            opcode = self.__engine.getLitteralOpcode(operator)
            asmCommand = self.__engine.getLitteralAsmCommand(operator)
            if opcode != "" and asmCommand != "":
                maxSize = self.__engine.getLitteralMaxSizeIn(operator)
                if not littOperand.isBetween(0, maxSize):
                    raise CompilationError(
                        f"Litteral trop grand pour {operator}",
                        {"lineNumber": lineNumber})
                self.__lines.append(
                    AsmLine(lineNumber, label, opcode, asmCommand, regOperands,
                            littOperand))
                return
            raise CompilationError(
                f"Pas de commande pour {operator} avec litteral dans le modèle de processeur",
                {"lineNumber": lineNumber})
        opcode = self.__engine.getOpcode(operator)
        asmCommand = self.__engine.getAsmCommand(operator)
        if asmCommand == "" or opcode == "":
            raise AttributesError(
                f"Pas de commande pour {operator} dans le modèle de processeur.",
                {"lineNumber": lineNumber})
        self.__lines.append(
            AsmLine(lineNumber, label, opcode, asmCommand, regOperands, None))
Example #2
0
    def pushStore(self, lineNumber: int, label: Optional[Label], source: int,
                  destination: Variable) -> None:
        """
        Ajoute une commande STORE dans l'assembleur.

        Réserve l'espace mémoire pour la variable.

        :param lineNumber: numéro de la ligne d'origine
        :type lineNumber: int
        :param label: label de l'instruction
        :type label: Optional[Label]
        :param source: registre source
        :type source: int
        :param destination: variable destination
        :type destination: Variable
        """
        opcode = self.__engine.getOpcode("store")
        asmCommand = self.__engine.getAsmCommand("store")
        if asmCommand == "" or opcode == "":
            raise AttributesError(
                "Pas de commande pour store dans le modèle de processeur.",
                {"lineNumber": lineNumber})
        memoryItem = self.__pushMemory(destination)
        asmLine = AsmLine(lineNumber, label, opcode, asmCommand, (source, ),
                          memoryItem)
        self.__lines.append(asmLine)
Example #3
0
    def pushJump(self,
                 lineNumber: int,
                 label: Optional[Label],
                 cible: Label,
                 operator: Optional[str] = None) -> None:
        """
        Ajoute une commande JUMP, saut conditionnel ou non, dans l'assembleur.

        :param lineNumber: numéro de la ligne d'origine
        :type lineNumber: int
        :param label: label de l'instruction
        :type label: Optional[Label]
        :param cible: étiquette cible
        :type cible: Label
        :param operator: comparaison parmi <, <=, >=, >, ==, !=. None pour Jump inconditionnel
        :type operator: str / None
        """
        if operator == None:
            operator = "goto"
        assert operator in ("<", "<=", ">", ">=", "==", "!=", "goto")
        opcode = self.__engine.getOpcode(operator)
        asmCommand = self.__engine.getAsmCommand(operator)
        if asmCommand == "" or opcode == "":
            raise AttributesError(
                f"Pas de commande pour {operator} dans le modèle de processeur.",
                {"lineNumber": lineNumber})
        self.__lines.append(
            AsmLine(lineNumber, label, opcode, asmCommand, (), cible))
Example #4
0
    def pushCmp(self, lineNumber: int, label: Optional[Label], operand1: int,
                operand2: int) -> None:
        """
        Ajoute une commande CMP, comparaison, dans l'assembleur.

        :param lineNumber: numéro de la ligne d'origine
        :type lineNumber: int
        :param label: label de l'instruction
        :type label: Optional[Label]
        :param operand1: registre premier opérande
        :type operand1: int
        :param operand2: registre second opérande
        :type operand2: int

        .. note:: Une telle commande doit précéder l'utilisation d'un saut conditionnel.
        """
        assert isinstance(operand1, int)
        assert isinstance(operand2, int)
        opcode = self.__engine.getOpcode("cmp")
        asmCommand = self.__engine.getAsmCommand("cmp")
        if asmCommand == "" or opcode == "":
            raise AttributesError(
                "Pas de commande pour cmp dans le modèle de processeur.",
                {"lineNumber": lineNumber})
        self.__lines.append(
            AsmLine(lineNumber, label, opcode, asmCommand,
                    (operand1, operand2), None))
Example #5
0
    def pushMoveLitteral(self, lineNumber: int, label: Optional[Label],
                         source: Litteral, destination: int) -> None:
        """
        Ajoute une commande MOVE avec littéral dans l'assembleur.

        :param lineNumber: numéro de la ligne d'origine
        :type lineNumber: int
        :param label: label de l'instruction
        :type label: Optional[Label]
        :param destination: registre destination
        :type destination: int
        :param source: littéral source
        :type source: Litteral
        """
        assert isinstance(source, Litteral)
        opcode = self.__engine.getLitteralOpcode("move")
        asmCommand = self.__engine.getLitteralAsmCommand("move")
        if opcode != "" and asmCommand != "":
            maxSize = self.__engine.getLitteralMaxSizeIn("move")
            if source.isBetween(0, maxSize):
                self.__lines.append(
                    AsmLine(lineNumber, label, opcode, asmCommand,
                            (destination, ), source))
                return
        self.pushLoad(lineNumber, label, source, destination)
Example #6
0
    def pushLoad(self, lineNumber: int, label: Optional[Label],
                 source: Union[Variable, Litteral], destination: int) -> None:
        """
        Ajoute une commande LOAD dans l'assembleur.

        Réserve l'espace mémoire pour la source.

        :param lineNumber: numéro de la ligne d'origine
        :type lineNumber: int
        :param label: label de l'instruction
        :type label: Optional[Label]
        :param destination: registre destination
        :type destination: int
        :param source: variable ou littéral source
        :type source: Litteral / Variable
        """
        opcode = self.__engine.getOpcode("load")
        asmCommand = self.__engine.getAsmCommand("load")
        if asmCommand == "" or opcode == "":
            raise AttributesError(
                "Pas de commande pour load dans le modèle de processeur.",
                {"lineNumber": lineNumber})
        if not self.__engine.valueFitsInMemory(source.value, False):
            raise CompilationError(
                f"Valeur {source.value} trop grande pour le modèle de processeur.",
                {"lineNumber": lineNumber})
        memoryItem = self.__pushMemory(source)
        asmLine = AsmLine(lineNumber, label, opcode, asmCommand,
                          (destination, ), memoryItem)
        self.__lines.append(asmLine)
Example #7
0
    def pushHalt(self, label: Optional[Label]) -> None:
        """Ajoute une commande HALT, fin de programme, à l'assembleur.

        :param label: label de l'instruction
        :type label: Optional[Label]
        """
        opcode = self.__engine.getOpcode("halt")
        asmCommand = self.__engine.getAsmCommand("halt")
        if asmCommand == "" or opcode == "":
            raise AttributesError(
                "Pas de commande pour halt dans le modèle de processeur.")
        self.__lines.append(AsmLine(-1, label, opcode, asmCommand, (), None))
Example #8
0
    def pushPrint(self, lineNumber: int, source: int) -> None:
        """
        Ajoute une commande PRINT, affichage à l'écran, dans l'assembleur.

        :param lineNumber: numéro de la ligne d'origine
        :type lineNumber: int
        :param source: registre dont on doit afficher le contenu
        :type source: int
        """
        assert isinstance(source, int)
        opcode = self.__engine.getOpcode("print")
        asmCommand = self.__engine.getAsmCommand("print")
        if asmCommand == "" or opcode == "":
            raise AttributesError(
                "Pas de commande pour print dans le modèle de processeur.",
                {"lineNumber": lineNumber})
        self.__lines.append(
            AsmLine(lineNumber, None, opcode, asmCommand, (source, ), None))
Example #9
0
    def pushInput(self, lineNumber: int, label: Optional[Label],
                  destination: Variable) -> None:
        """
        Ajoute une commande INPUT, lecture entrée, dans l'assembleur.

        :param lineNumber: numéro de la ligne d'origine
        :type lineNumber: int
        :param label: label de l'instruction
        :type label: Optional[Label]
        :param destination: variable cible
        :type destination: Variable
        """
        assert isinstance(destination, Variable)
        opcode = self.__engine.getOpcode("input")
        asmCommand = self.__engine.getAsmCommand("input")
        if asmCommand == "" or opcode == "":
            raise AttributesError(
                "Pas de commande pour input dans le modèle de processeur.",
                {"lineNumber": lineNumber})
        self.__lines.append(
            AsmLine(lineNumber, label, opcode, asmCommand, (), destination))
Example #10
0
    def pushMove(self, lineNumber: int, label: Optional[Label], source: int,
                 destination: int) -> None:
        """
        Ajoute une commande MOVE dans l'assembleur

        :param lineNumber: numéro de la ligne d'origine
        :type lineNumber: int
        :param label: label de l'instruction
        :type label: Optional[Label]
        :param destination: registre destination
        :type destination: int
        :param source: registre source
        :type source: int
        """
        opcode = self.__engine.getOpcode("move")
        asmCommand = self.__engine.getAsmCommand("move")
        if asmCommand == "" or opcode == "":
            raise AttributesError(
                "Pas de commande pour move dans le modèle de processeur.",
                {"lineNumber": lineNumber})
        moveOperands = (destination, source)
        self.__lines.append(
            AsmLine(lineNumber, label, opcode, asmCommand, moveOperands, None))
Example #11
0
    def __formatBinaryLine(self, asmItem: AsmLine) -> str:
        """Calcul le code binaire correspondant à un ligne assembleur

        :return: code binaire
        :rtype: str
        :raises:CompilationError si item à coder ne convient pas
        """
        elements = asmItem.getElementsToCode()
        if len(elements) == 0:
            return ""
        regSize = self.__engine.regBits
        wordSize = self.__engine.dataBits
        binaryCode = ""
        for elem in elements:
            if isinstance(elem, int):
                # codage d'un registre
                binaryElem = self.__formatBinaryElement(elem, regSize)
                if binaryElem is None:
                    raise CompilationError(
                        f"{asmItem} -> Codage de r{elem} impossible !",
                        {"lineNumber": asmItem.lineNumber})
                else:
                    binaryCode += binaryElem
                continue
            if isinstance(elem, Litteral):
                # litteral
                litteralSize = asmItem.getLastOperandSize(wordSize, regSize)
                binaryElem = self.__formatBinaryElement(
                    elem.value, litteralSize)
                if binaryElem is None:
                    raise CompilationError(
                        f"{asmItem} -> Codage de {Litteral.value} impossible !",
                        {"lineNumber": asmItem.lineNumber})
                else:
                    binaryCode += binaryElem
                continue
            if isinstance(elem, Variable):
                # variable
                adresseVariableSize = asmItem.getLastOperandSize(
                    wordSize, regSize)
                adresseToCode = self.getMemAbsPos(elem)
                if isinstance(adresseToCode, int):
                    binaryElem = self.__formatBinaryElement(
                        adresseToCode, adresseVariableSize)
                    if binaryElem is None:
                        raise CompilationError(
                            f"{asmItem} -> Codage de l'adresse {elem}[{adresseToCode}] impossible !",
                            {"lineNumber": asmItem.lineNumber})
                    else:
                        binaryCode += binaryElem
                else:
                    raise CompilationError(
                        f"{asmItem} -> Variable {elem.name} introuvable !",
                        {"lineNumber": asmItem.lineNumber})
                continue
            if isinstance(elem, Label):
                # label
                adresseLabelSize = asmItem.getLastOperandSize(
                    wordSize, regSize)
                adresseToCode = self.getLineLabel(elem)
                if isinstance(adresseToCode, int):
                    binaryElem = self.__formatBinaryElement(
                        adresseToCode, adresseLabelSize)
                    if binaryElem is None:
                        raise CompilationError(
                            f"{asmItem} -> Codage du saut {elem}[{adresseToCode}] impossible !",
                            {"lineNumber": asmItem.lineNumber})
                    else:
                        binaryCode += binaryElem
                else:
                    raise CompilationError(
                        f"{asmItem} -> Label {elem} introuvable !",
                        {"lineNumber": asmItem.lineNumber})
                continue
            binaryCode += elem
        if len(binaryCode) > wordSize:
            raise CompilationError(
                f"{asmItem} -> {binaryCode} : code binaire trop long !",
                {"lineNumber": asmItem.lineNumber})
        unusedBits = wordSize - len(binaryCode)
        return binaryCode + "0" * unusedBits