Commit ·
6b6699d
0
Parent(s):
Initial commit of AgentIC
Browse files- .gitignore +41 -0
- AZURE_STUDENT_GUIDE.md +88 -0
- CLOUD_DEPLOY.md +77 -0
- COOL_MODE.md +36 -0
- README.md +67 -0
- app.py +128 -0
- main.py +11 -0
- requirements.txt +7 -0
- scripts/verify_design.sh +91 -0
- src/agentic/__init__.py +4 -0
- src/agentic/agents/__init__.py +0 -0
- src/agentic/agents/designer.py +14 -0
- src/agentic/agents/testbench_designer.py +15 -0
- src/agentic/cli.py +232 -0
- src/agentic/config.py +16 -0
- src/agentic/tools/__init__.py +0 -0
- src/agentic/tools/vlsi_tools.py +133 -0
.gitignore
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Python
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.pyc
|
| 4 |
+
*.pyo
|
| 5 |
+
*.pyd
|
| 6 |
+
.Python
|
| 7 |
+
env/
|
| 8 |
+
venv/
|
| 9 |
+
.env
|
| 10 |
+
.venv
|
| 11 |
+
build/
|
| 12 |
+
develop-eggs/
|
| 13 |
+
dist/
|
| 14 |
+
downloads/
|
| 15 |
+
eggs/
|
| 16 |
+
.eggs/
|
| 17 |
+
lib/
|
| 18 |
+
lib64/
|
| 19 |
+
parts/
|
| 20 |
+
sdist/
|
| 21 |
+
var/
|
| 22 |
+
wheels/
|
| 23 |
+
*.egg-info/
|
| 24 |
+
.installed.cfg
|
| 25 |
+
*.egg
|
| 26 |
+
|
| 27 |
+
# AgentIC Specific
|
| 28 |
+
# Ignore massive run logs or temporary build artifacts if they end up here
|
| 29 |
+
runs/
|
| 30 |
+
*.log
|
| 31 |
+
*.vcd
|
| 32 |
+
work/
|
| 33 |
+
transcript
|
| 34 |
+
|
| 35 |
+
# System
|
| 36 |
+
.DS_Store
|
| 37 |
+
Thumbs.db
|
| 38 |
+
|
| 39 |
+
# OpenLane outputs (if copied here)
|
| 40 |
+
# Uncomment the line below if you don't want to version control large GDS files
|
| 41 |
+
# *.gds
|
AZURE_STUDENT_GUIDE.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ☁️ Azure Student Developer Pack Guide for AgentIC
|
| 2 |
+
|
| 3 |
+
Since your local PC is overheating, moving to Azure is the perfect solution. With the **Microsoft Azure Student Pack**, you get **$100 credit** and free access to specific services.
|
| 4 |
+
|
| 5 |
+
This guide will help you create a **Virtual Machine (VM)** to run OpenLane and AgentIC without burning your laptop.
|
| 6 |
+
|
| 7 |
+
## 1. Create the Virtual Machine (VM)
|
| 8 |
+
The "hectic" part is the OpenLane build process (compiling 30,000 transistors!).
|
| 9 |
+
|
| 10 |
+
1. Log in to the [Azure Portal](https://portal.azure.com).
|
| 11 |
+
2. Click **"Create a resource"** > **"Virtual Machine"**.
|
| 12 |
+
3. **Basics Tab**:
|
| 13 |
+
* **Subscription**: Azure for Students.
|
| 14 |
+
* **Resource Group**: Create new (e.g., `rg-agentic`).
|
| 15 |
+
* **Virtual Machine Name**: `vm-agentic`.
|
| 16 |
+
* **Region**: Pick one close to you (e.g., East US).
|
| 17 |
+
* **Image**: **Ubuntu Server 22.04 LTS - x64 Gen2**.
|
| 18 |
+
* **Size**: **Standard D4s v3** (4 vCPUs, 16 GiB memory).
|
| 19 |
+
* *Note:* This costs about ~$0.18/hour. Since you have $100 credits, you can run this for ~500 hours.
|
| 20 |
+
* *Important:* Remember to **STOP** the VM when you aren't using it to save credits!
|
| 21 |
+
4. **Administrator Account**:
|
| 22 |
+
* **Authentication type**: SSH public key.
|
| 23 |
+
* **Username**: `azureuser`.
|
| 24 |
+
* **Key source**: Generate new key pair.
|
| 25 |
+
5. **Review + create** > **Create**.
|
| 26 |
+
* Download the private key (`.pem` file) when prompted. Keep it safe!
|
| 27 |
+
|
| 28 |
+
## 2. Connect to the Cloud
|
| 29 |
+
1. Open your local terminal (Git Bash or WSL).
|
| 30 |
+
2. Move the key to a safe place and secure it:
|
| 31 |
+
```bash
|
| 32 |
+
mv ~/Downloads/vm-agentic_key.pem ~/.ssh/
|
| 33 |
+
chmod 400 ~/.ssh/vm-agentic_key.pem
|
| 34 |
+
```
|
| 35 |
+
3. Connect (replace `YOUR_VM_IP` with the Public IP from Azure Portal):
|
| 36 |
+
```bash
|
| 37 |
+
ssh -i ~/.ssh/vm-agentic_key.pem azureuser@YOUR_VM_IP
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
## 3. Install the Environment (One-Time Setup)
|
| 41 |
+
Copy and paste this block into your Azure SSH terminal to install everything:
|
| 42 |
+
|
| 43 |
+
```bash
|
| 44 |
+
# Update and Install Docker
|
| 45 |
+
sudo apt-get update
|
| 46 |
+
sudo apt-get install -y docker.io python3-pip python3-venv git make
|
| 47 |
+
sudo usermod -aG docker $USER
|
| 48 |
+
newgrp docker
|
| 49 |
+
|
| 50 |
+
# Setup OpenLane
|
| 51 |
+
git clone https://github.com/The-OpenROAD-Project/OpenLane.git ~/OpenLane
|
| 52 |
+
cd ~/OpenLane
|
| 53 |
+
# This download is heavy (~2GB), but it runs on Azure's fast internet!
|
| 54 |
+
make pull-openlane
|
| 55 |
+
|
| 56 |
+
# Get your AgentIC code
|
| 57 |
+
# (You can clone your repo, or we create a fresh one)
|
| 58 |
+
mkdir -p ~/AgentIC
|
| 59 |
+
```
|
| 60 |
+
|
| 61 |
+
## 4. Solving the "Thinking" Heat (The LLM)
|
| 62 |
+
Running Ollama (DeepSeek) locally is what heats up your GPU. On an Azure CPU VM, it will be slow.
|
| 63 |
+
**Recommendation:** Use the **DeepSeek API** instead. It costs pennies and offloads the "brain" work to DeepSeek's servers.
|
| 64 |
+
|
| 65 |
+
1. Get an API Key from [platform.deepseek.com](https://platform.deepseek.com).
|
| 66 |
+
2. On the Azure VM, export it:
|
| 67 |
+
```bash
|
| 68 |
+
export OPENAI_API_KEY="sk-..." # Your DeepSeek Key
|
| 69 |
+
export OPENAI_API_BASE="https://api.deepseek.com"
|
| 70 |
+
export LLM_MODEL="deepseek-chat"
|
| 71 |
+
```
|
| 72 |
+
|
| 73 |
+
## 5. Running the Flow
|
| 74 |
+
Now, your laptop stays cool while Azure does the work.
|
| 75 |
+
|
| 76 |
+
```bash
|
| 77 |
+
# On Azure VM
|
| 78 |
+
cd ~/AgentIC
|
| 79 |
+
python3 main.py build --name cloud_chip --desc "An 8-bit counter"
|
| 80 |
+
```
|
| 81 |
+
|
| 82 |
+
## 6. Retrieving the Result
|
| 83 |
+
When finished, download the GDS file to your laptop to view it:
|
| 84 |
+
|
| 85 |
+
```bash
|
| 86 |
+
# On Local Laptop
|
| 87 |
+
scp -i ~/.ssh/vm-agentic_key.pem azureuser@YOUR_VM_IP:~/AgentIC/cloud_chip.gds ./
|
| 88 |
+
```
|
CLOUD_DEPLOY.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Cloud Migration Guide for AgentIC + OpenLane
|
| 2 |
+
|
| 3 |
+
This guide explains how to move your local AI-to-GDSII flow to a cloud provider (AWS, GCP, Azure, Lambda Labs, or RunPod).
|
| 4 |
+
|
| 5 |
+
## 1. Hardware Requirements
|
| 6 |
+
OpenLane and Local LLMs are resource-intensive. Do not use a "Free Tier" (t2.micro) instance.
|
| 7 |
+
|
| 8 |
+
* **CPU**: 4 vCPUs minimum (8 recommended for Place & Route).
|
| 9 |
+
* **RAM**: 16 GB minimum (32 GB recommended).
|
| 10 |
+
* **Storage**: 50 GB SSD minimum (Docker images + PDKs take ~30GB).
|
| 11 |
+
* **GPU**: NVIDIA T4 (16GB VRAM) or better recommended if running Ollama locally.
|
| 12 |
+
|
| 13 |
+
## 2. Setup Script (Ubuntu 22.04 / 24.04)
|
| 14 |
+
Run these commands on your new cloud instance to replicate your environment.
|
| 15 |
+
|
| 16 |
+
### A. Install System Dependencies
|
| 17 |
+
```bash
|
| 18 |
+
sudo apt-get update && sudo apt-get install -y \
|
| 19 |
+
docker.io \
|
| 20 |
+
python3-pip \
|
| 21 |
+
python3-venv \
|
| 22 |
+
git \
|
| 23 |
+
make \
|
| 24 |
+
curl \
|
| 25 |
+
iverilog
|
| 26 |
+
|
| 27 |
+
# Add user to docker group (avoids sudo for docker)
|
| 28 |
+
sudo usermod -aG docker $USER
|
| 29 |
+
newgrp docker
|
| 30 |
+
```
|
| 31 |
+
|
| 32 |
+
### B. Install Ollama (for DeepSeek)
|
| 33 |
+
If you have a GPU, install the Nvidia Container Toolkit first. If CPU-only, just run:
|
| 34 |
+
```bash
|
| 35 |
+
curl -fsSL https://ollama.com/install.sh | sh
|
| 36 |
+
|
| 37 |
+
# Pull the model
|
| 38 |
+
ollama pull deepseek-r1
|
| 39 |
+
```
|
| 40 |
+
|
| 41 |
+
### C. Clone & Setup Your Workspace
|
| 42 |
+
```bash
|
| 43 |
+
# Clone OpenLane (Infrastructure)
|
| 44 |
+
git clone https://github.com/The-OpenROAD-Project/OpenLane.git ~/OpenLane
|
| 45 |
+
cd ~/OpenLane
|
| 46 |
+
make pull-openlane # Downloads the heavy Docker images
|
| 47 |
+
|
| 48 |
+
# Clone AgentIC (Your Logic)
|
| 49 |
+
# (Assuming you push your local code to a git repo first)
|
| 50 |
+
git clone <YOUR_GITHUB_REPO_URL> ~/AgentIC
|
| 51 |
+
|
| 52 |
+
# Setup Python Env
|
| 53 |
+
cd ~/AgentIC
|
| 54 |
+
python3 -m venv agentic_env
|
| 55 |
+
source agentic_env/bin/activate
|
| 56 |
+
pip install -r requirements.txt
|
| 57 |
+
```
|
| 58 |
+
|
| 59 |
+
## 3. Remote Access
|
| 60 |
+
To view your designs (GDSII files) or access the terminal easily, use VS Code Remote - SSH.
|
| 61 |
+
|
| 62 |
+
1. In local VS Code: Install "Remote - SSH" extension.
|
| 63 |
+
2. Connect to `ssh user@your-cloud-ip`.
|
| 64 |
+
3. Open the folder `/home/user/AgentIC`.
|
| 65 |
+
|
| 66 |
+
## 4. Modified Flow for Cloud (Headless)
|
| 67 |
+
Since you won't have a GUI window for `klayout` or unnecessary graphics:
|
| 68 |
+
|
| 69 |
+
1. Run the build command normally:
|
| 70 |
+
```bash
|
| 71 |
+
python main.py build --name cloud_adder --desc "8-bit adder"
|
| 72 |
+
```
|
| 73 |
+
2. **Viewing Results**: Do not try to open KLayout on the server. Instead, use the `scp` command to copy the final GDS file to your local machine:
|
| 74 |
+
```bash
|
| 75 |
+
# Run this on your LOCAL machine
|
| 76 |
+
scp user@your-cloud-ip:~/OpenLane/designs/cloud_adder/runs/agentrun/results/final/gds/cloud_adder.gds ./
|
| 77 |
+
```
|
COOL_MODE.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🔥 Cooling Down: How to Run Locally Safely
|
| 2 |
+
|
| 3 |
+
**No, your computer will not "blast".**
|
| 4 |
+
Modern CPUs and GPUs have safety sensors. If they get too hot (usually 100°C+), they will automatically slow down ("thermal throttle") or shut off the computer to prevent damage.
|
| 5 |
+
|
| 6 |
+
However, running a 5GB model like `deepseek-r1` pins your processor to 100% usage, which generates max heat.
|
| 7 |
+
|
| 8 |
+
## Solution: Use a "Lighter" Brain
|
| 9 |
+
Since you need to run strictly locally ($0 cost), the best way to reduce heat is to use a **smaller model**.
|
| 10 |
+
|
| 11 |
+
A 1.5B or 3B model requires **much less math** per second than a 7B/8B model. It will run faster and generate less heat.
|
| 12 |
+
|
| 13 |
+
### Recommended Models for Coding (Low Heat)
|
| 14 |
+
1. **DeepSeek Coder 1.3B** (Tiny, very fast, decent at Verilog)
|
| 15 |
+
2. **Qwen 2.5 Coder 3B** (Excellent balance of smarts and speed)
|
| 16 |
+
|
| 17 |
+
### How to Switch
|
| 18 |
+
1. **Open Terminal and Pull a Tiny Model:**
|
| 19 |
+
```bash
|
| 20 |
+
# Try the 1.3 Billion parameter version (approx 700MB - 1GB)
|
| 21 |
+
ollama pull deepseek-coder:1.3b
|
| 22 |
+
|
| 23 |
+
# OR try Qwen 3B (approx 2GB) - Better quality
|
| 24 |
+
ollama pull qwen2.5-coder:3b
|
| 25 |
+
```
|
| 26 |
+
|
| 27 |
+
2. **Update AgentIC to use it:**
|
| 28 |
+
Open `src/agentic/config.py` and change `LLM_MODEL`:
|
| 29 |
+
```python
|
| 30 |
+
# LLM_MODEL = "ollama/deepseek-r1" <-- Comment this out (Heat: High)
|
| 31 |
+
LLM_MODEL = "ollama/deepseek-coder:1.3b" # <-- Use this (Heat: Low)
|
| 32 |
+
```
|
| 33 |
+
|
| 34 |
+
3. **Physical Tips:**
|
| 35 |
+
* Prop up the back of your laptop for airflow.
|
| 36 |
+
* Use a cooling pad if you have one.
|
README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# AgentIC Workflow Guide
|
| 2 |
+
|
| 3 |
+
This document outlines the automated chip design workflow using **AgentIC** and **OpenLane**.
|
| 4 |
+
|
| 5 |
+
## Logic Flow
|
| 6 |
+
|
| 7 |
+
The system transforms natural language descriptions into physical GDSII manufacturing files through a multi-step agentic pipeline.
|
| 8 |
+
|
| 9 |
+
```mermaid
|
| 10 |
+
graph TD
|
| 11 |
+
User[User Command] -->|main.py build| A[AgentIC]
|
| 12 |
+
A -->|Step 1: Generated RTL| B(VLSI Design Agent)
|
| 13 |
+
B -->|vicky_adder.v| C{Syntax Check}
|
| 14 |
+
C -->|Pass| D(Verification Agent)
|
| 15 |
+
C -->|Fail| Z[Error / Retry]
|
| 16 |
+
D -->|vicky_adder_tb.v| E{Simulation}
|
| 17 |
+
E -->|Pass| F[OpenLane Integration]
|
| 18 |
+
E -->|Fail| Z
|
| 19 |
+
|
| 20 |
+
subgraph OpenLane Infrastructure
|
| 21 |
+
F -->|Docker Mount| G[OpenLane Flow]
|
| 22 |
+
G -->|flow.tcl| H[Synthesis yosys]
|
| 23 |
+
H --> I[Floorplan]
|
| 24 |
+
I --> J[Placement]
|
| 25 |
+
J --> K[Routing]
|
| 26 |
+
K --> L[GDSII Layout]
|
| 27 |
+
end
|
| 28 |
+
|
| 29 |
+
L -->|Output| M[Final GDSII & Reports]
|
| 30 |
+
```
|
| 31 |
+
|
| 32 |
+
## Directory Structure & Important Files
|
| 33 |
+
|
| 34 |
+
The workspace is consolidated into two main components:
|
| 35 |
+
|
| 36 |
+
### 1. AgentIC ( The "Brain" )
|
| 37 |
+
Controls the process.
|
| 38 |
+
- **`main.py`**: The entry point.
|
| 39 |
+
- **`src/agentic/`**: The core Python package.
|
| 40 |
+
- **`agents/`**: AI engineer definitions.
|
| 41 |
+
- **`tools/`**: Interfaces to VLSI tools.
|
| 42 |
+
- **`config.py`**: Configuration settings (paths, LLMs).
|
| 43 |
+
- **`scripts/verify_design.sh`**: A helper script for verification.
|
| 44 |
+
|
| 45 |
+
### 2. OpenLane ( The "Muscle" )
|
| 46 |
+
The execution engine.
|
| 47 |
+
- **`designs/simple_counter`**: **CRITICAL**. Used as a configuration template for all new AI designs.
|
| 48 |
+
- **`designs/<your_design>`**: Where your new chips will be created.
|
| 49 |
+
- **`flow.tcl`**: The main script run by the Docker container.
|
| 50 |
+
|
| 51 |
+
## How to Run
|
| 52 |
+
|
| 53 |
+
### 1. Build a new chip
|
| 54 |
+
```bash
|
| 55 |
+
cd ~/AgentIC
|
| 56 |
+
python main.py build --name vicky_adder --desc "A 4-bit adder with carry out"
|
| 57 |
+
```
|
| 58 |
+
|
| 59 |
+
### 2. Verify an existing chip
|
| 60 |
+
```bash
|
| 61 |
+
cd ~/AgentIC
|
| 62 |
+
python main.py verify vicky_adder
|
| 63 |
+
```
|
| 64 |
+
|
| 65 |
+
## Maintenance
|
| 66 |
+
- **Do not delete** `OpenLane/designs/simple_counter` - it is needed for config generation.
|
| 67 |
+
- **Do not delete** the `OpenLane` root files - they are mounted into the Docker container.
|
app.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import os
|
| 3 |
+
import pandas as pd
|
| 4 |
+
import subprocess
|
| 5 |
+
import glob
|
| 6 |
+
|
| 7 |
+
# Configuration
|
| 8 |
+
OPENLANE_ROOT = os.environ.get("OPENLANE_ROOT", os.path.expanduser("~/OpenLane"))
|
| 9 |
+
DESIGNS_DIR = os.path.join(OPENLANE_ROOT, "designs")
|
| 10 |
+
|
| 11 |
+
st.set_page_config(page_title="AgentIC Dashboard", page_icon="チップ", layout="wide")
|
| 12 |
+
|
| 13 |
+
st.title("🤖 AgentIC: AI Chip Design Studio")
|
| 14 |
+
st.markdown("Monitor your AI-generated silicon designs and metrics.")
|
| 15 |
+
|
| 16 |
+
# --- Sidebar: Project Selection ---
|
| 17 |
+
if not os.path.exists(DESIGNS_DIR):
|
| 18 |
+
st.error(f"OpenLane Design Directory not found at: {DESIGNS_DIR}")
|
| 19 |
+
st.stop()
|
| 20 |
+
|
| 21 |
+
designs = [d for d in os.listdir(DESIGNS_DIR) if os.path.isdir(os.path.join(DESIGNS_DIR, d))]
|
| 22 |
+
# Filter out standard openlane designs if needed, keeping it simple for now
|
| 23 |
+
selected_design = st.sidebar.selectbox("Select Design", designs)
|
| 24 |
+
|
| 25 |
+
# --- Main Content ---
|
| 26 |
+
|
| 27 |
+
if selected_design:
|
| 28 |
+
design_path = os.path.join(DESIGNS_DIR, selected_design)
|
| 29 |
+
|
| 30 |
+
# 1. Source Code Viewer
|
| 31 |
+
st.header(f"📦 Design: {selected_design}")
|
| 32 |
+
|
| 33 |
+
verilog_path = os.path.join(design_path, "src", f"{selected_design}.v")
|
| 34 |
+
if os.path.exists(verilog_path):
|
| 35 |
+
with open(verilog_path, "r") as f:
|
| 36 |
+
code = f.read()
|
| 37 |
+
with st.expander("Show Verilog Source", expanded=False):
|
| 38 |
+
st.code(code, language="verilog")
|
| 39 |
+
else:
|
| 40 |
+
st.warning("No Verilog source found.")
|
| 41 |
+
|
| 42 |
+
# 2. Build Status & Metrics
|
| 43 |
+
st.subheader("🏭 Fabrication Status")
|
| 44 |
+
|
| 45 |
+
# Check for GDS
|
| 46 |
+
# Note: AgentIC uses tag "agentrun", but users might use others.
|
| 47 |
+
# We look for the most recent run or 'agentrun'
|
| 48 |
+
runs_dir = os.path.join(design_path, "runs")
|
| 49 |
+
gds_path = None
|
| 50 |
+
report_path = None
|
| 51 |
+
|
| 52 |
+
if os.path.exists(runs_dir):
|
| 53 |
+
# Prefer 'agentrun' if it exists, else latest
|
| 54 |
+
if os.path.exists(os.path.join(runs_dir, "agentrun")):
|
| 55 |
+
run_name = "agentrun"
|
| 56 |
+
else:
|
| 57 |
+
# find latest run
|
| 58 |
+
all_runs = sorted(glob.glob(os.path.join(runs_dir, "*")), key=os.path.getmtime, reverse=True)
|
| 59 |
+
run_name = os.path.basename(all_runs[0]) if all_runs else None
|
| 60 |
+
|
| 61 |
+
if run_name:
|
| 62 |
+
st.info(f"Viewing Run: **{run_name}**")
|
| 63 |
+
|
| 64 |
+
# GDS Path
|
| 65 |
+
possible_gds = os.path.join(runs_dir, run_name, "results", "final", "gds", f"{selected_design}.gds")
|
| 66 |
+
if os.path.exists(possible_gds):
|
| 67 |
+
gds_path = possible_gds
|
| 68 |
+
st.success("✅ GDSII Layout Generated")
|
| 69 |
+
|
| 70 |
+
# Download Button
|
| 71 |
+
with open(gds_path, "rb") as f:
|
| 72 |
+
st.download_button(
|
| 73 |
+
label="⬇️ Download GDSII File",
|
| 74 |
+
data=f,
|
| 75 |
+
file_name=f"{selected_design}.gds",
|
| 76 |
+
mime="application/octet-stream"
|
| 77 |
+
)
|
| 78 |
+
else:
|
| 79 |
+
st.warning("⚠️ No GDSII file found in this run.")
|
| 80 |
+
|
| 81 |
+
# Metrics (CSV)
|
| 82 |
+
# OpenLane typically stores metrics in reports/metrics.csv
|
| 83 |
+
possible_csv = os.path.join(runs_dir, run_name, "reports", "metrics.csv")
|
| 84 |
+
if os.path.exists(possible_csv):
|
| 85 |
+
try:
|
| 86 |
+
df = pd.read_csv(possible_csv)
|
| 87 |
+
# Transpose for better reading if it's a single row
|
| 88 |
+
st.dataframe(df.T)
|
| 89 |
+
except Exception as e:
|
| 90 |
+
st.error(f"Could not read metrics CSV: {e}")
|
| 91 |
+
else:
|
| 92 |
+
st.info("No metrics.csv report found.")
|
| 93 |
+
else:
|
| 94 |
+
st.info("No runs found for this design.")
|
| 95 |
+
else:
|
| 96 |
+
st.info("No runs directory found.")
|
| 97 |
+
|
| 98 |
+
# --- New Design Creator ---
|
| 99 |
+
st.markdown("---")
|
| 100 |
+
st.subheader("✨ Create New Design")
|
| 101 |
+
|
| 102 |
+
with st.form("new_design_form"):
|
| 103 |
+
new_name = st.text_input("Design Name (no spaces)", "my_new_chip")
|
| 104 |
+
new_desc = st.text_area("Description", "A 8-bit shift register with enable signal.")
|
| 105 |
+
submitted = st.form_submit_button("🚀 Launch AI Designer")
|
| 106 |
+
|
| 107 |
+
if submitted:
|
| 108 |
+
if " " in new_name:
|
| 109 |
+
st.error("Design name cannot contain spaces.")
|
| 110 |
+
else:
|
| 111 |
+
cmd = ["python3", "main.py", "build", "--name", new_name, "--desc", new_desc]
|
| 112 |
+
|
| 113 |
+
with st.spinner("AI is thinking and building... (This generally takes 5-10 mins)"):
|
| 114 |
+
# We run this from the AgentIC root
|
| 115 |
+
process = subprocess.run(
|
| 116 |
+
cmd,
|
| 117 |
+
cwd=os.path.dirname(os.path.abspath(__file__)),
|
| 118 |
+
capture_output=True,
|
| 119 |
+
text=True
|
| 120 |
+
)
|
| 121 |
+
|
| 122 |
+
if process.returncode == 0:
|
| 123 |
+
st.success(f"Design '{new_name}' created successfully!")
|
| 124 |
+
st.text_area("Build Output", process.stdout, height=200)
|
| 125 |
+
st.rerun()
|
| 126 |
+
else:
|
| 127 |
+
st.error("Build failed.")
|
| 128 |
+
st.text_area("Error Log", process.stderr, height=200)
|
main.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
import sys
|
| 3 |
+
import os
|
| 4 |
+
|
| 5 |
+
# Add src to path so we can import the package
|
| 6 |
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src"))
|
| 7 |
+
|
| 8 |
+
from agentic.cli import app
|
| 9 |
+
|
| 10 |
+
if __name__ == "__main__":
|
| 11 |
+
app()
|
requirements.txt
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
crewai
|
| 2 |
+
crewai-tools
|
| 3 |
+
langchain_openai
|
| 4 |
+
typer
|
| 5 |
+
rich
|
| 6 |
+
streamlit
|
| 7 |
+
pandas
|
scripts/verify_design.sh
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
|
| 3 |
+
# Usage: ./verify_design.sh <design_name>
|
| 4 |
+
|
| 5 |
+
if [ -z "$1" ]; then
|
| 6 |
+
echo "Usage: ./verify_design.sh <design_name>"
|
| 7 |
+
exit 1
|
| 8 |
+
fi
|
| 9 |
+
|
| 10 |
+
DESIGN=$1
|
| 11 |
+
OPENLANE_ROOT=~/OpenLane
|
| 12 |
+
DESIGN_DIR=$OPENLANE_ROOT/designs/$DESIGN
|
| 13 |
+
|
| 14 |
+
echo "========================================"
|
| 15 |
+
echo "Verifying Design: $DESIGN"
|
| 16 |
+
echo "========================================"
|
| 17 |
+
|
| 18 |
+
# 1. Functional Verification (RTL Simulation)
|
| 19 |
+
echo "[1] Functional Verification (Icarus Verilog)"
|
| 20 |
+
if [ -f "$DESIGN_DIR/src/${DESIGN}_tb.v" ]; then
|
| 21 |
+
echo " Found Testbench: ${DESIGN}_tb.v"
|
| 22 |
+
cd $DESIGN_DIR/src
|
| 23 |
+
iverilog -o sim ${DESIGN}.v ${DESIGN}_tb.v
|
| 24 |
+
if [ $? -eq 0 ]; then
|
| 25 |
+
echo " Compilation Successful."
|
| 26 |
+
echo " Running Simulation..."
|
| 27 |
+
vvp sim > simulation.log
|
| 28 |
+
cat simulation.log
|
| 29 |
+
echo " (Check output above for expected behavior)"
|
| 30 |
+
else
|
| 31 |
+
echo " [ERROR] Compilation Failed."
|
| 32 |
+
fi
|
| 33 |
+
cd $OPENLANE_ROOT
|
| 34 |
+
else
|
| 35 |
+
echo " [WARNING] No testbench found at $DESIGN_DIR/src/${DESIGN}_tb.v"
|
| 36 |
+
echo " Please create one to run functional simulation."
|
| 37 |
+
fi
|
| 38 |
+
|
| 39 |
+
echo ""
|
| 40 |
+
echo "========================================"
|
| 41 |
+
|
| 42 |
+
# 2. Physical Verification (OpenLane Reports)
|
| 43 |
+
echo "[2] Physical Verification (Latest Run)"
|
| 44 |
+
LATEST_RUN=$(ls -td $DESIGN_DIR/runs/* | head -1)
|
| 45 |
+
|
| 46 |
+
if [ -z "$LATEST_RUN" ]; then
|
| 47 |
+
echo " [ERROR] No runs found for $DESIGN."
|
| 48 |
+
else
|
| 49 |
+
echo " Checking run: $(basename $LATEST_RUN)"
|
| 50 |
+
|
| 51 |
+
# Check DRC
|
| 52 |
+
DRC_RPT=$(find $LATEST_RUN -name "*drc.rpt" | head -1)
|
| 53 |
+
if [ -f "$DRC_RPT" ]; then
|
| 54 |
+
echo " --- DRC Report ($(basename $DRC_RPT)) ---"
|
| 55 |
+
COUNT=$(grep -c "violation" $DRC_RPT)
|
| 56 |
+
if [ "$COUNT" -eq "0" ]; then
|
| 57 |
+
# Some reports might use different format, check content
|
| 58 |
+
grep "Count: 0" $DRC_RPT > /dev/null
|
| 59 |
+
if [ $? -eq 0 ]; then
|
| 60 |
+
echo " [PASS] No DRC Violations found."
|
| 61 |
+
else
|
| 62 |
+
# Print last few lines
|
| 63 |
+
tail -n 5 $DRC_RPT
|
| 64 |
+
fi
|
| 65 |
+
else
|
| 66 |
+
echo " [FAIL] Found potential violations."
|
| 67 |
+
tail -n 5 $DRC_RPT
|
| 68 |
+
fi
|
| 69 |
+
else
|
| 70 |
+
echo " [WARNING] DRC Report not found."
|
| 71 |
+
fi
|
| 72 |
+
|
| 73 |
+
echo ""
|
| 74 |
+
|
| 75 |
+
# Check LVS
|
| 76 |
+
LVS_RPT=$(find $LATEST_RUN -name "*lvs.log" | head -1)
|
| 77 |
+
if [ -f "$LVS_RPT" ]; then
|
| 78 |
+
echo " --- LVS Report ($(basename $LVS_RPT)) ---"
|
| 79 |
+
if grep -q "Total errors = 0" $LVS_RPT; then
|
| 80 |
+
echo " [PASS] LVS Clean. Layout matches Schematic."
|
| 81 |
+
else
|
| 82 |
+
echo " [FAIL] LVS Mismatch."
|
| 83 |
+
grep "Total errors" $LVS_RPT
|
| 84 |
+
fi
|
| 85 |
+
else
|
| 86 |
+
echo " [WARNING] LVS Report not found."
|
| 87 |
+
fi
|
| 88 |
+
fi
|
| 89 |
+
|
| 90 |
+
echo "========================================"
|
| 91 |
+
echo "Verification Complete."
|
src/agentic/__init__.py
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
AgentIC - AI-Driven Chip Design Framework
|
| 3 |
+
"""
|
| 4 |
+
__version__ = "0.1.0"
|
src/agentic/agents/__init__.py
ADDED
|
File without changes
|
src/agentic/agents/designer.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# agents/designer.py
|
| 2 |
+
from crewai import Agent
|
| 3 |
+
from ..config import LLM_MODEL
|
| 4 |
+
|
| 5 |
+
def get_designer_agent():
|
| 6 |
+
return Agent(
|
| 7 |
+
role='VLSI Design Engineer',
|
| 8 |
+
goal='Create optimized Verilog for {design_input}',
|
| 9 |
+
backstory='Specialist in ECE from Lucknow University. Expert in Sky130 PDK.',
|
| 10 |
+
# IMPORTANT: Use the "ollama/" prefix so CrewAI doesn't look for OpenAI
|
| 11 |
+
llm=LLM_MODEL,
|
| 12 |
+
verbose=True,
|
| 13 |
+
allow_delegation=False
|
| 14 |
+
)
|
src/agentic/agents/testbench_designer.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# agents/testbench_designer.py
|
| 2 |
+
from crewai import Agent
|
| 3 |
+
|
| 4 |
+
def get_testbench_agent(llm):
|
| 5 |
+
"""Returns an agent specialized in writing Verilog testbenches."""
|
| 6 |
+
return Agent(
|
| 7 |
+
role='Verification Engineer',
|
| 8 |
+
goal='Create comprehensive Verilog testbenches for {design_name}',
|
| 9 |
+
backstory='''Expert in digital verification with deep knowledge of
|
| 10 |
+
Verilog simulation. Focuses on edge cases, reset behavior, and
|
| 11 |
+
timing checks. Always includes $monitor, $dumpfile, and $finish.''',
|
| 12 |
+
llm=llm,
|
| 13 |
+
verbose=True,
|
| 14 |
+
allow_delegation=False
|
| 15 |
+
)
|
src/agentic/cli.py
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
AgentIC - Natural Language to GDSII Pipeline
|
| 4 |
+
=============================================
|
| 5 |
+
Uses CrewAI + Ollama (DeepSeek) to generate chips from natural language.
|
| 6 |
+
|
| 7 |
+
Usage:
|
| 8 |
+
python main.py build --name counter --desc "8-bit counter with enable and reset"
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import os
|
| 12 |
+
import sys
|
| 13 |
+
import typer
|
| 14 |
+
from rich.console import Console
|
| 15 |
+
from rich.panel import Panel
|
| 16 |
+
from rich.progress import Progress, SpinnerColumn, TextColumn
|
| 17 |
+
from crewai import Agent, Task, Crew, LLM
|
| 18 |
+
|
| 19 |
+
# Local imports
|
| 20 |
+
from .config import OPENLANE_ROOT, LLM_MODEL, LLM_BASE_URL, LLM_API_KEY
|
| 21 |
+
from .tools.vlsi_tools import (
|
| 22 |
+
write_verilog,
|
| 23 |
+
run_syntax_check,
|
| 24 |
+
run_simulation,
|
| 25 |
+
run_openlane,
|
| 26 |
+
run_verification
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
# --- INITIALIZE ---
|
| 30 |
+
app = typer.Typer()
|
| 31 |
+
console = Console()
|
| 32 |
+
|
| 33 |
+
# Setup Brain
|
| 34 |
+
def get_llm():
|
| 35 |
+
"""Returns the LLM instance for agents."""
|
| 36 |
+
return LLM(
|
| 37 |
+
model=LLM_MODEL,
|
| 38 |
+
base_url=LLM_BASE_URL,
|
| 39 |
+
api_key=LLM_API_KEY
|
| 40 |
+
)
|
| 41 |
+
|
| 42 |
+
# --- THE BUILD COMMAND ---
|
| 43 |
+
@app.command()
|
| 44 |
+
def build(
|
| 45 |
+
name: str = typer.Option(..., "--name", "-n", help="Design name (e.g., counter)"),
|
| 46 |
+
desc: str = typer.Option(..., "--desc", "-d", help="Natural language description")
|
| 47 |
+
):
|
| 48 |
+
"""Build a chip from natural language description."""
|
| 49 |
+
|
| 50 |
+
console.print(Panel(
|
| 51 |
+
f"[bold cyan]AgentIC: Natural Language → GDSII[/bold cyan]\n"
|
| 52 |
+
f"Design: [yellow]{name}[/yellow]\n"
|
| 53 |
+
f"Description: {desc}",
|
| 54 |
+
title="🚀 Starting Pipeline"
|
| 55 |
+
))
|
| 56 |
+
|
| 57 |
+
llm = get_llm()
|
| 58 |
+
|
| 59 |
+
# ===== STEP 1: Generate RTL =====
|
| 60 |
+
console.print("\n[bold yellow]━━━ Step 1/5: Generating Verilog RTL ━━━[/bold yellow]")
|
| 61 |
+
|
| 62 |
+
rtl_agent = Agent(
|
| 63 |
+
role='VLSI Design Engineer',
|
| 64 |
+
goal=f'Create synthesizable Verilog for: {desc}',
|
| 65 |
+
backstory='Expert in digital design with Sky130 PDK experience.',
|
| 66 |
+
llm=llm,
|
| 67 |
+
verbose=False
|
| 68 |
+
)
|
| 69 |
+
|
| 70 |
+
rtl_task = Task(
|
| 71 |
+
description=f'''Design a Verilog module named "{name}" that implements: {desc}
|
| 72 |
+
|
| 73 |
+
CRITICAL REQUIREMENTS:
|
| 74 |
+
- Module name must be exactly "{name}"
|
| 75 |
+
- Use VERILOG-2005 ONLY (NOT SystemVerilog)
|
| 76 |
+
- Use "always @(*)" NOT "always_comb"
|
| 77 |
+
- Use "reg" for outputs in combinational logic
|
| 78 |
+
- Include clock (clk) and active-low reset (rst_n) if sequential
|
| 79 |
+
- Return ONLY the Verilog code wrapped in ```verilog fences
|
| 80 |
+
- NO explanations, NO comments about the code
|
| 81 |
+
|
| 82 |
+
Example format:
|
| 83 |
+
```verilog
|
| 84 |
+
module {name}(...);
|
| 85 |
+
...
|
| 86 |
+
endmodule
|
| 87 |
+
```
|
| 88 |
+
''',
|
| 89 |
+
expected_output='Complete Verilog-2005 module code in markdown fence',
|
| 90 |
+
agent=rtl_agent
|
| 91 |
+
)
|
| 92 |
+
|
| 93 |
+
with console.status("[cyan]AI is designing your chip...[/cyan]"):
|
| 94 |
+
rtl_result = Crew(agents=[rtl_agent], tasks=[rtl_task]).kickoff()
|
| 95 |
+
|
| 96 |
+
rtl_path = write_verilog(name, str(rtl_result))
|
| 97 |
+
console.print(f" ✓ RTL saved to: [green]{rtl_path}[/green]")
|
| 98 |
+
|
| 99 |
+
# ===== STEP 2: Syntax Check RTL =====
|
| 100 |
+
console.print("\n[bold yellow]━━━ Step 2/5: Syntax Verification ━━━[/bold yellow]")
|
| 101 |
+
|
| 102 |
+
success, errors = run_syntax_check(rtl_path)
|
| 103 |
+
if not success:
|
| 104 |
+
console.print(f"[bold red]✗ SYNTAX ERROR:[/bold red]\n{errors}")
|
| 105 |
+
raise typer.Exit(1)
|
| 106 |
+
console.print(" ✓ Verilog syntax is [green]valid[/green]")
|
| 107 |
+
|
| 108 |
+
# ===== STEP 3: Generate Testbench =====
|
| 109 |
+
console.print("\n[bold yellow]━━━ Step 3/5: Generating Testbench ━━━[/bold yellow]")
|
| 110 |
+
|
| 111 |
+
# Read the generated RTL for context
|
| 112 |
+
with open(rtl_path, 'r') as f:
|
| 113 |
+
rtl_code = f.read()
|
| 114 |
+
|
| 115 |
+
tb_agent = Agent(
|
| 116 |
+
role='Verification Engineer',
|
| 117 |
+
goal=f'Create a testbench for {name}',
|
| 118 |
+
backstory='Expert in Verilog verification and simulation.',
|
| 119 |
+
llm=llm,
|
| 120 |
+
verbose=False
|
| 121 |
+
)
|
| 122 |
+
|
| 123 |
+
tb_task = Task(
|
| 124 |
+
description=f'''Create a Verilog-2005 testbench for this module:
|
| 125 |
+
|
| 126 |
+
```verilog
|
| 127 |
+
{rtl_code}
|
| 128 |
+
```
|
| 129 |
+
|
| 130 |
+
CRITICAL REQUIREMENTS:
|
| 131 |
+
- Module name must be "{name}_tb"
|
| 132 |
+
- Use VERILOG-2005 ONLY (NOT SystemVerilog)
|
| 133 |
+
- Use explicit port connections: .clk(clk), .a(a), etc.
|
| 134 |
+
- Use integer delays like #5 or #10, NOT #5ns or #10ns
|
| 135 |
+
- Clock: forever #5 clk = ~clk (inside initial block)
|
| 136 |
+
- Put $monitor INSIDE an initial block
|
| 137 |
+
- Use $dumpfile("{name}.vcd") and $dumpvars(0, {name}_tb)
|
| 138 |
+
- End with $finish
|
| 139 |
+
- Return ONLY the testbench code wrapped in ```verilog fences
|
| 140 |
+
|
| 141 |
+
Example structure:
|
| 142 |
+
```verilog
|
| 143 |
+
module {name}_tb;
|
| 144 |
+
reg clk, rst_n;
|
| 145 |
+
// declare inputs as reg, outputs as wire
|
| 146 |
+
|
| 147 |
+
{name} uut(.clk(clk), .rst_n(rst_n), ...);
|
| 148 |
+
|
| 149 |
+
initial begin
|
| 150 |
+
clk = 0;
|
| 151 |
+
forever #5 clk = ~clk;
|
| 152 |
+
end
|
| 153 |
+
|
| 154 |
+
initial begin
|
| 155 |
+
$dumpfile("{name}.vcd");
|
| 156 |
+
$dumpvars(0, {name}_tb);
|
| 157 |
+
$monitor(...);
|
| 158 |
+
// test sequence
|
| 159 |
+
$finish;
|
| 160 |
+
end
|
| 161 |
+
endmodule
|
| 162 |
+
```
|
| 163 |
+
''',
|
| 164 |
+
expected_output='Complete Verilog-2005 testbench in markdown fence',
|
| 165 |
+
agent=tb_agent
|
| 166 |
+
)
|
| 167 |
+
|
| 168 |
+
with console.status("[cyan]AI is creating testbench...[/cyan]"):
|
| 169 |
+
tb_result = Crew(agents=[tb_agent], tasks=[tb_task]).kickoff()
|
| 170 |
+
|
| 171 |
+
tb_path = write_verilog(name, str(tb_result), is_testbench=True)
|
| 172 |
+
console.print(f" ✓ Testbench saved to: [green]{tb_path}[/green]")
|
| 173 |
+
|
| 174 |
+
# ===== STEP 4: Run Simulation =====
|
| 175 |
+
console.print("\n[bold yellow]━━━ Step 4/5: Running Simulation ━━━[/bold yellow]")
|
| 176 |
+
|
| 177 |
+
sim_success, sim_output = run_simulation(name)
|
| 178 |
+
if not sim_success:
|
| 179 |
+
console.print(f"[bold red]✗ SIMULATION FAILED:[/bold red]\n{sim_output}")
|
| 180 |
+
raise typer.Exit(1)
|
| 181 |
+
|
| 182 |
+
# Show last few lines of simulation
|
| 183 |
+
sim_lines = sim_output.strip().split('\n')
|
| 184 |
+
for line in sim_lines[-5:]:
|
| 185 |
+
console.print(f" [dim]{line}[/dim]")
|
| 186 |
+
console.print(" ✓ Simulation [green]passed[/green]")
|
| 187 |
+
|
| 188 |
+
# ===== STEP 5: Run OpenLane =====
|
| 189 |
+
console.print("\n[bold yellow]━━━ Step 5/5: Running OpenLane (RTL → GDSII) ━━━[/bold yellow]")
|
| 190 |
+
console.print(" [dim]This may take 5-10 minutes...[/dim]")
|
| 191 |
+
|
| 192 |
+
# Create config.tcl from template
|
| 193 |
+
template_config = f"{OPENLANE_ROOT}/designs/simple_counter/config.tcl"
|
| 194 |
+
new_config = f"{OPENLANE_ROOT}/designs/{name}/config.tcl"
|
| 195 |
+
|
| 196 |
+
if os.path.exists(template_config) and not os.path.exists(new_config):
|
| 197 |
+
with open(template_config, 'r') as f:
|
| 198 |
+
content = f.read().replace("simple_counter", name)
|
| 199 |
+
with open(new_config, 'w') as f:
|
| 200 |
+
f.write(content)
|
| 201 |
+
console.print(f" ✓ Config created from template")
|
| 202 |
+
|
| 203 |
+
ol_success, ol_result = run_openlane(name)
|
| 204 |
+
|
| 205 |
+
if ol_success:
|
| 206 |
+
console.print(f" ✓ GDSII generated: [green]{ol_result}[/green]")
|
| 207 |
+
else:
|
| 208 |
+
console.print(f"[bold red]✗ OpenLane failed[/bold red]")
|
| 209 |
+
console.print(f" Error: {ol_result[:500]}...")
|
| 210 |
+
raise typer.Exit(1)
|
| 211 |
+
|
| 212 |
+
# ===== FINAL: Summary =====
|
| 213 |
+
console.print("\n" + "="*50)
|
| 214 |
+
console.print(Panel(
|
| 215 |
+
f"[bold green]✓ CHIP GENERATION COMPLETE![/bold green]\n\n"
|
| 216 |
+
f"Design: [cyan]{name}[/cyan]\n"
|
| 217 |
+
f"GDSII: [yellow]{ol_result}[/yellow]\n\n"
|
| 218 |
+
f"Run verification: [dim]python main.py verify {name}[/dim]",
|
| 219 |
+
title="🎉 Success"
|
| 220 |
+
))
|
| 221 |
+
|
| 222 |
+
|
| 223 |
+
@app.command()
|
| 224 |
+
def verify(name: str = typer.Argument(..., help="Design name to verify")):
|
| 225 |
+
"""Run verification on an existing design."""
|
| 226 |
+
console.print(f"[yellow]Running verification for {name}...[/yellow]")
|
| 227 |
+
output = run_verification(name)
|
| 228 |
+
console.print(output)
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
if __name__ == "__main__":
|
| 232 |
+
app()
|
src/agentic/config.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
|
| 3 |
+
# Paths
|
| 4 |
+
WORKSPACE_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
| 5 |
+
OPENLANE_ROOT = os.environ.get("OPENLANE_ROOT", os.path.expanduser("~/OpenLane"))
|
| 6 |
+
DESIGNS_DIR = os.path.join(OPENLANE_ROOT, "designs")
|
| 7 |
+
SCRIPTS_DIR = os.path.join(WORKSPACE_ROOT, "scripts")
|
| 8 |
+
|
| 9 |
+
# LLM Configuration
|
| 10 |
+
LLM_MODEL = os.environ.get("LLM_MODEL", "ollama/deepseek-r1")
|
| 11 |
+
LLM_BASE_URL = os.environ.get("LLM_BASE_URL", "http://localhost:11434")
|
| 12 |
+
LLM_API_KEY = os.environ.get("OPENAI_API_KEY", "NA")
|
| 13 |
+
|
| 14 |
+
# Tool Settings
|
| 15 |
+
PDK_ROOT = os.environ.get('PDK_ROOT', os.path.expanduser('~/.ciel'))
|
| 16 |
+
OPENLANE_IMAGE = "ghcr.io/the-openroad-project/openlane:ff5509f65b17bfa4068d5336495ab1718987ff69-amd64"
|
src/agentic/tools/__init__.py
ADDED
|
File without changes
|
src/agentic/tools/vlsi_tools.py
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# tools/vlsi_tools.py
|
| 2 |
+
import os
|
| 3 |
+
import subprocess
|
| 4 |
+
from ..config import OPENLANE_ROOT, SCRIPTS_DIR, PDK_ROOT, OPENLANE_IMAGE
|
| 5 |
+
|
| 6 |
+
def write_verilog(design_name, code, is_testbench=False):
|
| 7 |
+
"""Writes Verilog code to the OpenLane design directory."""
|
| 8 |
+
suffix = "_tb" if is_testbench else ""
|
| 9 |
+
path = f"{OPENLANE_ROOT}/designs/{design_name}/src/{design_name}{suffix}.v"
|
| 10 |
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
| 11 |
+
|
| 12 |
+
# Clean LLM output (remove markdown fences, think tags, etc.)
|
| 13 |
+
clean_code = code
|
| 14 |
+
|
| 15 |
+
# Remove <think> tags if present (DeepSeek-R1 reasoning)
|
| 16 |
+
if "<think>" in clean_code:
|
| 17 |
+
import re
|
| 18 |
+
clean_code = re.sub(r'<think>.*?</think>', '', clean_code, flags=re.DOTALL)
|
| 19 |
+
|
| 20 |
+
# Extract code from markdown fences
|
| 21 |
+
if "```verilog" in clean_code:
|
| 22 |
+
clean_code = clean_code.split("```verilog")[1].split("```")[0].strip()
|
| 23 |
+
elif "```v" in clean_code:
|
| 24 |
+
clean_code = clean_code.split("```v")[1].split("```")[0].strip()
|
| 25 |
+
elif "```" in clean_code:
|
| 26 |
+
# Find the code block
|
| 27 |
+
parts = clean_code.split("```")
|
| 28 |
+
for i, part in enumerate(parts):
|
| 29 |
+
if i % 2 == 1 and "module" in part: # Odd indices are inside fences
|
| 30 |
+
clean_code = part.strip()
|
| 31 |
+
# Remove language identifier if present
|
| 32 |
+
lines = clean_code.split('\n')
|
| 33 |
+
if lines[0].strip() in ['verilog', 'v', 'systemverilog']:
|
| 34 |
+
clean_code = '\n'.join(lines[1:])
|
| 35 |
+
break
|
| 36 |
+
|
| 37 |
+
# Ensure we have a module
|
| 38 |
+
if "module" not in clean_code:
|
| 39 |
+
# Try to find module in original
|
| 40 |
+
if "module" in code:
|
| 41 |
+
start = code.find("module")
|
| 42 |
+
end = code.rfind("endmodule")
|
| 43 |
+
if end > start:
|
| 44 |
+
clean_code = code[start:end+9] # +9 for "endmodule"
|
| 45 |
+
|
| 46 |
+
# Sanitize model artifacts and fix common issues
|
| 47 |
+
import re
|
| 48 |
+
# Remove model tokens like <|begin▁of▁sentence|>
|
| 49 |
+
clean_code = re.sub(r'<[|\|][^>]+[|\|]>', '', clean_code)
|
| 50 |
+
# Fix SystemVerilog to Verilog-2005
|
| 51 |
+
clean_code = clean_code.replace('always_comb', 'always @(*)')
|
| 52 |
+
clean_code = clean_code.replace('always_ff', 'always')
|
| 53 |
+
clean_code = clean_code.replace('logic', 'reg')
|
| 54 |
+
# Fix time units: #5ns -> #5, #10ps -> #10
|
| 55 |
+
clean_code = re.sub(r'#(\d+)(ns|ps|us|ms|s)\b', r'#\1', clean_code)
|
| 56 |
+
# Fix wildcard port connections (SystemVerilog)
|
| 57 |
+
clean_code = re.sub(r'\(\s*\.\*\s*\)', '', clean_code)
|
| 58 |
+
# Remove any leftover special chars
|
| 59 |
+
clean_code = re.sub(r'[▁|]', '', clean_code)
|
| 60 |
+
|
| 61 |
+
with open(path, "w") as f:
|
| 62 |
+
f.write(clean_code)
|
| 63 |
+
return path
|
| 64 |
+
|
| 65 |
+
def run_syntax_check(file_path):
|
| 66 |
+
"""Runs iverilog syntax check."""
|
| 67 |
+
result = subprocess.run(
|
| 68 |
+
["iverilog", "-t", "null", file_path],
|
| 69 |
+
capture_output=True, text=True
|
| 70 |
+
)
|
| 71 |
+
return result.returncode == 0, result.stderr
|
| 72 |
+
|
| 73 |
+
def run_simulation(design_name):
|
| 74 |
+
"""Compiles and runs the testbench simulation."""
|
| 75 |
+
src_dir = f"{OPENLANE_ROOT}/designs/{design_name}/src"
|
| 76 |
+
rtl_file = f"{src_dir}/{design_name}.v"
|
| 77 |
+
tb_file = f"{src_dir}/{design_name}_tb.v"
|
| 78 |
+
sim_out = f"{src_dir}/sim"
|
| 79 |
+
|
| 80 |
+
# Compile
|
| 81 |
+
compile_result = subprocess.run(
|
| 82 |
+
["iverilog", "-o", sim_out, rtl_file, tb_file],
|
| 83 |
+
capture_output=True, text=True
|
| 84 |
+
)
|
| 85 |
+
if compile_result.returncode != 0:
|
| 86 |
+
return False, f"Compilation failed:\n{compile_result.stderr}"
|
| 87 |
+
|
| 88 |
+
# Run
|
| 89 |
+
run_result = subprocess.run(
|
| 90 |
+
["vvp", sim_out],
|
| 91 |
+
capture_output=True, text=True,
|
| 92 |
+
timeout=30
|
| 93 |
+
)
|
| 94 |
+
return True, run_result.stdout
|
| 95 |
+
|
| 96 |
+
def run_openlane(design_name):
|
| 97 |
+
"""Triggers the OpenLane flow via Docker."""
|
| 98 |
+
os.chdir(OPENLANE_ROOT)
|
| 99 |
+
|
| 100 |
+
# Direct Docker command (non-interactive)
|
| 101 |
+
cmd = [
|
| 102 |
+
"docker", "run", "--rm",
|
| 103 |
+
"-v", f"{OPENLANE_ROOT}:/openlane",
|
| 104 |
+
"-v", f"{PDK_ROOT}:{PDK_ROOT}",
|
| 105 |
+
"-e", f"PDK_ROOT={PDK_ROOT}",
|
| 106 |
+
"-e", "PDK=sky130A",
|
| 107 |
+
OPENLANE_IMAGE,
|
| 108 |
+
"./flow.tcl", "-design", design_name, "-tag", "agentrun", "-overwrite"
|
| 109 |
+
]
|
| 110 |
+
|
| 111 |
+
process = subprocess.run(
|
| 112 |
+
cmd,
|
| 113 |
+
capture_output=True,
|
| 114 |
+
text=True,
|
| 115 |
+
timeout=900 # 15 min timeout
|
| 116 |
+
)
|
| 117 |
+
|
| 118 |
+
# Check if GDS was created
|
| 119 |
+
gds_path = f"{OPENLANE_ROOT}/designs/{design_name}/runs/agentrun/results/final/gds/{design_name}.gds"
|
| 120 |
+
success = os.path.exists(gds_path)
|
| 121 |
+
|
| 122 |
+
return success, gds_path if success else process.stderr
|
| 123 |
+
|
| 124 |
+
def run_verification(design_name):
|
| 125 |
+
"""Runs the verify_design.sh script."""
|
| 126 |
+
script_path = os.path.join(SCRIPTS_DIR, "verify_design.sh")
|
| 127 |
+
|
| 128 |
+
result = subprocess.run(
|
| 129 |
+
["bash", script_path, design_name],
|
| 130 |
+
capture_output=True,
|
| 131 |
+
text=True
|
| 132 |
+
)
|
| 133 |
+
return result.stdout
|