Skip to content

Commit

Permalink
Merge 1091e4b into 6a859ad
Browse files Browse the repository at this point in the history
  • Loading branch information
snim2 committed Aug 7, 2016
2 parents 6a859ad + 1091e4b commit ad225e4
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 39 deletions.
68 changes: 41 additions & 27 deletions revelation/sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
from revelation.machine import State
from revelation.registers import reg_map
from revelation.storage import Memory
from revelation.utils import (get_coords_from_coreid, get_coreid_from_coords,
zfill)
from revelation.utils import format_thousands, get_coords_from_coreid
from revelation.utils import get_coreid_from_coords, zfill

from pydgin.misc import FatalError, NotImplementedInstError

Expand All @@ -30,10 +30,10 @@ def new_memory(logger):
return Memory(block_size=2**20, logger=logger)


def get_printable_location(pc, core, coreid, opcode):
def get_printable_location(pc, _, coreid, opcode, halted, idle):
hex_pc = pad_hex(pc)
mnemonic, _ = decode(opcode)
return 'Core ID: 0x%x PC: %s Instruction: %s' % (coreid, hex_pc, mnemonic)
return 'Core index: 0x%x PC: %s Instruction: %s' % (coreid, hex_pc, mnemonic)


class Revelation(Sim):
Expand All @@ -47,9 +47,10 @@ def __init__(self):
self.jit_enabled = True
if self.jit_enabled:
self.jitdriver = JitDriver(
greens = ['pc', 'core', 'coreid', 'opcode'],
reds = ['tick_counter', 'halted_cores', 'idle_cores',
'memory', 'sim', 'state', 'start_time'],
greens=['pc', 'core', 'coreid', 'opcode', 'halted_cores',
'idle_cores'],
reds=['tick_counter', 'max_insts', 'memory', 'sim', 'state',
'start_time'],
get_printable_location=get_printable_location)
self.default_trace_limit = 400000
self.max_insts = 0
Expand Down Expand Up @@ -193,32 +194,34 @@ def run(self):
"""Fetch, decode, execute, service interrupts loop.
Override Sim.run to provide multicore and close the logger on exit.
"""
self = hint(self, promote=True)
memory = hint(self.memory, promote=True) # Cores share the same memory.
coreid = 0 # We save these values so that get_location can print
opcode = 0 # a more meaningful trace in the JIT log.
# We save these coreid and opcode so that get_location can print
# a more meaningful trace in the JIT log.
coreid = self.states[self.core].coreid
opcode = 0
tick_counter = 0 # Number of instructions executed by all cores.
halted_cores, idle_cores = [], []
old_pc = 0
pc = self.states[self.core].fetch_pc()
old_pc = pc
start_time, end_time = time.time(), .0

