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
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.
12 * https://bugs.libre-soc.org/show_bug.cgi?id=424
16 from openpower
.decoder
.selectable_int
import (FieldSelectableInt
, SelectableInt
,
19 from openpower
.decoder
.helpers
import exts
, gtu
, ltu
, undefined
20 from openpower
.util
import log
25 def swap_order(x
, nbytes
):
26 x
= x
.to_bytes(nbytes
, byteorder
='little')
27 x
= int.from_bytes(x
, byteorder
='big', signed
=False)
31 class MemException(Exception):
37 def __init__(self
, row_bytes
=8, initial_mem
=None):
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
)
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
53 for i
, val
in enumerate(mem
):
54 initial_mem
[startaddr
+ row_bytes
*i
] = (val
, row_bytes
)
56 for addr
, val
in initial_mem
.items():
57 if isinstance(val
, tuple):
60 width
= row_bytes
# assume same width
61 #val = swap_order(val, width)
62 self
.st(addr
, val
, width
, swap
=False)
64 def _get_shifter_mask(self
, wid
, remainder
):
65 shifter
= ((self
.bytes_per_word
- wid
) - remainder
) * \
67 # XXX https://bugs.libre-soc.org/show_bug.cgi?id=377
69 shifter
= remainder
* 8
70 mask
= (1 << (wid
* 8)) - 1
71 log("width,rem,shift,mask", wid
, remainder
, hex(shifter
), hex(mask
))
74 # TODO: Implement ld/st of lesser width
75 def ld(self
, address
, width
=8, swap
=True, check_in_mem
=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
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")
87 if address
in self
.mem
:
88 val
= self
.mem
[address
]
93 log("ld mem @ 0x%x rem %d : 0x%x" % (ldaddr
, remainder
, val
))
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
)
101 val
= swap_order(val
, width
)
102 log("Read 0x%x from addr 0x%x" % (val
, ldaddr
))
105 def st(self
, addr
, v
, width
=8, swap
=True):
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")
117 v
= swap_order(v
, width
)
118 if width
!= self
.bytes_per_word
:
123 shifter
, mask
= self
._get
_shifter
_mask
(width
, remainder
)
124 val
&= ~
(mask
<< shifter
)
129 log("mem @ 0x%x: 0x%x" % (staddr
, self
.mem
[addr
]))
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)
136 def memassign(self
, addr
, sz
, val
):
137 log("memassign", addr
, sz
, val
)
138 self
.st(addr
.value
, val
.value
, sz
, swap
=False)
140 def dump(self
, printout
=True):
141 keys
= list(self
.mem
.keys())
145 res
.append(((k
*8), self
.mem
[k
]))
148 print ("%016x: %016x" % ((k
*8) & 0xffffffffffffffff, self
.mem
[k
]))