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 soc
.decoder
.selectable_int
import (FieldSelectableInt
, SelectableInt
,
19 from soc
.decoder
.power_enums
import SPR
as DEC_SPR
21 from soc
.decoder
.helpers
import exts
, gtu
, ltu
, undefined
26 def swap_order(x
, nbytes
):
27 x
= x
.to_bytes(nbytes
, byteorder
='little')
28 x
= int.from_bytes(x
, byteorder
='big', signed
=False)
35 def __init__(self
, row_bytes
=8, initial_mem
=None):
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
)
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
49 for i
, val
in enumerate(mem
):
50 initial_mem
[startaddr
+ row_bytes
*i
] = (val
, row_bytes
)
52 for addr
, (val
, width
) in initial_mem
.items():
53 #val = swap_order(val, width)
54 self
.st(addr
, val
, width
, swap
=False)
56 def _get_shifter_mask(self
, wid
, remainder
):
57 shifter
= ((self
.bytes_per_word
- wid
) - remainder
) * \
59 # XXX https://bugs.libre-soc.org/show_bug.cgi?id=377
61 shifter
= remainder
* 8
62 mask
= (1 << (wid
* 8)) - 1
63 print("width,rem,shift,mask", wid
, remainder
, hex(shifter
), hex(mask
))
66 # TODO: Implement ld/st of lesser width
67 def ld(self
, address
, width
=8, swap
=True, check_in_mem
=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
]
80 print("mem @ 0x{:x} rem {:d} : 0x{:x}".format(address
, remainder
, val
))
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
)
88 val
= swap_order(val
, width
)
89 print("Read 0x{:x} from addr 0x{:x}".format(val
, address
))
92 def st(self
, addr
, v
, width
=8, swap
=True):
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!"
100 v
= swap_order(v
, width
)
101 if width
!= self
.bytes_per_word
:
106 shifter
, mask
= self
._get
_shifter
_mask
(width
, remainder
)
107 val
&= ~
(mask
<< shifter
)
112 print("mem @ 0x{:x}: 0x{:x}".format(addr
, self
.mem
[addr
]))
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)
119 def memassign(self
, addr
, sz
, val
):
120 print("memassign", addr
, sz
, val
)
121 self
.st(addr
.value
, val
.value
, sz
, swap
=False)