a0ebcc4a91459cd00d75812cd8506f84aeb58497
[soc.git] / src / soc / 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 soc.decoder.selectable_int import (FieldSelectableInt, SelectableInt,
17 selectconcat)
18
19 from soc.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, width) in initial_mem.items():
51 #val = swap_order(val, width)
52 self.st(addr, val, width, swap=False)
53
54 def _get_shifter_mask(self, wid, remainder):
55 shifter = ((self.bytes_per_word - wid) - remainder) * \
56 8 # bits per byte
57 # XXX https://bugs.libre-soc.org/show_bug.cgi?id=377
58 # BE/LE mode?
59 shifter = remainder * 8
60 mask = (1 << (wid * 8)) - 1
61 print("width,rem,shift,mask", wid, remainder, hex(shifter), hex(mask))
62 return shifter, mask
63
64 # TODO: Implement ld/st of lesser width
65 def ld(self, address, width=8, swap=True, check_in_mem=False,
66 instr_fetch=False):
67 print("ld from addr 0x{:x} width {:d}".format(address, width),
68 swap, check_in_mem, instr_fetch)
69 remainder = address & (self.bytes_per_word - 1)
70 address = address >> self.word_log2
71 assert remainder & (width - 1) == 0, "Unaligned access unsupported!"
72 if address in self.mem:
73 val = self.mem[address]
74 elif check_in_mem:
75 return None
76 else:
77 val = 0
78 print("mem @ 0x{:x} rem {:d} : 0x{:x}".format(address, remainder, val))
79
80 if width != self.bytes_per_word:
81 shifter, mask = self._get_shifter_mask(width, remainder)
82 print("masking", hex(val), hex(mask << shifter), shifter)
83 val = val & (mask << shifter)
84 val >>= shifter
85 if swap:
86 val = swap_order(val, width)
87 print("Read 0x{:x} from addr 0x{:x}".format(val, address))
88 return val
89
90 def st(self, addr, v, width=8, swap=True):
91 staddr = addr
92 remainder = addr & (self.bytes_per_word - 1)
93 addr = addr >> self.word_log2
94 print("Writing 0x{:x} to ST 0x{:x} "
95 "memaddr 0x{:x}/{:x}".format(v, staddr, addr, remainder, swap))
96 assert remainder & (width - 1) == 0, "Unaligned access unsupported!"
97 if swap:
98 v = swap_order(v, width)
99 if width != self.bytes_per_word:
100 if addr in self.mem:
101 val = self.mem[addr]
102 else:
103 val = 0
104 shifter, mask = self._get_shifter_mask(width, remainder)
105 val &= ~(mask << shifter)
106 val |= v << shifter
107 self.mem[addr] = val
108 else:
109 self.mem[addr] = v
110 print("mem @ 0x{:x}: 0x{:x}".format(addr, self.mem[addr]))
111
112 def __call__(self, addr, sz):
113 val = self.ld(addr.value, sz, swap=False)
114 print("memread", addr, sz, val)
115 return SelectableInt(val, sz*8)
116
117 def memassign(self, addr, sz, val):
118 print("memassign", addr, sz, val)
119 self.st(addr.value, val.value, sz, swap=False)
120
121