{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "uINjDJNf39eD" }, "source": [ "# Semicustom digital design demo using OpenROAD\n", "\n", "## Sources\n", "\n", "### RTL description (Verilog)\n", "\n", "The OpenROAD workflow takes the circuit's RTL description as an input. For instance, it can be a three bits XOR gate.\n", "\n", "\n", "
\n", "\n", "\n", " \n", "#### ↕️ Types in Verilog\n", "\n", "\n", " \n", "```verilog\n", "// Three scalar nets\n", "wire op_b, op_a, result;\n", "// One 16-bit net\n", "wire [15:0] word_bus;\n", "// 1K-array of 8-bit nets\n", "wire [7:0] byte_array [0:1023];\n", "```\n", " \n", "
\n", "\n", "
\n", "\n", "\n", " \n", "#### ↕️ Assignation (non-blocking) in Verilog\n", "\n", "\n", " \n", "```verilog\n", "// 16-bit, hexadecimal constant\n", "assign address = 16'hCAFE;\n", "// Unsized, decimal constant\n", "assign counter = 'd42;\n", "// 1-bit, binary constant\n", "assign answer = 1'b1;\n", "\n", "// Ternary assignation\n", "assign muxed = which ? source_1 : source_2;\n", "\n", "// Concatenation\n", "assign padded_packet = {5'b00000,body,suffix};\n", "// Replication\n", "assign odd_mask = {10{2'b10}};\n", "\n", "// Indexing\n", "assign one_bit = bus[4];\n", "assign bits = bus[15:12];\n", "```\n", " \n", "
\n", "\n", "
\n", "\n", "\n", " \n", "#### ↕️ Operators in Verilog\n", "\n", "\n", " \n", "```verilog\n", "// Addition, substraction, negation\n", "assign sum = op_a + op_b; assign sub = op_a + op_b; assign opp = -op_a\n", "// Multiplication, division, modulo\n", "assign prod = op_a * op_b; assign div = op_a / op_b; assign rem = op_a & op_b\n", " \n", "// Bitwise not, or, and, xor\n", "assign n = ~m; assign a = b | c; assign d = e & f; assign x = y ^ z\n", "\n", "// Logical not, and, or\n", "assign ans = !v; assign ans = v || w; assign ans = v && w;\n", "// Logical equality, difference\n", "assign ans = v == w; assign ans = v != w;\n", "// Relations (strictly) greater, (strictly) lower than\n", "assign sg = a > b; assign gt = a >= b; assign sl = a < b; assign lt = a <= b;\n", " \n", "// Left, right shift by n bits\n", "assign l << n; assign r >> n;\n", "// Left, right arithmetic shift by n bits\n", "assign l <<< n; assign r >>> n;\n", "```\n", " \n", "
" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "id": "gpgkIYB739Ii" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Writing v/xor3.v\n" ] } ], "source": [ "%%writefile v/xor3.v\n", "module xor3(\n", " input wire a,\n", " input wire b,\n", " input wire c,\n", " output wire out\n", ");\n", " assign out = a ^ b ^ c;\n", "endmodule" ] }, { "cell_type": "markdown", "metadata": { "id": "hp8h5vH8TUXr" }, "source": [ "### Configuration file (JSON)\n", "\n", "A configuration file should be provided. It describes constraints and strategies applied during synthesis and implementation of the circuit." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "id": "rbT-vP0h0enK" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Writing build/config.json\n" ] } ], "source": [ "%%writefile build/config.json\n", "{\n", " \"DESIGN_NAME\": \"xor3\",\n", " \"VERILOG_FILES\": \"dir::../v/xor3.v\",\n", " \"CLOCK_TREE_SYNTH\": false,\n", " \"CLOCK_PORT\": null,\n", " \"FP_SIZING\": \"absolute\",\n", " \"DIE_AREA\": \"0 0 25 35\",\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": [ "## Workflow\n", "The provided `flow.tcl` is a script describing the OpenROAD workflow. A _GDS_ file will be generated using the RTL circuit description, the PDK and the configuration file." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "VP60fdObiP15", "outputId": "41aa85e4-c663-4778-d448-928dbe474b11" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "env: PDK=sky130A\n", "OpenLane 2023.04.07_0_gcb634fd5-conda\n", "All rights reserved. (c) 2020-2022 Efabless Corporation and contributors.\n", "Available under the Apache License, version 2.0. See the LICENSE file for more details.\n", "\n", "\u001b[36m[INFO]: Using configuration in 'build/config.json'...\u001b[39m\n", "\u001b[36m[INFO]: PDK Root: /home/pierre/anaconda3/envs/semicustom/share/pdk\u001b[39m\n", "\u001b[36m[INFO]: Process Design Kit: sky130A\u001b[39m\n", "\u001b[36m[INFO]: Standard Cell Library: sky130_fd_sc_hd\u001b[39m\n", "\u001b[36m[INFO]: Optimization Standard Cell Library: sky130_fd_sc_hd\u001b[39m\n", "\u001b[33m[WARNING]: DIODE_INSERTION_STRATEGY is now deprecated; use GRT_REPAIR_ANTENNAS, DIODE_ON_PORTS and RUN_HEURISTIC_DIODE_INSERTION instead.\u001b[39m\n", "\u001b[36m[INFO]: DIODE_INSERTION_STRATEGY set to 3. Setting GRT_REPAIR_ANTENNAS to 1\u001b[39m\n", "\u001b[36m[INFO]: Run Directory: /home/pierre/Documents/freechips/semicustom/build/runs/RUN_2023.04.30_19.27.15\u001b[39m\n", "\u001b[36m[INFO]: Preparing LEF files for the nom corner...\u001b[39m\n", "\u001b[36m[INFO]: Preparing LEF files for the min corner...\u001b[39m\n", "\u001b[36m[INFO]: Preparing LEF files for the max corner...\u001b[39m\n", "[STEP 1]\n", "\u001b[36m[INFO]: Running Synthesis (log: build/runs/RUN_2023.04.30_19.27.15/logs/synthesis/1-synthesis.log)...\u001b[39m\n", "[STEP 2]\n", "\u001b[36m[INFO]: Running Single-Corner Static Timing Analysis (log: build/runs/RUN_2023.04.30_19.27.15/logs/synthesis/2-sta.log)...\u001b[39m\n", "[STEP 3]\n", "\u001b[36m[INFO]: Running Initial Floorplanning (log: build/runs/RUN_2023.04.30_19.27.15/logs/floorplan/3-initial_fp.log)...\u001b[39m\n", "\u001b[36m[INFO]: Floorplanned with width 13.8 and height 10.88.\u001b[39m\n", "[STEP 4]\n", "\u001b[36m[INFO]: Running IO Placement...\u001b[39m\n", "[STEP 5]\n", "\u001b[36m[INFO]: Running Tap/Decap Insertion (log: build/runs/RUN_2023.04.30_19.27.15/logs/floorplan/5-tap.log)...\u001b[39m\n", "\u001b[36m[INFO]: Power planning with power {VPWR} and ground {VGND}...\u001b[39m\n", "[STEP 6]\n", "\u001b[36m[INFO]: Generating PDN (log: build/runs/RUN_2023.04.30_19.27.15/logs/floorplan/6-pdn.log)...\u001b[39m\n", "[STEP 7]\n", "\u001b[36m[INFO]: Running Global Placement (log: build/runs/RUN_2023.04.30_19.27.15/logs/placement/7-global.log)...\u001b[39m\n", "[STEP 8]\n", "\u001b[36m[INFO]: Running Single-Corner Static Timing Analysis (log: build/runs/RUN_2023.04.30_19.27.15/logs/placement/8-sta-global.log)...\u001b[39m\n", "[STEP 9]\n", "\u001b[36m[INFO]: Running Placement Resizer Design Optimizations (log: build/runs/RUN_2023.04.30_19.27.15/logs/placement/9-resizer.log)...\u001b[39m\n", "[STEP 10]\n", "\u001b[36m[INFO]: Running Detailed Placement (log: build/runs/RUN_2023.04.30_19.27.15/logs/placement/10-detailed.log)...\u001b[39m\n", "[STEP 11]\n", "\u001b[36m[INFO]: Running Single-Corner Static Timing Analysis (log: build/runs/RUN_2023.04.30_19.27.15/logs/placement/11-sta.log)...\u001b[39m\n", "[STEP 12]\n", "\u001b[36m[INFO]: Running Placement Resizer Timing Optimizations (log: build/runs/RUN_2023.04.30_19.27.15/logs/cts/12-resizer.log)...\u001b[39m\n", "[STEP 13]\n", "\u001b[36m[INFO]: Running Global Routing Resizer Design Optimizations (log: build/runs/RUN_2023.04.30_19.27.15/logs/routing/13-resizer_design.log)...\u001b[39m\n", "[STEP 14]\n", "\u001b[36m[INFO]: Running Single-Corner Static Timing Analysis (log: build/runs/RUN_2023.04.30_19.27.15/logs/routing/14-sta-resizer_design.log)...\u001b[39m\n", "[STEP 15]\n", "\u001b[36m[INFO]: Running Global Routing Resizer Timing Optimizations (log: build/runs/RUN_2023.04.30_19.27.15/logs/routing/15-resizer_timing.log)...\u001b[39m\n", "[STEP 16]\n", "\u001b[36m[INFO]: Running Single-Corner Static Timing Analysis (log: build/runs/RUN_2023.04.30_19.27.15/logs/routing/16-sta-resizer_timing.log)...\u001b[39m\n", "[STEP 17]\n", "\u001b[36m[INFO]: Running Global Routing (log: build/runs/RUN_2023.04.30_19.27.15/logs/routing/17-global.log)...\u001b[39m\n", "\u001b[36m[INFO]: Starting OpenROAD Antenna Repair Iterations...\u001b[39m\n", "[STEP 18]\n", "\u001b[36m[INFO]: Writing Verilog (log: build/runs/RUN_2023.04.30_19.27.15/logs/routing/17-global_write_netlist.log)...\u001b[39m\n", "[STEP 19]\n", "\u001b[36m[INFO]: Running Single-Corner Static Timing Analysis (log: build/runs/RUN_2023.04.30_19.27.15/logs/routing/19-sta-groute.log)...\u001b[39m\n", "[STEP 20]\n", "\u001b[36m[INFO]: Running Fill Insertion (log: build/runs/RUN_2023.04.30_19.27.15/logs/routing/20-fill.log)...\u001b[39m\n", "[STEP 21]\n", "\u001b[36m[INFO]: Running Detailed Routing (log: build/runs/RUN_2023.04.30_19.27.15/logs/routing/21-detailed.log)...\u001b[39m\n", "\u001b[36m[INFO]: No DRC violations after detailed routing.\u001b[39m\n", "[STEP 22]\n", "\u001b[36m[INFO]: Checking Wire Lengths (log: build/runs/RUN_2023.04.30_19.27.15/logs/routing/22-wire_lengths.log)...\u001b[39m\n", "[STEP 23]\n", "\u001b[36m[INFO]: Running SPEF Extraction at the min process corner (log: build/runs/RUN_2023.04.30_19.27.15/logs/signoff/23-parasitics_extraction.min.log)...\u001b[39m\n", "[STEP 24]\n", "\u001b[36m[INFO]: Running Multi-Corner Static Timing Analysis at the min process corner (log: build/runs/RUN_2023.04.30_19.27.15/logs/signoff/24-rcx_mcsta.min.log)...\u001b[39m\n", "[STEP 25]\n", "\u001b[36m[INFO]: Running SPEF Extraction at the max process corner (log: build/runs/RUN_2023.04.30_19.27.15/logs/signoff/25-parasitics_extraction.max.log)...\u001b[39m\n", "[STEP 26]\n", "\u001b[36m[INFO]: Running Multi-Corner Static Timing Analysis at the max process corner (log: build/runs/RUN_2023.04.30_19.27.15/logs/signoff/26-rcx_mcsta.max.log)...\u001b[39m\n", "[STEP 27]\n", "\u001b[36m[INFO]: Running SPEF Extraction at the nom process corner (log: build/runs/RUN_2023.04.30_19.27.15/logs/signoff/27-parasitics_extraction.nom.log)...\u001b[39m\n", "[STEP 28]\n", "\u001b[36m[INFO]: Running Multi-Corner Static Timing Analysis at the nom process corner (log: build/runs/RUN_2023.04.30_19.27.15/logs/signoff/28-rcx_mcsta.nom.log)...\u001b[39m\n", "[STEP 29]\n", "\u001b[36m[INFO]: Running Single-Corner Static Timing Analysis at the nom process corner (log: build/runs/RUN_2023.04.30_19.27.15/logs/signoff/29-rcx_sta.log)...\u001b[39m\n", "\u001b[33m[WARNING]: Module sky130_ef_sc_hd__decap_12 blackboxed during sta\u001b[39m\n", "\u001b[33m[WARNING]: Module sky130_fd_sc_hd__fill_1 blackboxed during sta\u001b[39m\n", "\u001b[33m[WARNING]: Module sky130_fd_sc_hd__fill_2 blackboxed during sta\u001b[39m\n", "[STEP 30]\n", "\u001b[36m[INFO]: Creating IR Drop Report (log: build/runs/RUN_2023.04.30_19.27.15/logs/signoff/30-irdrop.log)...\u001b[39m\n", "[STEP 31]\n", "\u001b[36m[INFO]: Running Magic to generate various views...\u001b[39m\n", "\u001b[36m[INFO]: Streaming out GDSII with Magic (log: build/runs/RUN_2023.04.30_19.27.15/logs/signoff/31-gdsii.log)...\u001b[39m\n", "\u001b[36m[INFO]: Generating MAGLEF views...\u001b[39m\n", "[STEP 32]\n", "\u001b[36m[INFO]: Streaming out GDSII with KLayout (log: build/runs/RUN_2023.04.30_19.27.15/logs/signoff/32-gdsii-klayout.log)...\u001b[39m\n", "[STEP 33]\n", "\u001b[36m[INFO]: Running XOR on the layouts using KLayout (log: build/runs/RUN_2023.04.30_19.27.15/logs/signoff/33-xor.log)...\u001b[39m\n", "\u001b[36m[INFO]: No XOR differences between KLayout and Magic gds.\u001b[39m\n", "[STEP 34]\n", "\u001b[36m[INFO]: Running Magic Spice Export from LEF (log: build/runs/RUN_2023.04.30_19.27.15/logs/signoff/34-spice.log)...\u001b[39m\n", "[STEP 35]\n", "\u001b[36m[INFO]: Writing Powered Verilog (logs: build/runs/RUN_2023.04.30_19.27.15/logs/signoff/35-write_powered_def.log, build/runs/RUN_2023.04.30_19.27.15/logs/signoff/35-write_powered_verilog.log)...\u001b[39m\n", "[STEP 36]\n", "\u001b[36m[INFO]: Writing Verilog (log: build/runs/RUN_2023.04.30_19.27.15/logs/signoff/35-write_powered_verilog.log)...\u001b[39m\n", "[STEP 37]\n", "\u001b[36m[INFO]: Running LVS (log: build/runs/RUN_2023.04.30_19.27.15/logs/signoff/37-lvs.lef.log)...\u001b[39m\n", "\u001b[31m[ERROR]: There are LVS errors in the design: See 'build/runs/RUN_2023.04.30_19.27.15/reports/signoff/37-xor3.lvs.rpt' for a summary and 'build/runs/RUN_2023.04.30_19.27.15/logs/signoff/37-lvs.lef.log' for details.\u001b[39m\n", "\u001b[31m[ERROR]: Step(37:lvs) failed with error:\n", "-code 1 -level 0 -errorstack {INNER {invokeStk1 throw_error} CALL {quit_on_lvs_error -rpt /home/pierre/Documents/freechips/semicustom/build/runs/RUN_2023.04.30_19.27.15/reports/signoff/37-xor3.lvs.rpt -log /home/pierre/Documents/freechips/semicustom/build/runs/RUN_2023.04.30_19.27.15/logs/signoff/37-lvs.lef.log} CALL run_lvs CALL run_lvs_step CALL {run_non_interactive_mode -design build}} -errorcode NONE -errorinfo {\n", " while executing\n", "\"throw_error\"\n", " (procedure \"quit_on_lvs_error\" line 13)\n", " invoked from within\n", "\"quit_on_lvs_error -rpt $count_lvs_rpt -log $log\"\n", " (procedure \"run_lvs\" line 76)\n", " invoked from within\n", "\"run_lvs\"\n", " (procedure \"run_lvs_step\" line 10)\n", " invoked from within\n", "\"run_lvs_step\"} -errorline 1\u001b[39m\n", "\u001b[36m[INFO]: Saving current set of views in 'build/runs/RUN_2023.04.30_19.27.15/results/final'...\u001b[39m\n", "\u001b[36m[INFO]: Generating final set of reports...\u001b[39m\n", "\u001b[36m[INFO]: Created manufacturability report at 'build/runs/RUN_2023.04.30_19.27.15/reports/manufacturability.rpt'.\u001b[39m\n", "\u001b[36m[INFO]: Created metrics report at 'build/runs/RUN_2023.04.30_19.27.15/reports/metrics.csv'.\u001b[39m\n", "\u001b[36m[INFO]: Saving runtime environment...\u001b[39m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[31m[ERROR]: Flow failed.\u001b[39m\r", "\r\n", "\u001b[36m[INFO]: The failure may have been because of the following warnings:\u001b[39m\r", "\r\n", "[WARNING]: Module sky130_ef_sc_hd__decap_12 blackboxed during sta\r", "\r\n", "[WARNING]: Module sky130_fd_sc_hd__fill_1 blackboxed during sta\r", "\r\n", "[WARNING]: Module sky130_fd_sc_hd__fill_2 blackboxed during sta\r", "\r\n", "\r", "\r\n" ] } ], "source": [ "%env PDK=sky130A\n", "!flow.tcl -design build" ] }, { "cell_type": "markdown", "metadata": { "id": "luguFgZ43AeL" }, "source": [ "## Output products\n", "\n", "### Display layout\n", "\n", "The implemented layout can be retrieved as follows:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 650 }, "id": "WOnhdtp3ivRi", "outputId": "b4bd26f8-d3da-47b7-e321-99272b0591ef", "scrolled": false }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "VPWR\n", "VGND\n", "VPB\n", "VNB\n", "decap_8\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "VGND\n", "VPWR\n", "B\n", "Y\n", "A\n", "VPB\n", "VNB\n", "xnor2_1\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "VGND\n", "VPWR\n", "VPB\n", "VNB\n", "decap_12\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "VGND\n", "VPWR\n", "VPB\n", "VNB\n", "decap_4\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "VGND\n", "VPWR\n", "VPB\n", "VNB\n", "fill_2\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "VPWR\n", "VGND\n", "VPB\n", "VNB\n", "decap_6\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "VPWR\n", "VGND\n", "VPB\n", "VNB\n", "decap_3\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "X\n", "A\n", "X\n", "A\n", "X\n", "VGND\n", "VPWR\n", "VPB\n", "VNB\n", "clkbuf_4\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "VGND\n", "VPWR\n", "X\n", "X\n", "X\n", "A\n", "VPB\n", "VNB\n", "clkbuf_1\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "VPWR\n", "VGND\n", "VPB\n", "VNB\n", "fill_1\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "VGND\n", "VPWR\n", "_0_\n", "a\n", "b\n", "c\n", "net1\n", "net2\n", "net3\n", "net4\n", "out\n", "VGND\n", "VPWR\n", "a\n", "b\n", "c\n", "out\n", "\n", "" ], "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import glob\n", "import gdstk\n", "import IPython.display\n", "\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')" ] }, { "cell_type": "markdown", "metadata": { "id": "NW_7YdgTZYQK" }, "source": [ "### Reporting\n", "\n", "Many reports are available under:\n", "\n", "```\n", "freeechips/semicustom/runs/RUN_YYYY.MM.DD_HH.MM.SS/reports/.\n", "```\n", "\n", "An overview of the main figures can be retrieved as well:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 1000 }, "id": "OWAwQI3fZC4W", "outputId": "d50dcf9f-30cd-42a3-dab5-12992bc9dca2", "scrolled": true }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
0
design/home/pierre/Documents/freechips/semicustom/build
design_namexor3
configRUN_2023.04.30_19.27.15
flow_statusflow failed
total_runtime0h0m17s0ms
routed_runtime0h0m10s0ms
(Cell/mm^2)/Core_Util13714.285714
DIEAREA_mm^20.000875
CellPer_mm^26857.142857
OpenDP_Util27.08
Final_Util-1
Peak_Memory_Usage_MB469.18
synth_cell_count2
tritonRoute_violations0
Short_violations0
MetSpc_violations0
OffGrid_violations0
MinHole_violations0
Other_violations0
Magic_violations-1
pin_antenna_violations-1
net_antenna_violations-1
lvs_total_errors17
cvc_total_errors-1
klayout_violations-1
wire_length88
vias30
wns0.0
pl_wns-1
optimized_wns-1
fastroute_wns-1
spef_wns0.0
tns0.0
pl_tns-1
optimized_tns-1
fastroute_tns-1
spef_tns0.0
HPWL98756.0
routing_layer1_pct0.0
routing_layer2_pct4.41
routing_layer3_pct4.6
routing_layer4_pct0.0
routing_layer5_pct0.0
routing_layer6_pct0.0
wires_count5
wire_bits5
public_wires_count4
public_wire_bits4
memories_count0
memory_bits0
processes_count0
cells_pre_abc2
AND0
DFF0
NAND0
NOR0
OR0
XOR2
XNOR0
MUX0
inputs3
outputs1
level2
DecapCells16
WelltapCells0
DiodeCells0
FillCells3
NonPhysCells6
TotalCells25
CoreArea_um^2150.144
power_slowest_internal_uW-1
power_slowest_switching_uW-1
power_slowest_leakage_uW-1
power_typical_internal_uW0.000001
power_typical_switching_uW0.000002
power_typical_leakage_uW0.0
power_fastest_internal_uW-1
power_fastest_switching_uW-1
power_fastest_leakage_uW-1
critical_path_ns0.64
suggested_clock_period10.0
suggested_clock_frequency100.0
CLOCK_PERIOD10.0
FP_ASPECT_RATIO1
FP_CORE_UTIL50
FP_PDN_HPITCH153.18
FP_PDN_VPITCH153.6
GRT_ADJUSTMENT0.3
GRT_REPAIR_ANTENNAS1
PL_TARGET_DENSITY0.6
RUN_HEURISTIC_DIODE_INSERTION0
STD_CELL_LIBRARYsky130_fd_sc_hd
SYNTH_MAX_FANOUT10
SYNTH_STRATEGYAREA 0
\n", "
" ], "text/plain": [ " 0\n", "design /home/pierre/Documents/freechips/semicustom/build\n", "design_name xor3\n", "config RUN_2023.04.30_19.27.15\n", "flow_status flow failed\n", "total_runtime 0h0m17s0ms\n", "routed_runtime 0h0m10s0ms\n", "(Cell/mm^2)/Core_Util 13714.285714\n", "DIEAREA_mm^2 0.000875\n", "CellPer_mm^2 6857.142857\n", "OpenDP_Util 27.08\n", "Final_Util -1\n", "Peak_Memory_Usage_MB 469.18\n", "synth_cell_count 2\n", "tritonRoute_violations 0\n", "Short_violations 0\n", "MetSpc_violations 0\n", "OffGrid_violations 0\n", "MinHole_violations 0\n", "Other_violations 0\n", "Magic_violations -1\n", "pin_antenna_violations -1\n", "net_antenna_violations -1\n", "lvs_total_errors 17\n", "cvc_total_errors -1\n", "klayout_violations -1\n", "wire_length 88\n", "vias 30\n", "wns 0.0\n", "pl_wns -1\n", "optimized_wns -1\n", "fastroute_wns -1\n", "spef_wns 0.0\n", "tns 0.0\n", "pl_tns -1\n", "optimized_tns -1\n", "fastroute_tns -1\n", "spef_tns 0.0\n", "HPWL 98756.0\n", "routing_layer1_pct 0.0\n", "routing_layer2_pct 4.41\n", "routing_layer3_pct 4.6\n", "routing_layer4_pct 0.0\n", "routing_layer5_pct 0.0\n", "routing_layer6_pct 0.0\n", "wires_count 5\n", "wire_bits 5\n", "public_wires_count 4\n", "public_wire_bits 4\n", "memories_count 0\n", "memory_bits 0\n", "processes_count 0\n", "cells_pre_abc 2\n", "AND 0\n", "DFF 0\n", "NAND 0\n", "NOR 0\n", "OR 0\n", "XOR 2\n", "XNOR 0\n", "MUX 0\n", "inputs 3\n", "outputs 1\n", "level 2\n", "DecapCells 16\n", "WelltapCells 0\n", "DiodeCells 0\n", "FillCells 3\n", "NonPhysCells 6\n", "TotalCells 25\n", "CoreArea_um^2 150.144\n", "power_slowest_internal_uW -1\n", "power_slowest_switching_uW -1\n", "power_slowest_leakage_uW -1\n", "power_typical_internal_uW 0.000001\n", "power_typical_switching_uW 0.000002\n", "power_typical_leakage_uW 0.0\n", "power_fastest_internal_uW -1\n", "power_fastest_switching_uW -1\n", "power_fastest_leakage_uW -1\n", "critical_path_ns 0.64\n", "suggested_clock_period 10.0\n", "suggested_clock_frequency 100.0\n", "CLOCK_PERIOD 10.0\n", "FP_ASPECT_RATIO 1\n", "FP_CORE_UTIL 50\n", "FP_PDN_HPITCH 153.18\n", "FP_PDN_VPITCH 153.6\n", "GRT_ADJUSTMENT 0.3\n", "GRT_REPAIR_ANTENNAS 1\n", "PL_TARGET_DENSITY 0.6\n", "RUN_HEURISTIC_DIODE_INSERTION 0\n", "STD_CELL_LIBRARY sky130_fd_sc_hd\n", "SYNTH_MAX_FANOUT 10\n", "SYNTH_STRATEGY AREA 0" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import glob\n", "import pandas as pd\n", "pd.options.display.max_rows = None\n", "\n", "pd.read_csv(sorted(glob.glob(\"./build/runs/*/reports/metrics.csv\"))[-1]).T" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# To have fun going further...\n", "\n", "## Sequential circuits in Verilog\n", "\n", "The tutorial above focuses on combinational circuits. Sequential circuits can obviously be described in Verilog as well. Sequential blocks feature an `always` block. Refer to the vendor's reference to get the sensitivity list's syntax (e.g. to determine if reset is synchronous or asynchronous).\n", "\n", "
\n", "\n", "\n", " \n", "#### ↕️ Sequential structures in Verilog\n", "\n", "\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", " counter <= 0;\n", " end else begin\n", " counter <= counter + 1;\n", " end\n", "end\n", "```\n", " \n", "
\n", "\n", "Advanced structures like the `case` structure can be used to describe finite state machines. FSM decoders can be described in an abstract way using `always` blocks in a fully combinational way:\n", "\n", "
\n", "\n", "\n", " \n", "#### ↕️ Advanced structures in Verilog\n", "\n", "\n", "\n", "```verilog\n", " \n", "/*\n", " * Case structure\n", " */\n", " \n", "case (state)\n", "\n", " 3'b000: idle_led <= 1'b1;\n", " \n", " 3'b001,\n", " 3'b010: work_led <= 1'b1;\n", " \n", " 3'b011: begin\n", " muxed <= spi_1;\n", " work_led <= 1'b1;\n", " end\n", " \n", " default: begin\n", " muxed <= 0;\n", " work_led <= 1'b0; \n", " idle_led <= 1'b1;\n", " end\n", "\n", "endcase\n", "\n", "/*\n", " * Combinational always structure\n", " * To describe priorities in a procedural fashion,\n", " * use blocking `<=` assignations instead of\n", " * non-blocking `=` assignations.\n", " */\n", " \n", "always @( * ) begin\n", " flag <= 1'b0;\n", " if (error) begin \n", " flag <= 1'b1;\n", " end\n", "end\n", "```\n", "\n", "
\n", " \n", "The counter example can be synthetized:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Writing v/cnt.v\n" ] } ], "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": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Overwriting build/config.json\n" ] } ], "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": 9, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "env: PDK=sky130A\n", "OpenLane 2023.04.07_0_gcb634fd5-conda\n", "All rights reserved. (c) 2020-2022 Efabless Corporation and contributors.\n", "Available under the Apache License, version 2.0. See the LICENSE file for more details.\n", "\n", "\u001b[36m[INFO]: Using configuration in 'build/config.json'...\u001b[39m\n", "\u001b[36m[INFO]: PDK Root: /home/pierre/anaconda3/envs/semicustom/share/pdk\u001b[39m\n", "\u001b[36m[INFO]: Process Design Kit: sky130A\u001b[39m\n", "\u001b[36m[INFO]: Standard Cell Library: sky130_fd_sc_hd\u001b[39m\n", "\u001b[36m[INFO]: Optimization Standard Cell Library: sky130_fd_sc_hd\u001b[39m\n", "\u001b[33m[WARNING]: DIODE_INSERTION_STRATEGY is now deprecated; use GRT_REPAIR_ANTENNAS, DIODE_ON_PORTS and RUN_HEURISTIC_DIODE_INSERTION instead.\u001b[39m\n", "\u001b[36m[INFO]: DIODE_INSERTION_STRATEGY set to 3. Setting GRT_REPAIR_ANTENNAS to 1\u001b[39m\n", "\u001b[36m[INFO]: Run Directory: /home/pierre/Documents/freechips/semicustom/build/runs/RUN_2023.04.30_19.28.02\u001b[39m\n", "\u001b[36m[INFO]: Preparing LEF files for the nom corner...\u001b[39m\n", "\u001b[36m[INFO]: Preparing LEF files for the min corner...\u001b[39m\n", "\u001b[36m[INFO]: Preparing LEF files for the max corner...\u001b[39m\n", "[STEP 1]\n", "\u001b[36m[INFO]: Running Synthesis (log: build/runs/RUN_2023.04.30_19.28.02/logs/synthesis/1-synthesis.log)...\u001b[39m\n", "\u001b[31m[ERROR]: during executing yosys script /home/pierre/anaconda3/envs/semicustom/share/openlane/scripts/yosys/synth.tcl\u001b[39m\n", "\u001b[31m[ERROR]: Log: build/runs/RUN_2023.04.30_19.28.02/logs/synthesis/1-synthesis.log\u001b[39m\n", "\u001b[31m[ERROR]: Last 10 lines:\n", " Yosys 0.27+30 (git sha1 e56dad56c, x86_64-conda-linux-gnu-cc 11.2.0 -fvisibility-inlines-hidden -fmessage-length=0 -march=nocona -mtune=haswell -ftree-vectorize -fPIC -fstack-protector-strong -fno-plt -O2 -ffunction-sections -fdebug-prefix-map=/root/conda-eda/conda-eda/workdir/conda-env/conda-bld/yosys_1681341442694/work=/usr/local/src/conda/yosys-0.27_33_ge56dad56c -fdebug-prefix-map=/home/pierre/anaconda3/envs/semicustom=/usr/local/src/conda-prefix -fPIC -Os -fno-merge-constants)\n", "\n", "[TCL: yosys -import] Command name collision: found pre-existing command `cd' -> skip.\n", "[TCL: yosys -import] Command name collision: found pre-existing command `eval' -> skip.\n", "[TCL: yosys -import] Command name collision: found pre-existing command `exec' -> skip.\n", "[TCL: yosys -import] Command name collision: found pre-existing command `read' -> skip.\n", "[TCL: yosys -import] Command name collision: found pre-existing command `trace' -> skip.\n", "ERROR: Can't open input file `/home/pierre/Documents/freechips/semicustom/build/v/cnt.v' for reading: No such file or directory\n", "ERROR: TCL interpreter returned an error: Yosys command produced an error\n", "child process exited abnormally\n", "\u001b[39m\n", "\u001b[31m[ERROR]: Creating issue reproducible...\u001b[39m\n", "\u001b[36m[INFO]: Saving runtime environment...\u001b[39m\n", "OpenLane TCL Issue Packager\n", "\n", "EFABLESS CORPORATION AND ALL AUTHORS OF THE OPENLANE PROJECT SHALL NOT BE HELD\n", "LIABLE FOR ANY LEAKS THAT MAY OCCUR TO ANY PROPRIETARY DATA AS A RESULT OF USING\n", "THIS SCRIPT. THIS SCRIPT IS PROVIDED ON AN \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n", "CONDITIONS OF ANY KIND.\n", "\n", "BY USING THIS SCRIPT, YOU ACKNOWLEDGE THAT YOU FULLY UNDERSTAND THIS DISCLAIMER\n", "AND ALL IT ENTAILS.\n", "\n", "Parsing config file(s)…\n", "Setting up /home/pierre/Documents/freechips/semicustom/build/runs/RUN_2023.04.30_19.28.02/issue_reproducible…\n", "Done.\n", "\u001b[36m[INFO]: Reproducible packaged: Please tarball and upload 'build/runs/RUN_2023.04.30_19.28.02/issue_reproducible' if you're going to submit an issue.\u001b[39m\n", "\u001b[31m[ERROR]: Step(1:synthesis) failed with error:\n", "-code 1 -level 0 -errorstack {INNER {invokeStk1 throw_error} CALL {run_tcl_script -tool yosys -no_consume /home/pierre/anaconda3/envs/semicustom/share/openlane/scripts/yosys/synth.tcl -indexed_log /home/pierre/Documents/freechips/semicustom/build/runs/RUN_2023.04.30_19.28.02/logs/synthesis/1-synthesis.log} CALL {run_yosys_script /home/pierre/anaconda3/envs/semicustom/share/openlane/scripts/yosys/synth.tcl -indexed_log /home/pierre/Documents/freechips/semicustom/build/runs/RUN_2023.04.30_19.28.02/logs/synthesis/1-synthesis.log} CALL {run_yosys -indexed_log /home/pierre/Documents/freechips/semicustom/build/runs/RUN_2023.04.30_19.28.02/logs/synthesis/1-synthesis.log} CALL run_synthesis CALL {run_non_interactive_mode -design build}} -errorcode NONE -errorinfo {\n", " while executing\n", "\"throw_error\"\n", " (procedure \"run_tcl_script\" line 219)\n", " invoked from within\n", "\"run_tcl_script -tool yosys -no_consume {*}$args\"\n", " (procedure \"run_yosys_script\" line 2)\n", " invoked from within\n", "\"run_yosys_script $::env(SYNTH_SCRIPT) -indexed_log $arg_values(-indexed_log)\"\n", " (procedure \"run_yosys\" line 44)\n", " invoked from within\n", "\"run_yosys -indexed_log $log\"\n", " (procedure \"run_synthesis\" line 13)\n", " invoked from within\n", "\"run_synthesis\"} -errorline 1\u001b[39m\n", "\u001b[36m[INFO]: Saving current set of views in 'build/runs/RUN_2023.04.30_19.28.02/results/final'...\u001b[39m\n", "\u001b[36m[INFO]: Generating final set of reports...\u001b[39m\n", "\u001b[36m[INFO]: Created manufacturability report at 'build/runs/RUN_2023.04.30_19.28.02/reports/manufacturability.rpt'.\u001b[39m\n", "\u001b[36m[INFO]: Created metrics report at 'build/runs/RUN_2023.04.30_19.28.02/reports/metrics.csv'.\u001b[39m\n", "\u001b[36m[INFO]: Saving runtime environment...\u001b[39m\n", "\u001b[31m[ERROR]: Flow failed.\u001b[39m\n" ] } ], "source": [ "%env PDK=sky130A\n", "!flow.tcl -design build" ] }, { "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", "\n", "High-Level Synthesis provides an imperative language and a compiler that synthesizes the imperative instructions into RTL. For instance, _XLS_ provides a _Rust_-like language:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Writing xls/x/find_max.x\n" ] } ], "source": [ "%%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(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(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 find_max_test() {\n", " let _= assert_eq(find_max(u32[1]:[39]), u32:39);\n", " let _= assert_eq(find_max(u32[2]:[4,90]), u32:90);\n", " let _= assert_eq(find_max(u32[3]:[7,21,15]), u32:21);\n", " let _= assert_eq(find_max(u32[8]:[1,3,45,1,5,56,0,34]), u32:56);\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Testing, parsing and linting can be performed prior to RTL synhesis:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ RUN UNITTEST ] find_max_impl_test\r\n", "[ OK ]\r\n", "[ RUN UNITTEST ] find_max_test\r\n", "[ OK ]\r\n", "[===============] 2 test(s) ran; 0 failed; 0 skipped.\r\n" ] } ], "source": [ "!interpreter_main xls/x/find_max.x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now that the imperative instructions are tested, the RTL design can be synthesized by _XLS_:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "module __find_max__find_max_impl(\r\n", " input wire [127:0] array,\r\n", " output wire [31:0] out\r\n", ");\r\n", " wire [31:0] array_unflattened[4];\r\n", " assign array_unflattened[0] = array[31:0];\r\n", " assign array_unflattened[1] = array[63:32];\r\n", " assign array_unflattened[2] = array[95:64];\r\n", " assign array_unflattened[3] = array[127:96];\r\n", " wire [31:0] array_index_74;\r\n", " wire [31:0] array_index_75;\r\n", " wire [31:0] array_index_78;\r\n", " wire [31:0] sel_79;\r\n", " wire [31:0] array_index_82;\r\n", " wire [31:0] sel_83;\r\n", " assign array_index_74 = array_unflattened[2'h1];\r\n", " assign array_index_75 = array_unflattened[2'h0];\r\n", " assign array_index_78 = array_unflattened[2'h2];\r\n", " assign sel_79 = array_index_74 > array_index_75 ? array_index_74 : array_index_75;\r\n", " assign array_index_82 = array_unflattened[2'h3];\r\n", " assign sel_83 = array_index_78 > sel_79 ? array_index_78 : sel_79;\r\n", " assign out = array_index_82 > sel_83 ? array_index_82 : sel_83;\r\n", "endmodule\r\n" ] } ], "source": [ "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" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Verilog simulation\n", "\n", "A test bench can be written to simulate the `xor3` circuit described above:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%writefile tb/xor3_tb.v\n", "module xor3_tb;\n", "\n", " wire value;\n", " reg w1, w2, w3;\n", " initial begin\n", " $dumpfile(\"tb/xor3_tb.vcd\");\n", " $dumpvars(0,xor3_tb);\n", " # 0 w1 = 0; w2 = 0; w3 = 0;\n", " # 5 w1 = 0; w2 = 0; w3 = 1;\n", " # 5 w1 = 0; w2 = 1; w3 = 0;\n", " # 5 w1 = 0; w2 = 1; w3 = 1;\n", " # 5 w1 = 1; w2 = 0; w3 = 0;\n", " # 5 w1 = 1; w2 = 0; w3 = 1;\n", " # 5 w1 = 1; w2 = 1; w3 = 0;\n", " # 5 w1 = 1; w2 = 1; w3 = 1;\n", " # 5 $finish;\n", " end\n", "\n", " xor3 xor3_i (w1, w2, w3, value);\n", "\n", " initial\n", " $monitor(\"At time %t, value = %h (%0d)\",\n", " $time, value, value);\n", "endmodule" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The simulation can then be performed using _Icarus Verilog_:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "!iverilog -o tb/xor3_tb tb/xor3_tb.v v/xor3.v\n", "!vvp tb/xor3_tb" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The waveforms are dumped in a `.vcd` file, located under:\n", "\n", "```\n", "tb/xor3_tb.vcd\n", "```\n", "\n", "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": {}, "source": [ "# References\n", "Inspired from:\n", "“Silicon Notebooks.” CHIPS Alliance, Apr. 08, 2023. Accessed: Apr. 10, 2023. [Online]. Available: https://github.com/chipsalliance/silicon-notebooks/blob/b65134a43b01ae31423f7ee87110740b2257ac42/digital-inverter-openlane.ipynb (Apache License 2.0)" ] } ], "metadata": { "colab": { "name": "digital-inverter-openlane.ipynb", "provenance": [] }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.16" } }, "nbformat": 4, "nbformat_minor": 1 }