Skip to content

Commit a87ad98

Browse files
committed
Merge branch 'feature_stream_generator' into develop
2 parents 27ee95e + 2dc45d3 commit a87ad98

File tree

5 files changed

+362
-1
lines changed

5 files changed

+362
-1
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
TARGET=$(shell ls *.py | grep -v test | grep -v parsetab.py)
2+
ARGS=
3+
4+
PYTHON=python3
5+
#PYTHON=python
6+
#OPT=-m pdb
7+
#OPT=-m cProfile -s time
8+
#OPT=-m cProfile -o profile.rslt
9+
10+
.PHONY: all
11+
all: test
12+
13+
.PHONY: run
14+
run:
15+
$(PYTHON) $(OPT) $(TARGET) $(ARGS)
16+
17+
.PHONY: test
18+
test:
19+
$(PYTHON) -m pytest -vv
20+
21+
.PHONY: check
22+
check:
23+
$(PYTHON) $(OPT) $(TARGET) $(ARGS) > tmp.v
24+
iverilog -tnull -Wall tmp.v
25+
rm -f tmp.v
26+
27+
.PHONY: clean
28+
clean:
29+
rm -rf *.pyc __pycache__ parsetab.py .cache *.out *.png *.dot tmp.v uut.vcd
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from __future__ import absolute_import
2+
from __future__ import print_function
3+
4+
import os
5+
import veriloggen
6+
import thread_stream_custom_counter
7+
8+
9+
def test(request):
10+
veriloggen.reset()
11+
12+
simtype = request.config.getoption('--sim')
13+
14+
rslt = thread_stream_custom_counter.run(filename=None, simtype=simtype,
15+
outputfile=os.path.splitext(os.path.basename(__file__))[0] + '.out')
16+
17+
verify_rslt = rslt.splitlines()[-1]
18+
assert(verify_rslt == '# verify: PASSED')
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
from __future__ import absolute_import
2+
from __future__ import print_function
3+
import sys
4+
import os
5+
6+
# the next line can be removed after installation
7+
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(
8+
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))))
9+
10+
from veriloggen import *
11+
import veriloggen.thread as vthread
12+
import veriloggen.types.axi as axi
13+
14+
15+
def mkLed():
16+
m = Module('blinkled')
17+
clk = m.Input('CLK')
18+
rst = m.Input('RST')
19+
20+
datawidth = 32
21+
addrwidth = 10
22+
myaxi = vthread.AXIM(m, 'myaxi', clk, rst, datawidth)
23+
ram_a = vthread.RAM(m, 'ram_a', clk, rst, datawidth, addrwidth)
24+
ram_b = vthread.RAM(m, 'ram_b', clk, rst, datawidth, addrwidth)
25+
ram_c = vthread.RAM(m, 'ram_c', clk, rst, datawidth, addrwidth)
26+
27+
strm = vthread.Stream(m, 'mystream', clk, rst)
28+
size = strm.parameter('size')
29+
a = strm.source('a')
30+
b = strm.source('b')
31+
32+
def op_func(x, y, x_size, y_size):
33+
x_cond = x == x_size - 1
34+
next_x = Mux(x_cond, 0, x + 1)
35+
y_cond = Ands(x_cond, y == y_size - 1)
36+
next_y = PatternMux((y_cond, 0), (x_cond, y + 1), (None, y))
37+
return next_x, next_y
38+
39+
x_size = 4
40+
y_size = 4
41+
42+
x, y = strm.CustomCounter(func=op_func,
43+
initvals=(0, 0), args=(x_size, y_size),
44+
width_list=(32, 32), signed_list=(True, True))
45+
46+
c = a + b + x + y - a - b
47+
strm.sink(c, 'c')
48+
49+
def comp_stream(size, offset):
50+
strm.set_parameter('size', size)
51+
strm.set_source('a', ram_a, offset, size)
52+
strm.set_source('b', ram_b, offset, size)
53+
strm.set_sink('c', ram_c, offset, size)
54+
strm.run()
55+
strm.join()
56+
57+
def comp_sequential(size, offset):
58+
sum = 0
59+
x = 0
60+
y = 0
61+
x_size = 4
62+
y_size = 4
63+
for i in range(size):
64+
a = ram_a.read(i + offset)
65+
b = ram_b.read(i + offset)
66+
sum = a + b + x + y - a - b
67+
ram_c.write(i + offset, sum)
68+
x_cond = x == x_size - 1
69+
if x_cond:
70+
x = 0
71+
else:
72+
x = x + 1
73+
y_cond = x_cond and (y == y_size - 1)
74+
if y_cond:
75+
y = 0
76+
elif x_cond:
77+
y = y + 1
78+
79+
def check(size, offset_stream, offset_seq):
80+
all_ok = True
81+
for i in range(size):
82+
st = ram_c.read(i + offset_stream)
83+
sq = ram_c.read(i + offset_seq)
84+
if vthread.verilog.NotEql(st, sq):
85+
all_ok = False
86+
if all_ok:
87+
print('# verify: PASSED')
88+
else:
89+
print('# verify: FAILED')
90+
91+
def comp(size):
92+
# stream
93+
offset = 0
94+
myaxi.dma_read(ram_a, offset, 0, size)
95+
myaxi.dma_read(ram_b, offset, 512, size)
96+
comp_stream(size, offset)
97+
myaxi.dma_write(ram_c, offset, 1024, size)
98+
99+
# sequential
100+
offset = size
101+
myaxi.dma_read(ram_a, offset, 0, size)
102+
myaxi.dma_read(ram_b, offset, 512, size)
103+
comp_sequential(size, offset)
104+
myaxi.dma_write(ram_c, offset, 1024 * 2, size)
105+
106+
# verification
107+
myaxi.dma_read(ram_c, 0, 1024, size)
108+
myaxi.dma_read(ram_c, offset, 1024 * 2, size)
109+
check(size, 0, offset)
110+
111+
vthread.finish()
112+
113+
th = vthread.Thread(m, 'th_comp', clk, rst, comp)
114+
fsm = th.start(32)
115+
116+
return m
117+
118+
119+
def mkTest(memimg_name=None):
120+
m = Module('test')
121+
122+
# target instance
123+
led = mkLed()
124+
125+
# copy paras and ports
126+
params = m.copy_params(led)
127+
ports = m.copy_sim_ports(led)
128+
129+
clk = ports['CLK']
130+
rst = ports['RST']
131+
132+
memory = axi.AxiMemoryModel(m, 'memory', clk, rst, memimg_name=memimg_name)
133+
memory.connect(ports, 'myaxi')
134+
135+
uut = m.Instance(led, 'uut',
136+
params=m.connect_params(led),
137+
ports=m.connect_ports(led))
138+
139+
# simulation.setup_waveform(m, uut)
140+
simulation.setup_clock(m, clk, hperiod=5)
141+
init = simulation.setup_reset(m, rst, m.make_reset(), period=100)
142+
143+
init.add(
144+
Delay(1000000),
145+
Systask('finish'),
146+
)
147+
148+
return m
149+
150+
151+
def run(filename='tmp.v', simtype='iverilog', outputfile=None):
152+
153+
if outputfile is None:
154+
outputfile = os.path.splitext(os.path.basename(__file__))[0] + '.out'
155+
156+
memimg_name = 'memimg_' + outputfile
157+
158+
test = mkTest(memimg_name=memimg_name)
159+
160+
if filename is not None:
161+
test.to_verilog(filename)
162+
163+
sim = simulation.Simulator(test, sim=simtype)
164+
rslt = sim.run(outputfile=outputfile)
165+
lines = rslt.splitlines()
166+
if simtype == 'verilator' and lines[-1].startswith('-'):
167+
rslt = '\n'.join(lines[:-1])
168+
return rslt
169+
170+
171+
if __name__ == '__main__':
172+
rslt = run(filename='tmp.v')
173+
print(rslt)

