Skip to content

Commit fcddcb7

Browse files
committed
Example: PicoRV32, and docs improvements
1 parent a6c741f commit fcddcb7

File tree

13 files changed

+19933
-5
lines changed

13 files changed

+19933
-5
lines changed
12.9 KB
Loading

docs/source/dev/arch.rst

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
Development Guide: Architecture
2+
===============================
3+
4+
Domains
5+
-------
6+
7+
The key challenge of PRGA is to make multiple tools work together seamlessly.
8+
PRGA tackles this challenge by dividing the architecture into three domains:
9+
the user domain, the logical domain, and the physical domain.
10+
11+
.. image:: /_static/images/domains.png
12+
13+
The figure above shows an IOB in different domains:
14+
15+
User Domain
16+
^^^^^^^^^^^
17+
18+
The figure to the left shows the IOB in the user domain. All instances in this
19+
domain are converted to `\<pb_type\>
20+
<http://docs.verilogtorouting.org/en/latest/arch/reference/#complex-blocks>`_
21+
s when generating `VPR <http://docs.verilogtorouting.org/en/latest/vpr/>`_ 's
22+
architecture description of the FPGA, and available to FPGA users. Each
23+
output port or input pin may be connected to more than one input port or
24+
output pin in this domain, indicating the configurability of these connections.
25+
These connections are converted to `\<interconnect\>
26+
<http://docs.verilogtorouting.org/en/latest/arch/reference/#interconnect>`_ tags
27+
when generating `VPR <http://docs.verilogtorouting.org/en/latest/vpr/>`_ 's
28+
architecture description.
29+
30+
Logical Domain
31+
^^^^^^^^^^^^^^
32+
33+
The figure in the middle shows the IOB in the logical domain. Configurable
34+
connections are implemented with switches. Configuration circuitry is also
35+
injected and connected.
36+
37+
Most of the code of PRGA works in this domain.
38+
39+
Physical Domain
40+
^^^^^^^^^^^^^^^
41+
42+
Physical domain is used for RTL generation as well as backend processing. Note
43+
that in the figure shown above, the IO pad instance is not present in the
44+
physical domain. Each pin of this logical-only instance is mapped to a physical
45+
port, shown as the dashed lines in the figure.

docs/source/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Contents
2727

2828
intro
2929
build_your_custom_fpga
30+
dev/arch
3031
prga.py/modules
3132

3233

docs/source/intro.rst

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,32 @@ PRGA is dependent on the following third-party tools:
2121
Python
2222
^^^^^^
2323

24-
PRGA works with Python 2.7.x and Python 3.7.x. However, `Python 2.x will reach
25-
its end of life on January 1st, 2020
24+
PRGA works with Python 2.7.x and Python 3.7.x. However, Python 2.x will reach
25+
its end of life on `January 1st, 2020
2626
<https://www.python.org/doc/sunset-python-2/>`_ , so we recommend using Python
2727
3.7.x if possible.
2828

