You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

276 lines
9.1 KiB
Python

from amaranth import *
from power_fv import pfv
from power_fv.insn.const import *
from . import InsnSpec
from .utils import iea
__all__ = ["AddSubSpec"]
class AddSubSpec(InsnSpec, Elaboratable):
def elaborate(self, platform):
m = Module()
m.d.comb += [
self.insn .eq(self.pfv.insn[32:]),
self.pfv.stb .eq(self.insn.is_valid() & ~self.pfv.insn[:32].any()),
self.pfv.intr.eq(0),
self.pfv.nia .eq(iea(self.pfv.cia + 4, self.pfv.msr.r_data.sf)),
self.pfv.msr.r_mask.sf.eq(1),
]
src_a = Signal(signed(64))
src_b = Signal(signed(64))
src_c = Signal()
result = Signal(unsigned(65))
ca_64 = Signal()
ca_32 = Signal()
ov_64 = Signal()
ov_32 = Signal()
# Operand A : (RA) or 0 or NIA or ~(RA)
if isinstance(self.insn, (ADDI, ADDIS)):
m.d.comb += [
self.pfv.ra.index.eq(self.insn.RA),
self.pfv.ra.r_stb.eq(self.insn.RA != 0),
src_a.eq(Mux(self.insn.RA != 0, self.pfv.ra.r_data, 0)),
]
elif isinstance(self.insn, ADDPCIS):
m.d.comb += src_a.eq(self.pfv.nia)
elif isinstance(self.insn, (
ADD , ADD_ , ADDO , ADDO_ ,
ADDIC, ADDIC_,
ADDC , ADDC_ , ADDCO , ADDCO_ ,
ADDE , ADDE_ , ADDEO , ADDEO_ ,
ADDME, ADDME_, ADDMEO, ADDMEO_,
ADDZE, ADDZE_, ADDZEO, ADDZEO_,
ADDEX,
)):
m.d.comb += [
self.pfv.ra.index.eq(self.insn.RA),
self.pfv.ra.r_stb.eq(1),
src_a.eq(self.pfv.ra.r_data),
]
elif isinstance(self.insn, (
SUBF , SUBF_ , SUBFO , SUBFO_ ,
SUBFIC,
SUBFC , SUBFC_ , SUBFCO , SUBFCO_ ,
SUBFE , SUBFE_ , SUBFEO , SUBFEO_ ,
SUBFME, SUBFME_, SUBFMEO, SUBFMEO_,
SUBFZE, SUBFZE_, SUBFZEO, SUBFZEO_,
NEG , NEG_ , NEGO , NEGO_ ,
)):
m.d.comb += [
self.pfv.ra.index.eq(self.insn.RA),
self.pfv.ra.r_stb.eq(1),
src_a.eq(~self.pfv.ra.r_data),
]
else:
assert False
# Operand B : SI or SI<<16 or D<<16 or (RB) or -1 or 0
if isinstance(self.insn, (ADDI, ADDIC, ADDIC_, SUBFIC)):
m.d.comb += src_b.eq(self.insn.SI)
elif isinstance(self.insn, ADDIS):
m.d.comb += src_b.eq(Cat(Const(0, 16), self.insn.SI).as_signed())
elif isinstance(self.insn, ADDPCIS):
imm_d = Signal(signed(16))
m.d.comb += [
imm_d.eq(Cat(self.insn.d2, self.insn.d1, self.insn.d0)),
src_b.eq(Cat(Const(0, 16), imm_d).as_signed()),
]
elif isinstance(self.insn, (
ADD , ADD_ , ADDO , ADDO_ ,
SUBF , SUBF_ , SUBFO , SUBFO_ ,
ADDC , ADDC_ , ADDCO , ADDCO_ ,
ADDE , ADDE_ , ADDEO , ADDEO_ ,
SUBFC, SUBFC_, SUBFCO, SUBFCO_,
SUBFE, SUBFE_, SUBFEO, SUBFEO_,
ADDEX,
)):
m.d.comb += [
self.pfv.rb.index.eq(self.insn.RB),
self.pfv.rb.r_stb.eq(1),
src_b.eq(self.pfv.rb.r_data),
]
elif isinstance(self.insn, (
ADDME , ADDME_ , ADDMEO , ADDMEO_ ,
SUBFME, SUBFME_, SUBFMEO, SUBFMEO_,
)):
m.d.comb += src_b.eq(-1)
elif isinstance(self.insn, (
ADDZE , ADDZE_ , ADDZEO , ADDZEO_ ,
SUBFZE, SUBFZE_, SUBFZEO, SUBFZEO_,
NEG , NEG_ , NEGO , NEGO_ ,
)):
m.d.comb += src_b.eq(0)
else:
assert False
# Operand C : 0 or 1 or XER.CA or XER.OV
if isinstance(self.insn, (
ADDI , ADDIS , ADDPCIS,
ADD , ADD_ , ADDO , ADDO_ ,
ADDIC, ADDIC_,
ADDC , ADDC_ , ADDCO , ADDCO_,
)):
m.d.comb += src_c.eq(0)
elif isinstance(self.insn, (
SUBF , SUBF_ , SUBFO , SUBFO_ ,
SUBFIC,
SUBFC , SUBFC_, SUBFCO, SUBFCO_,
NEG , NEG_ , NEGO , NEGO_ ,
)):
m.d.comb += src_c.eq(1)
elif isinstance(self.insn, (
ADDE , ADDE_ , ADDEO , ADDEO_ ,
SUBFE , SUBFE_ , SUBFEO , SUBFEO_ ,
ADDME , ADDME_ , ADDMEO , ADDMEO_ ,
ADDZE , ADDZE_ , ADDZEO , ADDZEO_ ,
SUBFME, SUBFME_, SUBFMEO, SUBFMEO_,
SUBFZE, SUBFZE_, SUBFZEO, SUBFZEO_,
)):
m.d.comb += [
self.pfv.xer.r_mask.ca.eq(1),
src_c.eq(self.pfv.xer.r_data.ca),
]
elif isinstance(self.insn, ADDEX):
m.d.comb += [
self.pfv.xer.r_mask.ov.eq(1),
src_c.eq(self.pfv.xer.r_data.ov),
]
else:
assert False
# Result : Operand A + Operand B + Operand C
src_a_zext = Signal(unsigned(65))
src_b_zext = Signal(unsigned(65))
result = Signal(unsigned(65))
m.d.comb += [
src_a_zext.eq(src_a.as_unsigned()),
src_b_zext.eq(src_b.as_unsigned()),
result.eq(src_a_zext + src_b_zext + src_c),
ca_64.eq(result[64]),
ca_32.eq(result[32] ^ src_a[32] ^ src_b[32]),
ov_64.eq((ca_64 ^ result[63]) & ~(src_a[63] ^ src_b[63])),
ov_32.eq((ca_32 ^ result[31]) & ~(src_a[31] ^ src_b[31])),
self.pfv.rt.index .eq(self.insn.RT),
self.pfv.rt.w_stb .eq(1),
self.pfv.rt.w_data.eq(result[:64]),
]
# Read XER.SO (to update CR0)
if isinstance(self.insn, (
ADD_ , ADDO_ , ADDIC_ ,
SUBF_ , SUBFO_ ,
ADDC_ , ADDCO_ , ADDE_ , ADDEO_ ,
SUBFC_ , SUBFCO_ , SUBFE_ , SUBFEO_ ,
ADDME_ , ADDMEO_ , ADDZE_ , ADDZEO_ ,
SUBFME_, SUBFMEO_, SUBFZE_, SUBFZEO_,
NEG_ , NEGO_ ,
)):
m.d.comb += self.pfv.xer.r_mask.so.eq(1)
# Write XER.SO, XER.OV and XER.OV32
if isinstance(self.insn, (
ADDO , ADDO_ , SUBFO , SUBFO_ ,
ADDCO , ADDCO_ , SUBFCO , SUBFCO_ ,
ADDEO , ADDEO_ , SUBFEO , SUBFEO_ ,
ADDMEO, ADDMEO_, SUBFMEO, SUBFMEO_,
ADDZEO, ADDZEO_, SUBFZEO, SUBFZEO_,
NEGO , NEGO_ ,
)):
m.d.comb += [
self.pfv.xer.w_mask.ov .eq(1),
self.pfv.xer.w_data.ov .eq(Mux(self.pfv.msr.r_data.sf, ov_64, ov_32)),
self.pfv.xer.w_mask.ov32.eq(1),
self.pfv.xer.w_data.ov32.eq(ov_32),
]
with m.If(self.pfv.xer.w_data.ov):
m.d.comb += [
self.pfv.xer.w_mask.so.eq(1),
self.pfv.xer.w_data.so.eq(1),
]
elif isinstance(self.insn, ADDEX):
m.d.comb += [
self.pfv.xer.w_mask.ov .eq(1),
self.pfv.xer.w_data.ov .eq(Mux(self.pfv.msr.r_data.sf, ca_64, ca_32)),
self.pfv.xer.w_mask.ov32.eq(1),
self.pfv.xer.w_data.ov32.eq(ca_32),
]
# Write XER.CA and XER.CA32
if isinstance(self.insn, (
ADDIC , ADDIC_ , SUBFIC ,
ADDC , ADDC_ , ADDCO , ADDCO_ ,
SUBFC , SUBFC_ , SUBFCO , SUBFCO_ ,
ADDE , ADDE_ , ADDEO , ADDEO_ ,
SUBFE , SUBFE_ , SUBFEO , SUBFEO_ ,
ADDME , ADDME_ , ADDMEO , ADDMEO_ ,
SUBFME, SUBFME_, SUBFMEO, SUBFMEO_,
ADDZE , ADDZE_ , ADDZEO , ADDZEO_ ,
SUBFZE, SUBFZE_, SUBFZEO, SUBFZEO_,
)):
m.d.comb += [
self.pfv.xer.w_mask.ca .eq(1),
self.pfv.xer.w_data.ca .eq(Mux(self.pfv.msr.r_data.sf, ca_64, ca_32)),
self.pfv.xer.w_mask.ca32.eq(1),
self.pfv.xer.w_data.ca32.eq(ca_32),
]
# Write CR0
if isinstance(self.insn, (
ADD_ , ADDO_ , ADDIC_ ,
SUBF_ , SUBFO_ ,
ADDC_ , ADDCO_ , ADDE_ , ADDEO_ ,
SUBFC_ , SUBFCO_ , SUBFE_ , SUBFEO_ ,
ADDME_ , ADDMEO_ , ADDZE_ , ADDZEO_ ,
SUBFME_, SUBFMEO_, SUBFZE_, SUBFZEO_,
NEG_ , NEGO_ ,
)):
cr0_w_mask = Record([("so", 1), ("eq_", 1), ("gt", 1), ("lt", 1)])
cr0_w_data = Record([("so", 1), ("eq_", 1), ("gt", 1), ("lt", 1)])
m.d.comb += [
cr0_w_mask .eq(0b1111),
cr0_w_data.so .eq(Mux(self.pfv.xer.w_mask.so, self.pfv.xer.w_data.so, self.pfv.xer.r_data.so)),
cr0_w_data.eq_.eq(~Mux(self.pfv.msr.r_data.sf, result[:64].any(), result[:32].any())),
cr0_w_data.gt .eq(~(cr0_w_data.lt | cr0_w_data.eq_)),
cr0_w_data.lt .eq(Mux(self.pfv.msr.r_data.sf, result[63], result[31])),
self.pfv.cr.w_mask.cr0.eq(cr0_w_mask),
self.pfv.cr.w_data.cr0.eq(cr0_w_data),
]
return m