1 """ Example 5: Making use of PyRTL and Introspection. """
3 from nmigen
import Signal
4 from nmigen
.hdl
.rec
import Record
5 from nmigen
import tracer
6 from nmigen
.compat
.fhdl
.bitcontainer
import value_bits_sign
7 from contextlib
import contextmanager
9 from singlepipe
import eq
12 # The following example shows how pyrtl can be used to make some interesting
13 # hardware structures using python introspection. In particular, this example
14 # makes a N-stage pipeline structure. Any specific pipeline is then a derived
15 # class of SimplePipeline where methods with names starting with "stage" are
16 # stages, and new members with names not starting with "_" are to be registered
21 def __init__(self
, pipe
, name
=None):
24 name
= tracer
.get_var_name(default
=None)
28 def like(cls
, pipe
, value
, name
=None, src_loc_at
=0, **kwargs
):
29 name
= name
or tracer
.get_var_name(depth
=2 + src_loc_at
,
32 src_loc_at_1
= 1 + src_loc_at
33 r
= ObjectProxy(pipe
, value
.name
)
34 for a
in value
.ports():
41 for a
in self
.ports():
43 ai
= getattr(i
, aname
)
49 for aname
in dir(self
):
50 a
= getattr(self
, aname
)
51 if isinstance(a
, Signal
) or isinstance(a
, ObjectProxy
) or \
52 isinstance(a
, Record
):
56 def __setattr__(self
, name
, value
):
57 if name
.startswith('_') or name
== 'name':
58 # do not do anything tricky with variables starting with '_'
59 object.__setattr
__(self
, name
, value
)
61 #rname = "%s_%s" % (self.name, name)
63 if isinstance(value
, ObjectProxy
):
64 new_pipereg
= ObjectProxy
.like(self
._pipe
, value
,
65 name
=rname
, reset_less
=True)
67 new_pipereg
= Signal
.like(value
, name
=rname
, reset_less
=True)
69 object.__setattr
__(self
, name
, new_pipereg
)
70 self
._pipe
.sync
+= eq(new_pipereg
, value
)
74 """ Pipeline builder stage with auto generation of pipeline registers.
77 def __init__(self
, pipe
, prev
=None):
80 self
._prev
_stage
= prev
82 print ("prev", prev
._preg
_map
)
83 if prev
._current
_stage
_num
in prev
._preg
_map
:
84 m
= prev
._preg
_map
[prev
._current
_stage
_num
]
85 self
._preg
_map
[prev
._current
_stage
_num
] = m
86 self
._current
_stage
_num
= prev
._current
_stage
_num
+ 1
87 if self
._current
_stage
_num
in prev
._preg
_map
:
88 m
= prev
._preg
_map
[self
._current
_stage
_num
]
89 self
._preg
_map
[self
._current
_stage
_num
] = m
90 print ("make current", m
)
92 self
._current
_stage
_num
= 0
94 def __getattr__(self
, name
):
96 return self
._preg
_map
[self
._current
_stage
_num
][name
]
99 'error, no pipeline register "%s" defined for stage %d'
100 % (name
, self
._current
_stage
_num
))
102 def __setattr__(self
, name
, value
):
103 if name
.startswith('_'):
104 # do not do anything tricky with variables starting with '_'
105 object.__setattr
__(self
, name
, value
)
107 next_stage
= self
._current
_stage
_num
+ 1
108 pipereg_id
= str(self
._current
_stage
_num
) + 'to' + str(next_stage
)
109 rname
= 'pipereg_' + pipereg_id
+ '_' + name
110 #new_pipereg = Signal(value_bits_sign(value), name=rname,
112 if isinstance(value
, ObjectProxy
):
113 new_pipereg
= ObjectProxy
.like(self
._pipe
, value
,
114 name
=rname
, reset_less
= True)
116 new_pipereg
= Signal
.like(value
, name
=rname
, reset_less
= True)
117 if next_stage
not in self
._preg
_map
:
118 self
._preg
_map
[next_stage
] = {}
119 self
._preg
_map
[next_stage
][name
] = new_pipereg
120 self
._pipe
.sync
+= eq(new_pipereg
, value
)
124 def __init__(self
, pipe
):
128 def Stage(self
, prev
=None):
129 stage
= PipelineStage(self
._pipe
, prev
)
135 class SimplePipeline
:
136 """ Pipeline builder with auto generation of pipeline registers.
139 def __init__(self
, pipe
):
141 self
._pipeline
_register
_map
= {}
142 self
._current
_stage
_num
= 0
146 for method
in dir(self
):
147 if method
.startswith('stage'):
148 stage_list
.append(method
)
149 for stage
in sorted(stage_list
):
150 stage_method
= getattr(self
, stage
)
152 self
._current
_stage
_num
+= 1
154 def __getattr__(self
, name
):
156 return self
._pipeline
_register
_map
[self
._current
_stage
_num
][name
]
158 raise AttributeError(
159 'error, no pipeline register "%s" defined for stage %d'
160 % (name
, self
._current
_stage
_num
))
162 def __setattr__(self
, name
, value
):
163 if name
.startswith('_'):
164 # do not do anything tricky with variables starting with '_'
165 object.__setattr
__(self
, name
, value
)
167 next_stage
= self
._current
_stage
_num
+ 1
168 pipereg_id
= str(self
._current
_stage
_num
) + 'to' + str(next_stage
)
169 rname
= 'pipereg_' + pipereg_id
+ '_' + name
170 #new_pipereg = Signal(value_bits_sign(value), name=rname,
172 if isinstance(value
, ObjectProxy
):
173 new_pipereg
= ObjectProxy
.like(self
._pipe
, value
,
174 name
=rname
, reset_less
= True)
176 new_pipereg
= Signal
.like(value
, name
=rname
, reset_less
= True)
177 if next_stage
not in self
._pipeline
_register
_map
:
178 self
._pipeline
_register
_map
[next_stage
] = {}
179 self
._pipeline
_register
_map
[next_stage
][name
] = new_pipereg
180 self
._pipe
.sync
+= eq(new_pipereg
, value
)