|
|
@ -0,0 +1,989 @@ |
|
|
|
#! /usr/bin/env python |
|
|
|
|
|
|
|
import sys |
|
|
|
import time |
|
|
|
import random |
|
|
|
from optparse import OptionParser |
|
|
|
|
|
|
|
# |
|
|
|
# HELPER |
|
|
|
# |
|
|
|
def dospace(howmuch): |
|
|
|
for i in range(howmuch): |
|
|
|
print '%24s' % ' ', |
|
|
|
|
|
|
|
# useful instead of assert |
|
|
|
def zassert(cond, str): |
|
|
|
if cond == False: |
|
|
|
print 'ABORT::', str |
|
|
|
exit(1) |
|
|
|
return |
|
|
|
|
|
|
|
class cpu: |
|
|
|
# |
|
|
|
# INIT: how much memory? |
|
|
|
# |
|
|
|
def __init__(self, memory, memtrace, regtrace, cctrace, compute, verbose): |
|
|
|
# |
|
|
|
# CONSTANTS |
|
|
|
# |
|
|
|
|
|
|
|
# conditions |
|
|
|
self.COND_GT = 0 |
|
|
|
self.COND_GTE = 1 |
|
|
|
self.COND_LT = 2 |
|
|
|
self.COND_LTE = 3 |
|
|
|
self.COND_EQ = 4 |
|
|
|
self.COND_NEQ = 5 |
|
|
|
|
|
|
|
# registers in system |
|
|
|
self.REG_ZERO = 0 |
|
|
|
self.REG_AX = 1 |
|
|
|
self.REG_BX = 2 |
|
|
|
self.REG_CX = 3 |
|
|
|
self.REG_DX = 4 |
|
|
|
self.REG_SP = 5 |
|
|
|
self.REG_BP = 6 |
|
|
|
|
|
|
|
# system memory: in KB |
|
|
|
self.max_memory = memory * 1024 |
|
|
|
|
|
|
|
# which memory addrs and registers to trace? |
|
|
|
self.memtrace = memtrace |
|
|
|
self.regtrace = regtrace |
|
|
|
self.cctrace = cctrace |
|
|
|
self.compute = compute |
|
|
|
self.verbose = verbose |
|
|
|
|
|
|
|
self.PC = 0 |
|
|
|
self.registers = {} |
|
|
|
self.conditions = {} |
|
|
|
self.labels = {} |
|
|
|
self.vars = {} |
|
|
|
self.memory = {} |
|
|
|
self.pmemory = {} # for printable version of what's in memory (instructions) |
|
|
|
|
|
|
|
self.condlist = [self.COND_GTE, self.COND_GT, self.COND_LTE, self.COND_LT, self.COND_NEQ, self.COND_EQ] |
|
|
|
self.regnums = [self.REG_ZERO, self.REG_AX, self.REG_BX, self.REG_CX, self.REG_DX, self.REG_SP, self.REG_BP] |
|
|
|
|
|
|
|
self.regnames = {} |
|
|
|
self.regnames['zero'] = self.REG_ZERO # hidden zero-valued register |
|
|
|
self.regnames['ax'] = self.REG_AX |
|
|
|
self.regnames['bx'] = self.REG_BX |
|
|
|
self.regnames['cx'] = self.REG_CX |
|
|
|
self.regnames['dx'] = self.REG_DX |
|
|
|
self.regnames['sp'] = self.REG_SP |
|
|
|
self.regnames['bp'] = self.REG_BP |
|
|
|
|
|
|
|
tmplist = [] |
|
|
|
for r in self.regtrace: |
|
|
|
zassert(r in self.regnames, 'Register %s cannot be traced because it does not exist' % r) |
|
|
|
tmplist.append(self.regnames[r]) |
|
|
|
self.regtrace = tmplist |
|
|
|
|
|
|
|
self.init_memory() |
|
|
|
self.init_registers() |
|
|
|
self.init_condition_codes() |
|
|
|
|
|
|
|
# |
|
|
|
# BEFORE MACHINE RUNS |
|
|
|
# |
|
|
|
def init_condition_codes(self): |
|
|
|
for c in self.condlist: |
|
|
|
self.conditions[c] = False |
|
|
|
|
|
|
|
def init_memory(self): |
|
|
|
for i in range(self.max_memory): |
|
|
|
self.memory[i] = 0 |
|
|
|
|
|
|
|
def init_registers(self): |
|
|
|
for i in self.regnums: |
|
|
|
self.registers[i] = 0 |
|
|
|
|
|
|
|
def dump_memory(self): |
|
|
|
print 'MEMORY DUMP' |
|
|
|
for i in range(self.max_memory): |
|
|
|
if i not in self.pmemory and i in self.memory and self.memory[i] != 0: |
|
|
|
print ' m[%d]' % i, self.memory[i] |
|
|
|
|
|
|
|
# |
|
|
|
# INFORMING ABOUT THE HARDWARE |
|
|
|
# |
|
|
|
def get_regnum(self, name): |
|
|
|
assert(name in self.regnames) |
|
|
|
return self.regnames[name] |
|
|
|
|
|
|
|
def get_regname(self, num): |
|
|
|
assert(num in self.regnums) |
|
|
|
for rname in self.regnames: |
|
|
|
if self.regnames[rname] == num: |
|
|
|
return rname |
|
|
|
return '' |
|
|
|
|
|
|
|
def get_regnums(self): |
|
|
|
return self.regnums |
|
|
|
|
|
|
|
def get_condlist(self): |
|
|
|
return self.condlist |
|
|
|
|
|
|
|
def get_reg(self, reg): |
|
|
|
assert(reg in self.regnums) |
|
|
|
return self.registers[reg] |
|
|
|
|
|
|
|
def get_cond(self, cond): |
|
|
|
assert(cond in self.condlist) |
|
|
|
return self.conditions[cond] |
|
|
|
|
|
|
|
def get_pc(self): |
|
|
|
return self.PC |
|
|
|
|
|
|
|
def set_reg(self, reg, value): |
|
|
|
assert(reg in self.regnums) |
|
|
|
self.registers[reg] = value |
|
|
|
|
|
|
|
def set_cond(self, cond, value): |
|
|
|
assert(cond in self.condlist) |
|
|
|
self.conditions[cond] = value |
|
|
|
|
|
|
|
def set_pc(self, pc): |
|
|
|
self.PC = pc |
|
|
|
|
|
|
|
# |
|
|
|
# INSTRUCTIONS |
|
|
|
# |
|
|
|
def halt(self): |
|
|
|
return -1 |
|
|
|
|
|
|
|
def iyield(self): |
|
|
|
return -2 |
|
|
|
|
|
|
|
def nop(self): |
|
|
|
return 0 |
|
|
|
|
|
|
|
def rdump(self): |
|
|
|
print 'REGISTERS::', |
|
|
|
print 'ax:', self.registers[self.REG_AX], |
|
|
|
print 'bx:', self.registers[self.REG_BX], |
|
|
|
print 'cx:', self.registers[self.REG_CX], |
|
|
|
print 'dx:', self.registers[self.REG_DX], |
|
|
|
|
|
|
|
def mdump(self, index): |
|
|
|
print 'm[%d] ' % index, self.memory[index] |
|
|
|
|
|
|
|
def move_i_to_r(self, src, dst): |
|
|
|
self.registers[dst] = src |
|
|
|
return 0 |
|
|
|
|
|
|
|
# memory: value, register, register |
|
|
|
def move_i_to_m(self, src, value, reg1, reg2): |
|
|
|
tmp = value + self.registers[reg1] + self.registers[reg2] |
|
|
|
self.memory[tmp] = src |
|
|
|
return 0 |
|
|
|
|
|
|
|
def move_m_to_r(self, value, reg1, reg2, dst): |
|
|
|
tmp = value + self.registers[reg1] + self.registers[reg2] |
|
|
|
# print 'doing mov', 'val:', value, 'r1:', self.get_regname(reg1), self.registers[reg1], 'r2:', self.get_regname(reg2), self.registers[reg2], 'dst', self.get_regname(dst), 'tmp', tmp, 'reg[dst]', self.registers[dst], 'mem', self.memory[tmp] |
|
|
|
self.registers[dst] = self.memory[tmp] |
|
|
|
|
|
|
|
def move_r_to_m(self, src, value, reg1, reg2): |
|
|
|
tmp = value + self.registers[reg1] + self.registers[reg2] |
|
|
|
self.memory[tmp] = self.registers[src] |
|
|
|
return 0 |
|
|
|
|
|
|
|
def move_r_to_r(self, src, dst): |
|
|
|
self.registers[dst] = self.registers[src] |
|
|
|
return 0 |
|
|
|
|
|
|
|
def add_i_to_r(self, src, dst): |
|
|
|
self.registers[dst] += src |
|
|
|
return 0 |
|
|
|
|
|
|
|
def add_r_to_r(self, src, dst): |
|
|
|
self.registers[dst] += self.registers[src] |
|
|
|
return 0 |
|
|
|
|
|
|
|
def sub_i_to_r(self, src, dst): |
|
|
|
self.registers[dst] -= src |
|
|
|
return 0 |
|
|
|
|
|
|
|
def sub_r_to_r(self, src, dst): |
|
|
|
self.registers[dst] -= self.registers[src] |
|
|
|
return 0 |
|
|
|
|
|
|
|
|
|
|
|
# |
|
|
|
# SUPPORT FOR LOCKS |
|
|
|
# |
|
|
|
def atomic_exchange(self, src, value, reg1, reg2): |
|
|
|
tmp = value + self.registers[reg1] + self.registers[reg2] |
|
|
|
old = self.memory[tmp] |
|
|
|
self.memory[tmp] = self.registers[src] |
|
|
|
self.registers[src] = old |
|
|
|
return 0 |
|
|
|
|
|
|
|
def fetchadd(self, src, value, reg1, reg2): |
|
|
|
tmp = value + self.registers[reg1] + self.registers[reg2] |
|
|
|
old = self.memory[tmp] |
|
|
|
self.memory[tmp] = self.memory[tmp] + self.registers[src] |
|
|
|
self.registers[src] = old |
|
|
|
|
|
|
|
# |
|
|
|
# TEST for conditions |
|
|
|
# |
|
|
|
def test_all(self, src, dst): |
|
|
|
self.init_condition_codes() |
|
|
|
if dst > src: |
|
|
|
self.conditions[self.COND_GT] = True |
|
|
|
if dst >= src: |
|
|
|
self.conditions[self.COND_GTE] = True |
|
|
|
if dst < src: |
|
|
|
self.conditions[self.COND_LT] = True |
|
|
|
if dst <= src: |
|
|
|
self.conditions[self.COND_LTE] = True |
|
|
|
if dst == src: |
|
|
|
self.conditions[self.COND_EQ] = True |
|
|
|
if dst != src: |
|
|
|
self.conditions[self.COND_NEQ] = True |
|
|
|
return 0 |
|
|
|
|
|
|
|
def test_i_r(self, src, dst): |
|
|
|
self.init_condition_codes() |
|
|
|
return self.test_all(src, self.registers[dst]) |
|
|
|
|
|
|
|
def test_r_i(self, src, dst): |
|
|
|
self.init_condition_codes() |
|
|
|
return self.test_all(self.registers[src], dst) |
|
|
|
|
|
|
|
def test_r_r(self, src, dst): |
|
|
|
self.init_condition_codes() |
|
|
|
return self.test_all(self.registers[src], self.registers[dst]) |
|
|
|
|
|
|
|
# |
|
|
|
# JUMPS |
|
|
|
# |
|
|
|
def jump(self, targ): |
|
|
|
self.PC = targ |
|
|
|
return 0 |
|
|
|
|
|
|
|
def jump_notequal(self, targ): |
|
|
|
if self.conditions[self.COND_NEQ] == True: |
|
|
|
self.PC = targ |
|
|
|
return 0 |
|
|
|
|
|
|
|
def jump_equal(self, targ): |
|
|
|
if self.conditions[self.COND_EQ] == True: |
|
|
|
self.PC = targ |
|
|
|
return 0 |
|
|
|
|
|
|
|
def jump_lessthan(self, targ): |
|
|
|
if self.conditions[self.COND_LT] == True: |
|
|
|
self.PC = targ |
|
|
|
return 0 |
|
|
|
|
|
|
|
def jump_lessthanorequal(self, targ): |
|
|
|
if self.conditions[self.COND_LTE] == True: |
|
|
|
self.PC = targ |
|
|
|
return 0 |
|
|
|
|
|
|
|
def jump_greaterthan(self, targ): |
|
|
|
if self.conditions[self.COND_GT] == True: |
|
|
|
self.PC = targ |
|
|
|
return 0 |
|
|
|
|
|
|
|
def jump_greaterthanorequal(self, targ): |
|
|
|
if self.conditions[self.COND_GTE] == True: |
|
|
|
self.PC = targ |
|
|
|
return 0 |
|
|
|
|
|
|
|
# |
|
|
|
# CALL and RETURN |
|
|
|
# |
|
|
|
def call(self, targ): |
|
|
|
self.registers[self.REG_SP] -= 4 |
|
|
|
self.memory[self.registers[self.REG_SP]] = self.PC |
|
|
|
self.PC = targ |
|
|
|
|
|
|
|
def ret(self): |
|
|
|
self.PC = self.memory[self.registers[self.REG_SP]] |
|
|
|
self.registers[self.REG_SP] += 4 |
|
|
|
|
|
|
|
# |
|
|
|
# STACK and related |
|
|
|
# |
|
|
|
def push_r(self, reg): |
|
|
|
self.registers[self.REG_SP] -= 4 |
|
|
|
self.memory[self.registers[self.REG_SP]] = self.registers[reg] |
|
|
|
return 0 |
|
|
|
|
|
|
|
def push_m(self, value, reg1, reg2): |
|
|
|
# print 'push_m', value, reg1, reg2 |
|
|
|
self.registers[self.REG_SP] -= 4 |
|
|
|
tmp = value + self.registers[reg1] + self.registers[reg2] |
|
|
|
# push address onto stack, not memory value itself |
|
|
|
self.memory[self.registers[self.REG_SP]] = tmp |
|
|
|
return 0 |
|
|
|
|
|
|
|
def pop(self): |
|
|
|
self.registers[self.REG_SP] += 4 |
|
|
|
|
|
|
|
def pop_r(self, dst): |
|
|
|
self.registers[dst] = self.registers[self.REG_SP] |
|
|
|
self.registers[self.REG_SP] += 4 |
|
|
|
|
|
|
|
# |
|
|
|
# HELPER func for getarg |
|
|
|
# |
|
|
|
def register_translate(self, r): |
|
|
|
if r in self.regnames: |
|
|
|
return self.regnames[r] |
|
|
|
zassert(False, 'Register %s is not a valid register' % r) |
|
|
|
return |
|
|
|
|
|
|
|
# |
|
|
|
# HELPER in parsing mov (quite primitive) and other ops |
|
|
|
# returns: (value, type) |
|
|
|
# where type is (TYPE_REGISTER, TYPE_IMMEDIATE, TYPE_MEMORY) |
|
|
|
# |
|
|
|
# FORMATS |
|
|
|
# %ax - register |
|
|
|
# $10 - immediate |
|
|
|
# 10 - direct memory |
|
|
|
# 10(%ax) - memory + reg indirect |
|
|
|
# 10(%ax,%bx) - memory + 2 reg indirect |
|
|
|
# 10(%ax,%bx,4) - XXX (not handled) |
|
|
|
# |
|
|
|
def getarg(self, arg): |
|
|
|
tmp1 = arg.replace(',', '') |
|
|
|
tmp = tmp1.replace(' \t', '') |
|
|
|
|
|
|
|
if tmp[0] == '$': |
|
|
|
zassert(len(tmp) == 2, 'correct form is $number (not %s)' % tmp) |
|
|
|
value = tmp.split('$')[1] |
|
|
|
zassert(value.isdigit(), 'value [%s] must be a digit' % value) |
|
|
|
return int(value), 'TYPE_IMMEDIATE' |
|
|
|
elif tmp[0] == '%': |
|
|
|
register = tmp.split('%')[1] |
|
|
|
return self.register_translate(register), 'TYPE_REGISTER' |
|
|
|
elif tmp[0] == '(': |
|
|
|
register = tmp.split('(')[1].split(')')[0].split('%')[1] |
|
|
|
return '%d,%d,%d' % (0, self.register_translate(register), self.register_translate('zero')), 'TYPE_MEMORY' |
|
|
|
elif tmp[0] == '.': |
|
|
|
targ = tmp |
|
|
|
return targ, 'TYPE_LABEL' |
|
|
|
elif tmp[0].isalpha() and not tmp[0].isdigit(): |
|
|
|
zassert(tmp in self.vars, 'Variable %s is not declared' % tmp) |
|
|
|
# print '%d,%d,%d' % (self.vars[tmp], self.register_translate('zero'), self.register_translate('zero')), 'TYPE_MEMORY' |
|
|
|
return '%d,%d,%d' % (self.vars[tmp], self.register_translate('zero'), self.register_translate('zero')), 'TYPE_MEMORY' |
|
|
|
elif tmp[0].isdigit() or tmp[0] == '-': |
|
|
|
# MOST GENERAL CASE: number(reg,reg) or number(reg) |
|
|
|
# we ignore the common x86 number(reg,reg,constant) for now |
|
|
|
neg = 1 |
|
|
|
if tmp[0] == '-': |
|
|
|
tmp = tmp[1:] |
|
|
|
neg = -1 |
|
|
|
s = tmp.split('(') |
|
|
|
if len(s) == 1: |
|
|
|
value = neg * int(tmp) |
|
|
|
# print '%d,%d,%d' % (int(value), self.register_translate('zero'), self.register_translate('zero')), 'TYPE_MEMORY' |
|
|
|
return '%d,%d,%d' % (int(value), self.register_translate('zero'), self.register_translate('zero')), 'TYPE_MEMORY' |
|
|
|
elif len(s) == 2: |
|
|
|
value = neg * int(s[0]) |
|
|
|
t = s[1].split(')')[0].split(',') |
|
|
|
if len(t) == 1: |
|
|
|
register = t[0].split('%')[1] |
|
|
|
# print '%d,%d,%d' % (int(value), self.register_translate(register), self.register_translate('zero')), 'TYPE_MEMORY' |
|
|
|
return '%d,%d,%d' % (int(value), self.register_translate(register), self.register_translate('zero')), 'TYPE_MEMORY' |
|
|
|
elif len(t) == 2: |
|
|
|
register1 = t[0].split('%')[1] |
|
|
|
register2 = t[1].split('%')[1] |
|
|
|
# print '%d,%d,%d' % (int(value), self.register_translate(register1), self.register_translate(register2)), 'TYPE_MEMORY' |
|
|
|
return '%d,%d,%d' % (int(value), self.register_translate(register1), self.register_translate(register2)), 'TYPE_MEMORY' |
|
|
|
else: |
|
|
|
print 'mov: bad argument [%s]' % tmp |
|
|
|
exit(1) |
|
|
|
return |
|
|
|
zassert(True, 'mov: bad argument [%s]' % arg) |
|
|
|
return |
|
|
|
|
|
|
|
# |
|
|
|
# LOAD a program into memory |
|
|
|
# make it ready to execute |
|
|
|
# |
|
|
|
def load(self, infile, loadaddr): |
|
|
|
pc = int(loadaddr) |
|
|
|
fd = open(infile) |
|
|
|
|
|
|
|
bpc = loadaddr |
|
|
|
data = 100 |
|
|
|
|
|
|
|
for line in fd: |
|
|
|
cline = line.rstrip() |
|
|
|
# print 'PASS 1', cline |
|
|
|
|
|
|
|
# remove everything after the comment marker |
|
|
|
ctmp = cline.split('#') |
|
|
|
assert(len(ctmp) == 1 or len(ctmp) == 2) |
|
|
|
if len(ctmp) == 2: |
|
|
|
cline = ctmp[0] |
|
|
|
|
|
|
|
# remove empty lines, and split line by spaces |
|
|
|
tmp = cline.split() |
|
|
|
if len(tmp) == 0: |
|
|
|
continue |
|
|
|
|
|
|
|
# only pay attention to labels and variables |
|
|
|
if tmp[0] == '.var': |
|
|
|
assert(len(tmp) == 2) |
|
|
|
assert(tmp[0] not in self.vars) |
|
|
|
self.vars[tmp[1]] = data |
|
|
|
data += 4 |
|
|
|
zassert(data < bpc, 'Load address overrun by static data') |
|
|
|
if self.verbose: print 'ASSIGN VAR', tmp[0], "-->", tmp[1], self.vars[tmp[1]] |
|
|
|
elif tmp[0][0] == '.': |
|
|
|
assert(len(tmp) == 1) |
|
|
|
self.labels[tmp[0]] = int(pc) |
|
|
|
if self.verbose: print 'ASSIGN LABEL', tmp[0], "-->", pc |
|
|
|
else: |
|
|
|
pc += 1 |
|
|
|
fd.close() |
|
|
|
|
|
|
|
if self.verbose: print '' |
|
|
|
|
|
|
|
# second pass: do everything else |
|
|
|
pc = int(loadaddr) |
|
|
|
fd = open(infile) |
|
|
|
for line in fd: |
|
|
|
cline = line.rstrip() |
|
|
|
# print 'PASS 2', cline |
|
|
|
|
|
|
|
# remove everything after the comment marker |
|
|
|
ctmp = cline.split('#') |
|
|
|
assert(len(ctmp) == 1 or len(ctmp) == 2) |
|
|
|
if len(ctmp) == 2: |
|
|
|
cline = ctmp[0] |
|
|
|
|
|
|
|
# remove empty lines, and split line by spaces |
|
|
|
tmp = cline.split() |
|
|
|
if len(tmp) == 0: |
|
|
|
continue |
|
|
|
|
|
|
|
# skip labels: all else must be instructions |
|
|
|
if cline[0] != '.': |
|
|
|
tmp = cline.split(None, 1) |
|
|
|
opcode = tmp[0] |
|
|
|
self.pmemory[pc] = cline.strip() |
|
|
|
|
|
|
|
# MAIN OPCODE LOOP |
|
|
|
if opcode == 'mov': |
|
|
|
rtmp = tmp[1].split(',', 1) |
|
|
|
zassert(len(tmp) == 2 and len(rtmp) == 2, 'mov: needs two args, separated by commas [%s]' % cline) |
|
|
|
arg1 = rtmp[0].strip() |
|
|
|
arg2 = rtmp[1].strip() |
|
|
|
(src, stype) = self.getarg(arg1) |
|
|
|
(dst, dtype) = self.getarg(arg2) |
|
|
|
# print 'MOV', src, stype, dst, dtype |
|
|
|
if stype == 'TYPE_MEMORY' and dtype == 'TYPE_MEMORY': |
|
|
|
print 'bad mov: two memory arguments' |
|
|
|
exit(1) |
|
|
|
elif stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_IMMEDIATE': |
|
|
|
print 'bad mov: two immediate arguments' |
|
|
|
exit(1) |
|
|
|
elif stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER': |
|
|
|
self.memory[pc] = 'self.move_i_to_r(%d, %d)' % (int(src), dst) |
|
|
|
elif stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER': |
|
|
|
self.memory[pc] = 'self.move_i_to_r(%d, %d)' % (int(src), dst) |
|
|
|
elif stype == 'TYPE_MEMORY' and dtype == 'TYPE_REGISTER': |
|
|
|
tmp = src.split(',') |
|
|
|
assert(len(tmp) == 3) |
|
|
|
self.memory[pc] = 'self.move_m_to_r(%d, %d, %d, %d)' % (int(tmp[0]), int(tmp[1]), int(tmp[2]), dst) |
|
|
|
elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_MEMORY': |
|
|
|
tmp = dst.split(',') |
|
|
|
assert(len(tmp) == 3) |
|
|
|
self.memory[pc] = 'self.move_r_to_m(%d, %d, %d, %d)' % (src, int(tmp[0]), int(tmp[1]), int(tmp[2])) |
|
|
|
elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_REGISTER': |
|
|
|
self.memory[pc] = 'self.move_r_to_r(%d, %d)' % (src, dst) |
|
|
|
elif stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_MEMORY': |
|
|
|
tmp = dst.split(',') |
|
|
|
assert(len(tmp) == 3) |
|
|
|
self.memory[pc] = 'self.move_i_to_m(%d, %d, %d, %d)' % (src, int(tmp[0]), int(tmp[1]), int(tmp[2])) |
|
|
|
else: |
|
|
|
zassert(False, 'malformed mov instruction') |
|
|
|
elif opcode == 'pop': |
|
|
|
if len(tmp) == 1: |
|
|
|
self.memory[pc] = 'self.pop()' |
|
|
|
elif len(tmp) == 2: |
|
|
|
arg = tmp[1].strip() |
|
|
|
(dst, dtype) = self.getarg(arg) |
|
|
|
zassert(dtype == 'TYPE_REGISTER', 'Can only pop into a register') |
|
|
|
self.memory[pc] = 'self.pop_r(%d)' % dst |
|
|
|
else: |
|
|
|
zassert(False, 'pop instruction must take zero/one args') |
|
|
|
elif opcode == 'push': |
|
|
|
(src, stype) = self.getarg(tmp[1].strip()) |
|
|
|
if stype == 'TYPE_REGISTER': |
|
|
|
self.memory[pc] = 'self.push_r(%d)' % (int(src)) |
|
|
|
elif stype == 'TYPE_MEMORY': |
|
|
|
tmp = src.split(',') |
|
|
|
assert(len(tmp) == 3) |
|
|
|
self.memory[pc] = 'self.push_m(%d,%d,%d)' % (int(tmp[0]), int(tmp[1]), int(tmp[2])) |
|
|
|
else: |
|
|
|
zassert(False, 'Cannot push anything but registers') |
|
|
|
elif opcode == 'call': |
|
|
|
(targ, ttype) = self.getarg(tmp[1].strip()) |
|
|
|
if ttype == 'TYPE_LABEL': |
|
|
|
self.memory[pc] = 'self.call(%d)' % (int(self.labels[targ])) |
|
|
|
else: |
|
|
|
zassert(False, 'Cannot call anything but a label') |
|
|
|
elif opcode == 'ret': |
|
|
|
assert(len(tmp) == 1) |
|
|
|
self.memory[pc] = 'self.ret()' |
|
|
|
elif opcode == 'add': |
|
|
|
rtmp = tmp[1].split(',', 1) |
|
|
|
zassert(len(tmp) == 2 and len(rtmp) == 2, 'add: needs two args, separated by commas [%s]' % cline) |
|
|
|
arg1 = rtmp[0].strip() |
|
|
|
arg2 = rtmp[1].strip() |
|
|
|
(src, stype) = self.getarg(arg1) |
|
|
|
(dst, dtype) = self.getarg(arg2) |
|
|
|
if stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER': |
|
|
|
self.memory[pc] = 'self.add_i_to_r(%d, %d)' % (int(src), dst) |
|
|
|
elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_REGISTER': |
|
|
|
self.memory[pc] = 'self.add_r_to_r(%d, %d)' % (int(src), dst) |
|
|
|
else: |
|
|
|
zassert(False, 'malformed usage of add instruction') |
|
|
|
elif opcode == 'sub': |
|
|
|
rtmp = tmp[1].split(',', 1) |
|
|
|
zassert(len(tmp) == 2 and len(rtmp) == 2, 'sub: needs two args, separated by commas [%s]' % cline) |
|
|
|
arg1 = rtmp[0].strip() |
|
|
|
arg2 = rtmp[1].strip() |
|
|
|
(src, stype) = self.getarg(arg1) |
|
|
|
(dst, dtype) = self.getarg(arg2) |
|
|
|
if stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER': |
|
|
|
self.memory[pc] = 'self.sub_i_to_r(%d, %d)' % (int(src), dst) |
|
|
|
elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_REGISTER': |
|
|
|
self.memory[pc] = 'self.sub_r_to_r(%d, %d)' % (int(src), dst) |
|
|
|
else: |
|
|
|
zassert(False, 'malformed usage of sub instruction') |
|
|
|
elif opcode == 'fetchadd': |
|
|
|
rtmp = tmp[1].split(',', 1) |
|
|
|
zassert(len(tmp) == 2 and len(rtmp) == 2, 'fetchadd: needs two args, separated by commas [%s]' % cline) |
|
|
|
arg1 = rtmp[0].strip() |
|
|
|
arg2 = rtmp[1].strip() |
|
|
|
(src, stype) = self.getarg(arg1) |
|
|
|
(dst, dtype) = self.getarg(arg2) |
|
|
|
tmp = dst.split(',') |
|
|
|
assert(len(tmp) == 3) |
|
|
|
if stype == 'TYPE_REGISTER' and dtype == 'TYPE_MEMORY': |
|
|
|
self.memory[pc] = 'self.fetchadd(%d, %d, %d, %d)' % (src, int(tmp[0]), int(tmp[1]), int(tmp[2])) |
|
|
|
else: |
|
|
|
zassert(False, 'poorly specified fetch and add') |
|
|
|
elif opcode == 'xchg': |
|
|
|
rtmp = tmp[1].split(',', 1) |
|
|
|
zassert(len(tmp) == 2 and len(rtmp) == 2, 'xchg: needs two args, separated by commas [%s]' % cline) |
|
|
|
arg1 = rtmp[0].strip() |
|
|
|
arg2 = rtmp[1].strip() |
|
|
|
(src, stype) = self.getarg(arg1) |
|
|
|
(dst, dtype) = self.getarg(arg2) |
|
|
|
tmp = dst.split(',') |
|
|
|
assert(len(tmp) == 3) |
|
|
|
if stype == 'TYPE_REGISTER' and dtype == 'TYPE_MEMORY': |
|
|
|
self.memory[pc] = 'self.atomic_exchange(%d, %d, %d, %d)' % (src, int(tmp[0]), int(tmp[1]), int(tmp[2])) |
|
|
|
else: |
|
|
|
zassert(False, 'poorly specified atomic exchange') |
|
|
|
elif opcode == 'test': |
|
|
|
rtmp = tmp[1].split(',', 1) |
|
|
|
zassert(len(tmp) == 2 and len(rtmp) == 2, 'test: needs two args, separated by commas [%s]' % cline) |
|
|
|
arg1 = rtmp[0].strip() |
|
|
|
arg2 = rtmp[1].strip() |
|
|
|
(src, stype) = self.getarg(arg1) |
|
|
|
(dst, dtype) = self.getarg(arg2) |
|
|
|
if stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER': |
|
|
|
self.memory[pc] = 'self.test_i_r(%d, %d)' % (int(src), dst) |
|
|
|
elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_REGISTER': |
|
|
|
self.memory[pc] = 'self.test_r_r(%d, %d)' % (int(src), dst) |
|
|
|
elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_IMMEDIATE': |
|
|
|
self.memory[pc] = 'self.test_r_i(%d, %d)' % (int(src), dst) |
|
|
|
else: |
|
|
|
zassert(False, 'malformed usage of test instruction') |
|
|
|
elif opcode == 'j': |
|
|
|
(targ, ttype) = self.getarg(tmp[1].strip()) |
|
|
|
zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip()) |
|
|
|
self.memory[pc] = 'self.jump(%d)' % int(self.labels[targ]) |
|
|
|
elif opcode == 'jne': |
|
|
|
(targ, ttype) = self.getarg(tmp[1].strip()) |
|
|
|
zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip()) |
|
|
|
self.memory[pc] = 'self.jump_notequal(%d)' % int(self.labels[targ]) |
|
|
|
elif opcode == 'je': |
|
|
|
(targ, ttype) = self.getarg(tmp[1].strip()) |
|
|
|
zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip()) |
|
|
|
self.memory[pc] = 'self.jump_equal(%d)' % self.labels[targ] |
|
|
|
elif opcode == 'jlt': |
|
|
|
(targ, ttype) = self.getarg(tmp[1].strip()) |
|
|
|
zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip()) |
|
|
|
self.memory[pc] = 'self.jump_lessthan(%d)' % int(self.labels[targ]) |
|
|
|
elif opcode == 'jlte': |
|
|
|
(targ, ttype) = self.getarg(tmp[1].strip()) |
|
|
|
zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip()) |
|
|
|
self.memory[pc] = 'self.jump_lessthanorequal(%s)' % self.labels[targ] |
|
|
|
elif opcode == 'jgt': |
|
|
|
(targ, ttype) = self.getarg(tmp[1].strip()) |
|
|
|
zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip()) |
|
|
|
self.memory[pc] = 'self.jump_greaterthan(%d)' % int(self.labels[targ]) |
|
|
|
elif opcode == 'jgte': |
|
|
|
(targ, ttype) = self.getarg(tmp[1].strip()) |
|
|
|
zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip()) |
|
|
|
self.memory[pc] = 'self.jump_greaterthanorequal(%s)' % self.labels[targ] |
|
|
|
elif opcode == 'nop': |
|
|
|
self.memory[pc] = 'self.nop()' |
|
|
|
elif opcode == 'halt': |
|
|
|
self.memory[pc] = 'self.halt()' |
|
|
|
elif opcode == 'yield': |
|
|
|
self.memory[pc] = 'self.iyield()' |
|
|
|
elif opcode == 'rdump': |
|
|
|
self.memory[pc] = 'self.rdump()' |
|
|
|
elif opcode == 'mdump': |
|
|
|
self.memory[pc] = 'self.mdump(%s)' % tmp[1] |
|
|
|
else: |
|
|
|
print 'illegal opcode: ', opcode |
|
|
|
exit(1) |
|
|
|
|
|
|
|
if self.verbose: print 'pc:%d LOADING %20s --> %s' % (pc, self.pmemory[pc], self.memory[pc]) |
|
|
|
|
|
|
|
# INCREMENT PC for loader |
|
|
|
pc += 1 |
|
|
|
# END: loop over file |
|
|
|
fd.close() |
|
|
|
if self.verbose: print '' |
|
|
|
return |
|
|
|
# END: load |
|
|
|
|
|
|
|
def print_headers(self, procs): |
|
|
|
# print some headers |
|
|
|
if len(self.memtrace) > 0: |
|
|
|
for m in self.memtrace: |
|
|
|
if m[0].isdigit(): |
|
|
|
print '%5d' % int(m), |
|
|
|
else: |
|
|
|
zassert(m in self.vars, 'Traced variable %s not declared' % m) |
|
|
|
print '%5s' % m, |
|
|
|
print ' ', |
|
|
|
if len(self.regtrace) > 0: |
|
|
|
for r in self.regtrace: |
|
|
|
print '%5s' % self.get_regname(r), |
|
|
|
print ' ', |
|
|
|
if cctrace == True: |
|
|
|
print '>= > <= < != ==', |
|
|
|
|
|
|
|
# and per thread |
|
|
|
for i in range(procs.getnum()): |
|
|
|
print ' Thread %d ' % i, |
|
|
|
print '' |
|
|
|
return |
|
|
|
|
|
|
|
def print_trace(self, newline): |
|
|
|
if len(self.memtrace) > 0: |
|
|
|
for m in self.memtrace: |
|
|
|
if self.compute: |
|
|
|
if m[0].isdigit(): |
|
|
|
print '%5d' % self.memory[int(m)], |
|
|
|
else: |
|
|
|
zassert(m in self.vars, 'Traced variable %s not declared' % m) |
|
|
|
print '%5d' % self.memory[self.vars[m]], |
|
|
|
else: |
|
|
|
print '%5s' % '?', |
|
|
|
print ' ', |
|
|
|
if len(self.regtrace) > 0: |
|
|
|
for r in self.regtrace: |
|
|
|
if self.compute: |
|
|
|
print '%5d' % self.registers[r], |
|
|
|
else: |
|
|
|
print '%5s' % '?', |
|
|
|
print ' ', |
|
|
|
if cctrace == True: |
|
|
|
for c in self.condlist: |
|
|
|
if self.compute: |
|
|
|
if self.conditions[c]: |
|
|
|
print '1 ', |
|
|
|
else: |
|
|
|
print '0 ', |
|
|
|
else: |
|
|
|
print '? ', |
|
|
|
if (len(self.memtrace) > 0 or len(self.regtrace) > 0 or cctrace == True) and newline == True: |
|
|
|
print '' |
|
|
|
return |
|
|
|
|
|
|
|
def setint(self, intfreq, intrand): |
|
|
|
if intrand == False: |
|
|
|
return intfreq |
|
|
|
return int(random.random() * intfreq) + 1 |
|
|
|
|
|
|
|
def run(self, procs, intfreq, intrand): |
|
|
|
# hw init: cc's, interrupt frequency, etc. |
|
|
|
interrupt = self.setint(intfreq, intrand) |
|
|
|
icount = 0 |
|
|
|
|
|
|
|
self.print_headers(procs) |
|
|
|
self.print_trace(True) |
|
|
|
|
|
|
|
while True: |
|
|
|
# need thread ID of current process |
|
|
|
tid = procs.getcurr().gettid() |
|
|
|
|
|
|
|
# FETCH |
|
|
|
prevPC = self.PC |
|
|
|
instruction = self.memory[self.PC] |
|
|
|
self.PC += 1 |
|
|
|
|
|
|
|
# DECODE and EXECUTE |
|
|
|
# key: self.PC may be changed during eval; thus MUST be incremented BEFORE eval |
|
|
|
rc = eval(instruction) |
|
|
|
|
|
|
|
# tracing details: ALWAYS AFTER EXECUTION OF INSTRUCTION |
|
|
|
self.print_trace(False) |
|
|
|
|
|
|
|
# output: thread-proportional spacing followed by PC and instruction |
|
|
|
dospace(tid) |
|
|
|
print prevPC, self.pmemory[prevPC] |
|
|
|
icount += 1 |
|
|
|
|
|
|
|
# halt instruction issued |
|
|
|
if rc == -1: |
|
|
|
procs.done() |
|
|
|
if procs.numdone() == procs.getnum(): |
|
|
|
return icount |
|
|
|
procs.next() |
|
|
|
procs.restore() |
|
|
|
|
|
|
|
self.print_trace(False) |
|
|
|
for i in range(procs.getnum()): |
|
|
|
print '----- Halt;Switch ----- ', |
|
|
|
print '' |
|
|
|
|
|
|
|
# do interrupt processing |
|
|
|
interrupt -= 1 |
|
|
|
if interrupt == 0 or rc == -2: |
|
|
|
interrupt = self.setint(intfreq, intrand) |
|
|
|
procs.save() |
|
|
|
procs.next() |
|
|
|
procs.restore() |
|
|
|
|
|
|
|
self.print_trace(False) |
|
|
|
for i in range(procs.getnum()): |
|
|
|
print '------ Interrupt ------ ', |
|
|
|
print '' |
|
|
|
# END: while |
|
|
|
return |
|
|
|
|
|
|
|
# |
|
|
|
# END: class cpu |
|
|
|
# |
|
|
|
|
|
|
|
|
|
|
|
# |
|
|
|
# PROCESS LIST class |
|
|
|
# |
|
|
|
class proclist: |
|
|
|
def __init__(self): |
|
|
|
self.plist = [] |
|
|
|
self.curr = 0 |
|
|
|
self.active = 0 |
|
|
|
|
|
|
|
def done(self): |
|
|
|
self.plist[self.curr].setdone() |
|
|
|
self.active -= 1 |
|
|
|
|
|
|
|
def numdone(self): |
|
|
|
return len(self.plist) - self.active |
|
|
|
|
|
|
|
def getnum(self): |
|
|
|
return len(self.plist) |
|
|
|
|
|
|
|
def add(self, p): |
|
|
|
self.active += 1 |
|
|
|
self.plist.append(p) |
|
|
|
|
|
|
|
def getcurr(self): |
|
|
|
return self.plist[self.curr] |
|
|
|
|
|
|
|
def save(self): |
|
|
|
self.plist[self.curr].save() |
|
|
|
|
|
|
|
def restore(self): |
|
|
|
self.plist[self.curr].restore() |
|
|
|
|
|
|
|
def next(self): |
|
|
|
for i in range(self.curr+1, len(self.plist)): |
|
|
|
if self.plist[i].isdone() == False: |
|
|
|
self.curr = i |
|
|
|
return |
|
|
|
for i in range(0, self.curr+1): |
|
|
|
if self.plist[i].isdone() == False: |
|
|
|
self.curr = i |
|
|
|
return |
|
|
|
|
|
|
|
# |
|
|
|
# PROCESS class |
|
|
|
# |
|
|
|
class process: |
|
|
|
def __init__(self, cpu, tid, pc, stackbottom, reginit): |
|
|
|
self.cpu = cpu # object reference |
|
|
|
self.tid = tid |
|
|
|
self.pc = pc |
|
|
|
self.regs = {} |
|
|
|
self.cc = {} |
|
|
|
self.done = False |
|
|
|
self.stack = stackbottom |
|
|
|
|
|
|
|
# init regs: all 0 or specially set to something |
|
|
|
for r in self.cpu.get_regnums(): |
|
|
|
self.regs[r] = 0 |
|
|
|
if reginit != '': |
|
|
|
# form: ax=1,bx=2 (for some subset of registers) |
|
|
|
for r in reginit.split(':'): |
|
|
|
tmp = r.split('=') |
|
|
|
assert(len(tmp) == 2) |
|
|
|
self.regs[self.cpu.get_regnum(tmp[0])] = int(tmp[1]) |
|
|
|
|
|
|
|
# init CCs |
|
|
|
for c in self.cpu.get_condlist(): |
|
|
|
self.cc[c] = False |
|
|
|
|
|
|
|
# stack |
|
|
|
self.regs[self.cpu.get_regnum('sp')] = stackbottom |
|
|
|
# print 'REG', self.cpu.get_regnum('sp'), self.regs[self.cpu.get_regnum('sp')] |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
def gettid(self): |
|
|
|
return self.tid |
|
|
|
|
|
|
|
def save(self): |
|
|
|
self.pc = self.cpu.get_pc() |
|
|
|
for c in self.cpu.get_condlist(): |
|
|
|
self.cc[c] = self.cpu.get_cond(c) |
|
|
|
for r in self.cpu.get_regnums(): |
|
|
|
self.regs[r] = self.cpu.get_reg(r) |
|
|
|
|
|
|
|
def restore(self): |
|
|
|
self.cpu.set_pc(self.pc) |
|
|
|
for c in self.cpu.get_condlist(): |
|
|
|
self.cpu.set_cond(c, self.cc[c]) |
|
|
|
for r in self.cpu.get_regnums(): |
|
|
|
self.cpu.set_reg(r, self.regs[r]) |
|
|
|
|
|
|
|
def setdone(self): |
|
|
|
self.done = True |
|
|
|
|
|
|
|
def isdone(self): |
|
|
|
return self.done == True |
|
|
|
|
|
|
|
# |
|
|
|
# main program |
|
|
|
# |
|
|
|
parser = OptionParser() |
|
|
|
parser.add_option('-s', '--seed', default=0, help='the random seed', action='store', type='int', dest='seed') |
|
|
|
parser.add_option('-t', '--threads', default=2, help='number of threads', action='store', type='int', dest='numthreads') |
|
|
|
parser.add_option('-p', '--program', default='', help='source program (in .s)', action='store', type='string', dest='progfile') |
|
|
|
parser.add_option('-i', '--interrupt', default=50, help='interrupt frequency', action='store', type='int', dest='intfreq') |
|
|
|
parser.add_option('-r', '--randints', default=False, help='if interrupts are random', action='store_true', dest='intrand') |
|
|
|
parser.add_option('-a', '--argv', default='', |
|
|
|
help='comma-separated per-thread args (e.g., ax=1,ax=2 sets thread 0 ax reg to 1 and thread 1 ax reg to 2); specify multiple regs per thread via colon-separated list (e.g., ax=1:bx=2,cx=3 sets thread 0 ax and bx and just cx for thread 1)', |
|
|
|
action='store', type='string', dest='argv') |
|
|
|
parser.add_option('-L', '--loadaddr', default=1000, help='address where to load code', action='store', type='int', dest='loadaddr') |
|
|
|
parser.add_option('-m', '--memsize', default=128, help='size of address space (KB)', action='store', type='int', dest='memsize') |
|
|
|
parser.add_option('-M', '--memtrace', default='', help='comma-separated list of addrs to trace (e.g., 20000,20001)', action='store', |
|
|
|
type='string', dest='memtrace') |
|
|
|
parser.add_option('-R', '--regtrace', default='', help='comma-separated list of regs to trace (e.g., ax,bx,cx,dx)', action='store', |
|
|
|
type='string', dest='regtrace') |
|
|
|
parser.add_option('-C', '--cctrace', default=False, help='should we trace condition codes', action='store_true', dest='cctrace') |
|
|
|
parser.add_option('-S', '--printstats',default=False, help='print some extra stats', action='store_true', dest='printstats') |
|
|
|
parser.add_option('-v', '--verbose', default=False, help='print some extra info', action='store_true', dest='verbose') |
|
|
|
parser.add_option('-c', '--compute', default=False, help='compute answers for me', action='store_true', dest='solve') |
|
|
|
(options, args) = parser.parse_args() |
|
|
|
|
|
|
|
print 'ARG seed', options.seed |
|
|
|
print 'ARG numthreads', options.numthreads |
|
|
|
print 'ARG program', options.progfile |
|
|
|
print 'ARG interrupt frequency', options.intfreq |
|
|
|
print 'ARG interrupt randomness',options.intrand |
|
|
|
print 'ARG argv', options.argv |
|
|
|
print 'ARG load address', options.loadaddr |
|
|
|
print 'ARG memsize', options.memsize |
|
|
|
print 'ARG memtrace', options.memtrace |
|
|
|
print 'ARG regtrace', options.regtrace |
|
|
|
print 'ARG cctrace', options.cctrace |
|
|
|
print 'ARG printstats', options.printstats |
|
|
|
print 'ARG verbose', options.verbose |
|
|
|
print '' |
|
|
|
|
|
|
|
seed = int(options.seed) |
|
|
|
numthreads = int(options.numthreads) |
|
|
|
intfreq = int(options.intfreq) |
|
|
|
zassert(intfreq > 0, 'Interrupt frequency must be greater than 0') |
|
|
|
intrand = int(options.intrand) |
|
|
|
progfile = options.progfile |
|
|
|
zassert(progfile != '', 'Program file must be specified') |
|
|
|
argv = options.argv.split(',') |
|
|
|
zassert(len(argv) == numthreads or len(argv) == 1, 'argv: must be one per-thread or just one set of values for all threads') |
|
|
|
|
|
|
|
loadaddr = options.loadaddr |
|
|
|
memsize = options.memsize |
|
|
|
|
|
|
|
memtrace = [] |
|
|
|
if options.memtrace != '': |
|
|
|
for m in options.memtrace.split(','): |
|
|
|
memtrace.append(m) |
|
|
|
|
|
|
|
regtrace = [] |
|
|
|
if options.regtrace != '': |
|
|
|
for r in options.regtrace.split(','): |
|
|
|
regtrace.append(r) |
|
|
|
|
|
|
|
cctrace = options.cctrace |
|
|
|
|
|
|
|
printstats = options.printstats |
|
|
|
verbose = options.verbose |
|
|
|
|
|
|
|
# |
|
|
|
# MAIN program |
|
|
|
# |
|
|
|
debug = False |
|
|
|
debug = False |
|
|
|
|
|
|
|
cpu = cpu(memsize, memtrace, regtrace, cctrace, options.solve, verbose) |
|
|
|
|
|
|
|
# load a program |
|
|
|
cpu.load(progfile, loadaddr) |
|
|
|
|
|
|
|
# process list |
|
|
|
procs = proclist() |
|
|
|
pid = 0 |
|
|
|
stack = memsize * 1000 |
|
|
|
for t in range(numthreads): |
|
|
|
if len(argv) > 1: |
|
|
|
arg = argv[pid] |
|
|
|
else: |
|
|
|
arg = argv[0] |
|
|
|
procs.add(process(cpu, pid, loadaddr, stack, arg)) |
|
|
|
stack -= 1000 |
|
|
|
pid += 1 |
|
|
|
|
|
|
|
# get first one ready! |
|
|
|
procs.restore() |
|
|
|
|
|
|
|
# run it |
|
|
|
t1 = time.clock() |
|
|
|
ic = cpu.run(procs, intfreq, intrand) |
|
|
|
t2 = time.clock() |
|
|
|
|
|
|
|
if printstats: |
|
|
|
print '' |
|
|
|
print 'STATS:: Instructions %d' % ic |
|
|
|
print 'STATS:: Emulation Rate %.2f kinst/sec' % (float(ic) / float(t2 - t1) / 1000.0) |
|
|
|
|
|
|
|
# use this for profiling |
|
|
|
# import cProfile |
|
|
|
# cProfile.run('run()') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|