29-
Installation
30-
------------
29+
30+
Examples
31+
--------
32+
33+
Examples are provided in the ``examples/`` directory. FPGA building examples are
34+
provided in the ``examples/fpga/`` directory, and RTL-to-verification examples
35+
are provided in the ``examples/target/`` directory.
36+
37+
To build an FPGA, run the following commands:
38+
39+
.. code-block:: bash
40+
41+
cd /path/to/prga/ # cd to the root
42+
cd examples/fpga/tiny/k4_N2_8x8 # choose one FPGA building example
43+
make # build the FPGA!
44+
45+
To implement a target design and simulate it with an FPGA design, run the
46+
following commands:
47+
48+
.. code-block:: bash
49+
50+
cd /path/to/prga/ # cd to the root
51+
cd examples/target/bcd2bin/tiny_k4_N2_8x8 # choose one design and one FPGA
52+
make # run all the way to verification
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include ../../Makefile.in
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# -*- encoding: ascii -*-
2+
3+
from prga.api.context import *
4+
from prga.api.flow import *
5+
from prga.api.config import *
6+
7+
from itertools import product
8+
9+
def run():
10+
width, height = 42, 34
11+
context = ArchitectureContext('top', width, height, BitchainConfigCircuitryDelegate)
12+
13+
# 1. routing stuff
14+
clk = context.create_global('clk', is_clock = True, bind_to_position = (0, 1))
15+
context.create_segment('L1', 48, 1)
16+
context.create_segment('L2', 16, 2)
17+
context.create_segment('L4', 8, 4)
18+
19+
# 2. create IOB
20+
iob = context.create_io_block('iob')
21+
while True:
22+
clkport = iob.create_global(clk)
23+
outpad = iob.create_input('outpad', 1)
24+
inpad = iob.create_output('inpad', 1)
25+
ioinst = iob.instances['io']
26+
iff = iob.instantiate(context.primitives['flipflop'], 'iff')
27+
off = iob.instantiate(context.primitives['flipflop'], 'off')
28+
iob.connect(clkport, iff.pins['clk'])
29+
iob.connect(ioinst.pins['inpad'], iff.pins['D'])
30+
iob.connect(iff.pins['Q'], inpad)
31+
iob.connect(ioinst.pins['inpad'], inpad)
32+
iob.connect(clkport, off.pins['clk'])
33+
iob.connect(off.pins['Q'], ioinst.pins['outpad'])
34+
iob.connect(outpad, ioinst.pins['outpad'])
35+
iob.connect(outpad, off.pins['D'])
36+
break
37+
38+
# 3. create tile
39+
iotiles = {}
40+
for orientation in iter(Orientation):
41+
if orientation.is_auto:
42+
continue
43+
iotiles[orientation] = context.create_tile(
44+
'io_tile_{}'.format(orientation.name), iob, 8, orientation)
45+
46+
# 5. create CLB
47+
clb = context.create_logic_block('clb')
48+
while True:
49+
clkport = clb.create_global(clk, Orientation.south)
50+
ceport = clb.create_input('ce', 1, Orientation.south)
51+
srport = clb.create_input('sr', 1, Orientation.south)
52+
cin = clb.create_input('cin', 1, Orientation.north)
53+
for i in range(4):
54+
inst = clb.instantiate(context.primitives['fraclut6sffc'], 'cluster{}'.format(i))
55+
clb.connect(clkport, inst.pins['clk'])
56+
clb.connect(ceport, inst.pins['ce'])
57+
clb.connect(srport, inst.pins['sr'])
58+
clb.connect(clb.create_input('ia' + str(i), 6, Orientation.west), inst.pins['ia'])
59+
clb.connect(clb.create_input('ib' + str(i), 1, Orientation.west), inst.pins['ib'])
60+
clb.connect(cin, inst.pins['cin'], pack_pattern = 'carrychain')
61+
cin = inst.pins['cout']
62+
clb.connect(inst.pins['oa'], clb.create_output('oa' + str(i), 1, Orientation.east))
63+
clb.connect(inst.pins['ob'], clb.create_output('ob' + str(i), 1, Orientation.east))
64+
clb.connect(inst.pins['q'], clb.create_output('q' + str(i), 1, Orientation.east))
65+
clb.connect(cin, clb.create_output('cout', 1, Orientation.south), pack_pattern = 'carrychain')
66+
break
67+
68+
# 6. create direct inter-block tunnels
69+
context.create_direct_tunnel('carrychain', clb.ports['cout'], clb.ports['cin'], (0, 1))
70+
71+
# 7. create tile
72+
clbtile = context.create_tile('clb_tile', clb)
73+
74+
# 8. create BRAM
75+
bram = context.create_logic_block('bram', 1, 2)
76+
while True:
77+
clkport = bram.create_global(clk, Orientation.south, position = (0, 0))
78+
addrport1 = bram.create_input('addr1', 10, Orientation.west, position = (0, 0))
79+
dinport1 = bram.create_input('data1', 8, Orientation.west, position = (0, 0))
80+
weport1 = bram.create_input('we1', 1, Orientation.west, position = (0, 0))
81+
doutport1 = bram.create_output('out1', 8, Orientation.east, position = (0, 0))
82+
addrport2 = bram.create_input('addr2', 10, Orientation.west, position = (0, 1))
83+
dinport2 = bram.create_input('data2', 8, Orientation.west, position = (0, 1))
84+
weport2 = bram.create_input('we2', 1, Orientation.west, position = (0, 1))
85+
doutport2 = bram.create_output('out2', 8, Orientation.east, position = (0, 1))
86+
inst = bram.instantiate(context.primitive_library.get_or_create_memory(10, 8,
87+
dualport = True), 'ram')
88+
bram.auto_connect(inst)
89+
break
90+
91+
# 9. create tile
92+
bramtile = context.create_tile('bram_tile', bram)
93+
94+
# 10. create sub-array
95+
subarray = context.create_array('subarray', 5, 4)
96+
for x, y in product(range(5), range(4)):
97+
if x == 2:
98+
if y % 2 == 0:
99+
subarray.instantiate_element(bramtile, (x, y))
100+
else:
101+
subarray.instantiate_element(clbtile, (x, y))
102+
103+
# 11. fill top-level array
104+
for x in range(width):
105+
for y in range(height):
106+
if x == 0:
107+
if y > 0 and y < height - 1:
108+
context.top.instantiate_element(iotiles[Orientation.west], (x, y))
109+
elif x == width - 1:
110+
if y > 0 and y < height - 1:
111+
context.top.instantiate_element(iotiles[Orientation.east], (x, y))
112+
elif y == 0:
113+
context.top.instantiate_element(iotiles[Orientation.south], (x, y))
114+
elif y == height - 1:
115+
context.top.instantiate_element(iotiles[Orientation.north], (x, y))
116+
elif x % 5 == 1 and y % 4 == 1:
117+
context.top.instantiate_element(subarray, (x, y))
118+
119+
# 12. flow
120+
flow = Flow((
121+
CompleteRoutingBox(BlockFCValue(BlockPortFCValue(0.25), BlockPortFCValue(0.1))),
122+
CompleteSwitch(),
123+
CompleteConnection(),
124+
GenerateVerilog('rtl'),
125+
InjectBitchainConfigCircuitry(),
126+
GenerateVPRXML('vpr'),
127+
CompletePhysical(),
128+
ZeroingBRAMWriteEnable(),
129+
ZeroingBlockPins(),
130+
GenerateYosysResources('syn'),
131+
))
132+
133+
# 13. run flow
134+
flow.run(context)
135+
136+
# 14. create a pickled version
137+
context.pickle('ctx.pickled')
138+
139+
if __name__ == '__main__':
140+
run()
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
TARGET := picorv32
2+
PICKLED_CONTEXT := $(FPGA_DIR)/ctx.pickled
3+
SIM_MAKEFILE := Makefile.sim
4+
PARTIAL_IOBINDING := io.partial
5+
6+
.PHONY: all project
7+
all: $(SIM_MAKEFILE) $(PICKLED_CONTEXT)
8+
make -f $(SIM_MAKEFILE)
9+
10+
project: $(SIM_MAKEFILE) $(PICKLED_CONTEXT)
11+
12+
clean:
13+
if [ -f $(SIM_MAKEFILE) ]; then make -f $(SIM_MAKEFILE) cleanall; fi
14+
rm -rf $(SIM_MAKEFILE) $(TARGET)_host_wrapper.v synth.ys io.pads
15+
16+
$(SIM_MAKEFILE): $(PICKLED_CONTEXT) $(PARTIAL_IOBINDING) ../$(TARGET)_host.v ../$(TARGET).v
17+
python -m prga_tools.bitchain.simproj \
18+
--fix_io $(PARTIAL_IOBINDING) \
19+
-t ../$(TARGET)_host.v --testbench_top picorv32_wrapper \
20+
--testbench_plus_args firmware=../firmware.hex max_cycle=10000000 quiet \
21+
-m ../$(TARGET).v --model_top picorv32_axi \
22+
--model_parameters COMPRESSED_ISA=1 ENABLE_MUL=1 ENABLE_DIV=1 ENABLE_IRQ=1 ENABLE_TRACE=1 \
23+
--makefile $@ \
24+
$(PICKLED_CONTEXT)
25+
26+
$(PICKLED_CONTEXT):
27+
make -C $(FPGA_DIR)
28+
29+
%:
30+
if [ -f $(SIM_MAKEFILE) ]; then make -f $(SIM_MAKEFILE) $@; \
31+
else echo "Simulation project not built yet. Run 'make project' first" && exit 1; fi

0 commit comments

Comments
 (0)