Simpler barrel shifter implementation

A different, more compact variant, avoiding recursive fun. This one does not confuse CXXRTL with too much combinatorial logic.

In [9]:
import sys
sys.path.insert(0, '../../')
In [10]:
from myirl.emulation.myhdl import *
In [11]:
Bool = Signal.Type(bool)

@block
def bs_stage(wout : Signal.Output,
             win : Signal, sh_bit : Signal, stage : int,
             ROTATE : (Bool, bool),
             LEFT : (Bool, bool),
             ASR : (Bool, bool), BITS : int):
    
    j = 2 ** stage
    
    # When ASR is a constant, we optimize to constants as well:
    if isinstance(ASR, bool):
        if ASR:
            pad_msb = j * [ win[BITS-1] ]
        else:
            pad_msb = [ intbv(0)[j:] ]
    else:
        pad_msb = j * [ win[BITS-1] & ASR ]
        
        
    @always_comb
    def worker():
        if sh_bit == False:
            wout.next = win
        else:
            if ROTATE:
                if LEFT:
                    wout.next = concat(win[BITS-j:0], win[BITS:BITS-j])
                else:
                    wout.next = concat(win[j:0], win[BITS:j])
            else:
                if LEFT:
                    wout.next = concat(win[BITS-j:0], *pad_msb)
                else:
                    wout.next = concat(*pad_msb, win[BITS:j])
                    
    return instances()


@block
def barrel_shifter(clk : ClkSignal,
                   ce : Signal,
                   val : Signal,
                   s : Signal,
                   result : Signal.Output,
                   left = True,
                   asr = False,
                   rotate = False, W_POWER = 5):
    
    BITS = 2 ** W_POWER
    
    worker = [ Signal(intbv()[BITS:]) for _ in range(W_POWER + 1) ]
    
    inst = [
        worker[0].wireup(val),
    ]
    
    for i in range(W_POWER):
        inst += [
            bs_stage(worker[i+1], worker[i], s[i], i, rotate, left, asr, BITS)
        ]
    
    @always(clk.posedge)
    def ff():
        if ce:
            result.next = worker[W_POWER]
        
    return instances()
    
In [12]:
from simulation import *

from myirl.simulation import print_
from myirl.emulation.factory_class import factory
from myirl.targets import pyosys

class example_design(factory.Module):
    def __init__(self, name, simclass, *args, **kwargs):
        super().__init__(name, simclass, *args, **kwargs)
        self.W_POWER = 4
        self.debug = False

        # Top level signal set
        self.clk = self.ClkSignal(name="clk")
        self.ce = self.Signal(bool())
        self.val, self.result = [ self.Signal(intbv(0xaa00)[2 ** self.W_POWER:]) for i in range(2) ]
        self.result.rename("res")
        self.s = self.Signal(intbv()[self.W_POWER:])
        self.left = self.Signal(bool())
        self.asr = self.Signal(bool())
        self.rotate = self.Signal(bool())
    
    def build(self):
        return barrel_shifter(
            clk = self.clk,
            ce = self.ce,
            val = self.val,
            s = self.s,
            result = self.result,
            rotate = self.rotate,
            left = self.left,
            asr = self.asr,
            W_POWER = self.W_POWER
        )
    
    def emit_rtlil(self, fileprefix):
        tgt = pyosys.RTLIL("barrel_shifter")
        inst = self.build()
        d = inst.elab(tgt)
        d[0].write_rtlil(fileprefix)

    @factory.testbench('ns')
    def tb_rtl(self):
        
        inst = self.build()

        clk = self.clk
        ce = self.ce
        val = self.val
        result = self.result
        s = self.s
        rot, asr, left = self.rotate, self.asr, self.left
        
        @self.always(delay(2))
        def clkgen():
            clk.next = ~clk

        TEST_VALUES = [
            (0xdead, True, False, False, 8, 0xad00),
            (0x8f01, True, False, False, 15, 0x8000),
            (0xdead, False, False, False, 8, 0x00de),
            (0xdead, False, True, False, 12, 0xeadd),
            # With ASR bit set (only effective with right shift)
            (0x8f01, False, False, True, 14, 0xfffe),
        ]

        @self.sequence
        def stim():
            for item in TEST_VALUES:
                ce.next = False
                s.next = item[4]
                left.next = item[1]
                rot.next = item[2]
                asr.next = item[3]
                
                val.next = item[0]
                yield(clk.posedge)
                ce.next = True
                yield(clk.posedge)
                yield(clk.posedge)

                print(result)
                assert result == item[5]

            raise StopSimulation

        return instances()    
In [13]:
from myirl.test.ghdl import GHDL
from yosys.simulator import CXXRTL

