From 9ab8188d3fb6203041e6a6db7311be47930b6be9 Mon Sep 17 00:00:00 2001 From: Sarah Mount Date: Fri, 29 Jul 2016 00:30:00 +0100 Subject: [PATCH] Use sparse memory model. Each block is 32MB - the same size as a single core-local memory, or default shared RAM. This is intended to speed up short running programs, who spend most of their time constructing blank memory. --- revelation/sim.py | 5 +- revelation/storage.py | 94 +++++--------------------- revelation/test/test_compiled_c.py | 5 +- revelation/test/test_multicore.py | 5 +- revelation/test/test_syscall_layout.py | 5 +- 5 files changed, 22 insertions(+), 92 deletions(-) diff --git a/revelation/sim.py b/revelation/sim.py index 97fb69f..c668de4 100644 --- a/revelation/sim.py +++ b/revelation/sim.py @@ -9,7 +9,7 @@ from revelation.isa import decode, reg_map from revelation.logger import Logger from revelation.machine import State -from revelation.storage import MemoryFactory +from revelation.storage import Memory import time @@ -19,11 +19,10 @@ EXIT_FILE_ERROR = 126 EXIT_CTRL_C = 130 LOG_FILENAME = 'r_trace.out' -MEMORY_SIZE = 2**32 # Global on-chip address space. def new_memory(logger): - return MemoryFactory(size=MEMORY_SIZE, logger=logger) + return Memory(block_size=2**20, logger=logger) class Revelation(Sim): diff --git a/revelation/storage.py b/revelation/storage.py index de8fc62..bc1845d 100644 --- a/revelation/storage.py +++ b/revelation/storage.py @@ -2,7 +2,6 @@ from pydgin.debug import Debug, pad, pad_hex from pydgin.jit import elidable, unroll_safe, hint -from pydgin.storage import _ByteMemory from pydgin.utils import specialize @@ -30,58 +29,32 @@ def get_register_size_by_address(register_address): return size -def MemoryFactory(data=None, size=2**10, logger=None): - """Choose memory model depending on whether we are translated. - """ - try: - from rpython.rlib.objectmodel import we_are_translated - sparse_storage = not we_are_translated() - except ImportError: - sparse_storage = True - if not sparse_storage: - return _RevelationByteMemory(data, size, logger) - else: - print "NOTE: Using sparse storage" - return _SparseMemory(_ByteMemory, logger=logger) - - -class _RevelationByteMemory(object): - """Memory model adapted from Pydgin. - Re-map addresses to core-local memory, deal with memory aliases. +class _BlockMemory(object): + """32MB block of memory, initialised to zero. """ - def __init__(self, data=None, size=2**10, logger=None): + def __init__(self, size=2**10, logger=None): """Initialise all memory to zero, as we don't know which memory. segments might hold memory-mapped registers. """ - self.data = data if data else ['\0'] * size + self.data = ['\0'] * size self.size = len(self.data) - self.debug = Debug() - self.logger = logger @unroll_safe - def read(self, start_addr, num_bytes, from_core=0x808, quiet=False): - if is_local_address(start_addr): - start_addr |= (from_core << 20) + 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]) - if (self.debug.enabled('mem') and self.logger and - not is_register_address(start_addr)): - self.logger.log(' :: RD.MEM[%s] = %s' %\ - (pad_hex(start_addr), pad_hex(value))) return value @elidable - def iread(self, start_addr, num_bytes, from_core=0x808, quiet=False): + 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 instructions are not modified (no side effects, assumes the addresses correspond to the same instructions). """ - if is_local_address(start_addr): - start_addr |= (from_core << 20) value = 0 for i in range(num_bytes - 1, -1, -1): value = value << 8 @@ -89,55 +62,27 @@ def iread(self, start_addr, num_bytes, from_core=0x808, quiet=False): return value @unroll_safe - def write(self, start_addr, num_bytes, value, from_core=0x808, quiet=False): - if is_local_address(start_addr): - start_addr |= (from_core << 20) - # Deal with register writes that are aliases to other locations. Better - # not to put these in the instruction semantics, as the aliased - # registers may be written to by a variety of instructions, and accessed - # as either registers or memory locations. - coreid_mask = start_addr & 0xfff00000 - if start_addr & 0xfffff == 0xf042c: # ILATST - ilat = self.read(coreid_mask | 0xf0428, 4) & 0x3ff - ilat |= (value & ((2 << 10) - 1)) - self.write(coreid_mask | 0xf0428, 4, ilat) - elif start_addr & 0xfffff == 0xf0430: # ILATCL - ilat = self.read(coreid_mask | 0xf0428, 4) & 0x3ff - ilat &= ~(value & ((2 << 10) - 1)) - self.write(coreid_mask | 0xf0428, 4, ilat) - elif start_addr & 0xfffff == 0xf0440: # FSTATUS - status = self.read(coreid_mask | 0xf0404, 4) - status |= (value & 0xfffffffc) # Can't write to lowest 2 bits. - self.write(coreid_mask | 0xf0404, 4, status) + 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) value = value >> 8 - if (self.debug.enabled('mem') and self.logger and not quiet and - not is_register_address(start_addr)): - self.logger.log(' :: WR.MEM[%s] = %s' % \ - (pad_hex(start_addr), pad_hex(value))) -class _SparseMemory(object): +class Memory(object): """Sparse memory model adapted from Pydgin. """ - _immutable_fields_ = ['BlockMemory', 'block_size', 'addr_mask', 'block_mask', - 'logger'] + _immutable_fields_ = ['block_size', 'addr_mask', 'block_mask', 'logger'] - def __init__(self, BlockMemory, block_size=2**10, logger=None): - self.BlockMemory = BlockMemory + def __init__(self, block_size=2**20, logger=None): self.block_size = block_size self.debug = Debug() self.logger = logger self.addr_mask = block_size - 1 self.block_mask = 0xffffffff ^ self.addr_mask - print 'sparse memory size %x addr mask %x block mask %x' \ - % (self.block_size, self.addr_mask, self.block_mask) self.block_dict = {} def add_block(self, block_addr): - self.block_dict[block_addr] = self.BlockMemory(data=['\0'] * self.block_size, - size=self.block_size) + self.block_dict[block_addr] = _BlockMemory(size=self.block_size) @elidable def get_block_mem(self, block_addr): @@ -147,7 +92,7 @@ def get_block_mem(self, block_addr): return block_mem @elidable - def iread(self, start_addr, num_bytes, from_core=0x808, quiet=False): + 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) @@ -173,19 +118,13 @@ def iread(self, start_addr, num_bytes, from_core=0x808, quiet=False): value = value1 | (value2 << (num_bytes1 * 8)) return value - def read(self, start_addr, num_bytes, from_core=0x808, quiet=False): + 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) - value = block_mem.read(start_addr & self.addr_mask, num_bytes) - masked_addr = 0xfffff & start_addr - if (self.debug.enabled('mem') and self.logger and - not is_register_address(masked_addr)): - self.logger.log(' :: RD.MEM[%s] = %s' %\ - (pad_hex(start_addr), pad_hex(value))) - return value + return block_mem.read(start_addr & self.addr_mask, num_bytes) def write(self, start_addr, num_bytes, value, from_core=0x808, quiet=False): if is_local_address(start_addr): @@ -244,7 +183,7 @@ def __init__(self, memory, coreid, logger): def __getitem__(self, index): address, bitsize, _ = _register_map[index] mask = (1 << bitsize) - 1 - value = self.memory.read(address, 4, from_core=self.coreid) & mask + value = self.memory.iread(address, 4, from_core=self.coreid) & mask if self.debug.enabled('rf') and self.logger and index < 64: self.logger.log(' :: RD.RF[%s] = %s' % (pad('%d' % index, 2), pad_hex(value, len=self.debug_nchars))) @@ -256,7 +195,8 @@ def __setitem__(self, index, value): return # registers need to be accessed by instructions. address, bitsize, _ = _register_map[index] # Lower 20 bits of address. mask = (1 << bitsize) - 1 - self.memory.write(address, 4, value & mask, from_core=self.coreid) + self.memory.write(address, 4, value & mask, from_core=self.coreid, + quiet=True) if self.debug.enabled('rf') and self.logger and index < 64: self.logger.log(' :: WR.RF[%s] = %s' % ((pad('%d' % index, 2), pad_hex(value, len=self.debug_nchars)))) diff --git a/revelation/test/test_compiled_c.py b/revelation/test/test_compiled_c.py index dfc75e8..1a264ca 100644 --- a/revelation/test/test_compiled_c.py +++ b/revelation/test/test_compiled_c.py @@ -73,10 +73,7 @@ def test_compiled_c_with_output(elf_file, expected, capfd): assert not revelation.states[0].running out, err = capfd.readouterr() assert err == '' - expected_full = (('NOTE: Using sparse storage\n' - 'sparse memory size 400 addr mask 3ff ' - 'block mask fffffc00\n' - 'Loading program %s on to core 0x808\n' % elf_filename) + expected_full = (('Loading program %s on to core 0x808\n' % elf_filename) + expected) assert out.startswith(expected_full) diff --git a/revelation/test/test_multicore.py b/revelation/test/test_multicore.py index 23ba7c2..89bb5b4 100644 --- a/revelation/test/test_multicore.py +++ b/revelation/test/test_multicore.py @@ -28,10 +28,7 @@ def test_two_cores_with_output(elf_file, expected, capfd): assert not revelation.states[1].running out, err = capfd.readouterr() assert err == '' - expected_full = (('NOTE: Using sparse storage\n' - 'sparse memory size 400 addr mask 3ff ' - 'block mask fffffc00\n' - 'Loading program %s on to core 0x808\n' + expected_full = (('Loading program %s on to core 0x808\n' 'Loading program %s on to core 0x809\n' % (elf_filename, elf_filename)) + expected) assert out.startswith(expected_full) diff --git a/revelation/test/test_syscall_layout.py b/revelation/test/test_syscall_layout.py index 71ec3ec..ef30be6 100644 --- a/revelation/test/test_syscall_layout.py +++ b/revelation/test/test_syscall_layout.py @@ -67,9 +67,6 @@ def test_open_close_syscall_layout(capfd): assert err == '' expected = ('open() successful.\nRead: 14 bytes.\nHello, world!\n' 'Read: 0 bytes.\nclose() successful.\n') - expected_full = (('NOTE: Using sparse storage\n' - 'sparse memory size 400 addr mask 3ff ' - 'block mask fffffc00\n' - 'Loading program %s on to core 0x808\n' % elf_filename) + expected_full = (('Loading program %s on to core 0x808\n' % elf_filename) + expected) assert out.startswith(expected_full)