Implement OP_CMP
[soc.git] / src / soc / alu / input_stage.py
1 # This stage is intended to adjust the input data before sending it to
2 # the acutal ALU. Things like handling inverting the input, carry_in
3 # generation for subtraction, and handling of immediates should happen
4 # here
5 from nmigen import (Module, Signal, Cat, Const, Mux, Repl, signed,
6 unsigned)
7 from nmutil.pipemodbase import PipeModBase
8 from soc.decoder.power_enums import InternalOp
9 from soc.alu.pipe_data import ALUInputData
10 from soc.decoder.power_enums import CryIn
11
12
13 class ALUInputStage(PipeModBase):
14 def __init__(self, pspec):
15 super().__init__(pspec, "input")
16
17 def ispec(self):
18 return ALUInputData(self.pspec)
19
20 def ospec(self):
21 return ALUInputData(self.pspec)
22
23 def elaborate(self, platform):
24 m = Module()
25 comb = m.d.comb
26
27 ##### operand A #####
28
29 # operand a to be as-is or inverted
30 a = Signal.like(self.i.a)
31
32 with m.If(self.i.ctx.op.insn_type != InternalOp.OP_CMP):
33 with m.If(self.i.ctx.op.invert_a):
34 comb += a.eq(~self.i.a)
35 with m.Else():
36 comb += a.eq(self.i.a)
37
38 comb += self.o.a.eq(a)
39 comb += self.o.b.eq(self.i.b)
40 with m.Else():
41 with m.If(self.i.ctx.op.invert_a):
42 comb += self.o.a.eq(~self.i.b)
43 with m.Else():
44 comb += self.o.a.eq(self.i.b)
45
46 comb += self.o.b.eq(self.i.a)
47
48
49 ##### carry-in #####
50
51 # either copy incoming carry or set to 1/0 as defined by op
52 with m.Switch(self.i.ctx.op.input_carry):
53 with m.Case(CryIn.ZERO):
54 comb += self.o.carry_in.eq(0)
55 with m.Case(CryIn.ONE):
56 comb += self.o.carry_in.eq(1)
57 with m.Case(CryIn.CA):
58 comb += self.o.carry_in.eq(self.i.carry_in)
59
60 ##### sticky overflow and context (both pass-through) #####
61
62 comb += self.o.so.eq(self.i.so)
63 comb += self.o.ctx.eq(self.i.ctx)
64
65 return m