Journal Conception d’un circuit intégré avec OpenRoad

Posté par  (site web personnel) . Licence CC By‑SA.
Étiquettes :
24
31
août
2025

Sommaire

Bonjour, Nal !

Y'a quelques temps, je t'avais expliqué comment faire un circuit integré avec QFlow. Aujourd'hui, je vais te montrer comment faire la même chose avec OpenRoad.

Le projet OpenRoad (“Foundations and Realization of Open, Accessible Design”) vise à simplifier la conception de circuits intégrés. Ils développent l'outil OpenROAD qui à partir d'une netlist s'occupe du P&R et cie pour générer un GDSII (voir journal précédent) ainsi qu'un flot RTL to GDSII complet.

Installation de OpenRoad

ahahahahah. Souffre. RTFM

Mais globalement,

  • Debian 11 / Ubuntu 20.04, 22.04: ils ont un dépôt, RTFM
  • compilation via Docker: RTFM
  • compilation depuis les sources: RTFM
  • nix flake. Cadeau, mon flake.nix :
{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
    openroad = {
      type = "git";
      url = "https://github.com/The-OpenROAD-Project/OpenROAD";
      submodules = true;
    };
    yosys = {
      type = "git";
      url = "https://github.com/The-OpenROAD-Project/yosys";
      submodules = true;
    };
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs =
    {
      self,
      nixpkgs,
      flake-utils,
      openroad,
      yosys,
      ...
    }:
    flake-utils.lib.eachDefaultSystem (
      system:
      let
        pkgs = import nixpkgs {
          inherit system;
        };
      in
      {
        devShells.default = pkgs.mkShell {
          buildInputs = [
            openroad.packages.${system}.default
            yosys.packages.${system}.default
          ];
          packages = with pkgs; [
            fish
            nil
            nixd
            nixfmt-rfc-style
            time
            klayout
            verilator
            perl
            python3
            python3Packages.pandas
            python3Packages.numpy
            python3Packages.firebase-admin
            python3Packages.click
            python3Packages.pyyaml
            python3Packages.yamlfix
          ];
          shellHook = ''
            exec ${pkgs.fish}/bin/fish
          '';
        };
      }
    );
}

J'ai préféré passé par nix parce que nix develop et pouf j'ai un shell avec un tous les outils nécessaires sans avoir à créer un AUR pour Arch (I use Arch, btw) ou configurer docker pour rendre accessible le projet au containeur contenant les outils.

Enfin bref, normalement maintenant tu dois avoir accès à openroad :

$ openroad 
OpenROAD GITDIR-NOTFOUND 
Features included (+) or not (-): +GPU +GUI +Python
This program is licensed under the BSD-3 license. See the LICENSE file for details.
Components of this program may be licensed under more restrictive licenses which must be honored.
openroad>

Installation de Openroad Flow

Maintenant, on récupère le dépôt du flot :

$ git clone https://github.com/The-OpenROAD-Project/OpenROAD-flow-scripts.git openroad-flow-scripts

Le design : un processeur PicoRV32

Cette fois-ci, plutôt que de faire un Adder, on va faire un processeur RISC-V, le PicoRV32.

PicoRV32 is a CPU core that implements the RISC-V RV32IMC Instruction Set. It can be configured as RV32E, RV32I, RV32IC, RV32IM, or RV32IMC core, and optionally contains a built-in interrupt controller.

$ git clone https://github.com/YosysHQ/picorv32.git picorv32

Configuration du flot

Normalement, on est censé mettre son design dans openroad-flow-scripts/flow/designs/src/mondesign/ et la configuration dans openroad-flow-scripts/flow/designs/<techno>/mondesign/, puis faire un coup de cd openroad-flow-scripts/flow/; make DESIGN_CONFIG=designs/<techno>/mondesign/config.mk pour faire des chocapics.

Mais je trouve ça assez bof de bosser dans le dépôt git d'un autre projet. Du coup on va foutre notre bazar ailleurs

Création du design

On va pas s'embêter et on crée juste l'arborescence attendue par le flot et on symlink les sources du processeur.

$ mkdir -p designs/src/picorv32
$ ln -s ../../../picorv32/picorv32.v designs/src/picorv32/

Configuration pour implémenter le design avec la techno ASAP7

ASAP7 est une bibliothèque de cellules standard opensource pour la technologie de fabrication de circuits intégrés en 7 nm.

Création de la configuration du design:

$ mkdir -p designs/asap7/picorv32
$ nvim designs/asap7/picorv32/config.mk
$ nvim designs/asap7/picorv32/constraint.sdc
Config.mk

La configuration du flot se fait par des variables d'environnement défini dans un Makefile.

RTFM pour la liste des variables disponibles.

# Nom du design
export DESIGN_NAME = picorv32

# Nom de la plateforme technologique de destination
export PLATFORM    = asap7

