Source code for bare68k.memcfg

from bare68k.consts import *
from bare68k.errors import *

MEM_NOALLOC = '_'
MEM_RAM = 'a'
MEM_ROM = 'o'
MEM_SPECIAL = 'S'
MEM_RESERVE = 'X'
MEM_EMPTY = 'E'
MEM_MIRROR = 'M'

PAGE_BYTES = 64 * 1024
PAGE_MASK = 0xffff
PAGE_SHIFT = 16


class MemoryRange(object):

    def __init__(self, start_page, num_pages, mem_type,
                 opts=None, traps=True, name=None):
        self.start_page = start_page
        self.num_pages = num_pages
        self.mem_type = mem_type
        self.opts = opts
        self.traps = traps
        self.name = name
        self.next_page = self.start_page + self.num_pages
        self.start_addr = start_page << PAGE_SHIFT

    def __repr__(self):
        return "MemoryRange(%d, %d, %s, opts=%r, traps=%r, name=%s)" % \
            (self.start_page, self.num_pages,
             self.mem_type, self.opts, self.traps, self.name)

    def __eq__(self, o):
        return self.start_page == o.start_page and self.num_pages == o.num_pages \
            and self.mem_type == o.mem_type and self.opts == o.opts \
            and self.traps == o.traps


[docs]class MemoryConfig(object): """Configuration class for the memory layout of your m68k system""" def __init__(self, auto_align=False): """setup default memory config""" # auto align size requests that are not page aligned self.auto_align = auto_align # page list to see allocation self.range_list = [] def _get_str_size(self, size_str, def_units): """get a size value from a string an honor K,M,G units returns (size_int, units_int) """ n = len(size_str) if n < 1: raise ConfigError("Invalid size given: " + size_str) all_digits = size_str.isdigit() if all_digits: size = int(size_str) return (size, def_units) else: unit_str = size_str[-1].lower() if unit_str == 'k': units = 1024 elif unit_str == 'm': units = 1024 * 1024 elif unit_str == 'g': units = 1024 * 1024 * 1024 elif unit_str == 'p': # for pages units = PAGE_BYTES else: raise ConfigError("Unknown size units: " + unit_str) size_str = size_str[:-1] if not size_str.isdigit(): raise ConfigError("Invalid size given: " + size_str) size = int(size_str) return(size, units) def _get_num_pages(self, size, units): """get a size value and make sure its page aligned and return the pages""" if type(size) is str: n_size, n_units = self._get_str_size(size, units) total = n_size * n_units else: total = size * units # is 64k page aligned? if total & PAGE_MASK != 0: if self.auto_align: pages = (total + PAGE_MASK) >> PAGE_SHIFT else: raise ConfigError( "Size value %s (units %s) is not page aligned!" % (size, units)) else: pages = total >> PAGE_SHIFT return pages def _get_page_addr(self, addr): """convert an absolute address to a page number""" return self._get_num_pages(addr, 1) def _store_page_range(self, begin_page, num_pages, mem_type, opts=None, sparse=False, traps=True, name=None): """make sure the given page range fits in the page list""" # create a new range r = MemoryRange(begin_page, num_pages, mem_type, opts, traps, name) # add to range_list rl = self.range_list if len(rl) == 0: # add first rl.append(r) return [r] else: # where to insert pos = 0 res = [] for e in rl: # lies before if r.start_page < e.start_page: # does fit if r.next_page <= e.start_page: rl.insert(pos, r) res.append(r) return res else: if sparse: # create partial range that fits np = e.start_page - r.start_page nr = MemoryRange(r.start_page, np, r.mem_type, r.opts, r.traps) rl.insert(pos, nr) res.append(nr) # keep remainder r = MemoryRange( e.next_page, r.num_pages - np, r.mem_type, r.opts, r.traps) else: raise ConfigError("%r overlaps %r!" % (r, e)) # liese inside elif r.start_page < e.next_page: if not sparse: raise ConfigError("%r overlaps %r!" % (r, e)) pos += 1 # append to end rl.append(r) res.append(r) return res def _prepare_rom(self, data, pad): if data is None: return None n = len(data) rem = n % PAGE_BYTES if rem == 0: return data else: if pad is False: raise ConfigError("ROM needs padding") else: fill = PAGE_BYTES - rem if pad is True: pad = 0 fill_data = bytes(bytearray([pad] * fill)) rom = data + fill_data return rom # page based def add_ram_range(self, begin_page, num_pages, sparse=False, traps=True, name=None): return self._store_page_range(begin_page, num_pages, MEM_RAM, sparse=sparse, traps=traps, name=name) def add_rom_range(self, begin_page, num_pages, data=None, pad=False, traps=True, name=None): rom = self._prepare_rom(data, pad) return self._store_page_range(begin_page, num_pages, MEM_ROM, opts=rom, traps=traps, name=name) def add_special_range(self, begin_page, num_pages, r_func, w_func, name=None): opts = (r_func, w_func) return self._store_page_range(begin_page, num_pages, MEM_SPECIAL, opts=opts, name=name) def add_empty_range(self, begin_page, num_pages, value=0xffffffff, name=None): return self._store_page_range(begin_page, num_pages, MEM_EMPTY, opts=value, name=name) def add_mirror_range(self, begin_page, num_pages, base_page, name=None): return self._store_page_range(begin_page, num_pages, MEM_MIRROR, opts=base_page, name=name) def add_reserve_range(self, begin_page, num_pages, name=None): return self._store_page_range(begin_page, num_pages, MEM_RESERVE, name=name) # address based def add_ram_range_addr(self, begin_addr, size, units=1024, sparse=False, traps=True, name=None): begin_page = self._get_page_addr(begin_addr) num_pages = self._get_num_pages(size, units) return self.add_ram_range(begin_page, num_pages, sparse, traps=traps, name=name) def add_rom_range_addr(self, begin_addr, size, data=None, units=1024, pad=False, traps=True, name=None): begin_page = self._get_page_addr(begin_addr) num_pages = self._get_num_pages(size, units) return self.add_rom_range(begin_page, num_pages, data, pad, traps=traps, name=name) def add_special_range_addr(self, begin_addr, size, r_func, w_func, units=1024, name=None): begin_page = self._get_page_addr(begin_addr) num_pages = self._get_num_pages(size, units) return self.add_special_range(begin_page, num_pages, r_func, w_func, name=name) def add_empty_range_addr(self, begin_addr, size, value=0xffffffff, units=1024, name=None): begin_page = self._get_page_addr(begin_addr) num_pages = self._get_num_pages(size, units) return self.add_empty_range(begin_page, num_pages, value, name=name) def add_mirror_range_addr(self, begin_addr, size, base_addr, units=1024, name=None): begin_page = self._get_page_addr(begin_addr) num_pages = self._get_num_pages(size, units) base_page = self._get_page_addr(base_addr) return self.add_mirror_range(begin_page, num_pages, base_page, name=name) def add_reserve_range_addr(self, begin_addr, size, units=1024, name=None): begin_page = self._get_page_addr(begin_addr) num_pages = self._get_num_pages(size, units) return self.add_reserve_range(begin_page, num_pages, name=name) # get result
[docs] def get_range_list(self): """return the list of memory ranges currently allocated""" return self.range_list
[docs] def get_page_list_str(self): """return a string showing page allocation""" s = "" rl = self.range_list if len(rl) == 0: return "" old_pos = 0 for r in rl: pos = r.start_page space = pos - old_pos if space > 0: s += MEM_NOALLOC * space np = r.num_pages s += r.mem_type * np old_pos = pos + r.num_pages return s
[docs] def get_num_pages(self): """return the total number of pages required to handle the given layout""" rl = self.range_list if len(rl) == 0: return 0 else: return rl[-1].next_page
[docs] def check(self, ram_at_zero=True, max_pages=256): """check if gurrent layout is valid""" n = self.get_num_pages() if n == 0: raise ConfigError("no memory entries found!") elif n > max_pages: raise ConfigError("too many pages: want=%d max=%d" % (n, max_pages)) if ram_at_zero: r = self.range_list[0] if r.start_page > 0 or r.mem_type != MEM_RAM: raise ConfigError("no RAM at page 0!")