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)
33 def __init__(self
, row_bytes
=8, initial_mem
=None):
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
)
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
47 for i
, val
in enumerate(mem
):
48 initial_mem
[startaddr
+ row_bytes
*i
] = (val
, row_bytes
)
50 for addr
, val
in initial_mem
.items():
51 if isinstance(val
, tuple):
54 width
= row_bytes
# assume same width
55 #val = swap_order(val, width)
56 self
.st(addr
, val
, width
, swap
=False)
58 def _get_shifter_mask(self
, wid
, remainder
):
59 shifter
= ((self
.bytes_per_word
- wid
) - remainder
) * \
61 # XXX https://bugs.libre-soc.org/show_bug.cgi?id=377
63 shifter
= remainder
* 8
64 mask
= (1 << (wid
* 8)) - 1
65 print("width,rem,shift,mask", wid
, remainder
, hex(shifter
), hex(mask
))
68 # TODO: Implement ld/st of lesser width
69 def ld(self
, address
, width
=8, swap
=True, check_in_mem
=False,
71 print("ld from addr 0x{:x} width {:d}".format(address
, width
),
72 swap
, check_in_mem
, instr_fetch
)
73 remainder
= address
& (self
.bytes_per_word
- 1)
74 address
= address
>> self
.word_log2
75 assert remainder
& (width
- 1) == 0, "Unaligned access unsupported!"
76 if address
in self
.mem
:
77 val
= self
.mem
[address
]
82 print("mem @ 0x{:x} rem {:d} : 0x{:x}".format(address
, remainder
, val
))
84 if width
!= self
.bytes_per_word
:
85 shifter
, mask
= self
._get
_shifter
_mask
(width
, remainder
)
86 print("masking", hex(val
), hex(mask
<< shifter
), shifter
)
87 val
= val
& (mask
<< shifter
)
90 val
= swap_order(val
, width
)
91 print("Read 0x{:x} from addr 0x{:x}".format(val
, address
))
94 def st(self
, addr
, v
, width
=8, swap
=True):
96 remainder
= addr
& (self
.bytes_per_word
- 1)
97 addr
= addr
>> self
.word_log2
98 print("Writing 0x{:x} to ST 0x{:x} "
99 "memaddr 0x{:x}/{:x}".format(v
, staddr
, addr
, remainder
, swap
))
100 assert remainder
& (width
- 1) == 0, "Unaligned access unsupported!"
102 v
= swap_order(v
, width
)
103 if width
!= self
.bytes_per_word
:
108 shifter
, mask
= self
._get
_shifter
_mask
(width
, remainder
)
109 val
&= ~
(mask
<< shifter
)
114 print("mem @ 0x{:x}: 0x{:x}".format(addr
, self
.mem
[addr
]))
116 def __call__(self
, addr
, sz
):
117 val
= self
.ld(addr
.value
, sz
, swap
=False)
118 print("memread", addr
, sz
, val
)
119 return SelectableInt(val
, sz
*8)
121 def memassign(self
, addr
, sz
, val
):
122 print("memassign", addr
, sz
, val
)
123 self
.st(addr
.value
, val
.value
, sz
, swap
=False)