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 soc
.fu
.alu
.pipe_data
import ALUInputData
, ALUOutputData
9 from ieee754
.part
.partsig
import PartitionedSignal
10 from soc
.decoder
.power_enums
import InternalOp
13 class ALUMainStage(PipeModBase
):
14 def __init__(self
, pspec
):
15 super().__init
__(pspec
, "main")
18 return ALUInputData(self
.pspec
)
21 return ALUOutputData(self
.pspec
) # TODO: ALUIntermediateData
23 def elaborate(self
, platform
):
26 carry_out
, o
, cr0
= self
.o
.xer_co
, self
.o
.o
, self
.o
.cr0
27 a
, b
, op
= self
.i
.a
, self
.i
.b
, self
.i
.ctx
.op
29 # check if op is 32-bit, and get sign bit from operand a
30 is_32bit
= Signal(reset_less
=True)
31 sign_bit
= Signal(reset_less
=True)
32 comb
+= is_32bit
.eq(op
.is_32bit
)
33 comb
+= sign_bit
.eq(Mux(is_32bit
, a
[31], a
[63]))
35 # little trick: do the add using only one add (not 2)
36 add_a
= Signal(a
.width
+ 2, reset_less
=True)
37 add_b
= Signal(a
.width
+ 2, reset_less
=True)
38 add_output
= Signal(a
.width
+ 2, reset_less
=True)
39 with m
.If((op
.insn_type
== InternalOp
.OP_ADD
) |
40 (op
.insn_type
== InternalOp
.OP_CMP
)):
41 # in bit 0, 1+carry_in creates carry into bit 1 and above
42 comb
+= add_a
.eq(Cat(self
.i
.carry_in
, a
, Const(0, 1)))
43 comb
+= add_b
.eq(Cat(Const(1, 1), b
, Const(0, 1)))
44 comb
+= add_output
.eq(add_a
+ add_b
)
46 ##########################
47 # main switch-statement for handling arithmetic operations
49 with m
.Switch(op
.insn_type
):
51 with m
.Case(InternalOp
.OP_CMP
):
52 # this is supposed to be inverted (b-a, not a-b)
53 # however we have a trick: instead of adding either 2x 64-bit
54 # MUXes to invert a and b, or messing with a 64-bit output,
55 # swap +ve and -ve test in the *output* stage using an XOR gate
56 comb
+= o
.eq(add_output
[1:-1])
59 with m
.Case(InternalOp
.OP_ADD
):
60 # bit 0 is not part of the result, top bit is the carry-out
61 comb
+= o
.eq(add_output
[1:-1])
62 comb
+= carry_out
.data
[0].eq(add_output
[-1]) # XER.CO
64 # XXX no! wrongggg, see microwatt OP_ADD code
65 # https://bugs.libre-soc.org/show_bug.cgi?id=319#c5
66 comb
+= carry_out
.data
[1].eq(add_output
[-1]) # XER.CO32
68 #### exts (sign-extend) ####
69 with m
.Case(InternalOp
.OP_EXTS
):
70 with m
.If(op
.data_len
== 1):
71 comb
+= o
.eq(Cat(a
[0:8], Repl(a
[7], 64-8)))
72 with m
.If(op
.data_len
== 2):
73 comb
+= o
.eq(Cat(a
[0:16], Repl(a
[15], 64-16)))
74 with m
.If(op
.data_len
== 4):
75 comb
+= o
.eq(Cat(a
[0:32], Repl(a
[31], 64-32)))
76 with m
.Case(InternalOp
.OP_CMPEQB
):
77 eqs
= Signal(8, reset_less
=True)
78 src1
= Signal(8, reset_less
=True)
79 comb
+= src1
.eq(a
[0:8])
81 comb
+= eqs
[i
].eq(src1
== b
[8*i
:8*(i
+1)])
82 comb
+= cr0
.data
.eq(Cat(Const(0, 2), eqs
.any(), Const(0, 1)))
84 ###### sticky overflow and context, both pass-through #####
86 comb
+= self
.o
.xer_so
.data
.eq(self
.i
.so
)
87 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)