A Barrel shifter performs the operation v << s
(or v >> s
with flipped bits) where s
is not constant.
An elegant implementation is the approach via cascaded multiplexer elements.
This cshift
primitive is later instanced procedurally, iterating through the variable i
import sys
sys.path.insert(0, "../..")
from myirl.emulation.myhdl import *
@block
def cshift(q : Signal.Output, a : Signal, b : Signal, sbit : Signal,
msb : Signal,
# These can take a signal or a fixed bool:
asr, rotate,
WRAP : bool):
carry = Signal(bool()) # Carry bit
u, v = [ Signal(bool()) for i in range(2) ]
@always_comb
def assign_carry():
if asr: # arithmetic shift right
carry.next = sbit & msb
else:
carry.next = 0
@always_comb
def assign():
u.next = a & ~sbit
if rotate == False:
if WRAP:
v.next = carry
else:
v.next = b & sbit
else:
v.next = b & sbit
@always_comb
def assign_q():
q.next = u | v
return instances()
@block
def shifter_stage(
shifter,
w_in : Signal,
w_out : Signal.Output,
msb : Signal,
nmux : int, sbit : Signal, DATA_WIDTH : int, W_POWER : int, asr : bool, rotate : bool
):
inst = []
# Create signal array
w = [ Signal(bool()) for i in range(DATA_WIDTH) ]
wo = concat(*reversed(w))
wi = [ w_in[i] for i in range(DATA_WIDTH) ]
MUX_W = DATA_WIDTH // nmux
for imux in range(nmux):
tmp = imux * MUX_W
# print(imux)
for i in range(tmp, tmp + MUX_W):
j = i + MUX_W//2
m = j % DATA_WIDTH
inst.append(shifter(w[m], wi[m], wi[i], sbit, msb, asr, rotate,
j >= DATA_WIDTH ))
@always_comb
def assign():
w_out.next = wo
return instances()
@block
def barrel_shifter(shifter, clk : ClkSignal, ce : Signal, val : Signal, s : Signal, result : Signal.Output, \
rotate = False, W_POWER = 5 ):
DATA_WIDTH = 2 ** W_POWER
print("DATA WIDTH", DATA_WIDTH, "ROTATE", rotate)
worker = [ val ]
worker = worker + [ Signal(intbv()[DATA_WIDTH:]) for i in range(W_POWER) ]
msb = val[DATA_WIDTH-1]
sbit = [ s[i] for i in range(len(s))]
shifter_stages = []
for stage in range(W_POWER):
K = W_POWER - stage - 1
print("Stage %d" % stage)
shifter_stages.append( \
shifter_stage(shifter, worker[stage], worker[stage + 1], msb, 2 ** stage, sbit[K], \
DATA_WIDTH, W_POWER, False, rotate) \
)
@always(clk.posedge)
def assign():
if ce == True:
result.next = worker[W_POWER]
return instances()
The translation into the target RTL or HDL takes place via a test bench factory function. This allows us to switch between different simulator back end methods. Here, we can choose between GHDL
and CXXRTL
.
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("result")
self.s = self.Signal(intbv()[self.W_POWER:])
def build(self):
return barrel_shifter(cshift,
clk = self.clk,
ce = self.ce,
val = self.val,
s = self.s,
result = self.result,
rotate = False,
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
@self.always(delay(2))
def clkgen():
clk.next = ~clk
TEST_VALUES = [
(0xdead, 8, 0xad00),
(0x8f01, 15, 0x8000),
]
@self.sequence
def stim():
for item in TEST_VALUES:
ce.next = False
s.next = item[1]
val.next = item[0]
yield(clk.posedge)
ce.next = True
yield(clk.posedge)
yield(clk.posedge)
print(result, type(result))
assert result == item[2]
raise StopSimulation
return instances()
from yosys.simulator import CXXRTL
d = example_design("rtlil_bs", CXXRTL)
d.emit_rtlil("test")
DATA WIDTH 16 ROTATE False Stage 0 Module rtlil_bs: Existing instance cshift, rename to cshift_1 Stage 1 Module rtlil_bs: Existing instance shifter_stage, rename to shifter_stage_1 Stage 2 Module rtlil_bs: Existing instance shifter_stage, rename to shifter_stage_2 Stage 3 Module rtlil_bs: Existing instance shifter_stage, rename to shifter_stage_3 Elaborating component shifter_stage__wrapped_wrapper_s16_s16_s1_8_s1_16_4_0_0 Adding module with name `shifter_stage_3` DEBUG: SKIP NON-SIGNAL ARGUMENT `shifter` : <class 'myirl.emulation.myhdl.wrapped_wrapper'> Elaborating component shifter_stage__wrapped_wrapper_s16_s16_s1_4_s1_16_4_0_0 Adding module with name `shifter_stage_2` DEBUG: SKIP NON-SIGNAL ARGUMENT `shifter` : <class 'myirl.emulation.myhdl.wrapped_wrapper'> Elaborating component shifter_stage__wrapped_wrapper_s16_s16_s1_2_s1_16_4_0_0 Adding module with name `shifter_stage_1` DEBUG: SKIP NON-SIGNAL ARGUMENT `shifter` : <class 'myirl.emulation.myhdl.wrapped_wrapper'> Elaborating component cshift_s1_s1_s1_s1_s1_0_0_1 Adding module with name `cshift_1` Elaborating component cshift_s1_s1_s1_s1_s1_0_0_0 Adding module with name `cshift` Elaborating component shifter_stage__wrapped_wrapper_s16_s16_s1_1_s1_16_4_0_0 Adding module with name `shifter_stage` DEBUG: SKIP NON-SIGNAL ARGUMENT `shifter` : <class 'myirl.emulation.myhdl.wrapped_wrapper'> Adding module with name `barrel_shifter` DEBUG: SKIP NON-SIGNAL ARGUMENT `shifter` : <class 'myirl.emulation.myhdl.wrapped_wrapper'> FINALIZE implementation `barrel_shifter` of `barrel_shifter`
from myirl.test.ghdl import GHDL
# XXX Note: we must carry out the simulation backend sequence in this order. Otherwise,
# a yet undetermined sticky effect will report a combinatorial loop error.
for sim in CXXRTL, GHDL:
d = example_design("testbench", sim)
tb = d.tb_rtl()
print(76 * '=')
tb.run(60)
Module testbench: Existing instance barrel_shifter, rename to barrel_shifter_1 DATA WIDTH 16 ROTATE False Stage 0 Module testbench: Existing instance shifter_stage, rename to shifter_stage_4 Module testbench: Existing instance cshift, rename to cshift_2 Module testbench: Existing instance cshift, rename to cshift_3 Stage 1 Module testbench: Existing instance shifter_stage, rename to shifter_stage_5 Stage 2 Module testbench: Existing instance shifter_stage, rename to shifter_stage_6 Stage 3 Module testbench: Existing instance shifter_stage, rename to shifter_stage_7 DEBUG: Skip non-simulation type <class '__main__.example_design'> DEBUG: Skip non-simulation type <class 'list'> ============================================================================ Elaborating component shifter_stage__wrapped_wrapper_s16_s16_s1_8_s1_16_4_0_0 Adding module with name `shifter_stage_7` DEBUG: SKIP NON-SIGNAL ARGUMENT `shifter` : <class 'myirl.emulation.myhdl.wrapped_wrapper'> Elaborating component shifter_stage__wrapped_wrapper_s16_s16_s1_4_s1_16_4_0_0 Adding module with name `shifter_stage_6` DEBUG: SKIP NON-SIGNAL ARGUMENT `shifter` : <class 'myirl.emulation.myhdl.wrapped_wrapper'> Elaborating component shifter_stage__wrapped_wrapper_s16_s16_s1_2_s1_16_4_0_0 Adding module with name `shifter_stage_5` DEBUG: SKIP NON-SIGNAL ARGUMENT `shifter` : <class 'myirl.emulation.myhdl.wrapped_wrapper'> Elaborating component cshift_s1_s1_s1_s1_s1_0_0_1 Adding module with name `cshift_3` Elaborating component cshift_s1_s1_s1_s1_s1_0_0_0 Adding module with name `cshift_2` Elaborating component shifter_stage__wrapped_wrapper_s16_s16_s1_1_s1_16_4_0_0 Adding module with name `shifter_stage_4` DEBUG: SKIP NON-SIGNAL ARGUMENT `shifter` : <class 'myirl.emulation.myhdl.wrapped_wrapper'> Adding module with name `barrel_shifter_1` DEBUG: SKIP NON-SIGNAL ARGUMENT `shifter` : <class 'myirl.emulation.myhdl.wrapped_wrapper'> FINALIZE implementation `barrel_shifter_1` of `barrel_shifter` Compiling /tmp/barrel_shifter_1_2922.pyx because it changed. [1/1] Cythonizing /tmp/barrel_shifter_1_2922.pyx running build_ext building 'barrel_shifter_1_2922' 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_1_2922 -I../../myirl/../ -I/tmp/ -I/usr/share/yosys/include -I/usr/include/python3.9 -c /tmp/barrel_shifter_1_2922.cpp -o build/temp.linux-x86_64-3.9/tmp/barrel_shifter_1_2922.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_1_2922 -I../../myirl/../ -I/tmp/ -I/usr/share/yosys/include -I/usr/include/python3.9 -c /tmp/barrel_shifter_1_2922_rtl.cpp -o build/temp.linux-x86_64-3.9/tmp/barrel_shifter_1_2922_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_1_2922.o build/temp.linux-x86_64-3.9/tmp/barrel_shifter_1_2922_rtl.o -o build/lib.linux-x86_64-3.9/barrel_shifter_1_2922.cpython-39-x86_64-linux-gnu.so copying build/lib.linux-x86_64-3.9/barrel_shifter_1_2922.cpython-39-x86_64-linux-gnu.so -> Open for writing: tb_rtl.vcd CXXRTL context: SKIP INTERFACE ITEM `shifter` CXXRTL context: SKIP INTERFACE ITEM `rotate` CXXRTL context: SKIP INTERFACE ITEM `W_POWER` <result> : 0xad00 <class 'simulation.Signal'> <result> : 0x8000 <class 'simulation.Signal'> STOP SIMULATION @22 Declare obj 'tb_rtl' in context '(example_design 'testbench')' Module testbench: Existing instance barrel_shifter, rename to barrel_shifter_2 DATA WIDTH 16 ROTATE False Stage 0 Module testbench: Existing instance shifter_stage, rename to shifter_stage_8 Module testbench: Existing instance cshift, rename to cshift_4 Module testbench: Existing instance cshift, rename to cshift_5 Stage 1 Module testbench: Existing instance shifter_stage, rename to shifter_stage_9 Stage 2 Module testbench: Existing instance shifter_stage, rename to shifter_stage_10 Stage 3 Module testbench: Existing instance shifter_stage, rename to shifter_stage_11 ============================================================================ Writing 'shifter_stage_11' to file /tmp/shifter_stage_11.vhdl Writing 'shifter_stage_10' to file /tmp/shifter_stage_10.vhdl Writing 'shifter_stage_9' to file /tmp/shifter_stage_9.vhdl Writing 'cshift_5' to file /tmp/cshift_5.vhdl Writing 'cshift_4' to file /tmp/cshift_4.vhdl Writing 'shifter_stage_8' to file /tmp/shifter_stage_8.vhdl Writing 'barrel_shifter_2' to file /tmp/barrel_shifter_2.vhdl Writing 'tb_rtl' to file /tmp/tb_rtl.vhdl Creating library file /tmp/module_defs.vhdl ==== COSIM stdout ==== analyze /home/testing/src/myhdl2/myirl/targets/../test/vhdl/txt_util.vhdl analyze /home/testing/src/myhdl2/myirl/targets/libmyirl.vhdl analyze /tmp/cshift_4.vhdl analyze /tmp/cshift_5.vhdl analyze /tmp/shifter_stage_8.vhdl analyze /tmp/shifter_stage_9.vhdl analyze /tmp/shifter_stage_10.vhdl analyze /tmp/shifter_stage_11.vhdl analyze /tmp/barrel_shifter_2.vhdl analyze /tmp/tb_rtl.vhdl elaborate tb_rtl ==== COSIM stdout ==== 0xAD00 <class 'myirl.emulation.signals.Signal'> 0x8000 <class 'myirl.emulation.signals.Signal'> simulation stopped @22ns
A bit more optimization can be done by moving the code into a cythonizeable library. See Cythonized barrel shifter
This primitive approach however is not very compact and this design should not be mass-instanced using CXXRTL due to issues with combinatorial logic.
See Compact barrel shifter implementation for an improved version.