power_insn: refactor opcode matching
[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 collections import defaultdict
16 from openpower.decoder.selectable_int import SelectableInt
17 from openpower.util import log, LogKind
18 import math
19
20
21 def swap_order(x, nbytes):
22 x = x.to_bytes(nbytes, byteorder='little')
23 x = int.from_bytes(x, byteorder='big', signed=False)
24 return x
25
26
27 class MemException(Exception):
28 pass
29
30 def process_mem(initial_mem, row_bytes=8):
31 res = {}
32 # different types of memory data structures recognised (for convenience)
33 if isinstance(initial_mem, list):
34 initial_mem = (0, initial_mem)
35 if isinstance(initial_mem, tuple):
36 startaddr, mem = initial_mem
37 initial_mem = {}
38 for i, val in enumerate(mem):
39 initial_mem[startaddr + row_bytes*i] = (val, row_bytes)
40
41 for addr, val in initial_mem.items():
42 if isinstance(val, tuple):
43 (val, width) = val
44 else:
45 width = row_bytes # assume same width
46 #val = swap_order(val, width)
47 res[addr] = (val, width)
48
49 return res
50
51
52 class Mem:
53
54 def __init__(self, row_bytes=8, initial_mem=None):
55 self.mem = {}
56 self.bytes_per_word = row_bytes
57 self.word_log2 = math.ceil(math.log2(row_bytes))
58 self.last_ld_addr = None
59 self.last_st_addr = None
60 log("Sim-Mem", initial_mem, self.bytes_per_word, self.word_log2)
61 if not initial_mem:
62 return
63
64 for addr, (val, width) in process_mem(initial_mem, row_bytes).items():
65 #val = swap_order(val, width)
66 self.st(addr, val, width, swap=False)
67
68 def _get_shifter_mask(self, wid, remainder):
69 shifter = ((self.bytes_per_word - wid) - remainder) * \
70 8 # bits per byte
71 # XXX https://bugs.libre-soc.org/show_bug.cgi?id=377
72 # BE/LE mode?
73 shifter = remainder * 8
74 mask = (1 << (wid * 8)) - 1
75 log("width,rem,shift,mask", wid, remainder, hex(shifter), hex(mask))
76 return shifter, mask
77
78 # TODO: Implement ld/st of lesser width
79 def ld(self, address, width=8, swap=True, check_in_mem=False,
80 instr_fetch=False):
81 log("ld from addr 0x%x width %d" % (address, width),
82 swap, check_in_mem, instr_fetch)
83 self.last_ld_addr = address # record last load
84 ldaddr = address
85 remainder = address & (self.bytes_per_word - 1)
86 address = address >> self.word_log2
87 if remainder & (width - 1) != 0:
88 exc = MemException("unaligned", "Unaligned access Error")
89 exc.dar = ldaddr
90 raise exc
91 if address in self.mem:
92 val = self.mem[address]
93 elif check_in_mem:
94 return None
95 else:
96 val = 0
97 log("ld mem @ 0x%x rem %d : 0x%x" % (ldaddr, remainder, val))
98
99 if width != self.bytes_per_word:
100 shifter, mask = self._get_shifter_mask(width, remainder)
101 log("masking", hex(val), hex(mask << shifter), shifter)
102 val = val & (mask << shifter)
103 val >>= shifter
104 if swap:
105 val = swap_order(val, width)
106 log("Read 0x%x from addr 0x%x" % (val, ldaddr))
107 return val
108
109 def st(self, addr, v, width=8, swap=True):
110 staddr = addr
111 self.last_st_addr = addr # record last store
112 remainder = addr & (self.bytes_per_word - 1)
113 addr = addr >> self.word_log2
114 log("Writing 0x%x to ST 0x%x memaddr 0x%x/%x swap %s" % \
115 (v, staddr, addr, remainder, str(swap)))
116 if remainder & (width - 1) != 0:
117 exc = MemException("unaligned", "Unaligned access Error")
118 exc.dar = staddr
119 raise exc
120 if swap:
121 v = swap_order(v, width)
122 if width != self.bytes_per_word:
123 if addr in self.mem:
124 val = self.mem[addr]
125 else:
126 val = 0
127 shifter, mask = self._get_shifter_mask(width, remainder)
128 val &= ~(mask << shifter)
129 val |= v << shifter
130 self.mem[addr] = val
131 else:
132 self.mem[addr] = v
133 log("mem @ 0x%x: 0x%x" % (staddr, self.mem[addr]))
134
135 def __call__(self, addr, sz):
136 val = self.ld(addr.value, sz, swap=False)
137 log("memread", addr, sz, val)
138 return SelectableInt(val, sz*8)
139
140 def memassign(self, addr, sz, val):
141 log("memassign", addr, sz, val)
142 self.st(addr.value, val.value, sz, swap=False)
143
144 def dump(self, printout=True):
145 keys = list(self.mem.keys())
146 keys.sort()
147 res = []
148 for k in keys:
149 res.append(((k*8), self.mem[k]))
150 if not printout:
151 continue
152 print ("%016x: %016x" % ((k*8) & 0xffffffffffffffff, self.mem[k]))
153 return res
154
155 def log_fancy(self, *, kind=LogKind.Default, name="Memory",
156 log2_line_size=4, log2_column_chunk_size=3):
157 line_size = 1 << log2_line_size
158 subline_mask = line_size - 1
159 column_chunk_size = 1 << log2_column_chunk_size
160
161 def make_line():
162 return bytearray(line_size)
163 mem_lines = defaultdict(make_line)
164 subword_range = range(1 << self.word_log2)
165 for k in self.mem.keys():
166 addr = k << self.word_log2
167 for _ in subword_range:
168 v = self.ld(addr, width=1)
169 mem_lines[addr >> log2_line_size][addr & subline_mask] = v
170 addr += 1
171
172 lines = []
173 last_line_index = None
174 for line_index in sorted(mem_lines.keys()):
175 line_addr = line_index << log2_line_size
176 if last_line_index is not None \
177 and last_line_index + 1 != line_index:
178 lines.append("*")
179 last_line_index = line_index
180 line_bytes = mem_lines[line_index]
181 line_str = f"0x{line_addr:08X}:"
182 for col_chunk in range(0, line_size,
183 column_chunk_size):
184 line_str += " "
185 for i in range(column_chunk_size):
186 line_str += f" {line_bytes[col_chunk + i]:02X}"
187 line_str += " |"
188 for i in range(line_size):
189 if 0x20 <= line_bytes[i] <= 0x7E:
190 line_str += chr(line_bytes[i])
191 else:
192 line_str += "."
193 line_str += "|"
194 lines.append(line_str)
195 lines = "\n".join(lines)
196 log(f"\n{name}:\n{lines}\n", kind=kind)