diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6a0dc8a --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +./**/test_strip.csv +./**/__pycache__ +unit_tests.py +tests/ diff --git a/Doc/Instructions.md b/Doc/Instructions.md new file mode 100644 index 0000000..3f6d794 --- /dev/null +++ b/Doc/Instructions.md @@ -0,0 +1,67 @@ +Instrucciones: + +En el diseño de las instrucciones se ha intentado mantener +libre los opcodes disponibles en la medida de lo posible para +posibilitar la introducción de nuevas instrucciónes en el futuro +haciendo los opcodes lo más largos posibles. + + D = Dirección + I = Inmediato + S = Bits de selección + R = Registro de lectura + W = Registro de escritura + +noop: 0000 00XX XXXX XXXX: No toma operandos + +jump: 0000 01DD DDDD DDDD: Salto a D + +jumpz: 0000 10DD DDDD DDDD: Salto a D si flag Zero = 1 + +nojumpz: 0000 11DD DDDD DDDD: Salto a D si flag Zero = 0 + +limm: 0001 IIII IIII WWWW: Cargar I en W + +jal: 0010 00DD DDDD DDDD: Salto a D guardando dir. retorno (PC + 1) + +ret: 0010 01XX XXXX XXXX: No toma operandos + +read: 0010 10SS XXXX WWWW: SS seleccionan el puerto de lectura + +write: 0010 11SS RRRR XXXX: SS seleccionan el puerto de escritura + +MOV: 1000 RRRR XXXX WWWW: Guarda R en W + +NEG: 1001 RRRR XXXX WWWW: Niega R y guarda en W + +ADD: 1010 RRRR RRRR WWWW: R1 + R2 -> W + +SUB: 1011 RRRR RRRR WWWW: R1 - R2 -> W + +AND: 1100 RRRR RRRR WWWW: R1 & R2 -> W + +OR: 1101 RRRR RRRR WWWW: R1 | R2 -> W + +SIGNA: 1110 RRRR XXXX WWWW: Cambia signo a R y guarda en W + +SIGNB: 1110 XXXX RRRR WWWW: Cambia signo a R y guarda en W + + +E/S: +La entrada salida se compone de un banco de cuatro registros para la +salida en el que se escriben los datos y cuatro puertos de entrada. +La salida se compone unicamente de varios multiplexores y wires. +No se han implementado escritura de inmediatos para no gastar opcodes +y por ser menos flexibles que la escritura desde registro. + +Timer: +El timer esta diseñado para tener una presición de 1ms al conectarse +a un relog de 24MHz. Es necesario pasarle un numero(8b) de ms que en +el caso de esta cpu se envia por el puerto 0 y permite generar señales +periódicas de entre 1ms y 250ms. + +Interrupciones: +La cpu permite 4 interrupciones externas que selecciónan una dirección +de memoria donde se deberá encontrar una subrutina que termine en una +instrucción ret que devuelva la ejecución del programa a su cauce normal. +Hasta que no implemente una pila para los JAL cualquier interrupción +sobrescribirá cualquier información presente en el registro de retorno. diff --git a/QTui/qtSCC/.gitignore b/QTui/qtSCC/.gitignore new file mode 100644 index 0000000..fab7372 --- /dev/null +++ b/QTui/qtSCC/.gitignore @@ -0,0 +1,73 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + diff --git a/QTui/qtSCC/bucle.csv b/QTui/qtSCC/bucle.csv new file mode 100644 index 0000000..b1ae83d --- /dev/null +++ b/QTui/qtSCC/bucle.csv @@ -0,0 +1,10 @@ +noop +limm 0 R1 +limm 1 R2 +limm 10 R3 +:for +add R1 R2 R1 +sub R3 R1 zero +jnz for +:end +jump end diff --git a/QTui/qtSCC/form.ui b/QTui/qtSCC/form.ui new file mode 100644 index 0000000..d488e97 --- /dev/null +++ b/QTui/qtSCC/form.ui @@ -0,0 +1,88 @@ + + + qtSCC + + + + 0 + 0 + 800 + 600 + + + + qtSCC + + + + + 10 + 10 + 781 + 581 + + + + + + + + + false + + + + + + + Search + + + + + + + Assemble + + + + + + + + + + + + + + + + true + + + + + + + + + + + + Save + + + + + + + + + + + + + + + diff --git a/QTui/qtSCC/main.py b/QTui/qtSCC/main.py new file mode 100755 index 0000000..2a474ad --- /dev/null +++ b/QTui/qtSCC/main.py @@ -0,0 +1,75 @@ +# This Python file uses the following encoding: utf-8 +import sys +import tempfile + +from PyQt5.QtGui import * +from PyQt5.QtWidgets import * +from PyQt5.QtCore import * + +from qtSCC import Ui_qtSCC +import os +sys.path.append(os.path.abspath('../../SCC')) +import SCCUtils + +class qtSCC(QMainWindow, Ui_qtSCC): + def __init__(self, *args, **kwargs): + super(qtSCC, self).__init__(*args, **kwargs) + self.setupUi(self) + self.virtual_file = tempfile.SpooledTemporaryFile(mode = "w+", encoding = "utf-8", dir = "/tmp/") + self.binaryCode = [] + self.translationQueue = [] + + self.SearchButton.clicked.connect(self.onSearchButtonClicked) + self.assembleButton.clicked.connect(self.onAssembleButtonClicked) + self.saveButton.clicked.connect(self.onSaveButtonClicked) + self.fileList.itemClicked.connect(self.onFileListItemClicked) + self.translateList.itemClicked.connect(self.onTranslateListItemClicked) + + self.show() + + def onSaveButtonClicked(self): + pass + # fileName = self.saveEdit.text() + # SCCUtils.writeList2File(fileName, self.binaryCode) + + def onAssembleButtonClicked(self): + for fileName in self.translationQueue: + binaryCode = self.assembleFile(fileName) + binFileName = fileName.split('.')[0]; + binFileName = binFileName + ".bin" + SCCUtils.writeList2File(binFileName, binaryCode) + self.translationQueue = []; + + def onSearchButtonClicked(self): + self.fileList.clear() + path = self.inputEdit.text() + path = QDir(path) + print(path.dirName()) + path.setFilter(QDir.Files) + contentsList = path.entryList() + for content in contentsList: + basePath = self.inputEdit.text() + filePath = os.path.join(basePath, content) + self.fileList.addItem(content) + + def onFileListItemClicked(self, item): + basePath = self.inputEdit.text() + filePath = os.path.join(basePath, item.text()) + self.translateList.addItem(item.text()) + self.translationQueue.append(filePath) + + def onTranslateListItemClicked(self, item): + self.translationQueue.remove(item.text()) + self.translateList.takeItem(self.translateList.currentRow()) + + def assembleFile(self, fileName): + with open(fileName, 'r') as inputFile: + SCCUtils.strip_input(self.virtual_file, inputFile) + SCCUtils.operateFile(self.virtual_file, SCCUtils.resolveDirections) + binaryCode = SCCUtils.operateFile(self.virtual_file, SCCUtils.translate) + return binaryCode + +if __name__ == "__main__": + app = QApplication([]) + window = qtSCC() + app.exec_() diff --git a/QTui/qtSCC/main.pyproject b/QTui/qtSCC/main.pyproject new file mode 100644 index 0000000..7d87836 --- /dev/null +++ b/QTui/qtSCC/main.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["main.py","form.ui","qtSCC.py"] +} diff --git a/QTui/qtSCC/main.pyproject.user b/QTui/qtSCC/main.pyproject.user new file mode 100644 index 0000000..e3803c2 --- /dev/null +++ b/QTui/qtSCC/main.pyproject.user @@ -0,0 +1,280 @@ + + + + + + EnvironmentId + {7c7d081b-5747-45bc-be8a-d21fa9398b84} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + *.md, *.MD, Makefile + false + true + + + + ProjectExplorer.Project.PluginSettings + + + true + true + true + true + true + + + 0 + true + + true + Builtin.Questionable + + true + Builtin.DefaultTidyAndClazy + 6 + + + + true + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + Desktop + {c334e0b1-3017-498a-a866-1e8f5e327be9} + -1 + 0 + 0 + 0 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + + 2 + + main + PythonEditor.RunConfiguration./home/david/Documents/ULL/Disenno/compiler/QTui/qtSCC/main.py + /home/david/Documents/ULL/Disenno/compiler/QTui/qtSCC/main.py + false + {30058bf9-10bb-4a47-9c8c-82886b053a6c} + /home/david/Documents/ULL/Disenno/compiler/QTui/qtSCC/main.py + + false + + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + + 2 + + qtSCC + PythonEditor.RunConfiguration./home/david/Documents/ULL/Disenno/compiler/QTui/qtSCC/qtSCC.py + /home/david/Documents/ULL/Disenno/compiler/QTui/qtSCC/qtSCC.py + false + {30058bf9-10bb-4a47-9c8c-82886b053a6c} + /home/david/Documents/ULL/Disenno/compiler/QTui/qtSCC/qtSCC.py + + false + + false + true + false + false + true + + /home/david/Documents/ULL/Disenno/compiler/QTui/qtSCC + + 2 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + diff --git a/QTui/qtSCC/qtSCC.py b/QTui/qtSCC/qtSCC.py new file mode 100644 index 0000000..88585bc --- /dev/null +++ b/QTui/qtSCC/qtSCC.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'form.ui' +# +# Created by: PyQt5 UI code generator 5.15.0 +# +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt5 import QtCore, QtGui, QtWidgets +import sys + + + +class Ui_qtSCC(object): + + def setupUi(self, qtSCC): + qtSCC.setObjectName("qtSCC") + qtSCC.resize(800, 600) + self.verticalLayoutWidget = QtWidgets.QWidget(qtSCC) + self.verticalLayoutWidget.setGeometry(QtCore.QRect(10, 10, 781, 581)) + self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") + self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget) + self.verticalLayout.setContentsMargins(0, 0, 0, 0) + self.verticalLayout.setObjectName("verticalLayout") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.inputEdit = QtWidgets.QLineEdit(self.verticalLayoutWidget) + self.inputEdit.setReadOnly(False) + self.inputEdit.setObjectName("inputEdit") + self.horizontalLayout_2.addWidget(self.inputEdit) + self.SearchButton = QtWidgets.QPushButton(self.verticalLayoutWidget) + self.SearchButton.setObjectName("SearchButton") + self.horizontalLayout_2.addWidget(self.SearchButton) + self.assembleButton = QtWidgets.QPushButton(self.verticalLayoutWidget) + self.assembleButton.setObjectName("assembleButton") + self.horizontalLayout_2.addWidget(self.assembleButton) + self.verticalLayout.addLayout(self.horizontalLayout_2) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.fileList = QtWidgets.QListWidget(self.verticalLayoutWidget) + self.fileList.setObjectName("fileList") + self.horizontalLayout.addWidget(self.fileList) + self.verticalLayout_2 = QtWidgets.QVBoxLayout() + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.translateList = QtWidgets.QListWidget(self.verticalLayoutWidget) + self.translateList.setObjectName("translateList") + self.verticalLayout_2.addWidget(self.translateList) + self.horizontalLayout_3 = QtWidgets.QHBoxLayout() + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.saveEdit = QtWidgets.QLineEdit(self.verticalLayoutWidget) + self.saveEdit.setObjectName("saveEdit") + self.horizontalLayout_3.addWidget(self.saveEdit) + self.saveButton = QtWidgets.QPushButton(self.verticalLayoutWidget) + self.saveButton.setObjectName("saveButton") + self.horizontalLayout_3.addWidget(self.saveButton) + self.verticalLayout_2.addLayout(self.horizontalLayout_3) + self.horizontalLayout.addLayout(self.verticalLayout_2) + self.verticalLayout.addLayout(self.horizontalLayout) + + self.retranslateUi(qtSCC) + QtCore.QMetaObject.connectSlotsByName(qtSCC) + + def retranslateUi(self, qtSCC): + _translate = QtCore.QCoreApplication.translate + qtSCC.setWindowTitle(_translate("qtSCC", "qtSCC")) + self.SearchButton.setText(_translate("qtSCC", "Search")) + self.assembleButton.setText(_translate("qtSCC", "Assemble")) + self.saveButton.setText(_translate("qtSCC", "Save")) + + diff --git a/SCC/SCCDicts.py b/SCC/SCCDicts.py new file mode 100644 index 0000000..818776d --- /dev/null +++ b/SCC/SCCDicts.py @@ -0,0 +1,81 @@ + +directions = {} + +# O -> opcode +# 0 -> empty +# X -> opcode +# Z -> opcode +# Y -> opcode +JUMP_RULE = 'OOOOOOXXXXXXXXXX' +ALU_LEFT_RULE = 'OOOOXXXX0000YYYY' +ALU_RIGHT_RULE = 'OOOO0000XXXXYYYY' +ALU_BOTH_RULE = 'OOOOXXXXYYYYZZZZ' +IMM_RULE = 'OOOOXXXXXXXXYYYY' +NOOP_RULE = 'OOOOOO0000000000' +PORT_READ_RULE = 'OOOOOOXX0000YYYY' +PORT_WRITE_RULE = 'OOOOOOXXYYYYZZZZ' +WORD_WRITE_RULE = 'OOOOYYYYXXXXXXXX' +WORD_READ_RULE = 'OOOOXXXXXXXXYYYY' +ADDR_WRITE_RULE = 'OOOOXXXXYYYY0000' +ADDR_READ_RULE = 'OOOO0000XXXXYYYY' + +prep_rules = { + } + +registers = { 'zero':'0000', + 'R1': '0001', + 'R2': '0010', + 'R3': '0011', + 'R4': '0100', + 'R5': '0101', + 'R6': '0110', + 'R7': '0111', + 'R8': '1000', + 'R9': '1001', + 'R10': '1010', + 'R11': '1011', + 'R12': '1100', + 'R13': '1101', + 'R14': '1110', + 'R15': '1111' + } + +rules = { 'noop': NOOP_RULE, + 'jump': JUMP_RULE, + 'jz': JUMP_RULE, + 'jnz': JUMP_RULE, + 'li': IMM_RULE, + 'lw': WORD_READ_RULE, + 'sw': WORD_WRITE_RULE, + 'la': ADDR_READ_RULE, + 'sa': ADDR_WRITE_RULE, + 'call': JUMP_RULE, + 'ret': NOOP_RULE, + 'mov': ALU_LEFT_RULE, + 'not': ALU_LEFT_RULE, + 'add': ALU_BOTH_RULE, + 'sub': ALU_BOTH_RULE, + 'and': ALU_BOTH_RULE, + 'or': ALU_BOTH_RULE, + 'neg': ALU_LEFT_RULE + } + +opcodeDict = { 'noop':'000000', + 'jump':"000001", + 'jz':'000010', + 'jnz':'000011', + 'li':'0001', + 'call':'010000', + 'ret':'010100', + 'lw':'0010', + 'sw':'0011', + 'la':'0110', + 'sa':'0111', + 'mov':'1000', + 'not':'1001', + 'add':'1010', + 'sub':'1011', + 'and':'1100', + 'or':'1101', + 'neg':'1110' + } diff --git a/SCC/SCCUtils.py b/SCC/SCCUtils.py new file mode 100644 index 0000000..fecccf9 --- /dev/null +++ b/SCC/SCCUtils.py @@ -0,0 +1,143 @@ +import csv +import re + +from SCCDicts import * + +def writeList2File(fileName, list, append=0): + mode = ('w', 'a')[append] + with open(fileName, mode) as file: + for item in list: + file.write(f'{item}\n') + +def isRegister(operand): + return registers[operand] + +def isImm(operand): + + if int(operand) > 128: + raise Exception(f'Operand too large. Must be under 8 bits. Received {operand}') + + operand = format(int(operand), '08b') + return operand + +def isOther(operand): + if operand in prep_rules: + return opType(prep_rules[operand]) + if operand in directions: + return directions[operand] + else: + raise Exception(f'Operand not recognized. Received {operand}') + +def isAddr(operand): + address = re.search(r'([0-9]+)', operand).group() + + if re.match(r'^io\([0-9]+\)',operand): + return '000000' + format(int(address), '02b') + if re.match(r'^int\([0-9]+\)',operand): + return '00001' + format(int(address), '03b') + if re.match(r'^data\([0-9]+\)',operand): + return '1' + format(int(address), '07b') + +def opType(operand): + regexps = [r'(?:R(?:1[0-5]|[1-9])|zero)', r'[0-9]+', r'(io|data|int)\(([0-9]+)\)', r'[:a-zA-Z0-9]'] + functions = [isRegister, isImm, isAddr, isOther] # This is a function list + index = -1 + for regex in regexps: + index += 1 + if re.match(regex, operand): + # Now a function is applied to the item to turn it into binary code + return functions[index](operand) + + raise Exception(f'Operand {operand} is not valid') + +def operateFile(file, func): + result = func(file) + file.seek(0) + return result + +def translate(file): + #Transform assembly instructions into machine code. + + result = [] + for line in file: + operation = '' + opcode = '' + + line = line.strip('\n') + items = line.split(' ') + items = list(filter(None, items)) + + if items[0] in opcodeDict: + operation = rules[items[0]] + opcode = opcodeDict[items[0]] + operation = re.sub(r'O+', opcode, operation) + + items.remove(items[0]) + + s = 'X' + for item in items: + operand = opType(item) + occurences = len(re.search(s+'+', operation).group()) + operation = re.sub(s+'+', operand[:occurences], operation) + s = chr((ord(s) + 1)) + + result.append(str(operation)) + elif items[0][0] == ':': + continue + else: + raise Exception(f'ERROR: {line.split()[0]} in not a valid opcode') + return result + +def resolveDirections(file): + + instructionDir = 0 + for line in file: + match = re.search(r'^:([a-zA-Z0-9_-]+)', line) + if match: + directions[match.group(1)] = format(instructionDir, '010b') + else: + instructionDir += 1 + + +def strip_input(out_file, csvFile): + #with open(path, 'r') as csvFile: + lines = csvFile.read().splitlines() + code_section = preprocess(lines) + for line in lines[code_section:]: + line = line.strip() + if line: + if re.match(r'^#', line): #If line is a comment ignore it + continue + elif re.search(r'#', line): #Strip comment ater instruction + index = re.search(r'#', line).start() + out_file.write(line[0:index]+'\n') + else: #Add instruction to virtual file + out_file.write(line+'\n') + #Make file ready to be read again + out_file.seek(0) + + +def read_mem_file( input_file ): + #assembly_code will contain the lines of assembly code to translate + with open(input_file, 'r') as infile: + return_code = [] + assembly_code = csv.DictReader(infile, delimiter = ' ', + fieldnames = ["opcode", "op1", "op2"], + restval = None, + quoting = csv.QUOTE_NONE) + for instruction in assembly_code: + opc, op1, op2 = instruction["opcode"], instruction["op1"], instruction["op2"] + return_code.append({"opcode":opc, "op1":op1, "op2":op2}) + return return_code + +def preprocess( lines ): + begining = 0 + for line in lines: + if line != '.code': + match = re.search(r'^use ([a-zA-Z0-9]+) as ([a-zA-Z0-9\(\)]+$)',line) + if match is not None: + prep_rules[match.group(1)] = match.group(2) + begining += 1 + else: + return begining + 1 + return None diff --git a/SCC/__pycache__/SCCDicts.cpython-38.pyc b/SCC/__pycache__/SCCDicts.cpython-38.pyc new file mode 100644 index 0000000..4860d8b Binary files /dev/null and b/SCC/__pycache__/SCCDicts.cpython-38.pyc differ diff --git a/SCC/__pycache__/SCCDicts.cpython-39.pyc b/SCC/__pycache__/SCCDicts.cpython-39.pyc new file mode 100644 index 0000000..032adf7 Binary files /dev/null and b/SCC/__pycache__/SCCDicts.cpython-39.pyc differ diff --git a/SCC/__pycache__/SCCUtils.cpython-38.pyc b/SCC/__pycache__/SCCUtils.cpython-38.pyc new file mode 100644 index 0000000..2c4cd68 Binary files /dev/null and b/SCC/__pycache__/SCCUtils.cpython-38.pyc differ diff --git a/SCC/__pycache__/SCCUtils.cpython-39.pyc b/SCC/__pycache__/SCCUtils.cpython-39.pyc new file mode 100644 index 0000000..49c6519 Binary files /dev/null and b/SCC/__pycache__/SCCUtils.cpython-39.pyc differ diff --git a/SCC/assembler.py b/SCC/assembler.py new file mode 100755 index 0000000..aef4e29 --- /dev/null +++ b/SCC/assembler.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 + +import sys +import tempfile + +from SCCUtils import * + + +def main(argv): + #Create virtual file + + in_file_name = "" + out_file_name = "" + + for i in range(len(argv)): + if argv[i] == "-i": + in_file_name = argv[i + 1] + i = i + 1 + elif argv[i] == "-o": + out_file_name = argv[i + 1] + i = i + 1 + + virtual_file = tempfile.SpooledTemporaryFile(mode = "w+", encoding = "utf-8", dir = "/tmp/") + + #Open input file + input_file = open( in_file_name, 'r' ) + #Strip file + strip_input(virtual_file, input_file) + #resolve jump directions + operateFile(virtual_file, resolveDirections) + #translate asm into machine code + instructions = operateFile(virtual_file, translate) + input_file.close() + #write codd to file + writeList2File(out_file_name, instructions) + + + + + +if __name__ == "__main__": + main(sys.argv) diff --git a/SCC/bucle.csv b/SCC/bucle.csv new file mode 100644 index 0000000..b1ae83d --- /dev/null +++ b/SCC/bucle.csv @@ -0,0 +1,10 @@ +noop +limm 0 R1 +limm 1 R2 +limm 10 R3 +:for +add R1 R2 R1 +sub R3 R1 zero +jnz for +:end +jump end diff --git a/SCC/sasm.vim b/SCC/sasm.vim new file mode 100644 index 0000000..d0942d2 --- /dev/null +++ b/SCC/sasm.vim @@ -0,0 +1,39 @@ +" Vim syntax file +" Language: SASM +" Maintainer: David Martin +" Latest Revision: 6/4/2021 d/m/y + +if exists("b:current_syntax") + finish +endif + + +syn match comment '#.*$' +syn match preproc '^\.code$' +syn keyword preproc use nextgroup=const +syn keyword preproc as +syn keyword opcode noop ret sw lw sa la call or add sub not movsyn +syn keyword opcode li nextgroup=number,const +syn keyword opaddr jump jz jnz call nextgroup=addrtag,number skipwhite +syn match const '\w\+' +syn match number '\d\+' +syn match addr '[a-zA-Z0-9_-]\+$' +syn match addrtag ':[a-zA-Z0-9_-]\+' +syn match addr 'io(\d\+)' +syn match addr 'data(\d\+)' +syn match addr 'int(\d\+)' +syn match reg 'R\d' + +let b:current_syntax = "sasm" +hi def link opcode Type +hi def link opaddr Type +hi def link addr Constant +hi def link const PreProc +hi def link reg Statement +hi def link comment Comment +hi def link addrtag Statement +hi def link preproc PreProc +hi def link number Constant +"hi def link opaddr Statement +"hi def link op3Reg Statement + diff --git a/SCC/test b/SCC/test new file mode 100644 index 0000000..252c759 --- /dev/null +++ b/SCC/test @@ -0,0 +1,8 @@ +0000000000000000 +0001000000000001 +0001000000010010 +0001000010100011 +1010000100100001 +1011001100010000 +0000110000000100 +0000010000000111 diff --git a/SCC/test_strip.csv b/SCC/test_strip.csv new file mode 100644 index 0000000..5539198 --- /dev/null +++ b/SCC/test_strip.csv @@ -0,0 +1,5 @@ +#This is a comment +jump etiqueta +:etiqueta +add zero R2 R1 #This is a commented line +limm 127 R3 diff --git a/compile.py b/compile.py deleted file mode 100755 index 019293e..0000000 --- a/compile.py +++ /dev/null @@ -1,212 +0,0 @@ -#!/usr/bin/env python3 - -import csv -import sys -import tempfile -import re - -JUMP_RULE = 'OOOOOOXXXXXXXXXX' -ALU_LEFT_RULE = 'OOOOXXXX0000YYYY' -ALU_RIGHT_RULE = 'OOOO0000XXXXYYYY' -ALU_BOTH_RULE = 'OOOOXXXXYYYYZZZZ' -IMM_RULE = 'OOOOXXXXXXXXYYYY' -NOOP_RULE = 'OOOOOO0000000000' -PORT_READ_RULE = 'OOOOOOXX0000YYYY' -PORT_WRITE_RULE = 'OOOOOOXXYYYYZZZZ' - -registers = { 'zero':'0000', - 'R1': '0001', - 'R2': '0010', - 'R3': '0011', - 'R4': '0100', - 'R5': '0101', - 'R6': '0110', - 'R7': '0111', - 'R8': '1000', - 'R9': '1001', - 'R10': '1010', - 'R11': '1011', - 'R12': '1100', - 'R13': '1101', - 'R14': '1110', - 'R15': '1111' - } - -rules = { 'noop': NOOP_RULE, - 'jump': JUMP_RULE, - 'jz': JUMP_RULE, - 'jnz': JUMP_RULE, - 'limm': IMM_RULE, - 'jal': JUMP_RULE, - 'ret': NOOP_RULE, - 'read': PORT_READ_RULE, - 'write': PORT_WRITE_RULE, - 'mov': ALU_LEFT_RULE, - 'not': ALU_LEFT_RULE, - 'add': ALU_BOTH_RULE, - 'sub': ALU_BOTH_RULE, - 'and': ALU_BOTH_RULE, - 'or': ALU_BOTH_RULE, - 'neg': ALU_LEFT_RULE - } - -opcodeDict = { 'noop':'000000', - 'jump':"000001", - 'jz':'000010', - 'jnz':'000011', - 'limm':'0001', - 'jal':'001000', - 'ret':'001001', - 'read':'001010', - 'write':'001011', - 'mov':'1000', - 'not':'1001', - 'add':'1010', - 'sub':'1011', - 'and':'1100', - 'or':'1101', - 'neg':'1110' - } - -directions = {} - -def isRegister(operand): - return registers[operand] - -def isImm(operand): - - if int(operand) > 128: - raise Exception(f'Operand too large. Must be under 8 bits') - - operand = format(int(operand), '08b') - return operand - -def isOther(operand): - if operand in directions: - return directions[operand] - else: - raise Exception(f'Operand not recognized') - - -def opType(operand): - regexps = [r'(?:R(?:1[0-5]|[1-9])|zero)', r'[0-9]+', r'[:a-zA-Z0-9]'] - functions = [isRegister, isImm, isOther] - index = -1 - for regex in regexps: - index += 1 - if re.match(regex, operand): - return functions[index](operand) - - raise Exception(f'operand ', operand, f' is not valid') - -def operateFile(file, func): - result = func(file) - file.seek(0) - return result - -def translate(file): - #Transform assembly instructions into machine code. - - result = [] - for line in file: - operation = '' - opcode = '' - - line = line.strip('\n') - items = line.split(' ') - items = list(filter(None, items)) - - if items[0] in opcodeDict: - operation = rules[items[0]] - opcode = opcodeDict[items[0]] - operation = re.sub(r'O+', opcode, operation) - - items.remove(items[0]) - - s = 'X' - for item in items: - operand = opType(item) - operation = re.sub(s+'+', operand, operation) - s = chr((ord(s) + 1)) - - result.append(str(operation)) - elif items[0][0] == ':': - continue - else: - raise Exception(f'ERROR: {line[0]} in not a valid opcode') - return result - -def resolveDirections(file): - - instructionDir = 0 - for line in file: - line = line.strip('\n') - match = re.search(r'^:([a-zA-Z0-9]*)', line) - if match: - directions[match.group(1)] = format(instructionDir, '010b') - else: - instructionDir += 1 - - -def read_file(path): - file = tempfile.TemporaryFile() - strip_input(file, path) - return read_mem_file(file) - - -def strip_input(out_file, csvFile): - #with open(path, 'r') as csvFile: - lines = csvFile.read().splitlines() - for line in lines: - if re.match(r'^#', line): #If line is a comment ignore it - continue - elif re.search(r'#', line): #Strip comment ater instruction - index = re.search(r'#', line).start() - out_file.write(line[0:index]+'\n') - else: #Add instruction to virtual file - out_file.write(line+'\n') - #Make file ready to be read again - out_file.seek(0) - - -def read_mem_file( input_file ): - #assembly_code will contain the lines of assembly code to translate - with open(input_file, 'r') as infile: - return_code = [] - assembly_code = csv.DictReader(infile, delimiter = ' ', - fieldnames = ["opcode", "op1", "op2"], - restval = None, - quoting = csv.QUOTE_NONE) - for instruction in assembly_code: - opc, op1, op2 = instruction["opcode"], instruction["op1"], instruction["op2"] - return_code.append({"opcode":opc, "op1":op1, "op2":op2}) - return return_code - -#def strip_comments(): - - -def main(argv): - #Create virtual file - virtual_file = tempfile.SpooledTemporaryFile(mode = "w+", encoding = "utf-8", dir = "/tmp/") - - #Open input file - input_file = open( "test_strip.csv", 'r' ) - - #Strip file - strip_input(virtual_file, input_file) - - operateFile(virtual_file, resolveDirections) - instructions = operateFile(virtual_file, translate) - input_file.close() - - - with open('a.out', 'w') as file: - for instruction in instructions: - file.write(f'{instruction}\n') - - - - - -if __name__ == "__main__": - main(sys.argv)