pfv: add configurable memory alignment constraints.

Before this commit, the `mem_aligned` parameter assumed a 64-bit data
bus when set to True.
main
Jean-François Nguyen 2 years ago
parent 1d8916f2df
commit 7aaeff1122

@ -138,7 +138,7 @@ class MicrowattWrapper(Elaboratable):
""") """)


def __init__(self, *, bus_fairness=False, **kwargs): def __init__(self, *, bus_fairness=False, **kwargs):
self.pfv = pfv.Interface(mem_aligned=False, illegal_insn_heai=False, muldiv_altops=True) self.pfv = pfv.Interface(mem_alignment=0, illegal_insn_heai=False, muldiv_altops=True)
self.wb_insn = wishbone.Interface(addr_width=29, data_width=64, granularity=8, self.wb_insn = wishbone.Interface(addr_width=29, data_width=64, granularity=8,
features=("stall",)) features=("stall",))
self.wb_data = wishbone.Interface(addr_width=29, data_width=64, granularity=8, self.wb_data = wishbone.Interface(addr_width=29, data_width=64, granularity=8,

@ -31,7 +31,7 @@ class InsnCheck(PowerFVCheck, metaclass=InsnCheckMeta):
self.spec = self.spec_cls( self.spec = self.spec_cls(
insn = self.insn, insn = self.insn,
gpr_width = self.dut.pfv.gpr_width, gpr_width = self.dut.pfv.gpr_width,
mem_aligned = self.dut.pfv.mem_aligned, mem_alignment = self.dut.pfv.mem_alignment,
illegal_insn_heai = self.dut.pfv.illegal_insn_heai, illegal_insn_heai = self.dut.pfv.illegal_insn_heai,
muldiv_altops = self.dut.pfv.muldiv_altops, muldiv_altops = self.dut.pfv.muldiv_altops,
) )

@ -118,33 +118,27 @@ class LoadStoreSpec(InsnSpec, Elaboratable):


m.d.comb += ea.eq(iea(ea_base + ea_offset, self.pfv.msr.r_data.sf)) m.d.comb += ea.eq(iea(ea_base + ea_offset, self.pfv.msr.r_data.sf))


byte_offset = Signal(3) # The value of `pfv.mem.addr` must be equal to EA, rounded down to a multiple of
half_offset = Signal(2) # ``2 ** pfv.mem_alignment``.
word_offset = Signal(1)


# If `pfv.mem_aligned` is set, `pfv.mem.addr` points to the dword containing EA. m.d.comb += [
# If `pfv.mem_aligned` is unset, `pfv.mem.addr` is equal to EA. self.pfv.mem.addr[self.pfv.mem_alignment:].eq(ea[self.pfv.mem_alignment:]),
self.pfv.mem.addr[:self.pfv.mem_alignment].eq(0),
]


m.d.comb += self.pfv.mem.addr[3:].eq(ea[3:]) # Raise an Alignment Interrupt if EA is misaligned to the size of the storage operand
# and to ``2 ** pfv.mem_alignment``.


if self.pfv.mem_aligned: byte_offset = Signal(3)
m.d.comb += [ half_offset = Signal(2)
self.pfv.mem.addr[:3].eq(0), word_offset = Signal(1)
byte_offset.eq(ea[:3]),
]
else:
m.d.comb += [
self.pfv.mem.addr[:3].eq(ea[:3]),
byte_offset.eq(0),
]


m.d.comb += [ m.d.comb += [
byte_offset.eq(ea[:self.pfv.mem_alignment]),
half_offset.eq(byte_offset[1:]), half_offset.eq(byte_offset[1:]),
word_offset.eq(byte_offset[2:]), word_offset.eq(byte_offset[2:]),
] ]


# Raise an Alignment Interrupt if EA is misaligned wrt. `pfv.mem`

ea_misaligned = Signal() ea_misaligned = Signal()


if isinstance(self.insn, ( if isinstance(self.insn, (

@ -109,11 +109,12 @@ class Interface(Record):
gpr_width : int gpr_width : int
General-purpose register width. Either 32 or 64. Compliance with Power ISA versions above General-purpose register width. Either 32 or 64. Compliance with Power ISA versions above
v2.7B requires 64-bit wide GPRs. v2.7B requires 64-bit wide GPRs.
mem_aligned : bool mem_alignment : log2 of int
If ``True``, an Alignment interrupt is expected if the effective address of a Load/Store Memory alignment. This parameter restricts the alignment of Load/Store accesses to either
operation is not aligned to its operand; ``mem.addr`` is also expected to be aligned to ``2 ** pfv.mem_alignment`` bytes, or to the size of their operand. Otherwise, an Alignment
8 bytes. If ``False``, ``mem.addr`` is expected to point to the least- or most-significant interrupt is triggered. A core that can transparently handle misaligned accesses may set
byte of the storage operand, depending on the current endian mode. this value to 0, whereas one that requires software intervention may set it to the width
of its data bus (as a log2).
illegal_insn_heai : bool illegal_insn_heai : bool
If ``True``, an illegal instruction triggers an Hypervisor Emulation Assistance interrupt. If ``True``, an illegal instruction triggers an Hypervisor Emulation Assistance interrupt.
Otherwise, it triggers an Illegal Instruction type Program interrupt (which was removed in Otherwise, it triggers an Illegal Instruction type Program interrupt (which was removed in
@ -218,13 +219,16 @@ class Interface(Record):
srr1 : Record(:func:`reg_port_layout`) srr1 : Record(:func:`reg_port_layout`)
Save/Restore Register 1 access. Save/Restore Register 1 access.
""" """
def __init__(self, *, gpr_width=64, mem_aligned=False, illegal_insn_heai=False, def __init__(self, *, gpr_width=64, mem_alignment=0, illegal_insn_heai=False,
muldiv_altops=False, name=None, src_loc_at=0): muldiv_altops=False, name=None, src_loc_at=0):
if gpr_width not in (32, 64): if gpr_width not in (32, 64):
raise ValueError("GPR width must be 32 or 64, not {!r}".format(gpr_width)) raise ValueError("GPR width must be 32 or 64, not {!r}".format(gpr_width))
if mem_alignment not in (0, 1, 2, 3):
raise ValueError("Memory alignment must be an integer between 0 and 3, not {!r}"
.format(mem_alignment))


self.gpr_width = gpr_width self.gpr_width = gpr_width
self.mem_aligned = bool(mem_aligned) self.mem_alignment = mem_alignment
self.illegal_insn_heai = bool(illegal_insn_heai) self.illegal_insn_heai = bool(illegal_insn_heai)
self.muldiv_altops = bool(muldiv_altops) self.muldiv_altops = bool(muldiv_altops)



Loading…
Cancel
Save