Keep the valid signal from the formal engine ALU stable, until read
[soc.git] / src / soc / logical / main_stage.py
1 # This stage is intended to do most of the work of executing Logical
2 # instructions. This is OR, AND and XOR, however input and output
3 # stages also perform bit-negation on input(s) and output, as well as
4 # carry and overflow generation.
5 # This module however should not gate the carry or overflow, that's up
6 # to the output stage
7
8 from nmigen import (Module, Signal, Cat, Repl, Mux, Const)
9 from nmutil.pipemodbase import PipeModBase
10 from soc.logical.pipe_data import ALUInputData
11 from soc.alu.pipe_data import ALUOutputData
12 from ieee754.part.partsig import PartitionedSignal
13 from soc.decoder.power_enums import InternalOp
14
15
16 class LogicalMainStage(PipeModBase):
17 def __init__(self, pspec):
18 super().__init__(pspec, "main")
19
20 def ispec(self):
21 return ALUInputData(self.pspec)
22
23 def ospec(self):
24 return ALUOutputData(self.pspec) # TODO: ALUIntermediateData
25
26 def elaborate(self, platform):
27 m = Module()
28 comb = m.d.comb
29
30 ##########################
31 # main switch for logic ops AND, OR and XOR, parity, and popcount
32
33 with m.Switch(self.i.ctx.op.insn_type):
34 with m.Case(InternalOp.OP_AND):
35 comb += self.o.o.eq(self.i.a & self.i.b)
36 with m.Case(InternalOp.OP_OR):
37 comb += self.o.o.eq(self.i.a | self.i.b)
38 with m.Case(InternalOp.OP_XOR):
39 comb += self.o.o.eq(self.i.a ^ self.i.b)
40 ###### popcount #######
41 # TODO with m.Case(InternalOp.OP_POPCNT):
42 ###### parity #######
43 # TODO with m.Case(InternalOp.OP_PRTY):
44
45 ###### sticky overflow and context, both pass-through #####
46
47 comb += self.o.so.eq(self.i.so)
48 comb += self.o.ctx.eq(self.i.ctx)
49
50 return m