d = example_design("testbench", CXXRTL)
d.emit_rtlil("barrelshifter")
tb = d.tb_rtl()
print(76 * '=')
tb.run(60)
 Module testbench: Existing instance bs_stage, rename to bs_stage_1 
 Module testbench: Existing instance bs_stage, rename to bs_stage_2 
 Module testbench: Existing instance bs_stage, rename to bs_stage_3 
Creating process 'barrel_shifter/ff' with sensitivity (clk'rising,)
 Elaborating component bs_stage_s16_s16_s1_3_s1_s1_s1_16 
 Adding module with name `bs_stage_3` 
 Elaborating component bs_stage_s16_s16_s1_2_s1_s1_s1_16 
 Adding module with name `bs_stage_2` 
 Elaborating component bs_stage_s16_s16_s1_1_s1_s1_s1_16 
 Adding module with name `bs_stage_1` 
 Elaborating component bs_stage_s16_s16_s1_0_s1_s1_s1_16 
 Adding module with name `bs_stage` 
 Adding module with name `barrel_shifter` 
 FINALIZE implementation `barrel_shifter` of `barrel_shifter` 
Output filename: barrelshifter.il

-- Running command `tee -q hierarchy -top \barrel_shifter' --

-- Running command `tee -q write_cxxrtl -namespace barrel_shifter_14d3  -header /tmp/barrel_shifter_14d3_rtl.cpp' --

-- Running command `tee -q hierarchy -top \barrel_shifter' --

-- Running command `write_rtlil barrelshifter.il' --

6. Executing RTLIL backend.
DEBUG: Skip non-simulation type <class '__main__.example_design'>
DEBUG: Skip non-simulation type <class 'list'>
============================================================================
 Elaborating component bs_stage_s16_s16_s1_3_s1_s1_s1_16 
 Adding module with name `bs_stage_3` 
 Elaborating component bs_stage_s16_s16_s1_2_s1_s1_s1_16 
 Adding module with name `bs_stage_2` 
 Elaborating component bs_stage_s16_s16_s1_1_s1_s1_s1_16 
 Adding module with name `bs_stage_1` 
 Elaborating component bs_stage_s16_s16_s1_0_s1_s1_s1_16 
 Adding module with name `bs_stage` 
 Adding module with name `barrel_shifter` 
 FINALIZE implementation `barrel_shifter` of `barrel_shifter` 
Compiling /tmp/barrel_shifter_141b.pyx because it changed.
[1/1] Cythonizing /tmp/barrel_shifter_141b.pyx
running build_ext
building 'barrel_shifter_141b' extension
x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -ffile-prefix-map=/build/python3.9-RNBry6/python3.9-3.9.2=. -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -g -ffile-prefix-map=/build/python3.9-RNBry6/python3.9-3.9.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -DCOSIM_NAMESPACE=barrel_shifter_141b -I../../myirl/../ -I/tmp/ -I/usr/share/yosys/include -I/usr/include/python3.9 -c /tmp/barrel_shifter_141b.cpp -o build/temp.linux-x86_64-3.9/tmp/barrel_shifter_141b.o
x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -ffile-prefix-map=/build/python3.9-RNBry6/python3.9-3.9.2=. -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -g -ffile-prefix-map=/build/python3.9-RNBry6/python3.9-3.9.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -DCOSIM_NAMESPACE=barrel_shifter_141b -I../../myirl/../ -I/tmp/ -I/usr/share/yosys/include -I/usr/include/python3.9 -c /tmp/barrel_shifter_141b_rtl.cpp -o build/temp.linux-x86_64-3.9/tmp/barrel_shifter_141b_rtl.o
x86_64-linux-gnu-g++ -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-z,relro -g -fwrapv -O2 -Wl,-z,relro -g -fwrapv -O2 -g -ffile-prefix-map=/build/python3.9-RNBry6/python3.9-3.9.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 build/temp.linux-x86_64-3.9/tmp/barrel_shifter_141b.o build/temp.linux-x86_64-3.9/tmp/barrel_shifter_141b_rtl.o -o build/lib.linux-x86_64-3.9/barrel_shifter_141b.cpython-39-x86_64-linux-gnu.so
copying build/lib.linux-x86_64-3.9/barrel_shifter_141b.cpython-39-x86_64-linux-gnu.so -> 
Open for writing: tb_rtl.vcd
 CXXRTL context: SKIP INTERFACE ITEM `W_POWER` 
<res> : 0xad00
<res> : 0x8000
<res> : 0x00de
<res> : 0xeadd
<res> : 0xfffe
STOP SIMULATION @58 
In [ ]: