Skip to content

Commit a306957

Browse files
committed
Added Example 8 and Intro To Hardware
1 parent b547a39 commit a306957

File tree

4 files changed

+1200
-0
lines changed

4 files changed

+1200
-0
lines changed
Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"# Example 8: Interfacing with Verilog."
8+
]
9+
},
10+
{
11+
"cell_type": "markdown",
12+
"metadata": {},
13+
"source": [
14+
"While there is much more about PyRTL design to discuss, at some point somebody\n",
15+
"might ask you to do something with your code other than have it print\n",
16+
"pretty things out to the terminal. We provide **import from and export to\n",
17+
"Verilog of designs**, export of **waveforms to VCD**, and a set of **transforms\n",
18+
"that make doing netlist-level transforms and analyis directly in pyrtl easy.**"
19+
]
20+
},
21+
{
22+
"cell_type": "code",
23+
"execution_count": 1,
24+
"metadata": {
25+
"collapsed": true
26+
},
27+
"outputs": [],
28+
"source": [
29+
"import pyrtl\n",
30+
"from pyrtl.analysis import estimate"
31+
]
32+
},
33+
{
34+
"cell_type": "code",
35+
"execution_count": 2,
36+
"metadata": {
37+
"collapsed": true
38+
},
39+
"outputs": [],
40+
"source": [
41+
"pyrtl.reset_working_block()"
42+
]
43+
},
44+
{
45+
"cell_type": "markdown",
46+
"metadata": {},
47+
"source": [
48+
"## Importing From Verilog"
49+
]
50+
},
51+
{
52+
"cell_type": "markdown",
53+
"metadata": {},
54+
"source": [
55+
"Sometimes it is useful to pull in components written in Verilog to be used\n",
56+
"as subcomponents of PyRTL designs or to be subject to analysis written over\n",
57+
"the PyRTL core. One standard format supported by PyRTL is **\"blif\" format:**\n",
58+
"https://www.ece.cmu.edu/~ee760/760docs/blif.pdf\n",
59+
"\n",
60+
"Many tools support outputing hardware designs to this format, including the\n",
61+
"free open source project \"Yosys\". Blif files can then be imported either\n",
62+
"as a string or directly from a file name by the function input_from_blif.\n",
63+
"Here is a simple example of a **1 bit full adder imported and then simulated**\n",
64+
"from this blif format."
65+
]
66+
},
67+
{
68+
"cell_type": "code",
69+
"execution_count": 3,
70+
"metadata": {
71+
"collapsed": true
72+
},
73+
"outputs": [],
74+
"source": [
75+
"full_adder_blif = \"\"\"\n",
76+
"# Generated by Yosys 0.3.0+ (git sha1 7e758d5, clang 3.4-1ubuntu3 -fPIC -Os)\n",
77+
".model full_adder\n",
78+
".inputs x y cin\n",
79+
".outputs sum cout\n",
80+
".names $false\n",
81+
".names $true\n",
82+
"1\n",
83+
".names y $not$FA.v:12$3_Y\n",
84+
"0 1\n",
85+
".names x $not$FA.v:11$1_Y\n",
86+
"0 1\n",
87+
".names cin $not$FA.v:15$6_Y\n",
88+
"0 1\n",
89+
".names ind3 ind4 sum\n",
90+
"1- 1\n",
91+
"-1 1\n",
92+
".names $not$FA.v:15$6_Y ind2 ind3\n",
93+
"11 1\n",
94+
".names x $not$FA.v:12$3_Y ind1\n",
95+
"11 1\n",
96+
".names ind2 $not$FA.v:16$8_Y\n",
97+
"0 1\n",
98+
".names cin $not$FA.v:16$8_Y ind4\n",
99+
"11 1\n",
100+
".names x y $and$FA.v:19$11_Y\n",
101+
"11 1\n",
102+
".names ind0 ind1 ind2\n",
103+
"1- 1\n",
104+
"-1 1\n",
105+
".names cin ind2 $and$FA.v:19$12_Y\n",
106+
"11 1\n",
107+
".names $and$FA.v:19$11_Y $and$FA.v:19$12_Y cout\n",
108+
"1- 1\n",
109+
"-1 1\n",
110+
".names $not$FA.v:11$1_Y y ind0\n",
111+
"11 1\n",
112+
".end\n",
113+
"\"\"\""
114+
]
115+
},
116+
{
117+
"cell_type": "code",
118+
"execution_count": 4,
119+
"metadata": {
120+
"collapsed": true
121+
},
122+
"outputs": [],
123+
"source": [
124+
"pyrtl.input_from_blif(full_adder_blif)\n",
125+
"# have to find the actual wire vectors generated from the names in the blif file\n",
126+
"x, y, cin = [pyrtl.working_block().get_wirevector_by_name(s) for s in ['x', 'y', 'cin']]\n",
127+
"io_vectors = pyrtl.working_block().wirevector_subset((pyrtl.Input, pyrtl.Output))"
128+
]
129+
},
130+
{
131+
"cell_type": "code",
132+
"execution_count": 5,
133+
"metadata": {
134+
"collapsed": true
135+
},
136+
"outputs": [],
137+
"source": [
138+
"# we are only going to trace the input and output vectors for clarity\n",
139+
"sim_trace = pyrtl.SimulationTrace(wires_to_track=io_vectors)"
140+
]
141+
},
142+
{
143+
"cell_type": "markdown",
144+
"metadata": {},
145+
"source": [
146+
"### Now simulate the logic with some random inputs"
147+
]
148+
},
149+
{
150+
"cell_type": "code",
151+
"execution_count": 6,
152+
"metadata": {},
153+
"outputs": [
154+
{
155+
"ename": "NameError",
156+
"evalue": "name 'random' is not defined",
157+
"output_type": "error",
158+
"traceback": [
159+
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
160+
"\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)",
161+
"\u001b[1;32m<ipython-input-6-186a99891e24>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[1;31m# here we actually generate random booleans for the inputs\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m sim.step({\n\u001b[1;32m----> 5\u001b[1;33m \u001b[1;34m'x'\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mrandom\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mchoice\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 6\u001b[0m \u001b[1;34m'y'\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mrandom\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mchoice\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 7\u001b[0m \u001b[1;34m'cin'\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mrandom\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mchoice\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
162+
"\u001b[1;31mNameError\u001b[0m: name 'random' is not defined"
163+
]
164+
}
165+
],
166+
"source": [
167+
"sim = pyrtl.Simulation(tracer=sim_trace)\n",
168+
"for i in range(15):\n",
169+
" # here we actually generate random booleans for the inputs\n",
170+
" sim.step({\n",
171+
" 'x': random.choice([0, 1]),\n",
172+
" 'y': random.choice([0, 1]),\n",
173+
" 'cin': random.choice([0, 1])\n",
174+
" })\n",
175+
"sim_trace.render_trace(symbol_len=5, segment_size=5)"
176+
]
177+
},
178+
{
179+
"cell_type": "markdown",
180+
"metadata": {},
181+
"source": [
182+
"## Exporting to Verilog\n",
183+
"\n",
184+
"However, not only do we want to have a method to import from Verilog, we also\n",
185+
"want a way to **export it back out to Verilog** as well. To demonstrate PyRTL's\n",
186+
"ability to export in Verilog, we will create a **sample 3-bit counter**. However\n",
187+
"unlike the example in example2, we extend it to be **synchronously resetting**."
188+
]
189+
},
190+
{
191+
"cell_type": "code",
192+
"execution_count": null,
193+
"metadata": {
194+
"collapsed": true
195+
},
196+
"outputs": [],
197+
"source": [
198+
"pyrtl.reset_working_block()\n",
199+
"\n",
200+
"zero = pyrtl.Input(1, 'zero')\n",
201+
"counter_output = pyrtl.Output(3, 'counter_output')\n",
202+
"counter = pyrtl.Register(3, 'counter')\n",
203+
"counter.next <<= pyrtl.mux(zero, counter + 1, 0)\n",
204+
"counter_output <<= counter"
205+
]
206+
},
207+
{
208+
"cell_type": "markdown",
209+
"metadata": {},
210+
"source": [
211+
"The counter **gets 0 in the next cycle if the \"zero\" signal goes high, otherwise just\n",
212+
"counter + 1.** Note that both \"0\" and \"1\" are bit extended to the proper length and\n",
213+
"here we are making use of that native add operation.\n",
214+
"\n",
215+
"Let's dump this bad boy out\n",
216+
"to a verilog file and see what is looks like (here we are using StringIO just to\n",
217+
"print it to a string for demo purposes, most likely you will want to pass a normal\n",
218+
"open file)."
219+
]
220+
},
221+
{
222+
"cell_type": "code",
223+
"execution_count": null,
224+
"metadata": {
225+
"collapsed": true
226+
},
227+
"outputs": [],
228+
"source": [
229+
"print(\"--- PyRTL Representation ---\")\n",
230+
"print(pyrtl.working_block())\n",
231+
"print()\n",
232+
"\n",
233+
"print(\"--- Verilog for the Counter ---\")\n",
234+
"with io.StringIO() as vfile:\n",
235+
" pyrtl.OutputToVerilog(vfile)\n",
236+
" print(vfile.getvalue())\n",
237+
"\n",
238+
"print(\"--- Simulation Results ---\")\n",
239+
"sim_trace = pyrtl.SimulationTrace([counter_output, zero])\n",
240+
"sim = pyrtl.Simulation(tracer=sim_trace)\n",
241+
"for cycle in range(15):\n",
242+
" sim.step({'zero': random.choice([0, 0, 0, 1])})\n",
243+
"sim_trace.render_trace()"
244+
]
245+
},
246+
{
247+
"cell_type": "markdown",
248+
"metadata": {},
249+
"source": [
250+
"We already did the *\"hard\" work* of generating a test input for this simulation so\n",
251+
"we might want to reuse that work when we take this design through a verilog toolchain.\n",
252+
"The class *__OutputVerilogTestbench__ grabs the inputs used in the simulation trace\n",
253+
"and sets them up in a standard verilog testbench.*"
254+
]
255+
},
256+
{
257+
"cell_type": "code",
258+
"execution_count": null,
259+
"metadata": {
260+
"collapsed": true
261+
},
262+
"outputs": [],
263+
"source": [
264+
"print(\"--- Verilog for the TestBench ---\")\n",
265+
"with io.StringIO() as tbfile:\n",
266+
" pyrtl.output_verilog_testbench(dest_file=tbfile, simulation_trace=sim_trace)\n",
267+
" print(tbfile.getvalue())"
268+
]
269+
},
270+
{
271+
"cell_type": "markdown",
272+
"metadata": {},
273+
"source": [
274+
"### Now let's talk about transformations of the hardware block. \n",
275+
"Many times when you are\n",
276+
"doing some hardware-level analysis you might wish to ignore higher level things like\n",
277+
"multi-bit wirevectors, adds, concatination, etc. and just thing about wires and basic\n",
278+
"gates. **PyRTL supports \"lowering\" of designs** into this more restricted set of functionality\n",
279+
"though the function *\"synthesize\".* Once we lower a design to this form we can then **apply\n",
280+
"basic optimizations** like constant propgation and dead wire elimination as well. By\n",
281+
"printing it out to verilog we can see exactly how the design changed."
282+
]
283+
},
284+
{
285+
"cell_type": "code",
286+
"execution_count": null,
287+
"metadata": {
288+
"collapsed": true
289+
},
290+
"outputs": [],
291+
"source": [
292+
"print(\"--- Optimized Single-bit Verilog for the Counter ---\")\n",
293+
"pyrtl.synthesize()\n",
294+
"pyrtl.optimize()\n",
295+
"\n",
296+
"with io.StringIO() as vfile:\n",
297+
" pyrtl.OutputToVerilog(vfile)\n",
298+
" print(vfile.getvalue())"
299+
]
300+
}
301+
],
302+
"metadata": {
303+
"kernelspec": {
304+
"display_name": "Python 3",
305+
"language": "python",
306+
"name": "python3"
307+
},
308+
"language_info": {
309+
"codemirror_mode": {
310+
"name": "ipython",
311+
"version": 3
312+
},
313+
"file_extension": ".py",
314+
"mimetype": "text/x-python",
315+
"name": "python",
316+
"nbconvert_exporter": "python",
317+
"pygments_lexer": "ipython3",
318+
"version": "3.6.3"
319+
}
320+
},
321+
"nbformat": 4,
322+
"nbformat_minor": 2
323+
}

0 commit comments

Comments
 (0)