add ascii graphic for extsw svp64 operation
[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.power_enums import SPR as DEC_SPR
20
21 from soc.decoder.helpers import exts, gtu, ltu, undefined
22 import math
23 import sys
24
25
26 def swap_order(x, nbytes):
27 x = x.to_bytes(nbytes, byteorder='little')
28 x = int.from_bytes(x, byteorder='big', signed=False)
29 return x
30
31
32
33 class Mem:
34
35 def __init__(self, row_bytes=8, initial_mem=None):
36 self.mem = {}
37 self.bytes_per_word = row_bytes
38 self.word_log2 = math.ceil(math.log2(row_bytes))
39 print("Sim-Mem", initial_mem, self.bytes_per_word, self.word_log2)
40 if not initial_mem:
41 return
42
43 # different types of memory data structures recognised (for convenience)
44 if isinstance(initial_mem, list):
45 initial_mem = (0, initial_mem)
46 if isinstance(initial_mem, tuple):
47 startaddr, mem = initial_mem
48 initial_mem = {}
49 for i, val in enumerate(mem):
50 initial_mem[startaddr + row_bytes*i] = (val, row_bytes)
51
52 for addr, (val, width) in initial_mem.items():
53 #val = swap_order(val, width)
54 self.st(addr, val, width, swap=False)
55
56 def _get_shifter_mask(self, wid, remainder):
57 shifter = ((self.bytes_per_word - wid) - remainder) * \
58 8 # bits per byte
59 # XXX https://bugs.libre-soc.org/show_bug.cgi?id=377
60 # BE/LE mode?
61 shifter = remainder * 8
62 mask = (1 << (wid * 8)) - 1
63 print("width,rem,shift,mask", wid, remainder, hex(shifter), hex(mask))
64 return shifter, mask
65
66 # TODO: Implement ld/st of lesser width
67 def ld(self, address, width=8, swap=True, check_in_mem=False,
68 instr_fetch=False):
69 print("ld from addr 0x{:x} width {:d}".format(address, width),
70 swap, check_in_mem, instr_fetch)
71 remainder = address & (self.bytes_per_word - 1)
72 address = address >> self.word_log2
73 assert remainder & (width - 1) == 0, "Unaligned access unsupported!"
74 if address in self.mem:
75 val = self.mem[address]
76 elif check_in_mem:
77 return None
78 else:
79 val = 0
80 print("mem @ 0x{:x} rem {:d} : 0x{:x}".format(address, remainder, val))
81
82 if width != self.bytes_per_word:
83 shifter, mask = self._get_shifter_mask(width, remainder)
84 print("masking", hex(val), hex(mask << shifter), shifter)
85 val = val & (mask << shifter)
86 val >>= shifter
87 if swap:
88 val = swap_order(val, width)
89 print("Read 0x{:x} from addr 0x{:x}".format(val, address))
90 return val
91
92 def st(self, addr, v, width=8, swap=True):
93 staddr = addr
94 remainder = addr & (self.bytes_per_word - 1)
95 addr = addr >> self.word_log2
96 print("Writing 0x{:x} to ST 0x{:x} "
97 "memaddr 0x{:x}/{:x}".format(v, staddr, addr, remainder, swap))
98 assert remainder & (width - 1) == 0, "Unaligned access unsupported!"
99 if swap:
100 v = swap_order(v, width)
101 if width != self.bytes_per_word:
102 if addr in self.mem:
103 val = self.mem[addr]
104 else:
105 val = 0
106 shifter, mask = self._get_shifter_mask(width, remainder)
107 val &= ~(mask << shifter)
108 val |= v << shifter
109 self.mem[addr] = val
110 else:
111 self.mem[addr] = v
112 print("mem @ 0x{:x}: 0x{:x}".format(addr, self.mem[addr]))
113
114 def __call__(self, addr, sz):
115 val = self.ld(addr.value, sz, swap=False)
116 print("memread", addr, sz, val)
117 return SelectableInt(val, sz*8)
118
119 def memassign(self, addr, sz, val):
120 print("memassign", addr, sz, val)
121 self.st(addr.value, val.value, sz, swap=False)
122
123