include Error keyword in message
[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 class MemException(Exception):
31 pass
32
33
34 class Mem:
35
36 def __init__(self, row_bytes=8, initial_mem=None):
37 self.mem = {}
38 self.bytes_per_word = row_bytes
39 self.word_log2 = math.ceil(math.log2(row_bytes))
40 print("Sim-Mem", initial_mem, self.bytes_per_word, self.word_log2)
41 if not initial_mem:
42 return
43
44 # different types of memory data structures recognised (for convenience)
45 if isinstance(initial_mem, list):
46 initial_mem = (0, initial_mem)
47 if isinstance(initial_mem, tuple):
48 startaddr, mem = initial_mem
49 initial_mem = {}
50 for i, val in enumerate(mem):
51 initial_mem[startaddr + row_bytes*i] = (val, row_bytes)
52
53 for addr, val in initial_mem.items():
54 if isinstance(val, tuple):
55 (val, width) = val
56 else:
57 width = row_bytes # assume same width
58 #val = swap_order(val, width)
59 self.st(addr, val, width, swap=False)
60
61 def _get_shifter_mask(self, wid, remainder):
62 shifter = ((self.bytes_per_word - wid) - remainder) * \
63 8 # bits per byte
64 # XXX https://bugs.libre-soc.org/show_bug.cgi?id=377
65 # BE/LE mode?
66 shifter = remainder * 8
67 mask = (1 << (wid * 8)) - 1
68 print("width,rem,shift,mask", wid, remainder, hex(shifter), hex(mask))
69 return shifter, mask
70
71 # TODO: Implement ld/st of lesser width
72 def ld(self, address, width=8, swap=True, check_in_mem=False,
73 instr_fetch=False):
74 print("ld from addr 0x{:x} width {:d}".format(address, width),
75 swap, check_in_mem, instr_fetch)
76 remainder = address & (self.bytes_per_word - 1)
77 address = address >> self.word_log2
78 if remainder & (width - 1) != 0:
79 exc = MemException("unaligned", "Unaligned access Error")
80 exc.dar = address
81 raise exc
82 if address in self.mem:
83 val = self.mem[address]
84 elif check_in_mem:
85 return None
86 else:
87 val = 0
88 print("mem @ 0x{:x} rem {:d} : 0x{:x}".format(address, remainder, val))
89
90 if width != self.bytes_per_word:
91 shifter, mask = self._get_shifter_mask(width, remainder)
92 print("masking", hex(val), hex(mask << shifter), shifter)
93 val = val & (mask << shifter)
94 val >>= shifter
95 if swap:
96 val = swap_order(val, width)
97 print("Read 0x{:x} from addr 0x{:x}".format(val, address))
98 return val
99
100 def st(self, addr, v, width=8, swap=True):
101 staddr = addr
102 remainder = addr & (self.bytes_per_word - 1)
103 addr = addr >> self.word_log2
104 print("Writing 0x{:x} to ST 0x{:x} "
105 "memaddr 0x{:x}/{:x}".format(v, staddr, addr, remainder, swap))
106 if remainder & (width - 1) != 0:
107 exc = MemException("unaligned", "Unaligned access Error")
108 exc.dar = address
109 raise exc
110 if swap:
111 v = swap_order(v, width)
112 if width != self.bytes_per_word:
113 if addr in self.mem:
114 val = self.mem[addr]
115 else:
116 val = 0
117 shifter, mask = self._get_shifter_mask(width, remainder)
118 val &= ~(mask << shifter)
119 val |= v << shifter
120 self.mem[addr] = val
121 else:
122 self.mem[addr] = v
123 print("mem @ 0x{:x}: 0x{:x}".format(addr, self.mem[addr]))
124
125 def __call__(self, addr, sz):
126 val = self.ld(addr.value, sz, swap=False)
127 print("memread", addr, sz, val)
128 return SelectableInt(val, sz*8)
129
130 def memassign(self, addr, sz, val):
131 print("memassign", addr, sz, val)
132 self.st(addr.value, val.value, sz, swap=False)
133
134