From 681036ddc3891904f13c84197cd90e2472cb3e1c Mon Sep 17 00:00:00 2001 From: Ekaitz Zarraga Date: Fri, 23 Jul 2021 20:49:14 +0200 Subject: Change folder name --- pyscv/memory.py | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 pyscv/memory.py (limited to 'pyscv/memory.py') diff --git a/pyscv/memory.py b/pyscv/memory.py new file mode 100644 index 0000000..84bf0bd --- /dev/null +++ b/pyscv/memory.py @@ -0,0 +1,112 @@ +from ctypes import c_uint8, c_uint16, c_uint32 + +class Addressable: + def __init__(self, start=0, end=0): + self.start = start + self.end = end + def addr_to_pos(self, addr): + if not (self.start <= addr < self.end): + raise KeyError("Address out of space") + return addr - self.start + +def merge_bytes (byte_iter): + val = 0 + for i,v in enumerate(byte_ouput): + val += v.value << 8 * i + return val +def split_bytes (val, byte_count): + return tuple( c_uint8(val >> 8 * i) for i in range(byte_count) ) + +class Memory32 (Addressable): + """ + This is a raw 32-bit word memory addressable at a byte level. + Internally it is defined as c_uint8 list. + Special functions are needed to access halfs (c_uint16) and words + (c_uint32). + """ + + def __init__(self, start=0, end=0, bigEndian=False): + super().__init__(start, end) + self.bigEndian = bigEndian + self.lastChange = None + # Pre-allocate or allocate or allocate per write? + self.data = [None] * (end - start) + + def get_byte(self, addr): + return self.data[ self.addr_to_pos(addr) ] + def set_byte(self, addr, val): + if not isinstance(val, c_uint8): + if val > 0xFF: + raise ValueError("Value is larger than a byte") + self.data[ self.addr_to_pos(addr) ] = val if isinstance(val, c_uint8) else c_uint8(val) + self.lastChange = range(addr, addr+1) + + + def get_half(self,addr): + byte_output = (get_byte(addr), get_byte(addr+1)) + if self.bigEndian: + byte_output = reversed(byte_output) + return c_uint16( merge_bytes(byte_output) ) + + def set_half(self, addr, val): + if not isinstance(val, c_uint16): + if val > 0xFFFF: + raise ValueError("Value is larger than a half") + bytes = split_bytes(val, 2) + if self.bigEndian: + bytes = reversed(bytes) + for i,v in enumerate(bytes): + self.set_byte(addr+i, v) + self.lastChange = range(addr,addr+2) + + def get_word(self, pos): + byte_output = tuple(get_byte(addr+i) for i in range(4)) + if self.bigEndian: + byte_output = reversed(byte_output) + return c_uint32( merge_bytes(byte_output) ) + + def set_word(self, addr, val): + if not isinstance(val, c_uint32): + if val > 0xFFFFFFFF: + raise ValueError("Value is larger than a word") + bytes = split_bytes(val, 4) + if self.bigEndian: + bytes = reversed(bytes) + for i,v in enumerate(bytes): + self.set_byte(addr+i, v) + self.lastChange = range(addr,addr+4) + + def __str__(self): + out = " " + out += "-" * 50 + out += "\n" + for i,d in enumerate(self.data): + if d is not None: + addr = i+self.start + out += "->" if addr in self.lastChange else " " + out += f"| {addr:#20x} | {d.value:#5} | {d.value:#04x} | {d.value:#010b} |" + out += "\n" + out += " " + out += "-" * 50 + out += "\n" + return out + + +class Memory32RO (Memory32): + def set_byte(self, addr, val): + raise NotImplementedError("Trying to write in a read-only memory") + def set_half(self, addr, val): + raise NotImplementedError("Trying to write in a read-only memory") + def set_word(self, addr, val): + raise NotImplementedError("Trying to write in a read-only memory") + +class CodeMemory32 (Memory32RO): + def __init__(self, start=0, end=0): + super().__init__(writable=False,start=start,end=end) + + +if __name__ == "__main__": + m = Memory32(start=100,end=200) + print(m.start, m.end) + m.set_byte(100, 246) + print(m) -- cgit v1.2.3