Skip to content

Instantly share code, notes, and snippets.

@blakev
Created December 2, 2014 20:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save blakev/6395f72ffbf95f4856bc to your computer and use it in GitHub Desktop.
Save blakev/6395f72ffbf95f4856bc to your computer and use it in GitHub Desktop.
Assembler and VM written in Python
#!/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)
#print
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])
;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
#!/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