# Fichiers sources
export VERILOG_FILES = $(DESIGN_HOME)/src/$(DESIGN_NICKNAME)/$(DESIGN_NAME).v

# Fichier de contraintes temporelles
export SDC_FILE      = $(DESIGN_HOME)/$(PLATFORM)/$(DESIGN_NICKNAME)/constraint.sdc

# Densité du circuit. (100 = pas d'espace libre)
# Réduire la valeur pour simplifier le placement et le routage.
# Augmenter la valeur pour réduire la taille du circuit.
export CORE_UTILIZATION       = 70

# Forme du circuit. 1 pour carré
export CORE_ASPECT_RATIO      = 1

# Taille des marges
export CORE_MARGIN            = 5

# Compacité du placement (1.0 un seul blob de cellules)
# Réduire la valeur pour disperser les cellules et améliorer le routage
# Augmenter la valeur pour regrouper les cellules et avoir de meilleures performances (In'ch Allah).
export PLACE_DENSITY          = 0.7

# Configuration du CPU
# RTFM https://github.com/YosysHQ/picorv32?tab=readme-ov-file#verilog-module-parameters
export VERILOG_TOP_PARAMS = \
    BARREL_SHIFTER 1 \
    COMPRESSED_ISA 1 \
    ENABLE_MUL 1 \
    ENABLE_DIV 1 \
  ENABLE_IRQ 1
Constraint.sdc

On crée un fichier de contraintes temporelles afin de s'assurer que le design respecte les contraintes de temporelles (si si, je vous jure). Aka, si je donne une horloge de 1GHz à mon processeur, est-ce que tous les signaux internes du processeur arrivent à destination à temps ?

current_design riscv_top

set clk_name clk
set clk_port_name clk
set clk_period 1000
set clk_io_pct 0.125

set clk_port [get_ports $clk_port_name]

create_clock -name $clk_name -period $clk_period $clk_port

set non_clock_inputs [all_inputs -no_clocks]
set_input_delay [expr $clk_period * $clk_io_pct] -clock $clk_name $non_clock_inputs
set_output_delay [expr $clk_period * $clk_io_pct] -clock $clk_name [all_outputs]

Bref

Normalement, là, votre dossier ressemble à ça :

$ tree
├── designs
│   ├── asap7
│   │   └── picorv32
│   │       ├── config.mk
│   │       └── constraint.sdc
│   └── src
│       └── picorv32
│           └── picorv32.v -> ../../../picorv32/picorv32.v
├── openroad-flow-scripts
└── picorv32

Exécution du flot

$ export DESIGN_HOME=$PWD/designs
$ export WORK_HOME=$PWD/work
$ make -C openroad-flow-scripts/flow DESIGN_CONFIG=$DESIGN_HOME/asap7/picorv32/config.mk

Maintenant vous pouvez allez vous faire un café. Vous avez probablement le temps de passer au torréfacteur prendre du café vert, rentrer chez vous, le torréfier au four, le moudre, puis préparer un espresso pendant que le flot s'exécute.

Dans le dossier work, vous devriez voir les résultats de l'exécution du flot, notamment :

  • work/logs/asap7/picorv32/base/ : les journaux de l'exécution du flot
  • work/reports/asap7/picorv32/base/ : les rapports sur notre design
  • work/results/asap7/picorv32/base/ : les résultats de l'exécution du flot

Synthèse logique

Nous avons un beau bébé de presque 19k portes logiques et d'une surface combinée de 2225 chaipasquoi² (μm² ?)

=== picorv32 ===
Number of wires:              18804
Number of wire bits:          19186
Number of public wires:         282
Number of public wire bits:     664
Number of ports:                 27
Number of port bits:            409
Number of memories:               0
Number of memory bits:            0
Number of processes:              0
Number of cells:              18718
  AND2x2_ASAP7_75t_R            489
  AND3x1_ASAP7_75t_R            668
  AND4x1_ASAP7_75t_R            172
  AND5x1_ASAP7_75t_R             56
  AO211x2_ASAP7_75t_R             9
  AO21x1_ASAP7_75t_R           1767
  AO221x1_ASAP7_75t_R           211
  AO222x2_ASAP7_75t_R            32
  AO22x1_ASAP7_75t_R             91
  AO31x2_ASAP7_75t_R              6
  AO32x1_ASAP7_75t_R            163
  AO33x2_ASAP7_75t_R              2
  AOI211x1_ASAP7_75t_R           45
  AOI21x1_ASAP7_75t_R           187
  AOI221x1_ASAP7_75t_R           12
  AOI22x1_ASAP7_75t_R            13
  BUFx2_ASAP7_75t_R            1706
  BUFx3_ASAP7_75t_R               4
  DFFHQNx1_ASAP7_75t_R         2382
  FAx1_ASAP7_75t_R               39
  HAxp5_ASAP7_75t_R             327
  INVx1_ASAP7_75t_R            1669
  NAND2x1_ASAP7_75t_R          2107
  NAND3x1_ASAP7_75t_R            17
  NOR2x1_ASAP7_75t_R            436
  NOR3x1_ASAP7_75t_R              9
  OA211x2_ASAP7_75t_R          1668
  OA21x2_ASAP7_75t_R           1990
  OA222x2_ASAP7_75t_R            75
  OA22x2_ASAP7_75t_R             48
  OA31x2_ASAP7_75t_R             19
  OA33x2_ASAP7_75t_R              5
  OAI21x1_ASAP7_75t_R           292
  OAI22x1_ASAP7_75t_R           119
  OR2x2_ASAP7_75t_R             249
  OR3x1_ASAP7_75t_R            1058
  OR4x1_ASAP7_75t_R             135
  OR5x1_ASAP7_75t_R              52
  TIELOx1_ASAP7_75t_R             1
  XNOR2x2_ASAP7_75t_R           190
  XOR2x2_ASAP7_75t_R            198

