diff --git a/cores/microwatt/microwatt_cli/core.py b/cores/microwatt/microwatt_cli/core.py index b5cc828..d7743b0 100644 --- a/cores/microwatt/microwatt_cli/core.py +++ b/cores/microwatt/microwatt_cli/core.py @@ -138,7 +138,7 @@ class MicrowattWrapper(Elaboratable): """) 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, features=("stall",)) self.wb_data = wishbone.Interface(addr_width=29, data_width=64, granularity=8, diff --git a/power_fv/check/insn/__init__.py b/power_fv/check/insn/__init__.py index e48271c..f8500fc 100644 --- a/power_fv/check/insn/__init__.py +++ b/power_fv/check/insn/__init__.py @@ -31,7 +31,7 @@ class InsnCheck(PowerFVCheck, metaclass=InsnCheckMeta): self.spec = self.spec_cls( insn = self.insn, 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, muldiv_altops = self.dut.pfv.muldiv_altops, ) diff --git a/power_fv/insn/spec/loadstore.py b/power_fv/insn/spec/loadstore.py index f2acf7d..03cfcd4 100644 --- a/power_fv/insn/spec/loadstore.py +++ b/power_fv/insn/spec/loadstore.py @@ -118,33 +118,27 @@ class LoadStoreSpec(InsnSpec, Elaboratable): m.d.comb += ea.eq(iea(ea_base + ea_offset, self.pfv.msr.r_data.sf)) - byte_offset = Signal(3) - half_offset = Signal(2) - word_offset = Signal(1) + # The value of `pfv.mem.addr` must be equal to EA, rounded down to a multiple of + # ``2 ** pfv.mem_alignment``. - # If `pfv.mem_aligned` is set, `pfv.mem.addr` points to the dword containing EA. - # If `pfv.mem_aligned` is unset, `pfv.mem.addr` is equal to EA. + m.d.comb += [ + 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: - m.d.comb += [ - self.pfv.mem.addr[:3].eq(0), - byte_offset.eq(ea[:3]), - ] - else: - m.d.comb += [ - self.pfv.mem.addr[:3].eq(ea[:3]), - byte_offset.eq(0), - ] + byte_offset = Signal(3) + half_offset = Signal(2) + word_offset = Signal(1) m.d.comb += [ + byte_offset.eq(ea[:self.pfv.mem_alignment]), half_offset.eq(byte_offset[1:]), word_offset.eq(byte_offset[2:]), ] - # Raise an Alignment Interrupt if EA is misaligned wrt. `pfv.mem` - ea_misaligned = Signal() if isinstance(self.insn, ( diff --git a/power_fv/pfv.py b/power_fv/pfv.py index bb39a93..01a9fb9 100644 --- a/power_fv/pfv.py +++ b/power_fv/pfv.py @@ -109,11 +109,12 @@ class Interface(Record): gpr_width : int General-purpose register width. Either 32 or 64. Compliance with Power ISA versions above v2.7B requires 64-bit wide GPRs. - mem_aligned : bool - If ``True``, an Alignment interrupt is expected if the effective address of a Load/Store - operation is not aligned to its operand; ``mem.addr`` is also expected to be aligned to - 8 bytes. If ``False``, ``mem.addr`` is expected to point to the least- or most-significant - byte of the storage operand, depending on the current endian mode. + mem_alignment : log2 of int + Memory alignment. This parameter restricts the alignment of Load/Store accesses to either + ``2 ** pfv.mem_alignment`` bytes, or to the size of their operand. Otherwise, an Alignment + interrupt is triggered. A core that can transparently handle misaligned accesses may set + 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 If ``True``, an illegal instruction triggers an Hypervisor Emulation Assistance interrupt. 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`) 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): if gpr_width not in (32, 64): 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.mem_aligned = bool(mem_aligned) + self.mem_alignment = mem_alignment self.illegal_insn_heai = bool(illegal_insn_heai) self.muldiv_altops = bool(muldiv_altops)