File size: 6,053 Bytes
2dfa1c8
d8ff16a
 
 
 
 
2dfa1c8
d8ff16a
 
 
 
 
 
 
2dfa1c8
 
d8ff16a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cca9a63
d8ff16a
cca9a63
 
 
d8ff16a
 
 
cca9a63
 
 
 
d8ff16a
 
 
 
 
 
cca9a63
d8ff16a
cca9a63
d8ff16a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
---
title: ChipForge RTL Debugging Environment
emoji: πŸ”§
colorFrom: purple
colorTo: green
sdk: docker
pinned: false
app_port: 8000
base_path: /web
tags:
  - openenv
  - verilog
  - rtl
  - semiconductor
---

# ChipForge β€” RTL Debugging Environment

An OpenEnv environment where an AI agent debugs buggy Verilog RTL code using real EDA tools (**Verilator** for simulation/lint, **Yosys** for synthesis).

The agent receives buggy Verilog, inspects code, runs tools, reads error logs, edits lines to fix bugs, and submits the corrected design for grading.

## Quick Start

```python
from chipforge import ChipforgeAction, ChipforgeEnv

try:
    env = ChipforgeEnv.from_docker_image("chipforge-env:latest")

    # Start a new episode (loads a random buggy RTL task)
    result = env.reset()
    print(f"Task: {result.observation.task_description}")

    # View the buggy RTL
    result = env.step(ChipforgeAction(action_type="view_rtl"))
    print(result.observation.rtl_code)

    # Run simulation to see errors
    result = env.step(ChipforgeAction(action_type="run_simulation"))
    print(f"Status: {result.observation.sim_status}")
    print(f"Error: {result.observation.error_summary}")

    # Fix the bug
    result = env.step(ChipforgeAction(
        action_type="edit_line",
        line_number=13,
        new_content="assign sum = x1 ^ cin;"
    ))

    # Verify the fix
    result = env.step(ChipforgeAction(action_type="run_simulation"))
    print(f"Status: {result.observation.sim_status}")

    # Submit solution
    result = env.step(ChipforgeAction(action_type="submit"))
    print(f"Reward: {result.observation.reward}")

finally:
    env.close()
```

## Action Space

| Action | Parameters | Description |
|--------|-----------|-------------|
| `view_design` | β€” | View current RTL code with line numbers |
| `view_testbench` | β€” | View the testbench code |
| `view_simulation_log` | β€” | View output from last simulation run |
| `view_synthesis_log` | β€” | View output from last synthesis run |
| `view_lint_log` | β€” | View output from last lint run |
| `run_simulation` | β€” | Compile + simulate with Verilator |
| `run_synthesis` | β€” | Synthesize with Yosys |
| `run_lint` | β€” | Run Verilator lint checks |
| `edit_line` | `target`, `line_number`, `new_content` | Replace a single line in target ("design" / "testbench") |
| `append_line` | `target`, `new_content` | Append a single line to target ("design" / "testbench") |
| `insert_lines` | `target`, `line_number`, `new_content` | Insert multiple lines at target ("design" / "testbench") |
| `replace_lines` | `target`, `line_number`, `end_line_number`, `new_content` | Replace multiple lines in target ("design" / "testbench") |
| `submit` | β€” | Submit fix and get final reward |

## Observation Space

| Field | Type | Description |
|-------|------|-------------|
| `rtl_code` | str | Current RTL (always populated) |
| `testbench_code` | str | Testbench (populated by `view_testbench`) |
| `log_output` | str | Tool output (populated by `view_*_log`) |
| `sim_status` | str | `not_run` / `pass` / `fail` / `error` |
| `synth_status` | str | `not_run` / `pass` / `warning` / `error` |
| `lint_status` | str | `not_run` / `clean` / `warning` / `error` |
| `error_summary` | str | One-line error hint |
| `task_description` | str | Description of the current task |
| `step_count` | int | Steps taken so far |
| `max_steps` | int | Maximum allowed steps (20) |

## Reward

| Component | Value | Condition |
|-----------|-------|-----------|
| Compiles | +0.2 | No syntax errors |
| Simulation passes | +0.3 | Output matches expected truth table |
| Synthesis clean | +0.3 | No warnings (e.g., no latches) |
| Lint clean | +0.2 | No lint warnings |
| Step penalty | -0.01/step | Encourages efficiency |

Maximum reward: **1.0** (all checks pass, minimal steps).

## Tasks

| # | Name | Difficulty | Bug Type |
|---|------|-----------|----------|
| 1 | `task_easy_syntax` | Easy | Incomplete XOR expression |
| 2 | `task_easy_missing_semicolon` | Easy | Missing semicolon on wire declaration |
| 3 | `task_medium_logic_bug` | Medium | Wrong operator in sum computation |
| 4 | `task_medium_wrong_operator` | Medium | XOR instead of AND in carry logic |
| 5 | `task_hard_latch_inference` | Hard | Missing else branch β†’ latch inferred |

## Tools Used

| Tool | Role | Installed via |
|------|------|--------------|
| **Verilator** | Simulation + Linting | OSS CAD Suite |
| **Yosys** | Synthesis | OSS CAD Suite |

Both tools are bundled in the Docker image via [OSS CAD Suite](https://github.com/YosysHQ/oss-cad-suite-build).

## Building & Running

```bash
# Build Docker image
docker build -t chipforge-env:latest -f server/Dockerfile .

# Run locally (for development)
uvicorn chipforge.server.app:app --reload

# Deploy to Hugging Face Spaces
openenv push
```

## Project Structure

```
chipforge/
β”œβ”€β”€ __init__.py              # Module exports
β”œβ”€β”€ models.py                # Action + Observation models
β”œβ”€β”€ client.py                # ChipforgeEnv client
β”œβ”€β”€ openenv.yaml             # OpenEnv manifest
β”œβ”€β”€ pyproject.toml           # Dependencies
└── server/
    β”œβ”€β”€ app.py               # FastAPI application
    β”œβ”€β”€ chipforge_environment.py  # Core environment logic
    β”œβ”€β”€ Dockerfile           # Container with Verilator + Yosys
    └── tasks/               # RTL debugging tasks
        β”œβ”€β”€ task_easy_syntax/
        β”œβ”€β”€ task_easy_missing_semicolon/
        β”œβ”€β”€ task_medium_logic_bug/
        β”œβ”€β”€ task_medium_wrong_operator/
        └── task_hard_latch_inference/
```

## Example Agent Episode

```
reset()  β†’  Task: "Fix the syntax error in the full adder RTL"

view_rtl  β†’  see buggy code with line numbers
run_simulation  β†’  sim_status="error", error_summary="syntax error near '^'"
edit_line(13, "assign sum = x1 ^ cin;")  β†’  "Line 13 updated"
run_simulation  β†’  sim_status="pass"
run_synthesis  β†’  synth_status="pass"
submit  β†’  reward=0.93
```