def writeByte(self, address, num): if num == None: report(self.line, self.column, f'{num}, Wrote Nothing ', RuntimeWarning) return address = self.toSigned(address) memory[address] = num
def buildStmt(self): #We have no errors at the start of the stmt self.currentStmtError = False #Since Stmt doesn't hold any data but instead contains links to other nodes #We use peek and not advance currentToken = self.peek() #If it's a single length insturction we build that up if self.isSingleLength(currentToken): singleNode = self.buildSingleChain() stmt = (singleNode) #If it's a double instruction, we build that elif self.isDoubleLength(currentToken): doubleNode = self.buildDouble() stmt = (doubleNode) #Otherwise we have a Parser Error for not having an instruction else: report(currentToken.line, currentToken.column, "Invalid Instruction : " + currentToken.text, ParsingError) self.currentStmtError = True #If we've had an error in the statement we let our error handler handle it if (self.currentStmtError): self.hadError = True self.errorHandle() return return stmt
def buildOperation(self): #buildOperation consumes the next opeartion token so we use advance here operationToken = self.advance() #We match the next token with the appropriate type if self.isPrefix(operationToken): label = 'Prefix' elif self.isOffset(operationToken): label = 'Offset' else: label = 'Single' node = reps.Node(label, True, self.distance) operandToken = self.peek() #After checking if the following token is a Number we eat it and move on if self.isInteger(operandToken): self.advance() node.setInstruc(operationToken) node.setOperand(operandToken) self.distance += 1 #We then check if the next Token is NEXT and if so we just consume it self.eatIfNext() #If not we have an error and we let the error handler in buildstmt handle it else: report(operandToken.line, operandToken.column, "Invalid Operand: " + operandToken.text, ParsingError) self.currentStmtError = True return node
def buildSingleChain(self): #First we check what type the next token currentToken = self.peek() #If we match S O we build that and return if not self.isPrefix(currentToken): operationNode = self.buildOperation() return operationNode #If we have a prefix we branch to match (P O) I tree = reps.Node('Chain', distance=self.distance) while self.isPrefix(currentToken): prefixNode = self.buildOperation() tree.add(prefixNode) currentToken = self.peek() #This sequence must end with a S O if self.isSingleLength(currentToken): operationNode = self.buildOperation() tree.add(operationNode) #If it doesn't end in S O we have an error #We check if a relevant error has already been raised. If so we don't raise another error elif self.currentStmtError == False: report(currentToken.line, currentToken.column, "Not a Single Length Instruction: " + currentToken.text, ParsingError) self.currentStmtError = True return tree
def LDL(self): value = self.readMem(self.workspace(self.Oreg)) if value == None: report( self.line, self.column, f'At: {self.currentInstrucName} {self.Oreg}, Loaded Nothing', RuntimeWarning) self.push(value) self.Oreg = 0
def pop(self): #Pop an item from the stack [A,B,C] and let the user know if it would be invalid. result = self.Areg self.Areg = self.Breg self.Breg = self.Creg if self.stackdepth == 0: report(self.line, self.column, f'{self.currentInstrucName}Stack is empty', RuntimeWarning) else: self.stackdepth -= 1 return result
def LDNL(self): if not self.isValidReg('Areg', True): return if self.Areg & self.byteSelectMask == 0: index = self.Areg + self.bytesPerWord * self.Oreg self.Areg = self.readMem(index) else: report( self.line, self.column, f'At: {self.currentInstrucName} {self.Oreg}, Loaded Nothing', RuntimeWarning) self.Oreg = 0
def STNL(self): if not self.isValidReg('Areg', True): return if self.Areg & self.byteSelectMask == 0: movement = self.pop() value = self.pop() if value == None: report( self.line, self.column, f'At: {self.currentInstrucName} {self.Oreg}, Stored \'None\' ', RuntimeWarning) movement = movement + self.Oreg self.Oreg = 0
def execute(self, name): self.currentInstrucName = name try: eval('self.' + name + '()') #If we can't match that means we've not implemented it yet except Warning: pass except AttributeError: message = f'{name} is not yet implemented in the simulator' report(self.line, self.column, message, InstructionNotImplemented) self.error = True except Exception as inst: print(inst)
def ADC(self): self.Areg += self.Oreg if self.Areg > 2**(self.bit - 1) - 1: report( self.line, self.column, f'At: {self.currentInstrucName} {self.Oreg+self}, Integer Overflow', RunTimeError) self.haltFlag = True elif self.Areg < -2**(self.bit - 1): report( self.line, self.column, f'At: {self.currentInstrucName} {self.Oreg+self}, Integer Underflow', RunTimeError) self.haltFlag = True self.Oreg = 0
def readMem(self, address): address = self.toSigned(address) if address % self.bytesPerWord == 0: i = 0 result = 0 while i < self.bytesPerWord: result += (self.memory[address + i]) * (2**(8 * i)) i += 1 else: report( self.line, self.column, f'At: {self.currentInstrucName}, {address} is not a wordLength Address', RuntimeWarning) result = None return result
def isValidReg(self, reg, error): registerValue = eval('self.' + reg) if registerValue == None: if error: report( self.line, self.column, f'At: {self.currentInstrucName} {self.Oreg}, {reg} is Empty', RunTimeError) self.hadError = True else: report( self.line, self.column, f'At: {self.currentInstrucName} {self.Oreg}, {reg} + is Empty', RuntimeWarning) return False else: return True
def scanToken(self): char = self.advance() #If the next charecter is a letter we are only interested #in it if it the start of an instruction if self.isAlpha(char): #Check if the following word is an insturction isInstruc = self.isInstruc() #If we have an instruction we add it and move on to the next token if (isInstruc): name = self.code[self.start:self.current] self.addToken(name, name) return #If we don't match here the error is caught at the end of the scan #and the token is rejected there #If the charecter is a "-" and the one after is a digit, we have a number if (char == "-" and self.isDigit(self.peek())): self.number() return #If the next charecter is a digit we make an integer token if self.isDigit(char): self.number() return #If we've hit a space or a tab then we move onto the next token if char == ' ' or char == '\t': return #If we're at a new line we increment the line counter if char == '\n': self.addToken('NEXT','NEWLINE',text = 'NEWLINE') self.lineno += 1 self.column = 0 return if char == ';': self.addToken('NEXT',';') return #If nothing matches then we have a lexical error #We create the unmatched string and then print it unmatched = self.code[self.start:self.current] report(self.lineno, self.column, "Unrecognised token: " + unmatched, LexicalError) self.hadError = True
def ADD(self): if not self.isValidReg('Areg', True): return if not self.isValidReg('Breg', True): return value = self.pop() self.Areg += value if self.Areg > 2**(self.bit - 1) - 1: report( self.line, self.column, f'At: {self.currentInstrucName} {self.Oreg+self}, Integer Overflow', RunTimeError) self.haltFlag = True elif self.Areg < -2**(self.bit - 1): report( self.line, self.column, f'At: {self.currentInstrucName} {self.Oreg+self}, Integer Underflow', RunTimeError) self.haltFlag = True
def OPR(self): if self.Oreg < 0: report(self.line, self.column, f'OPR {self.Oreg} is not valid', RunTimeError) self.Oreg = 0 self.haltFlag = True return instructionCodeToRun = hex(self.Oreg)[2:].upper() #If we've only got a single length we add a zero so we can match it correctly if len(instructionCodeToRun) == 1: instructionCodeToRun = '0' + instructionCodeToRun instructionCodeToRun = '#' + instructionCodeToRun try: instruction = reps.TokenType(instructionCodeToRun).name self.execute(instruction) except ValueError: report(self.line, self.column, f'OPR {self.Oreg} is not valid', RunTimeError) self.haltFlag = True finally: self.Oreg = 0 return
def writeMem(self, address, num): address = self.toSigned(address) if num == None: report(self.line, self.column, f'{num}, Wrote Nothing ', RuntimeWarning) return #Normalise it to n bits num = self.toSigned(num) num = self.fromSigned(num) if address % self.bytesPerWord == 0: i = 0 while i < self.bytesPerWord - 1: #Set it to be the lowest bye self.memory[address + i] = num & 0xFF num = num >> 8 i += 1 self.memory[address + i] = num else: report( self.line, self.column, f'At: {self.currentInstrucName}, {address} is not a wordLength Address', RuntimeWarning)