veriloggen/stream/stypes.py

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3729,6 +3729,146 @@ def CounterValid(size, step=1, interval=None, initval=0, offset=None,
37293729
return data, valid
37303730

37313731

3732+
class _CustomCounter(_SpecialOperator):
3733+
latency = 1
3734+
3735+
default_width = 32
3736+
default_point = 0
3737+
default_signed = True
3738+
3739+
def __init__(self, func, initvals, args=None, reset=None,
3740+
width_list=None, point_list=None, signed_list=None):
3741+
3742+
_args = list(initvals)
3743+
3744+
if args is not None:
3745+
_args.extend(args)
3746+
3747+
if reset is not None:
3748+
_args.append(reset)
3749+
3750+
_SpecialOperator.__init__(self, *_args)
3751+
3752+
self.func = func
3753+
self.reset = self.args[-1] if reset is not None else None
3754+
self.num_vars = len(initvals)
3755+
3756+
if width_list is not None:
3757+
if len(width_list) != self.num_vars:
3758+
raise ValueError('width_list must have %d values, not %d.' %
3759+
(self.num_vars, len(width_list)))
3760+
3761+
total_width = 0
3762+
for width in width_list:
3763+
total_width += width
3764+
3765+
else:
3766+
total_width = self.default_width * self.num_vars
3767+
width_list = [self.default_width] * self.num_vars
3768+
3769+
self.width = total_width
3770+
self.width_list = width_list
3771+
3772+
if signed_list is not None:
3773+
if len(signed_list) != self.num_vars:
3774+
raise ValueError('signed_list must have %d values, not %d.' %
3775+
(self.num_vars, len(signed_list)))
3776+
3777+
else:
3778+
signed_list = [self.default_signed] * self.num_vars
3779+
3780+
self.signed = False
3781+
self.signed_list = signed_list
3782+
3783+
if point_list is not None:
3784+
if len(point_list) != self.num_vars:
3785+
raise ValueError('point_list must have %d values, not %d.' %
3786+
(self.num_vars, len(point_list)))
3787+
else:
3788+
point_list = [self.default_point] * self.num_vars
3789+
3790+
self.point = 0
3791+
self.point_list = point_list
3792+
3793+
def _implement(self, m, seq, svalid=None, senable=None):
3794+
if self.latency != 1:
3795+
raise ValueError("Latency must be '%d', not '%d'" %
3796+
(self.latency, 1))
3797+
3798+
width = self.get_width()
3799+
signed = self.get_signed()
3800+
3801+
arg_data = [arg.sig_data for arg in self.args]
3802+
3803+
enable_cond = senable
3804+
if self.iteration_interval != 1:
3805+
enable_cond = _and_vars(enable_cond, svalid)
3806+
3807+
resetdata = arg_data[-1] if self.reset is not None else None
3808+
3809+
vars = [m.Reg(self.name('var_%d' % i), var_width, initval=0, signed=var_signed)
3810+
for i, (var_width, var_point, var_signed) in enumerate(
3811+
zip(self.width_list, self.point_list, self.signed_list))]
3812+
3813+
data = m.Wire(self.name('data'), width, signed=signed)
3814+
data.assign(vtypes.Cat(*vars))
3815+
self.sig_data = data
3816+
3817+
args = arg_data[self.num_vars:self.num_vars + self.num_vars]
3818+
func_args = vars + args
3819+
next_vars = self.func(*func_args)
3820+
3821+
if len(next_vars) != len(vars):
3822+
raise ValueError('CustomCounter function must return %d values.' % len(vars))
3823+
3824+
for var, next_var in zip(vars, next_vars):
3825+
seq(var(next_var), cond=enable_cond)
3826+
3827+
initvals = arg_data[:self.num_vars]
3828+
3829+
if resetdata is not None:
3830+
reset_cond = _and_vars(enable_cond, resetdata)
3831+
for var, initval in zip(vars, initvals):
3832+
seq(var(initval), cond=reset_cond)
3833+
3834+
# multicycle control
3835+
if self.iteration_interval != 1:
3836+
ii_count = m.Reg(self.name('ii_count'),
3837+
int(ceil(log(self.iteration_interval, 2))) + 1, initval=0)
3838+
ii_stall_cond = m.Wire(self.name('ii_stall_cond'))
3839+
ii_stall_cond.assign(ii_count > 0)
3840+
util.add_disable_cond(self.strm.internal_oready,
3841+
ii_stall_cond, vtypes.Int(0))
3842+
3843+
seq.If(ii_count == 0, enable_cond)(
3844+
ii_count.inc()
3845+
)
3846+
seq.If(ii_count > 0)(
3847+
ii_count.inc()
3848+
)
3849+
seq.If(ii_count == self.iteration_interval - 1)(
3850+
ii_count(0)
3851+
)
3852+
3853+
3854+
def CustomCounter(func, initvals, args=None, reset=None,
3855+
width_list=None, point_list=None, signed_list=None):
3856+
3857+
v = _CustomCounter(func, initvals, args, reset,
3858+
width_list, point_list, signed_list)
3859+
3860+
return_values = []
3861+
3862+
s = 0
3863+
for width, point, signed in zip(reversed(v.width_list), reversed(v.point_list), reversed(v.signed_list)):
3864+
r = Slice(v, s + width - 1, s)
3865+
r = Cast(r, width=width, point=point, signed=signed)
3866+
s += width
3867+
return_values.append(r)
3868+
3869+
return tuple(reversed(return_values))
3870+
3871+
37323872
class Int(_Constant):
37333873

37343874
def __init__(self, value, signed=True):

veriloggen/thread/stream.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3761,7 +3761,8 @@ def __getattr__(self, attr):
37613761
(f.__name__.startswith('Reduce') or
37623762
f.__name__.startswith('Counter') or
37633763
f.__name__.startswith('Pulse') or
3764-
f.__name__.startswith('Producer'))):
3764+
f.__name__.startswith('Producer') or
3765+
f.__name__.startswith('CustomCounter'))):
37653766

37663767
if self.reduce_reset is None:
37673768
self._make_reduce_reset()

0 commit comments

Comments
 (0)