while True:
while len(halted_cores) != len(self.states):
self.jitdriver.jit_merge_point(pc=self.states[self.core].fetch_pc(),
core=self.core,
coreid=coreid,
opcode=opcode,
tick_counter=tick_counter,
max_insts=self.max_insts,
halted_cores=halted_cores,
idle_cores=idle_cores,
memory=memory,
memory=self.memory,
sim=self,
state=self.states[self.core],
start_time=start_time)
# Fetch PC, decode instruction and execute.
pc = hint(self.states[self.core].fetch_pc(), promote=True)
coreid = hint(self.states[self.core].coreid, promote=True)
pc = self.states[self.core].fetch_pc()
old_pc = pc
opcode = memory.iread(pc, 4, from_core=self.states[self.core].coreid)
opcode = self.memory.iread(pc, 4,
from_core=self.states[self.core].coreid)
try:
instruction, function = self.decode(opcode)
self.pre_execute()
Expand All @@ -230,54 +233,65 @@ def run(self):
(mnemonic, pad_hex(pc)))
print 'Exception message: %s' % error.msg
# Ensure that entry_point() returns correct exit code.
return EXIT_GENERAL_ERROR # pragma: no cover
return EXIT_GENERAL_ERROR # pragma: no cover
# Update instruction counters.
tick_counter += 1
self.states[self.core].num_insts += 1
# Halt if we have reached the maximum instruction count or
# no more cores are running.
if self.max_insts != 0 and self.states[self.core].num_insts >= self.max_insts:
print 'Reached the max_insts (%d), exiting.' % self.max_insts
if (self.max_insts > 0 and
self.states[self.core].num_insts >= self.max_insts):
print ('Core 0x%x has reached the max_insts (%d), exiting.' %
(coreid, self.max_insts))
break
if not self.states[self.core].running:
halted_cores = hint(halted_cores, promote=True)
halted_cores.append(self.core)
if len(halted_cores) == len(self.states):
break
if not self.states[self.core].ACTIVE:
idle_cores = hint(idle_cores, promote=True)
idle_cores.append(self.core)
# Switch cores after every instruction. TODO: Switch interval.
if tick_counter % self.switch_interval == 0 and len(self.states) > 1:
self.core = hint(self.core, promote=True)
while True:
self.core = hint(self.next_core(self.core), promote=True)
self.core = self.next_core(self.core)
if not (self.core in halted_cores or self.core in idle_cores):
break
# Idle cores can be reactivated by interrupts.
elif (self.core in idle_cores and self.fetch_latch() > 0):
idle_cores.remove(self.core)
self._service_interrupts()
coreid = hint(self.states[self.core].coreid, promote=True)
if self.states[self.core].fetch_pc() < old_pc:
self.jitdriver.can_enter_jit(pc=self.states[self.core].fetch_pc(),
core=self.core,
coreid=coreid,
coreid=self.states[self.core].coreid,
opcode=opcode,
tick_counter=tick_counter,
max_insts=self.max_insts,
halted_cores=halted_cores,
idle_cores=idle_cores,
memory=memory,
memory=self.memory,
sim=self,
state=self.states[self.core],
start_time=start_time)
# End of fetch-decode-execute-service interrupts loop.
if self.collect_times:
end_time = time.time()
print 'Done! Total ticks simulated = %d' % tick_counter
print 'Total ticks simulated = %s.' % format_thousands(tick_counter)
for state in self.states:
row, col = get_coords_from_coreid(state.coreid)
print ('Core %s (%s, %s): STATUS=0x%s, Instructions executed=%d' %
print ('Core %s (%s, %s) STATUS: 0x%s, Instructions executed: %s' %
(hex(state.coreid), zfill(str(row), 2), zfill(str(col), 2),
pad_hex(state.rf[reg_map['STATUS']]), state.num_insts))
pad_hex(state.rf[reg_map['STATUS']]),
format_thousands(state.num_insts)))
if self.collect_times:
print 'Total execution time: %fs' % (end_time - start_time)
execution_time = end_time - start_time
speed = format_thousands(int(tick_counter / execution_time))
print 'Total execution time: %fs.' % (execution_time)
print 'Simulator speed: %s instructions / second.' % speed
if self.logger:
self.logger.close()
return EXIT_SUCCESS
Expand Down
13 changes: 3 additions & 10 deletions revelation/storage.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from pydgin.debug import Debug, pad, pad_hex
from pydgin.jit import elidable, unroll_safe, hint
from pydgin.utils import specialize

from revelation.registers import reg_memory_map

Expand All @@ -15,6 +15,7 @@ def is_register_address(address):
class _BlockMemory(object):
"""32MB block of memory, initialised to zero.
"""
_immutable_fields_ = ['size']

def __init__(self, size=2**10, logger=None):
"""Initialise all memory to zero, as we don't know which memory.
Expand All @@ -23,15 +24,13 @@ def __init__(self, size=2**10, logger=None):
self.data = ['\0'] * size
self.size = len(self.data)

@unroll_safe
def read(self, start_addr, num_bytes):
value = 0
for i in range(num_bytes - 1, -1, -1):
value = value << 8
value = value | ord(self.data[start_addr + i])
return value

@elidable
def iread(self, start_addr, num_bytes):
"""This is instruction read, which is otherwise identical to read. The
only difference is the elidable annotation, which we assume the
Expand All @@ -44,7 +43,6 @@ def iread(self, start_addr, num_bytes):
value = value | ord(self.data[start_addr + i])
return value

