got cos intermediate working on iterative dct
[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 from openpower.util import log
21 import math
22 import sys
23
24
25 def swap_order(x, nbytes):
26 x = x.to_bytes(nbytes, byteorder='little')
27 x = int.from_bytes(x, byteorder='big', signed=False)
28 return x
29
30
31 class MemException(Exception):
32 pass
33
34
35 class Mem:
36
37 def __init__(self, row_bytes=8, initial_mem=None):
38 self.mem = {}
39 self.bytes_per_word = row_bytes
40 self.word_log2 = math.ceil(math.log2(row_bytes))
41 self.last_ld_addr = None
42 self.last_st_addr = None
43 log("Sim-Mem", initial_mem, self.bytes_per_word, self.word_log2)
44 if not initial_mem:
45 return
46
47 # different types of memory data structures recognised (for convenience)
48 if isinstance(initial_mem, list):
49 initial_mem = (0, initial_mem)
50 if isinstance(initial_mem, tuple):
51 startaddr, mem = initial_mem
52 initial_mem = {}
53 for i, val in enumerate(mem):
54 initial_mem[startaddr + row_bytes*i] = (val, row_bytes)
55
56 for addr, val in initial_mem.items():
57 if isinstance(val, tuple):
58 (val, width) = val
59 else:
60 width = row_bytes # assume same width
61 #val = swap_order(val, width)
62 self.st(addr, val, width, swap=False)
63
64 def _get_shifter_mask(self, wid, remainder):
65 shifter = ((self.bytes_per_word - wid) - remainder) * \
66 8 # bits per byte
67 # XXX https://bugs.libre-soc.org/show_bug.cgi?id=377
68 # BE/LE mode?
69 shifter = remainder * 8
70 mask = (1 << (wid * 8)) - 1
71 log("width,rem,shift,mask", wid, remainder, hex(shifter), hex(mask))
72 return shifter, mask
73
74 # TODO: Implement ld/st of lesser width
75 def ld(self, address, width=8, swap=True, check_in_mem=False,
76 instr_fetch=False):
77 log("ld from addr 0x%x width %d" % (address, width),
78 swap, check_in_mem, instr_fetch)
79 self.last_ld_addr = address # record last load
80 ldaddr = address
81 remainder = address & (self.bytes_per_word - 1)
82 address = address >> self.word_log2
83 if remainder & (width - 1) != 0:
84 exc = MemException("unaligned", "Unaligned access Error")
85 exc.dar = ldaddr
86 raise exc
87 if address in self.mem:
88 val = self.mem[address]
89 elif check_in_mem:
90 return None
91 else:
92 val = 0
93 log("ld mem @ 0x%x rem %d : 0x%x" % (ldaddr, remainder, val))
94
95 if width != self.bytes_per_word:
96 shifter, mask = self._get_shifter_mask(width, remainder)
97 log("masking", hex(val), hex(mask << shifter), shifter)
98 val = val & (mask << shifter)
99 val >>= shifter
100 if swap:
101 val = swap_order(val, width)
102 log("Read 0x%x from addr 0x%x" % (val, ldaddr))
103 return val
104
105 def st(self, addr, v, width=8, swap=True):
106 staddr = addr
107 self.last_st_addr = addr # record last store
108 remainder = addr & (self.bytes_per_word - 1)
109 addr = addr >> self.word_log2
110 log("Writing 0x%x to ST 0x%x memaddr 0x%x/%x swap %s" % \
111 (v, staddr, addr, remainder, str(swap)))
112 if remainder & (width - 1) != 0:
113 exc = MemException("unaligned", "Unaligned access Error")
114 exc.dar = staddr
115 raise exc
116 if swap:
117 v = swap_order(v, width)
118 if width != self.bytes_per_word:
119 if addr in self.mem:
120 val = self.mem[addr]
121 else:
122 val = 0
123 shifter, mask = self._get_shifter_mask(width, remainder)
124 val &= ~(mask << shifter)
125 val |= v << shifter
126 self.mem[addr] = val
127 else:
128 self.mem[addr] = v
129 log("mem @ 0x%x: 0x%x" % (staddr, self.mem[addr]))
130
131 def __call__(self, addr, sz):
132 val = self.ld(addr.value, sz, swap=False)
133 log("memread", addr, sz, val)
134 return SelectableInt(val, sz*8)
135
136 def memassign(self, addr, sz, val):
137 log("memassign", addr, sz, val)
138 self.st(addr.value, val.value, sz, swap=False)
139
140 def dump(self, printout=True):
141 keys = list(self.mem.keys())
142 keys.sort()
143 res = []
144 for k in keys:
145 res.append(((k*8), self.mem[k]))
146 if not printout:
147 continue
148 print ("%016x: %016x" % ((k*8) & 0xffffffffffffffff, self.mem[k]))
149 return res