better hls example
* Add `find_max` hls example * Add gitignores * Make build cleaner * Add exercises in semicustom * Add food for brain in semicustom
This commit is contained in:
parent
f84ef005bb
commit
967205d427
4 changed files with 183 additions and 43 deletions
2
fullcustom/.gitignore
vendored
Normal file
2
fullcustom/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
.ipynb_checkpoints
|
||||
comp.out
|
1
semicustom/.gitignore
vendored
Normal file
1
semicustom/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.ipynb_checkpoints
|
2
semicustom/build/.gitignore
vendored
Normal file
2
semicustom/build/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
|
@ -136,21 +136,17 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%writefile config.json\n",
|
||||
"%%writefile build/config.json\n",
|
||||
"{\n",
|
||||
" \"DESIGN_NAME\": \"xor3\",\n",
|
||||
" \"VERILOG_FILES\": \"dir::v/xor3.v\",\n",
|
||||
" \"VERILOG_FILES\": \"dir::../v/xor3.v\",\n",
|
||||
" \"CLOCK_TREE_SYNTH\": false,\n",
|
||||
" \"CLOCK_PORT\": null,\n",
|
||||
" \"PL_RANDOM_GLB_PLACEMENT\": true,\n",
|
||||
" \"FP_SIZING\": \"absolute\",\n",
|
||||
" \"DIE_AREA\": \"0 0 40 40\",\n",
|
||||
" \"PL_TARGET_DENSITY\": 0.8,\n",
|
||||
" \"DIE_AREA\": \"0 0 25 35\",\n",
|
||||
" \"FP_PDN_AUTO_ADJUST\": false,\n",
|
||||
" \"FP_PDN_VPITCH\": 10,\n",
|
||||
" \"FP_PDN_HPITCH\": 10,\n",
|
||||
" \"FP_PDN_VOFFSET\": 5,\n",
|
||||
" \"FP_PDN_HOFFSET\": 5,\n",
|
||||
" \"FP_PDN_VOFFSET\": 0,\n",
|
||||
" \"FP_PDN_HOFFSET\": 0,\n",
|
||||
" \"DIODE_INSERTION_STRATEGY\": 3\n",
|
||||
"}"
|
||||
]
|
||||
|
@ -176,7 +172,7 @@
|
|||
"outputs": [],
|
||||
"source": [
|
||||
"%env PDK=sky130A\n",
|
||||
"!flow.tcl -design ."
|
||||
"!flow.tcl -design build"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -210,7 +206,7 @@
|
|||
"import gdstk\n",
|
||||
"import IPython.display\n",
|
||||
"\n",
|
||||
"gdsii = sorted(glob.glob(\"./runs/*/results/final/gds/*.gds\"))[-1]\n",
|
||||
"gdsii = sorted(glob.glob(\"./build/runs/*/results/final/gds/*.gds\"))[-1]\n",
|
||||
"top = gdstk.read_gds(gdsii).top_level()\n",
|
||||
"top[0].write_svg('svg/inverter.svg')\n",
|
||||
"IPython.display.SVG('svg/inverter.svg')"
|
||||
|
@ -243,26 +239,15 @@
|
|||
},
|
||||
"id": "OWAwQI3fZC4W",
|
||||
"outputId": "d50dcf9f-30cd-42a3-dab5-12992bc9dca2",
|
||||
"scrolled": false
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import glob\n",
|
||||
"import pandas as pd\n",
|
||||
"pd.options.display.max_rows = None\n",
|
||||
"\n",
|
||||
"metrics = pd.read_csv(sorted(glob.glob(\"./runs/*/reports/metrics.csv\"))[-1])\n",
|
||||
"\n",
|
||||
"print(f\"tritonRoute_violations {metrics['tritonRoute_violations'][0]}\")\n",
|
||||
"print(f\"Short_violations {metrics['Short_violations'][0]}\")\n",
|
||||
"print(f\"OffGrid_violations {metrics['OffGrid_violations'][0]}\")\n",
|
||||
"print(f\"MinHole_violations {metrics['MinHole_violations'][0]}\")\n",
|
||||
"print(f\"Other_violations {metrics['Other_violations'][0]}\")\n",
|
||||
"print(f\"Magic_violations {metrics['Magic_violations'][0]}\")\n",
|
||||
"print(f\"pin_antenna_violations {metrics['pin_antenna_violations'][0]}\")\n",
|
||||
"print(f\"net_antenna_violations {metrics['net_antenna_violations'][0]}\")\n",
|
||||
"print(f\"lvs_total_errors {metrics['lvs_total_errors'][0]}\")\n",
|
||||
"print(f\"cvc_total_errors {metrics['cvc_total_errors'][0]}\")\n",
|
||||
"print(f\"klayout_violations {metrics['klayout_violations'][0]}\")"
|
||||
"pd.read_csv(sorted(glob.glob(\"./build/runs/*/reports/metrics.csv\"))[-1]).T"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -283,9 +268,22 @@
|
|||
"\n",
|
||||
"</summary>\n",
|
||||
"\n",
|
||||
"Nets which store data are declared as `reg`s:\n",
|
||||
" \n",
|
||||
"```verilog\n",
|
||||
"// Three scalar register\n",
|
||||
"reg op_b, op_a, result;\n",
|
||||
"// One 16-bit register\n",
|
||||
"reg [15:0] word_bus;\n",
|
||||
"// 1K-array of 8-bit registers\n",
|
||||
"reg [7:0] byte_array [0:1023];\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"The following structure updates the memory points:\n",
|
||||
" \n",
|
||||
"```verilog\n",
|
||||
"always @(posedge clk or negedge rst) begin\n",
|
||||
" if (rst) begin \n",
|
||||
" if (!rst) begin \n",
|
||||
" counter <= 0;\n",
|
||||
" end else begin\n",
|
||||
" counter <= counter + 1;\n",
|
||||
|
@ -347,7 +345,95 @@
|
|||
"```\n",
|
||||
"\n",
|
||||
"</details></blockquote>\n",
|
||||
" \n",
|
||||
"The counter example can be synthetized:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%writefile v/cnt.v\n",
|
||||
"module cnt(\n",
|
||||
" input wire clk,\n",
|
||||
" input wire rst,\n",
|
||||
" output wire [7:0] count\n",
|
||||
");\n",
|
||||
"\n",
|
||||
" reg [7:0] counter;\n",
|
||||
" assign count = counter;\n",
|
||||
"\n",
|
||||
" always @(posedge clk or negedge rst) begin\n",
|
||||
" if (!rst) begin \n",
|
||||
" counter <= 0;\n",
|
||||
" end else begin\n",
|
||||
" counter <= counter + 1;\n",
|
||||
" end\n",
|
||||
" end\n",
|
||||
"\n",
|
||||
"endmodule"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"For sequential circuits, one must specify to synthesize the clock tree as well:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%writefile build/config.json\n",
|
||||
"{\n",
|
||||
" \"DESIGN_NAME\": \"cnt\",\n",
|
||||
" \"VERILOG_FILES\": \"dir::v/cnt.v\",\n",
|
||||
" \"CLOCK_TREE_SYNTH\": true,\n",
|
||||
" \"CLOCK_PORT\": \"clk\",\n",
|
||||
" \"FP_SIZING\": \"absolute\",\n",
|
||||
" \"DIE_AREA\": \"0 0 40 50\",\n",
|
||||
" \"FP_PDN_AUTO_ADJUST\": false,\n",
|
||||
" \"FP_PDN_VOFFSET\": 0,\n",
|
||||
" \"FP_PDN_HOFFSET\": 0,\n",
|
||||
" \"DIODE_INSERTION_STRATEGY\": 3\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The flow can be started:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%env PDK=sky130A\n",
|
||||
"!flow.tcl -design ."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The cell above can be reused to display the lyaout."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## High-Level Synthesis (HLS)\n",
|
||||
"\n",
|
||||
"RTL description of circuits does not follow an imperative programming paradigm. It is a description language that produces highly parallelized designs.\n",
|
||||
|
@ -361,18 +447,41 @@
|
|||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%writefile xls/x/adder.x\n",
|
||||
"pub fn adder(in1: u1, in2: u1) -> u2 {\n",
|
||||
" let sum: u2 = in1 as u2 + in2 as u2;\n",
|
||||
" sum\n",
|
||||
"%%writefile xls/x/find_max.x\n",
|
||||
"\n",
|
||||
"//\n",
|
||||
"// Input: an array of 32-bit unsigned integers (u32) of parametrized length N\n",
|
||||
"// Output: the largest element of the array\n",
|
||||
"//\n",
|
||||
"pub fn find_max<N: u32>(array: u32[N]) -> u32 {\n",
|
||||
" let max: u32 = u32:0;\n",
|
||||
" for (i, max): (u32, u32) in range(u32:0,N) {\n",
|
||||
" if (array[i] > max) {array[i]} else {max}\n",
|
||||
" }(max)\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"//\n",
|
||||
"// Input: an array of 32-bit unsigned integers (u32) of parametrized length 4\n",
|
||||
"// Output: the largest element of the array\n",
|
||||
"//\n",
|
||||
"pub fn find_max_impl(array: u32[4]) -> u32 {\n",
|
||||
" find_max<u32:4>(array)\n",
|
||||
"}\n",
|
||||
" \n",
|
||||
"#[test]\n",
|
||||
"fn find_max_impl_test() {\n",
|
||||
" let _= assert_eq(find_max_impl(u32[4]:[45,3,15,6]), u32:45);\n",
|
||||
" let _= assert_eq(find_max_impl(u32[4]:[3,45,15,6]), u32:45);\n",
|
||||
" let _= assert_eq(find_max_impl(u32[4]:[15,3,45,6]), u32:45);\n",
|
||||
" let _= assert_eq(find_max_impl(u32[4]:[6,3,15,45]), u32:45);\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"#[test]\n",
|
||||
"fn adder_test() {\n",
|
||||
" let _= assert_eq(adder(u1:0, u1:0), u2:0b00);\n",
|
||||
" let _= assert_eq(adder(u1:0, u1:1), u2:0b01);\n",
|
||||
" let _= assert_eq(adder(u1:1, u1:1), u2:0b10);\n",
|
||||
" _\n",
|
||||
"fn find_max_test() {\n",
|
||||
" let _= assert_eq(find_max<u32:1>(u32[1]:[39]), u32:39);\n",
|
||||
" let _= assert_eq(find_max<u32:2>(u32[2]:[4,90]), u32:90);\n",
|
||||
" let _= assert_eq(find_max<u32:3>(u32[3]:[7,21,15]), u32:21);\n",
|
||||
" let _= assert_eq(find_max<u32:8>(u32[8]:[1,3,45,1,5,56,0,34]), u32:56);\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
|
@ -391,7 +500,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!interpreter_main xls/x/adder.x"
|
||||
"!interpreter_main xls/x/find_max.x"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -407,11 +516,12 @@
|
|||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"XLS_DESIGN_NAME = 'adder'\n",
|
||||
"!ir_converter_main --top={XLS_DESIGN_NAME} xls/x/{XLS_DESIGN_NAME}.x > xls/ir/{XLS_DESIGN_NAME}.ir\n",
|
||||
"!opt_main xls/ir/{XLS_DESIGN_NAME}.ir > xls/ir/{XLS_DESIGN_NAME}_opt.ir\n",
|
||||
"!codegen_main --generator=combinational xls/ir/{XLS_DESIGN_NAME}_opt.ir > v/{XLS_DESIGN_NAME}.v\n",
|
||||
"!cat v/{XLS_DESIGN_NAME}.v"
|
||||
"XLS_DESIGN_NAME = 'find_max_impl'\n",
|
||||
"XLS_DESIGN_FILE = 'find_max'\n",
|
||||
"!ir_converter_main --top={XLS_DESIGN_NAME} xls/x/{XLS_DESIGN_FILE}.x > xls/ir/{XLS_DESIGN_FILE}.ir\n",
|
||||
"!opt_main xls/ir/{XLS_DESIGN_FILE}.ir > xls/ir/{XLS_DESIGN_FILE}_opt.ir\n",
|
||||
"!codegen_main --generator=combinational xls/ir/{XLS_DESIGN_FILE}_opt.ir > v/{XLS_DESIGN_FILE}.v\n",
|
||||
"!cat v/{XLS_DESIGN_FILE}.v"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -420,7 +530,7 @@
|
|||
"source": [
|
||||
"## Verilog simulation\n",
|
||||
"\n",
|
||||
"A test bench can be written to simulate the circuit described above:"
|
||||
"A test bench can be written to simulate the `xor3` circuit described above:"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -466,7 +576,9 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!iverilog -o tb/xor3_tb tb/xor3_tb.v v/xor3.v\n",
|
||||
|
@ -486,6 +598,29 @@
|
|||
"It can be opened with https://vc.drom.io/ for instance."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Some ideas...\n",
|
||||
"\n",
|
||||
"Here are a couple ideas to spend a good time exploring those beautiful pieces of software:\n",
|
||||
"\n",
|
||||
" * Play with RTL2GDS configuration parameters and observe the impact on the layout.\n",
|
||||
" * Simulate the `cnt` sequential circuit.\n",
|
||||
" * Simulate the `find_max_impl` circuit synthesized using HLS.\n",
|
||||
" * Try to make _Klayout_ GUI work (no warranty).\n",
|
||||
"\n",
|
||||
" **Do not start from scratch! Use the provided examples, examples you can find on the internet and the documentation to adapt from them!**\n",
|
||||
" \n",
|
||||
" > Good luck and read the docs. 😉\n",
|
||||
" \n",
|
||||
"## More food for the brain\n",
|
||||
"\n",
|
||||
" * GDS2RTL flow configuration parameters: https://armleo-openlane.readthedocs.io/en/latest/docs/source/configuration.html\n",
|
||||
" * DSLX language reference: https://google.github.io/xls/dslx_reference/"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
Loading…
Reference in a new issue