@unroll_safe
def write(self, start_addr, num_bytes, value, from_core=0x808):
for i in range(num_bytes):
self.data[start_addr + i] = chr(value & 0xff)
Expand All @@ -68,19 +66,15 @@ def __init__(self, block_size=2**20, logger=None):
def add_block(self, block_addr):
self.block_dict[block_addr] = _BlockMemory(size=self.block_size)

@elidable
def get_block_mem(self, block_addr):
if block_addr not in self.block_dict:
self.add_block(block_addr)
block_mem = self.block_dict[block_addr]
return block_mem

@elidable
def iread(self, start_addr, num_bytes, from_core=0x808):
if is_local_address(start_addr):
start_addr |= (from_core << 20)
start_addr = hint(start_addr, promote=True)
num_bytes = hint(num_bytes, promote=True)
end_addr = start_addr + num_bytes - 1
block_addr = self.block_mask & start_addr
block_mem = self.get_block_mem(block_addr)
Expand All @@ -106,7 +100,6 @@ def read(self, start_addr, num_bytes, from_core=0x808):
if is_local_address(start_addr):
start_addr |= (from_core << 20)
block_addr = self.block_mask & start_addr
block_addr = hint(block_addr, promote=True)
block_mem = self.get_block_mem(block_addr)
masked_addr = 0xfffff & start_addr
value = block_mem.read(start_addr & self.addr_mask, num_bytes)
Expand Down Expand Up @@ -149,7 +142,6 @@ def write(self, start_addr, num_bytes, value, from_core=0x808, quiet=False):
ilat |= 0x10
self.write(coreid_mask | 0xf0428, 4, ilat)
block_addr = self.block_mask & start_addr
block_addr = hint(block_addr, promote=True)
block_mem = self.get_block_mem(block_addr)
block_mem.write(start_addr & self.addr_mask, num_bytes, value)
masked_addr = 0xfffff & start_addr
Expand Down Expand Up @@ -190,6 +182,7 @@ def __getitem__(self, index):
pad_hex(value, len=self.debug_nchars)))
return value

@specialize.argtype(2)
def __setitem__(self, index, value):
if index == 0x65: # COREID register. Read only. Other Read/Write only
return # registers need to be accessed by instructions.
Expand Down
17 changes: 15 additions & 2 deletions revelation/test/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
from revelation.utils import (get_exponent, get_mantissa, bits2float,
float2bits, is_nan, is_inf, is_zero, sext_3, sext_11, sext_24, zfill)
from revelation.utils import get_exponent, get_mantissa, bits2float
from revelation.utils import float2bits, format_thousands, is_nan, is_inf
from revelation.utils import is_zero, sext_3, sext_11, sext_24, zfill

import math


def test_format_number():
assert '1' == format_thousands(1)
assert '11' == format_thousands(11)
assert '111' == format_thousands(111)
assert '1,111' == format_thousands(1111)
assert '11,111' == format_thousands(11111)
assert '1,111,111' == format_thousands(1111111)
assert '11,111,111' == format_thousands(11111111)
assert '111,111,111' == format_thousands(111111111)
assert '1,111,111,111' == format_thousands(1111111111)


def test_zfill():
assert '000001' == zfill('1', 6)
assert '+00001' == zfill('+1', 6)
Expand Down
13 changes: 13 additions & 0 deletions revelation/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@
import math


def format_thousands(number):
"""Format a number with a comma after every third digit.
"""
chars = []
number_s = str(number)
size = len(number_s)
for index in xrange(size - 1, -1, -1):
if (size - index) > 1 and (size - index - 1) % 3 == 0:
chars.insert(0, ',')
chars.insert(0, number_s[index])
return ''.join(chars)


def zfill(string, width):
"""zfill(x, width) -> string
Pad a numeric string x with zeros on the left, to fill a field
Expand Down

0 comments on commit ad225e4

Please sign in to comment.