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
24 def swap_order(x
, nbytes
):
25 x
= x
.to_bytes(nbytes
, byteorder
='little')
26 x
= int.from_bytes(x
, byteorder
='big', signed
=False)
30 class MemException(Exception):
36 def __init__(self
, row_bytes
=8, initial_mem
=None):
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
)
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
50 for i
, val
in enumerate(mem
):
51 initial_mem
[startaddr
+ row_bytes
*i
] = (val
, row_bytes
)
53 for addr
, val
in initial_mem
.items():
54 if isinstance(val
, tuple):
57 width
= row_bytes
# assume same width
58 #val = swap_order(val, width)
59 self
.st(addr
, val
, width
, swap
=False)
61 def _get_shifter_mask(self
, wid
, remainder
):
62 shifter
= ((self
.bytes_per_word
- wid
) - remainder
) * \
64 # XXX https://bugs.libre-soc.org/show_bug.cgi?id=377
66 shifter
= remainder
* 8
67 mask
= (1 << (wid
* 8)) - 1
68 print("width,rem,shift,mask", wid
, remainder
, hex(shifter
), hex(mask
))
71 # TODO: Implement ld/st of lesser width
72 def ld(self
, address
, width
=8, swap
=True, check_in_mem
=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")
82 if address
in self
.mem
:
83 val
= self
.mem
[address
]
88 print("mem @ 0x{:x} rem {:d} : 0x{:x}".format(address
, remainder
, val
))
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
)
96 val
= swap_order(val
, width
)
97 print("Read 0x{:x} from addr 0x{:x}".format(val
, address
))
100 def st(self
, addr
, v
, width
=8, swap
=True):
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")
111 v
= swap_order(v
, width
)
112 if width
!= self
.bytes_per_word
:
117 shifter
, mask
= self
._get
_shifter
_mask
(width
, remainder
)
118 val
&= ~
(mask
<< shifter
)
123 print("mem @ 0x{:x}: 0x{:x}".format(addr
, self
.mem
[addr
]))
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)
130 def memassign(self
, addr
, sz
, val
):
131 print("memassign", addr
, sz
, val
)
132 self
.st(addr
.value
, val
.value
, sz
, swap
=False)