The SOC is designed to be compliant with POWER 3.0B with somewhere near 300 instructions excluding Vector instructions.


The Decoder currently uses a class called PowerOp which get instantiated for every instruction. PowerOp class instantiation has member signals who's values get set respectively for each instruction.

We use Pythons Enums to help with common decoder values. Below is the POWER add insruction.

opcode unit internal op in1 in2 in3 out CR in CR out inv A inv out cry in cry out ldst len BR sgn ext upd rsrv 32b sgn rc lk sgl pipe comment form
0b0100001010 ALU OP_ADD RA RB NONE RT 0 0 0 0 ZERO 0 NONE 0 0 0 0 0 0 RC 0 0 add XO

Here is an example of a toy multiplexer that sets various fields in the PowerOP signal class to the correct values for the add instruction when select==1 is set. This should give you a feel for how we work with enums and PowerOP.

from nmigen import Module, Elaboratable, Signal, Cat, Mux
from soc.decoder.power_enums import (Function, Form, InternalOp,
                         In1Sel, In2Sel, In3Sel, OutSel, RC, LdstLen,
                         CryIn, get_csv, single_bit_flags,
                         get_signal_name, default_values)
from soc.decoder.power_fields import DecodeFields
from soc.decoder.power_fieldsn import SigDecode, SignalBitRange
from soc.decoder.power_decoder import PowerOp

class Op_Add_Example(Elaboratable):
    def __init__(self): = Signal()
        self.op_add = PowerOp()

    def elaborate(self, platform):
        m = Module()
        op_add = self.op_add

        with m.If( == 1):
            m.d.comb += op_add.function_unit.eq(Function['ALU'])
            m.d.comb += op_add.form.eq(Form['XO'])
            m.d.comb += op_add.internal_op.eq(InternalOp['OP_ADD'])
            m.d.comb += op_add.in1_sel.eq(In1Sel['RA'])
            m.d.comb += op_add.in2_sel.eq(In2Sel['RB'])
            m.d.comb += op_add.in3_sel.eq(In3Sel['NONE'])
            m.d.comb += op_add.out_sel.eq(OutSel['RT'])
            m.d.comb += op_add.rc_sel.eq(RC['RC'])
            m.d.comb += op_add.ldst_len.eq(LdstLen['NONE'])
            m.d.comb += op_add.cry_in.eq(CryIn['ZERO'])

        with m.Else():
            m.d.comb += op_add.function_unit.eq(0)
            m.d.comb += op_add.form.eq(0)
            m.d.comb += op_add.internal_op.eq(0)
            m.d.comb += op_add.in1_sel.eq(0)
            m.d.comb += op_add.in2_sel.eq(0)
            m.d.comb += op_add.in3_sel.eq(0)
            m.d.comb += op_add.out_sel.eq(0)
            m.d.comb += op_add.rc_sel.eq(0)
            m.d.comb += op_add.ldst_len.eq(0)
            m.d.comb += op_add.cry_in.eq(0)

        return m

from nmigen.back import verilog
verilog_file = "op_add_example.v"
top = Op_Add_Example()
f = open(verilog_file, "w")
verilog =  verilog.convert(top, name='top', strip_internal_attrs=True, ports= top.op_add.ports())
print(f"Verilog Written to: {verilog_file}")