Created
December 2, 2014 20:11
-
-
Save blakev/6395f72ffbf95f4856bc to your computer and use it in GitHub Desktop.
Assembler and VM written in Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import sys, os, re | |
errorDict = { | |
0: "Default error for, %s" | |
} | |
warningDict = { | |
0: "Default warning for, %s", | |
100:"%s Label already found in symbol table." | |
} | |
def doWarning(code = 0, spec = "", line = 0): | |
print "Warning! %s@%s, %s"%('', line, warningDict[code]%(spec)) | |
def doError(code = 0, spec = "", line = 0): | |
print "Error! %s@%s, %s"%('', line, errorDict[code]%(spec)) | |
sys.exit(1) | |
trapDict = { | |
'1' : 1, | |
'2' : 2, | |
'3' : 3, | |
'4' : 4, | |
'10': 10, | |
'11': 11, | |
'0' : 0 | |
} | |
regDict = { | |
'R0' :1, | |
'R1' :2, | |
'R2' :3, | |
'R3' :4, | |
'R4' :5, | |
'R5' :6, | |
'R6' :7, | |
'R7' :8, | |
'R8' :9, | |
'R9' :10, | |
'R10':11, | |
'R11':12, | |
'R12':13, | |
'R13':14, | |
'R14':15 | |
} | |
opCodeDict = { | |
'JMP':1, | |
'JMR':2, | |
'MOV':3, | |
'LDA':4, | |
'STR':5, | |
'LDR':6, | |
'ADD':7, | |
'SUB':8, | |
'DIV':9, | |
'MUL':10, | |
'TRP':11, | |
'CMP':12, | |
'BNZ':13, | |
'BGT':14, | |
'BLT':15, | |
'BRZ':16, | |
'LDB':17, | |
'STB':18, | |
'RUN':19, | |
'END':20, | |
'BLK':21, | |
'LCK':22, | |
'ULK':23 | |
} | |
def DINT(args): # .INT 4 byte IMM | |
n = int(args[1]) | |
N1 = n & 255 | |
N2 = (n >> 8) & 255 | |
N3 = (n >> 16) & 255 | |
N4 = (n >> 24) & 255 | |
return [N4, N3, N2, N1] | |
def DBYT(args): # .BYT 1 byte IMM (255 signed) | |
t = args[1] | |
if t[0] == "'": #string | |
return [ord(c) for c in reduce(lambda x,y : str(x) + " " + str(y), args[1:]).strip("'")] | |
else: #int | |
return [int(t) % 255] | |
def DALN(*args): # .ALN <empty> | |
return [0 for p in range(0, (4 - (PC % 4)))] | |
def CMP(args): | |
RD = regDict[args[1]] | |
RS = regDict[args[2]] | |
return [opCodeDict['CMP'], (RD << 4) + RS, 0, 0] | |
def BNZ(args): | |
RS = regDict[args[1]] | |
ADDR = symTable[args[2]] | |
ADDR1 = ADDR & 255 | |
ADDR2 = (ADDR >> 8) & 255 | |
return [opCodeDict['BNZ'], RS, ADDR2, ADDR1] | |
def BGT(args): | |
RS = regDict[args[1]] | |
ADDR = symTable[args[2]] | |
ADDR1 = ADDR & 255 | |
ADDR2 = (ADDR >> 8) & 255 | |
return [opCodeDict['BGT'], RS, ADDR2, ADDR1] | |
def BLT(args): | |
RS = regDict[args[1]] | |
ADDR = symTable[args[2]] | |
ADDR1 = ADDR & 255 | |
ADDR2 = (ADDR >> 8) & 255 | |
return [opCodeDict['BLT'], RS, ADDR2, ADDR1] | |
def BRZ(args): | |
RS = regDict[args[1]] | |
ADDR = symTable[args[2]] | |
ADDR1 = ADDR & 255 | |
ADDR2 = (ADDR >> 8) & 255 | |
return [opCodeDict['BRZ'], RS, ADDR2, ADDR1] | |
def JMP(args): # JMP 2 byte IMM | |
ADDR = symTable[args[1]] | |
ADDR1 = ADDR & 255 | |
ADDR2 = (ADDR >> 8) & 255 | |
return [opCodeDict['JMP'], 0, ADDR2, ADDR1] | |
def JMR(args): # JMR RS | |
RS = regDict[args[1]] | |
return [opCodeDict['JMR'], RS, 0, 0] | |
def MOV(args): # MOV RD, RS | |
RD = regDict[args[1]] | |
RS = regDict[args[2]] | |
return [opCodeDict['MOV'], (RD << 4) + RS, 0, 0] | |
def LDA(args): # LDA RD, 2 byte IMM | |
RD = regDict[args[1]] | |
ADDR = symTable[args[2]] | |
ADDR1 = ADDR & 255 | |
ADDR2 = (ADDR >> 8) & 255 | |
return [opCodeDict['LDA'], (RD << 4), ADDR2, ADDR1] | |
def STR(args): # STR RS, 2 byte IMM | |
RS = regDict[args[1]] | |
ADDR = symTable.get(args[2], None) | |
if ADDR != None: | |
ADDR1 = ADDR & 255 | |
ADDR2 = (ADDR >> 8) & 255 | |
return [opCodeDict['STR'], RS, ADDR2, ADDR1] | |
else: | |
RD = regDict[args[2]] | |
return [opCodeDict['STR'], (RD << 4) + RS, 0, 0] | |
def STB(args): | |
RS = regDict[args[1]] | |
ADDR = symTable.get(args[2], None) | |
if ADDR != None: | |
ADDR1 = ADDR & 255 | |
ADDR2 = (ADDR >> 8) & 255 | |
return [opCodeDict['STB'], RS, ADDR2, ADDR1] | |
else: | |
RD = regDict[args[2]] | |
return [opCodeDict['STB'], (RD << 4) + RS, 0, 0] | |
def LDR(args): # LDR RD, 2 byte IMM | |
RD = regDict[args[1]] | |
ADDR = symTable.get(args[2], None) | |
if ADDR != None: | |
ADDR1 = ADDR & 255 | |
ADDR2 = (ADDR >> 8) & 255 | |
return [opCodeDict['LDR'], (RD << 4), ADDR2, ADDR1] | |
else: | |
RS = regDict[args[2]] | |
return [opCodeDict['LDR'], (RD << 4) + RS, 0, 0] | |
def LDB(args): | |
RD = regDict[args[1]] | |
ADDR = symTable.get(args[2], None) | |
if ADDR != None: | |
ADDR1 = ADDR & 255 | |
ADDR2 = (ADDR >> 8) & 255 | |
return [opCodeDict['LDB'], (RD << 4), ADDR2, ADDR1] | |
else: | |
RS = regDict[args[2]] | |
return [opCodeDict['LDB'], (RD << 4) + RS, 0, 0] | |
def ADD(args): # ADD, RD, RS | |
RD = regDict[args[1]] | |
RS = regDict[args[2]] | |
return [opCodeDict['ADD'], (RD << 4) + RS, 0, 0] | |
def SUB(args): # SUB, RD, RS | |
RD = regDict[args[1]] | |
RS = regDict[args[2]] | |
return [opCodeDict['SUB'], (RD << 4) + RS, 0, 0] | |
def DIV(args): # DIV, RD, RS | |
RD = regDict[args[1]] | |
RS = regDict[args[2]] | |
return [opCodeDict['DIV'], (RD << 4) + RS, 0, 0] | |
def MUL(args): # MUL, RD, RS | |
RD = regDict[args[1]] | |
RS = regDict[args[2]] | |
return [opCodeDict['MUL'], (RD << 4) + RS, 0, 0] | |
def TRP(args): # TRP 1 byte IMM | |
IMM = trapDict.get(args[1], 0) | |
return [opCodeDict['TRP'], 0, 0, IMM % 255] | |
def RUN(args): #RUN reg, label | |
RD = regDict[args[1]] | |
ADDR = symTable.get(args[2], None) | |
ADDR1 = ADDR & 255 | |
ADDR2 = (ADDR >> 8) & 255 | |
return [opCodeDict['RUN'], (RD << 4), ADDR2, ADDR1] | |
def END(args): | |
return [opCodeDict['END'], 0, 0, 0] | |
def BLK(args): | |
return [opCodeDict['BLK'], 0, 0, 0] | |
def LCK(args): # LCK label | |
ADDR = symTable.get(args[1], None) | |
ADDR1 = ADDR & 255 | |
ADDR2 = (ADDR >> 8) & 255 | |
return [opCodeDict['LCK'], 0, ADDR2, ADDR1] | |
def ULK(args): | |
ADDR = symTable.get(args[1], None) | |
ADDR1 = ADDR & 255 | |
ADDR2 = (ADDR >> 8) & 255 | |
return [opCodeDict['ULK'], 0, ADDR2, ADDR1] | |
def DEFAULT(args): | |
return [255, 255, 255, 255] | |
opConstDict = { | |
'.BYT': DBYT, | |
'.INT': DINT, | |
'.ALN': DALN, | |
'JMP':JMP, | |
'JMR':JMR, | |
'MOV':MOV, | |
'LDA':LDA, | |
'STR':STR, | |
'LDR':LDR, | |
'ADD':ADD, | |
'SUB':SUB, | |
'DIV':DIV, | |
'MUL':MUL, | |
'TRP':TRP, | |
'CMP':CMP, | |
'BNZ':BNZ, | |
'BGT':BGT, | |
'BLT':BLT, | |
'BRZ':BRZ, | |
'LDB':LDB, | |
'STB':STB, | |
'RUN':RUN, | |
'END':END, | |
'BLK':BLK, | |
'LCK':LCK, | |
'ULK':ULK, | |
'DEFAULT':DEFAULT | |
} | |
oPC = 0 | |
PC = oPC | |
symTable = {} | |
stream = "" | |
def asm(word): | |
global stream | |
stream += word | |
def hexify(byte): | |
return str(hex(byte)).split("x")[1].zfill(2) | |
def findLabel(dic, val): | |
return [k for k, v in dic.iteritems() if v == val][0] | |
def byteSize(p): | |
if p[1][0] == "'": | |
return len(reduce(lambda x,y : str(x) + " " + str(y), p[1:]).strip("'")) | |
else: return 1 | |
def firstPass(fileObject): | |
def processLine(progLine, PC): | |
p = progLine.split() | |
if p[0] not in opConstDict: | |
symTable[p[0]] = PC | |
if p[0] in symTable.keys(): | |
p.pop(0) | |
if p[0] == '.BYT': | |
PC = PC + byteSize(p) | |
elif p[0] == '.ALN': | |
PC = PC + (4 - (PC % 4)) | |
else: | |
PC = PC + 4 | |
return PC | |
global PC | |
PC = oPC | |
global symTable | |
for ln in fileObject.readlines(): | |
ln = ln[:ln.find(";")].rstrip(" \n\r\t") | |
if ln != "": | |
PC = processLine(ln, PC) | |
def secondPass(fileObject): | |
def determineLine(progLine, PC): | |
p = progLine.split() | |
if p[0] in symTable.keys(): | |
p.pop(0) | |
for byte in opConstDict.get(p[0], DEFAULT)([a.strip(",") for a in p]): | |
#print byte, | |
word = hexify(byte) #int(hexify(byte), 16) | |
asm(word) | |
if p[0] == '.BYT': | |
PC = PC + byteSize(p) | |
elif p[0] == '.ALN': | |
PC = PC + (4 - (PC % 4)) | |
else: | |
PC = PC + 4 | |
return PC | |
global PC | |
PC = oPC | |
global symTable | |
for ln in fileObject.readlines(): | |
ln = ln[:ln.find(";")].rstrip(" \n\r\t") | |
if ln != "": | |
PC = determineLine(ln, PC) | |
def main(fileName): | |
try: | |
inputName = fileName | |
outputName = fileName.split(".")[0] + ".hex" | |
f = open(fileName, "r") | |
sym = firstPass(f) | |
f.close() | |
f = open(fileName, "r") | |
secondPass(f) | |
f.close() | |
f = open(outputName, 'w') | |
f.write(str(oPC) + "\n") | |
f.write(stream) | |
f.close() | |
#print symTable | |
# | |
#print "Assembled to outfile file, %s"%(outputName) | |
except: print "There was an error with, %s"%(inputName) | |
return symTable | |
if __name__ == "__main__": | |
if len(sys.argv) > 1: | |
try: main(sys.argv[1]) | |
except: print "File not found error." | |
else: main(raw_input("Enter file location: ").split("\\")[-1]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;Initalize | |
main .INT 0 | |
;LDA R6, StackBase ;Get address of stack base | |
;LDA R5, StackPtr ;Get address of stack pointer | |
;STR R6, R5 ;Put address of stack base into stack pointer | |
LDA R6, array ;Get address of array | |
LDA R5, arrayPtr ;Get address of arrayIndex | |
STR R6, R5 ;Put the address of the array into the array pointer | |
;Start of program | |
loop LDR R3, arrayCtr ;Load R3 with the Array counter | |
BRZ R3, printArray | |
TRP 4 ;Get character into R0 | |
MOV R1, R0 ;Copy R0 to R1 | |
TRP 10 ;Convert to int | |
BLT R0, notNum | |
MOV R0, R1 | |
TRP 10 | |
MOV R1, R0 | |
BRZ R1, end | |
MOV R2, R0 ;Copy R0 to R2 | |
;<- valid number in R2 | |
LDR R3, arrayPtr ;Load R3 with the array pointer (which is addr) | |
LDR R4, line ;Load R4 with a line (#4) | |
STR R2, R3 ;Save number to address of array pointer | |
ADD R3, R4 ;Add one word to R3 | |
STR R3, arrayPtr | |
LDA R10, fac1 ;"Factorial of" | |
JMP print | |
MOV R0, R2 ;Copy R2 to R0 | |
TRP 1 ;<number> | |
LDA R10, fac2 ;"is" | |
JMP print | |
;Factorial Function | |
MOV R1, R2 ;<- Copy R0 (through R2) to R1, n | |
RUN R3, calcFac ;go to facFun | |
endMain JMP loop | |
end BLK | |
JMP printArray | |
;A non-number was entered | |
notNum MOV R0, R1 ;Move the char back into R0 | |
TRP 3 | |
LDA R10, isNot | |
JMP print | |
JMP loop | |
;Print array | |
printArray .INT 0 | |
LDR R0, newL | |
TRP 3 | |
LDA R6, array ;Get address of array | |
LDA R5, arrayBot ;Get address of arrayBot | |
STR R6, R5 ;Put the address of the array into the array bot mem location | |
;arrayBot, arrayPtr | |
LDR R1, zero ;Load R1 with #0 | |
LDA R2, array ;Load R2 with array[0] | |
LDR R4, cnt ;Load R4 with cnt | |
LDR R8, two | |
MUL R4, R8 | |
LDR R7, one ;Load R7 with #1 | |
SUB R4, R7 | |
LDR R8, cnt | |
pLoop LDR R5, line ;Load R5 with line (#4); | |
MUL R5, R1 | |
MOV R6, R5 | |
ADD R5, R2 | |
LDR R0, R5 | |
TRP 1 | |
LDR R0, newL | |
TRP 3 | |
LDR R5, line | |
MUL R5, R4 | |
SUB R5, R6 | |
ADD R5, R2 | |
LDR R0, R5 | |
TRP 1 | |
LDR R0, newL | |
TRP 3 | |
ADD R1, R7 | |
MOV R3, R1 ;Copy R1 into R3 | |
CMP R3, R8 ;Compare R3 and R4 (cnt) | |
BLT R3, pLoop ;loop if R3 < R4 | |
TRP 0 | |
;------- | |
calcFac JMP facFun | |
LCK arrLck | |
MOV R0, R2 | |
TRP 1 | |
LDR R3, arrayPtr ;Load R3 with the array pointer (which is addr) | |
LDR R4, line ;Load R4 with a line (#4) | |
STR R2, R3 ;Save number to address of array pointer | |
ADD R3, R4 ;Add one word to R3 | |
STR R3, arrayPtr | |
LDR R3, arrayCtr ;Load R3 with array counter | |
LDR R4, one ;Load R4 with #1 | |
SUB R3, R4 ;Decrement array Ctr by one | |
STR R3, arrayCtr | |
LDR R3, cnt ;Load R3 with cnt | |
ADD R3, R4 ;Add 1 to R3 | |
STR R3, cnt ;Store cnt | |
ULK arrLck | |
LDR R0, newL | |
TRP 3 | |
END | |
;Factorial Function | |
;Parameters: | |
; -R1: n | |
; -R2: return value | |
facFun MOV R3, R14 ;Copy R14 into R3 | |
BGT R1, pushFac ;If R1 > 0 | |
LDR R2, one ;Load R2 with #1 | |
JMR R3 ;Return to the calling line | |
;Push for factorial function | |
pushFac MOV R5, R12 ;Load StackPtr into R5 | |
MOV R6, R12 ;Load StackPtr into R6 | |
LDR R7, line ;R7 The size of one line (or integer) | |
ADD R5, R7 ;Add one word to R5 | |
STR R3, R5 ;Save R14 to the stack | |
ADD R5, R7 ; | |
STR R6, R5 ;Save R6 (return address) to stack | |
ADD R5, R7 ; | |
STR R1, R5 ;Save R1 (n, parameter) to stack | |
;-- End push | |
MOV R12, R5 ;Save R5 back to Stack Pointer | |
LDR R2, one | |
SUB R1, R2 ;Decrease R1 (n) by #1 | |
JMP facFun | |
;Pop | |
MOV R5, R12 ;Load StackPtr into R5 | |
LDR R7, line | |
LDR R1, R5 ;Load R1 with StackPtr - 0 (n) | |
SUB R5, R7 | |
LDR R6, R5 ;Load R6 with StackPtr - 1 (Stack Address) | |
SUB R5, R7 | |
LDR R3, R5 ;Load R14 with StackPtr - 2 (Return Address) | |
MOV R12, R6 ;Save R6 as new Stack Pointer | |
MUL R2, R1 | |
JMR R3 | |
;Print String Function | |
;LDA R10, <Start of String> | |
;Print Function, return address stored here | |
print STR R14, printReturn;Store R14 into print function as return address | |
LDR R11, printBYTE ;Load R11 with size of BYTE (1) | |
printFu LDB R0, R10 ;Load R0 with Data from address in R10 | |
BRZ R0, printo ;If R0 is 0, leave function (end of string) | |
TRP 3 ;Else, print character in R0 | |
ADD R10, R11 ;Incremember R10 to next BYTE address | |
JMP printFu ;Jump to top of print function | |
printo LDR R14, printReturn;Load R14 with the return address | |
JMR R14 ;Go there | |
printReturn .INT 0 | |
printBYTE .INT 1 | |
printLock .INT -1 | |
;--Global Variables | |
newL .INT 13 | |
line .INT 4 | |
one .INT 1 | |
two .INT 2 | |
zero .INT 0 | |
isNot .BYT ' is not a number.' | |
.BYT 13 | |
.BYT 0 | |
.ALN | |
fac1 .BYT 'Factorial of ' | |
.BYT 0 | |
.ALN | |
fac2 .BYT ' is ' | |
.BYT 0 | |
.ALN | |
arrayBot .INT 0 | |
arrayPtr .INT 0 | |
arrayCtr .INT 15 ;15 array slots | |
cnt .INT 0 | |
arrLck .INT -1 | |
array .INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
.INT 0 | |
;--Stack Variable | |
StackPtr .INT 0 | |
StackBase .INT 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import glob, os, sys, math, random | |
import msvcrt | |
from time import sleep | |
from string import digits | |
# Library Functions | |
def getChar(echo=False): | |
char = msvcrt.getch() | |
if echo: | |
if ord(char) == 13: print | |
else: sys.stdout.write(char), | |
return ord(char) | |
#Globals | |
MAX_SIZE = 64536 #2 ^ 16 - 1000 | |
STACK_OFFSET = 8192 | |
STACK_SIZE = 512 | |
MAX_THREADS = 6 | |
AVAILABLE_THREADS = [1,2,3,4,5,6] | |
THREAD_INSTRUCTIONS = 3 | |
defaultReg = { | |
1:0, | |
2:0, | |
3:0, | |
4:0, | |
5:0, | |
6:0, | |
7:0, | |
8:0, | |
9:0, | |
10:0, | |
11:0, | |
12:0, | |
13:0, | |
14:0, | |
15:0 | |
} | |
class Thread: | |
def __init__(self, PC=0, ID=0, regDict=defaultReg): | |
self.PC = PC | |
self.ID = ID | |
self.regDict = regDict.copy() | |
self.regDict[13] = (self.ID * STACK_SIZE) + STACK_OFFSET #Set R12 to stack register Address | |
def __str__(self): | |
return str(ID) | |
class VM: | |
def __init__(self, PC, streamData, symTable=None, debugFile=None): | |
self.debugFile = debugFile | |
self.symTable = symTable | |
self.stream = streamData | |
self.byteStream = [] | |
self.threadCounter = 1 | |
self.curThread = 0 | |
self.regDict = {} | |
self.PC = 0 | |
self.threads = { | |
0: Thread(PC, 0), #create the main thread as 0, with the PC | |
} | |
self.run = True | |
self.opCodeDict = { | |
0 : self._NOP, | |
1 : self._JMP, | |
2 : self._JMR, | |
3 : self._MOV, | |
4 : self._LDA, | |
5 : self._STR, | |
6 : self._LDR, | |
7 : self._ADD, | |
8 : self._SUB, | |
9 : self._DIV, | |
10 : self._MUL, | |
11 : self._TRP, | |
12 : self._CMP, | |
13 : self._BNZ, | |
14 : self._BGT, | |
15 : self._BLT, | |
16 : self._BRZ, | |
17 : self._LDB, | |
18 : self._STB, | |
19 : self._RUN, | |
20 : self._END, | |
21 : self._BLK, | |
22 : self._LCK, | |
23 : self._ULK | |
} | |
for x in xrange(0, len(self.stream), 2): | |
self.byteStream.append(self.stream[x]+self.stream[x+1]) | |
for x in xrange(0, MAX_SIZE - len(self.stream), 2): | |
self.byteStream.append("00") | |
self.running() | |
self.writeOutput() | |
#----debug related methods | |
def writeOutput(self): | |
if self.debugFile != None: | |
for thread in self.threads.keys(): | |
self.debugFile.write("%s: %s\n\n"%(thread, self.threads[thread].regDict)) | |
for x in xrange(0, len(self.byteStream), 4): | |
line = self.getLine(x) | |
self.debugFile.write('%d:\t%s \t%s\n'%(x, ''.join(line), self.deconstruct(line))) | |
#----thread related methods | |
def uniqueID(self): | |
seed = int(random.getrandibts(8)) | |
while True: | |
yield seed | |
seed += 1 | |
#----virtual machine related methods | |
def _NOP(self, ln): | |
self.PC += 4 | |
def _CMP(self, ln): | |
RD = (ln[1] >> 4) & 15 | |
RS = (ln[1]) & 15 | |
if self.regDict[RD] == self.regDict[RS]: self.regDict[RD] = 0 | |
elif self.regDict[RD] > self.regDict[RS]: self.regDict[RD] = 1 | |
elif self.regDict[RD] < self.regDict[RS]: self.regDict[RD] = -1 | |
self.PC += 4 | |
def _BNZ(self, ln): | |
RS = (ln[1]) & 15 | |
ADDR1 = ln[2] << 8 | |
ADDR2 = ln[3] | |
if self.regDict[RS] != 0: | |
self.regDict[15] = self.PC | |
self.PC = ADDR1 + ADDR2 | |
else: self.PC += 4 | |
def _BGT(self, ln): | |
RS = (ln[1]) & 15 | |
ADDR1 = ln[2] << 8 | |
ADDR2 = ln[3] | |
if self.regDict[RS] > 0: | |
self.regDict[15] = self.PC | |
self.PC = ADDR1 + ADDR2 | |
else: self.PC += 4 | |
def _BLT(self, ln): | |
RS = (ln[1]) & 15 | |
ADDR1 = ln[2] << 8 | |
ADDR2 = ln[3] | |
if self.regDict[RS] < 0: | |
self.regDict[15] = self.PC | |
self.PC = ADDR1 + ADDR2 | |
else: self.PC += 4 | |
def _BRZ(self, ln): | |
RS = (ln[1]) & 15 | |
ADDR2 = ln[2] << 8 | |
ADDR1 = ln[3] | |
if self.regDict[RS] == 0: | |
self.regDict[15] = self.PC | |
self.PC = ADDR1 + ADDR2 | |
else: self.PC += 4 | |
def _JMP(self, ln): | |
self.regDict[15] = self.PC + 4 #15 = R14 | |
ADDR2 = ln[2] << 8 | |
ADDR1 = ln[3] | |
self.PC = ADDR1 + ADDR2 | |
def _JMR(self, ln): | |
RS = (ln[1]) & 15 | |
self.PC = self.regDict[RS] | |
def _MOV(self, ln): | |
RD = (ln[1] >> 4) & 15 | |
RS = (ln[1]) & 15 | |
self.regDict[RD] = self.regDict[RS] | |
self.PC += 4 | |
def _LDA(self, ln): | |
RD = (ln[1] >> 4) & 15 | |
ADDR2 = ln[2] << 8 | |
ADDR1 = ln[3] | |
ADDR = ADDR1 + ADDR2 | |
self.regDict[RD] = ADDR | |
self.PC += 4 | |
def _LDB(self, ln): | |
RD = ln[1] >> 4 | |
RS = ln[1] & 15 | |
if RS == 0: #get value from label LDB R0, LABEL | |
ADDR2 = ln[2] << 8 | |
ADDR1 = ln[3] | |
ADDR = ADDR1 + ADDR2 | |
self.regDict[RD] = self.deconstruct(self.getByte(ADDR))[0] & 255 | |
else: #get value from memory address stored in register LDB R0, R5 | |
self.regDict[RD] = self.deconstruct(self.getByte(self.regDict[RS]))[0] & 255 | |
self.PC += 4 | |
def _LDR(self, ln): | |
RD = ln[1] >> 4 | |
RS = ln[1] & 15 | |
if RS == 0: #get value from label LDR R0, LABEL | |
ADDR2 = ln[2] << 8 | |
ADDR1 = ln[3] | |
ADDR = ADDR1 + ADDR2 | |
self.regDict[RD] = self.getInt(self.deconstruct(self.getLine(ADDR))) | |
else: #get value from memory address stored in register LDR R0, R5 | |
self.regDict[RD] = self.getInt(self.deconstruct(self.getLine(self.regDict[RS]))) | |
self.PC += 4 | |
def _STB(self, ln): | |
RD = ln[1] >> 4 | |
RS = ln[1] & 15 | |
if RD == 0: | |
ADDR2 = ln[2] << 8 | |
ADDR1 = ln[3] | |
ADDR = ADDR1 + ADDR2 | |
self.byteStream[ADDR] = self.constructByte(self.regDict[RS]) | |
else: # STB R1, R0 (take the value of R1, store it in memory location R0) | |
self.byteStream[self.regDict[RD]] = self.constructByte(self.regDict[RS]) | |
self.PC += 4 | |
def _STR(self, ln): | |
RD = ln[1] >> 4 | |
RS = ln[1] & 15 | |
newBytes = self.construct(self.regDict[RS]) | |
if RD == 0: | |
ADDR2 = ln[2] << 8 | |
ADDR1 = ln[3] | |
ADDR = ADDR1 + ADDR2 | |
for n in xrange(0, 4): self.byteStream[ADDR+n] = str(newBytes[n]) | |
else: # STR R1, R0 (take the value of R1, store it in memory location R0) | |
ADDR = self.regDict[RD] | |
for n in xrange(0, 4): self.byteStream[ADDR+n] = str(newBytes[n]) | |
self.PC += 4 | |
def _ADD(self, ln): | |
RD = (ln[1] >> 4) & 15 | |
RS = (ln[1]) & 15 | |
self.regDict[RD] = self.regDict[RD] + self.regDict[RS] | |
self.PC += 4 | |
def _SUB(self, ln): | |
RD = (ln[1] >> 4) & 15 | |
RS = (ln[1]) & 15 | |
self.regDict[RD] = self.regDict[RD] - self.regDict[RS] | |
self.PC += 4 | |
def _DIV(self, ln): | |
RD = (ln[1] >> 4) & 15 | |
RS = (ln[1]) & 15 | |
self.regDict[RD] = int(int(math.ceil(self.regDict[RD]) / int(self.regDict[RS]))) | |
self.PC += 4 | |
def _MUL(self, ln): | |
RD = (ln[1] >> 4) & 15 | |
RS = (ln[1]) & 15 | |
self.regDict[RD] = self.regDict[RD] * self.regDict[RS] | |
self.PC += 4 | |
def _TRP(self, ln): | |
code = ln[3] | |
if code == 0: | |
self.run = False | |
elif code == 1: #print int from R0 | |
sys.stdout.write(str(self.regDict[1])) #1 = R0 | |
sys.stdout.flush() | |
elif code == 2: | |
pass | |
elif code == 3: #print char from R0 | |
c = chr(self.regDict[1] & 255) | |
if ord(c) == 13: sys.stdout.write("\n") | |
else: sys.stdout.write(c) | |
elif code == 4: #put char (int) into R0 | |
self.regDict[1] = getChar() | |
elif code == 10: #R0, char -> int | |
if chr(self.regDict[1]) in digits: self.regDict[1] -= 48 | |
else: self.regDict[1] = -1 | |
elif code == 11: # R0, int -> char | |
if str(self.regDict[1]) in digits: self.regDict[1] += 48 | |
else: self.regDict[1] = -1 | |
self.PC += 4 | |
def _RUN(self, ln): | |
#print self.regDict | |
RD = (ln[1] >> 4) & 15 | |
ADDR2 = ln[2] << 8 | |
ADDR1 = ln[3] | |
self.regDict[RD] = self.createThread((ADDR1 + ADDR2)) | |
self.PC += 4 | |
def _END(self, ln): | |
if self.curThread == 0: self.PC += 4 | |
else: | |
AVAILABLE_THREADS.append(self.curThread) | |
del self.threads[self.curThread] | |
def _BLK(self, ln): | |
if self.curThread != 0: self.PC += 4 | |
if self.curThread == 0 and len(self.threads) == 1: self.PC += 4 | |
def _LCK(self, ln): | |
ADDR = (ln[2] << 8) + ln[3] | |
owner = self.getInt(self.deconstruct(self.getLine(ADDR))) | |
if owner == -1: | |
newBytes = self.construct(self.curThread) | |
for n in xrange(0, 4): self.byteStream[ADDR+n] = str(newBytes[n]) | |
self.PC += 4 | |
else: pass | |
def _ULK(self, ln): | |
ADDR = (ln[2] << 8) + ln[3] | |
owner = self.getInt(self.deconstruct(self.getLine(ADDR))) | |
if owner == self.curThread: | |
newBytes = self.construct(-1) | |
for n in xrange(0, 4): self.byteStream[ADDR+n] = str(newBytes[n]) | |
self.PC += 4 | |
def createThread(self, addr): | |
if len(AVAILABLE_THREADS) <= 0: | |
print "Warning! Max thread count of %d exceeded, terminating execution."%(MAX_THREADS) | |
self.run = False | |
newID = AVAILABLE_THREADS.pop() | |
self.threads[newID] = Thread(addr, newID, self.regDict) | |
return newID | |
def running(self): | |
while self.run: | |
#debug mode | |
# | |
#monitorList = ['array', 'array1', 'array2', 'array3', 'arrayCtr', 'arrayPtr'] | |
# | |
#if self.symTable != None: | |
# for label in set(self.symTable.keys()).intersection(monitorList): | |
# print "%s\t%s\t%s"%(label, self.symTable[label], self.deconstruct(self.getLine(self.symTable[label]))) | |
# print "-"*20 | |
# | |
scheduledThreads = [] | |
for key in self.threads.keys(): | |
scheduledThreads.append(key) | |
for curThread in scheduledThreads: | |
if curThread in self.threads.keys(): | |
self.curThread = self.threads[curThread].ID | |
self.regDict = self.threads[curThread].regDict.copy() | |
self.PC = self.threads[curThread].PC | |
for inst in xrange(0, THREAD_INSTRUCTIONS): | |
self.regDict[14] = self.PC #R13 | |
line = self.deconstruct(self.getLine(self.PC)) | |
self.opCodeDict.get(line[0], self._NOP)(line) | |
#reasons to break execution | |
if curThread not in self.threads.keys(): | |
break | |
if self.run == False: | |
scheduledThreads = [] | |
break | |
#cleanup thread values | |
if curThread in self.threads.keys(): | |
self.threads[curThread].regDict = self.regDict.copy() | |
self.threads[curThread].PC = self.PC | |
if self.PC < 0: | |
print "Warning! Underflow, reached below start of allocated memory." | |
self.run = False | |
if self.PC >= len(self.byteStream): | |
print "Warning! Overflow, reached end of allocated memory." | |
self.run = False | |
def getInt(self, ln): #return integer of deconstructed line, return int | |
N1 = int(ln[3]) | |
N2 = int(ln[2]) << 8 | |
N3 = int(ln[1]) << 16 | |
N4 = int(ln[0]) << 24 | |
NT = N1 + N2 + N3 + N4 | |
if NT > 2147483647: NT -= 4294967296 | |
return NT | |
def getLine(self, pc): #getline at program counter, return hex[word] | |
return self.byteStream[pc:pc+4] | |
def getByte(self, pc): | |
return self.byteStream[pc:pc+1] | |
def deconstruct(self, line): #dehexify line, from getLine, return word | |
return [int(n.strip("L"), 16) for n in line] | |
def constructByte(self, num): | |
return str(hex(num & 255)).split("x")[1].zfill(2) | |
def construct(self, num): #construct a hexline from int, return word | |
def rHex(n): return str(hex(n)).split("x")[1].zfill(2) | |
return [rHex((num >> 24) & 255), rHex((num >> 16) & 255), rHex((num >> 8) & 255), rHex(num & 255)] | |
def main(filename, symTable=None): | |
debug = True | |
if filename.split(".")[1] == "hex": | |
try: | |
f = open(filename, "r") | |
oPC = int(f.readline().strip(" \n\r\t")) | |
stream = f.readline().strip(" \n\r\t") | |
if debug: | |
debugFile = open(filename.split(".")[0] + ".output", "w") | |
debugFile.write("DEBUG DUMP FOR: %s\n\n"%(filename)) | |
v = VM(oPC, stream, symTable, debugFile) | |
if debug: debugFile.close() | |
f.close() | |
# raw_input() #keeps console open after running | |
except: print "There was an error with, %s"%(filename) | |
else: print "Not a valid file type." | |
if __name__ == "__main__": | |
if len(sys.argv) > 1: | |
try: main(sys.argv[1]) | |
except: print "File not found error." | |
else: main(raw_input("Enter file location: ").split("\\")[-1]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment