resolving imports changing over
[openpower-isa.git] / src / openpower / decoder / isa / mem.py
1 # SPDX-License-Identifier: LGPLv3+
2 # Copyright (C) 2020, 2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
3 # Funded by NLnet http://nlnet.nl
4 """core of the python-based POWER9 simulator
5
6 this is part of a cycle-accurate POWER9 simulator. its primary purpose is
7 not speed, it is for both learning and educational purposes, as well as
8 a method of verifying the HDL.
9
10 related bugs:
11
12 * https://bugs.libre-soc.org/show_bug.cgi?id=424
13 """
14
15 from copy import copy
16 from openpower.decoder.selectable_int import (FieldSelectableInt, SelectableInt,
17 selectconcat)
18
19 from openpower.decoder.helpers import exts, gtu, ltu, undefined
20 import math
21 import sys
22
23
24 def swap_order(x, nbytes):
25 x = x.to_bytes(nbytes, byteorder='little')
26 x = int.from_bytes(x, byteorder='big', signed=False)
27 return x
28
29
30
31 class Mem:
32
33 def __init__(self, row_bytes=8, initial_mem=None):
34 self.mem = {}
35 self.bytes_per_word = row_bytes
36 self.word_log2 = math.ceil(math.log2(row_bytes))
37 print("Sim-Mem", initial_mem, self.bytes_per_word, self.word_log2)
38 if not initial_mem:
39 return
40
41 # different types of memory data structures recognised (for convenience)
42 if isinstance(initial_mem, list):
43 initial_mem = (0, initial_mem)
44 if isinstance(initial_mem, tuple):
45 startaddr, mem = initial_mem
46 initial_mem = {}
47 for i, val in enumerate(mem):
48 initial_mem[startaddr + row_bytes*i] = (val, row_bytes)
49
50 for addr, val in initial_mem.items():
51 if isinstance(val, tuple):
52 (val, width) = val
53 else:
54 width = row_bytes # assume same width
55 #val = swap_order(val, width)
56 self.st(addr, val, width, swap=False)
57
58 def _get_shifter_mask(self, wid, remainder):
59 shifter = ((self.bytes_per_word - wid) - remainder) * \
60 8 # bits per byte
61 # XXX https://bugs.libre-soc.org/show_bug.cgi?id=377
62 # BE/LE mode?
63 shifter = remainder * 8
64 mask = (1 << (wid * 8)) - 1
65 print("width,rem,shift,mask", wid, remainder, hex(shifter), hex(mask))
66 return shifter, mask
67
68 # TODO: Implement ld/st of lesser width
69 def ld(self, address, width=8, swap=True, check_in_mem=False,
70 instr_fetch=False):
71 print("ld from addr 0x{:x} width {:d}".format(address, width),
72 swap, check_in_mem, instr_fetch)
73 remainder = address & (self.bytes_per_word - 1)
74 address = address >> self.word_log2
75 assert remainder & (width - 1) == 0, "Unaligned access unsupported!"
76 if address in self.mem:
77 val = self.mem[address]
78 elif check_in_mem:
79 return None
80 else:
81 val = 0
82 print("mem @ 0x{:x} rem {:d} : 0x{:x}".format(address, remainder, val))
83
84 if width != self.bytes_per_word:
85 shifter, mask = self._get_shifter_mask(width, remainder)
86 print("masking", hex(val), hex(mask << shifter), shifter)
87 val = val & (mask << shifter)
88 val >>= shifter
89 if swap:
90 val = swap_order(val, width)
91 print("Read 0x{:x} from addr 0x{:x}".format(val, address))
92 return val
93
94 def st(self, addr, v, width=8, swap=True):
95 staddr = addr
96 remainder = addr & (self.bytes_per_word - 1)
97 addr = addr >> self.word_log2
98 print("Writing 0x{:x} to ST 0x{:x} "
99 "memaddr 0x{:x}/{:x}".format(v, staddr, addr, remainder, swap))
100 assert remainder & (width - 1) == 0, "Unaligned access unsupported!"
101 if swap:
102 v = swap_order(v, width)
103 if width != self.bytes_per_word:
104 if addr in self.mem:
105 val = self.mem[addr]
106 else:
107 val = 0
108 shifter, mask = self._get_shifter_mask(width, remainder)
109 val &= ~(mask << shifter)
110 val |= v << shifter
111 self.mem[addr] = val
112 else:
113 self.mem[addr] = v
114 print("mem @ 0x{:x}: 0x{:x}".format(addr, self.mem[addr]))
115
116 def __call__(self, addr, sz):
117 val = self.ld(addr.value, sz, swap=False)
118 print("memread", addr, sz, val)
119 return SelectableInt(val, sz*8)
120
121 def memassign(self, addr, sz, val):
122 print("memassign", addr, sz, val)
123 self.st(addr.value, val.value, sz, swap=False)
124
125