whoops forgot that the mul pipeline is actually a pipeline (3 stage, first one)
[soc.git] / src / soc / fu / mul / post_stage.py
1 # This stage is intended to do most of the work of analysing the multiply result
2
3 from nmigen import (Module, Signal, Cat, Repl, Mux, signed)
4 from nmutil.pipemodbase import PipeModBase
5 from soc.fu.alu.pipe_data import ALUOutputData
6 from soc.fu.mul.pipe_data import MulOutputData
7 from ieee754.part.partsig import PartitionedSignal
8 from soc.decoder.power_enums import InternalOp
9
10
11 class MulMainStage3(PipeModBase):
12 def __init__(self, pspec):
13 super().__init__(pspec, "mul3")
14
15 def ispec(self):
16 return MulOutputData(self.pspec) # pipeline stage output format
17
18 def ospec(self):
19 return ALUOutputData(self.pspec) # defines pipeline stage output format
20
21 def elaborate(self, platform):
22 m = Module()
23 comb = m.d.comb
24
25 # convenience variables
26 cry_o, o, cr0 = self.o.xer_ca, self.o.o, self.o.cr0
27 ov_o = self.o.xer_ov
28 o_i, cry_i, op = self.i.o, self.i.xer_ca, self.i.ctx.op
29
30 # check if op is 32-bit, and get sign bit from operand a
31 is_32bit = Signal(reset_less=True)
32 comb += is_32bit.eq(op.is_32bit)
33
34 # check negate: select signed/unsigned
35 mul_o = Signal(o_i.width, reset_less=True)
36 comb += mul_o.eq(Mux(self.i.neg_res, -o_i, o_i))
37 comb += o.ok.eq(1)
38
39 # OP_MUL_nnn - select hi32/hi64/lo64 from result
40 with m.Switch(op.insn_type):
41 # hi-32 replicated twice
42 with m.Case(InternalOp.OP_MUL_H32):
43 comb += o.data.eq(Repl(mul_o[32:64], 2))
44 # hi-64
45 with m.Case(InternalOp.OP_MUL_H64):
46 comb += o.data.eq(mul_o[64:128])
47 # lo-64 - overflow
48 with m.Default():
49 comb += o.data.eq(mul_o[0:64])
50
51 # compute overflow
52 mul_ov = Signal(reset_less=True)
53 with m.If(is_32bit):
54 m32 = mul_o[32:64]
55 comb += mul_ov.eq(m32.bool() & ~m32.all())
56 with m.Else():
57 m64 = mul_o[64:128]
58 comb += mul_ov.eq(m64.bool() & ~m64.all())
59
60 # 32-bit (ov[1]) and 64-bit (ov[0]) overflow
61 ov = Signal(2, reset_less=True)
62 comb += ov[0].eq(mul_ov)
63 comb += ov[1].eq(mul_ov)
64 comb += ov_o.data.eq(ov)
65 comb += ov_o.ok.eq(1)
66
67 # https://bugs.libre-soc.org/show_bug.cgi?id=319#c5
68 ca = Signal(2, reset_less=True)
69 comb += ca[0].eq(mul_o[-1]) # XER.CA - XXX more?
70 comb += ca[1].eq(mul_o[32] ^ (self.i.neg_res32)) # XER.CA32
71 comb += cry_o.data.eq(ca)
72 comb += cry_o.ok.eq(1)
73
74 ###### sticky overflow and context, both pass-through #####
75
76 comb += self.o.xer_so.data.eq(self.i.xer_so)
77 comb += self.o.ctx.eq(self.i.ctx)
78
79 return m
80