1 # This stage is intended to do most of the work of executing the Arithmetic
2 # instructions. This would be like the additions, compares, and sign-extension
3 # as well as carry and overflow generation. This module
4 # however should not gate the carry or overflow, that's up to the
6 from nmigen
import (Module
, Signal
, Cat
, Repl
, Mux
, Const
)
7 from nmutil
.pipemodbase
import PipeModBase
8 from nmutil
.extend
import exts
9 from soc
.fu
.alu
.pipe_data
import ALUInputData
, ALUOutputData
10 from ieee754
.part
.partsig
import PartitionedSignal
11 from soc
.decoder
.power_enums
import MicrOp
14 # microwatt calc_ov function.
15 def calc_ov(msb_a
, msb_b
, ca
, msb_r
):
16 return (ca ^ msb_r
) & ~
(msb_a ^ msb_b
)
19 class ALUMainStage(PipeModBase
):
20 def __init__(self
, pspec
):
21 super().__init
__(pspec
, "main")
24 return ALUInputData(self
.pspec
) # defines pipeline stage input format
27 return ALUOutputData(self
.pspec
) # defines pipeline stage output format
29 def elaborate(self
, platform
):
33 # convenience variables
34 cry_o
, o
, cr0
= self
.o
.xer_ca
, self
.o
.o
, self
.o
.cr0
36 a
, b
, cry_i
, op
= self
.i
.a
, self
.i
.b
, self
.i
.xer_ca
, self
.i
.ctx
.op
38 # check if op is 32-bit, and get sign bit from operand a
39 is_32bit
= Signal(reset_less
=True)
40 sign_bit
= Signal(reset_less
=True)
41 comb
+= is_32bit
.eq(op
.is_32bit
)
42 comb
+= sign_bit
.eq(Mux(is_32bit
, a
[31], a
[63]))
44 # little trick: do the add using only one add (not 2)
45 # LSB: carry-in [0]. op/result: [1:-1]. MSB: carry-out [-1]
46 add_a
= Signal(a
.width
+ 2, reset_less
=True)
47 add_b
= Signal(a
.width
+ 2, reset_less
=True)
48 add_o
= Signal(a
.width
+ 2, reset_less
=True)
49 with m
.If((op
.insn_type
== MicrOp
.OP_ADD
) |
50 (op
.insn_type
== MicrOp
.OP_CMP
)):
51 # in bit 0, 1+carry_in creates carry into bit 1 and above
52 comb
+= add_a
.eq(Cat(cry_i
[0], a
, Const(0, 1)))
53 comb
+= add_b
.eq(Cat(Const(1, 1), b
, Const(0, 1)))
54 comb
+= add_o
.eq(add_a
+ add_b
)
56 ##########################
57 # main switch-statement for handling arithmetic operations
59 with m
.Switch(op
.insn_type
):
62 #### CMP, CMPL v3.0B p85-86
64 with m
.Case(MicrOp
.OP_CMP
):
65 # this is supposed to be inverted (b-a, not a-b)
66 # however we have a trick: instead of adding either 2x 64-bit
67 # MUXes to invert a and b, or messing with a 64-bit output,
68 # swap +ve and -ve test in the *output* stage using an XOR gate
69 comb
+= o
.data
.eq(add_o
[1:-1])
70 comb
+= o
.ok
.eq(0) # use o.data but do *not* actually output
73 #### add v3.0B p67, p69-72
75 with m
.Case(MicrOp
.OP_ADD
):
76 # bit 0 is not part of the result, top bit is the carry-out
77 comb
+= o
.data
.eq(add_o
[1:-1])
78 comb
+= o
.ok
.eq(1) # output register
80 # see microwatt OP_ADD code
81 # https://bugs.libre-soc.org/show_bug.cgi?id=319#c5
82 ca
= Signal(2, reset_less
=True)
83 comb
+= ca
[0].eq(add_o
[-1]) # XER.CA
84 comb
+= ca
[1].eq(add_o
[33] ^
(a
[32] ^ b
[32])) # XER.CA32
85 comb
+= cry_o
.data
.eq(ca
)
86 comb
+= cry_o
.ok
.eq(1)
87 # 32-bit (ov[1]) and 64-bit (ov[0]) overflow
88 ov
= Signal(2, reset_less
=True)
89 comb
+= ov
[0].eq(calc_ov(a
[-1], b
[-1], ca
[0], add_o
[-2]))
90 comb
+= ov
[1].eq(calc_ov(a
[31], b
[31], ca
[1], add_o
[32]))
91 comb
+= ov_o
.data
.eq(ov
)
95 #### exts (sign-extend) v3.0B p96
97 with m
.Case(MicrOp
.OP_EXTS
):
98 with m
.If(op
.data_len
== 1):
99 comb
+= o
.data
.eq(exts(a
, 8, 64))
100 with m
.If(op
.data_len
== 2):
101 comb
+= o
.data
.eq(exts(a
, 16, 64))
102 with m
.If(op
.data_len
== 4):
103 comb
+= o
.data
.eq(exts(a
, 32, 64))
104 comb
+= o
.ok
.eq(1) # output register
107 #### cmpeqb v3.0B p88
109 with m
.Case(MicrOp
.OP_CMPEQB
):
110 eqs
= Signal(8, reset_less
=True)
111 src1
= Signal(8, reset_less
=True)
112 comb
+= src1
.eq(a
[0:8])
114 comb
+= eqs
[i
].eq(src1
== b
[8*i
:8*(i
+1)])
115 comb
+= o
.data
[0].eq(eqs
.any())
116 comb
+= o
.ok
.eq(0) # use o.data but do *not* actually output
117 comb
+= cr0
.data
.eq(Cat(Const(0, 2), eqs
.any(), Const(0, 1)))
120 ###### sticky overflow and context, both pass-through #####
122 comb
+= self
.o
.xer_so
.data
.eq(self
.i
.xer_so
)
123 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)