Chip area for module '\picorv32': 2225.345400

Floorplan

Le floorplan de notre design. On peut voir la powergrid au centre du die.

Floor plan de notre design. Au centre, on peut voir la powergrid

Placement

Les portes logiques placés sur le die. On peut voir que le placement des IO en bordure du die est un peu caca. Cela mériterai de faire un script qui place manuellement les IO.

Placement des portes logiques

Arbre d'horloge

L'arbre d'horloge de notre design. L'arbre d'horloge est responsable de la distribution du signal d'horloge à toutes les portes logiques afin d'assurer la bonne synchronisation de notre circuit.

Arbre d'horloge de notre design

Routage

Le routage de notre design. Le routage est responsable de la connexion des portes logiques entre elles et de la distribution des signaux à travers le circuit.

Routage de notre design

Résultat

Bon ben voila, notre picorv32, prêt à être envoyé chez un fondeur pour fabrication :

Résultat de notre design

Conclusion

OpenRoad, c'est cool, ça permet d'avoir rapidement et facilement un truc qui fonctionne. À partir de là, y'a plus qu'à itérer pour améliorer la config et optimiser le design.

  • # qq infos supplémentaires pour les gens intéressés

    Posté par  . Évalué à 3 (+2/-0).

    • ce 7nm ne peut pas être produit, la bibliothèque de cellules standards utilise des règles de dessin approximatives, et des modèles SPICE (de transistor) fictifs (certainement réalistes quand aux performances électriques possibles); le tout à des fins éducatives
    • il existe quelque openPDKs qui permettent de faire des puces manufacturables avec une tool chain et des "tech files" (fichiers de config avec les spécifications de la technologie) open source: sky130 (Skywater 0.13um 1.8V), gf180mcu (GlobalFoundries 0.18um mais avec des transistors de 3.3V), IHP ihp-sg13g2 (IHP, un institut de recherche allemand, à la frontière avec la Pologne, 0.13um 1.5V avec en prime des transistors bipolaires optimisés pour des applications RF)
    • efabless était une boite qui avait optimisé le coup de production de prototype en boitier QFN, et le coup de production en petit et moyen volume, originellement pour sky130, avec plus de 10 tape-out open source financés par Google si les contributions étaient publiées en open source; efabless a fermé début Mars
    • tinytapeout permet d'implémenter son circuit en commun sur des puces; maintenant actif for sky130 et ihp-sg13g2 (https://tinytapeout.com/chips/ttihp0p2/)
    • depuis le shutdown d'efabless, https://chipfoundry.io/ offre le même service pour sky130 (eFabless a beaucoup publié d'open source) mais en plus cher (gros point faible: les instances mémoires RAM qui sont proprio et maintenant assez cher (prix/projet: 2500$ https://chipfoundry.io/commercial-sram)
    • à l'heure actuelle IHP fournit des puces avec des conditions un peu pourries (https://tinytapeout.com/ihp-loan-terms , ceci est un google doc): en gros il y a des restrictions de prêt à des tiers, et il faut être en mesure de rendre toutes les puces après 2 ans, le tout que pour des européens. A priori, l'IHP va revoir ça prochainement.
    • ceci peut être un loisir chronophage, et très coûteux à concrétiser; ceci dit, c'est chouette sur le principe de pouvoir faire toute la partie design de circuit avec une tool chain open source et de pouvoir démonter tous les rouages pour comprendre comme ça fonctionne (si on a le temps) + c'est très abordable pour des universités et projets éducatifs ou de recherche
    • en cas de circuit purement logique, il vaut mieux considérer des FPGAs
  • # Compliqué les nouveaux patrons de tapisserie

    Posté par  (site web personnel) . Évalué à 3 (+0/-0).

    Je plains Ysabeau quand je vois les nouveaux patrons de tapisserie qui vous proposez.

Envoyer un commentaire

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.