from nmigen import Elaboratable, Module, Signal, Const
from openpower.decoder.power_enums import (SVP64RMMode, Function, SVPtype,
- SVP64PredMode, SVP64sat)
+ SVP64PredMode, SVP64sat, SVP64LDSTmode)
from openpower.consts import EXTRA3, SVP64MODE
from openpower.sv.svp64 import SVP64Rec
from nmutil.util import sel
('sv_pred_sz', 1), # predicate source zeroing
('sv_pred_dz', 1), # predicate dest zeroing
('sv_saturate', SVP64sat),
+ ('sv_ldstmode', SVP64LDSTmode),
('SV_Ptype', SVPtype),
#('sv_RC1', 1),
]
https://libre-soc.org/openpower/sv/ldst/
LD/ST immed:
-00 str sz dz normal mode
+00 0 dz els normal mode (with element-stride)
+00 1 dz rsvd bit-reversed mode
01 inv CR-bit Rc=1: ffirst CR sel
01 inv els RC1 Rc=0: ffirst z/nonz
10 N dz els sat mode: N=0/1 u/s
class SVP64RMModeDecode(Elaboratable):
def __init__(self, name=None):
+ ##### inputs #####
self.rm_in = SVP64Rec(name=name)
self.fn_in = Signal(Function) # LD/ST is different
self.ptype_in = Signal(SVPtype)
self.rc_in = Signal()
- self.ldst_idx = Signal()
+ self.ldst_ra_vec = Signal() # set when RA is vec, indicate Index mode
+ self.ldst_imz_in = Signal() # set when LD/ST immediate is zero
+
+ ##### outputs #####
# main mode (normal, reduce, saturate, ffirst, pred-result)
self.mode = Signal(SVP64RMMode)
self.saturate = Signal(SVP64sat)
self.RC1 = Signal()
- self.cr_sel = Signal(2)
- self.inv = Signal(1)
+ self.cr_sel = Signal(2) # bit of CR to test (index 0-3)
+ self.inv = Signal(1) # and whether it's inverted (like branch BO)
self.map_evm = Signal(1)
self.map_crm = Signal(1)
+ self.reverse_gear = Signal(1) # elements to go VL-1..0
+ self.ldstmode = Signal(SVP64LDSTmode) # LD/ST Mode (strided type)
def elaborate(self, platform):
m = Module()
with m.Case(3):
comb += self.mode.eq(SVP64RMMode.PREDRES) # predicate result
+ # extract "reverse gear" for mapreduce mode
+ with m.If((~is_ldst) & # not for LD/ST
+ (mode2 == 0) & # first 2 bits == 0
+ mode[SVP64MODE.REDUCE] & # bit 2 == 1
+ (~mode[SVP64MODE.PARALLEL])): # not parallel mapreduce
+ comb += self.reverse_gear.eq(mode[SVP64MODE.RG]) # finally, whew
+
# extract zeroing
with m.Switch(mode2):
with m.Case(0): # needs further decoding (LDST no mapreduce)
with m.If(is_ldst):
- comb += self.pred_sz.eq(mode[SVP64MODE.SZ])
+ # XXX TODO, work out which of these is most appropriate
+ # set both? or just the one? or one if LD, the other if ST?
+ comb += self.pred_sz.eq(mode[SVP64MODE.DZ])
comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
with m.Elif(mode[SVP64MODE.REDUCE]):
with m.If(self.rm_in.subvl == Const(0, 2)): # no SUBVL
comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
with m.Case(1, 3):
with m.If(is_ldst):
- with m.If(~self.ldst_idx):
+ with m.If(~self.ldst_ra_vec):
comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
with m.Elif(self.rc_in):
comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
with m.Case(2):
- with m.If(is_ldst & ~self.ldst_idx):
+ with m.If(is_ldst & ~self.ldst_ra_vec):
comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
with m.Else():
comb += self.pred_sz.eq(mode[SVP64MODE.SZ])
comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
+ # extract saturate
+ with m.Switch(mode2):
+ with m.Case(2):
+ with m.If(mode[SVP64MODE.N]):
+ comb += self.saturate.eq(SVP64sat.UNSIGNED)
+ with m.Else():
+ comb += self.saturate.eq(SVP64sat.SIGNED)
+ with m.Default():
+ comb += self.saturate.eq(SVP64sat.NONE)
+
+ # extract els (element strided mode bit)
+ # see https://libre-soc.org/openpower/sv/ldst/
+ els = Signal()
+ with m.If(is_ldst):
+ with m.Switch(mode2):
+ with m.Case(0):
+ comb += els.eq(mode[SVP64MODE.ELS_NORMAL])
+ with m.Case(2):
+ comb += els.eq(mode[SVP64MODE.ELS_SAT])
+ with m.Case(1, 3):
+ with m.If(self.rc_in):
+ comb += els.eq(mode[SVP64MODE.ELS_FFIRST_PRED])
+
+ # Bit-reversed Mode
+ with m.If(mode[SVP64MODE.LDST_BITREV]):
+ comb += self.ldstmode.eq(SVP64LDSTmode.BITREVERSE)
+ # RA is vectorised
+ with m.Elif(self.ldst_ra_vec):
+ comb += self.ldstmode.eq(SVP64LDSTmode.INDEXED)
+ # not element-strided, therefore unit...
+ with m.Elif(~els):
+ comb += self.ldstmode.eq(SVP64LDSTmode.UNITSTRIDE)
+ # but if the LD/ST immediate is zero, allow cache-inhibited
+ # loads from same location, therefore don't do element-striding
+ with m.Elif(~self.ldst_imz_in):
+ comb += self.ldstmode.eq(SVP64LDSTmode.ELSTRIDE)
+
# extract src/dest predicate. use EXTRA3.MASK because EXTRA2.MASK
# is in exactly the same bits
srcmask = sel(m, self.rm_in.extra, EXTRA3.MASK)