Skip to content

Commit 1e68b38

Browse files
committed
Merge remote-tracking branch 'origin/main' into text
2 parents 6686c8c + 60558fd commit 1e68b38

File tree

54 files changed

+8801
-19398
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+8801
-19398
lines changed

Cargo.lock

Lines changed: 1682 additions & 834 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ tower-lsp-server = "0.22"
3131

3232
geometry = { version = "0.7", registry = "substrate" }
3333
enumify = { version = "0.2", registry = "substrate" }
34+
uniquify = { version = "0.4", registry = "substrate" }

README.md

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,12 @@ vim.cmd([[autocmd BufRead,BufNewFile *.ar setfiletype argon]])
5858
To open an example Argon workspace, run the following from the root directory of your Argon clone:
5959

6060
```
61-
vim core/compiler/examples/argon_workspace/lib.ar
61+
vim pdks/sky130/lib.ar
6262
```
6363

6464
Start the GUI by running `:Argon gui`.
6565

66-
From within the GUI, type `:openCell test()` to open the `test` cell. You should now be able to edit layouts
66+
From within the GUI, type `:openCell inv(1200., 2000., 4)` to open the `inv` cell. You should now be able to edit layouts
6767
in both Neovim and the GUI.
6868

6969
### VS Code
@@ -92,7 +92,7 @@ cd ../..
9292
To open an example Argon workspace, run the following from the root directory of your Argon clone:
9393

9494
```bash
95-
code --extensionDevelopmentPath=$(pwd)/plugins/vscode core/compiler/examples/argon_workspace
95+
code --extensionDevelopmentPath=$(pwd)/plugins/vscode pdks/sky130/lib.ar
9696
```
9797

9898
We recommend defining an alias in your shell configuration to simplify future commands:
@@ -104,7 +104,7 @@ alias codear="code --extensionDevelopmentPath=<absolute_path_to_argon_repo>/plug
104104
With this alias defined, you can now run:
105105

106106
```bash
107-
codear core/compiler/examples/argon_workspace
107+
codear pdks/sky130
108108
```
109109

110110
Open the `lib.ar` file within the workspace. You can then start the GUI by running `Command Palette > Argon: Start GUI`.
@@ -149,10 +149,8 @@ Hit `d` to use the Dimension tool and click on the top edge of each rectangle. C
149149
The dimension should now be highlighted yellow, indicating that you are editing that dimension. Type `5.` and hit enter to set the value
150150
of the dimension (the decimal point is important, since just `5` is considered an integer literal rather than a float).
151151

152-
> [!WARNING]
153-
> Double check that there are no errors in your code editor, or the GUI will not be able to
154-
> display the updated cell. If you make a mistake,
155-
> you can undo and redo changes from the GUI using `u` and `Ctrl + r`,
152+
> [!TIP]
153+
> If you make a mistake, you can undo and redo changes from the GUI using `u` and `Ctrl + r`,
156154
> respectively, or manually modify the code in the text editor if needed.
157155
158156
Repeat for the other 3 sides of the rectangle.

core/compiler/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ edition = "2024"
77
derive-where = { version = "1", features = ["serde"] }
88
nalgebra = "0.34"
99
klayout-lyp = "0.1.1"
10+
gds21 = "0.2"
1011

1112
anyhow = { workspace = true }
1213
cfgrammar = { workspace = true }
@@ -19,13 +20,15 @@ serde = { workspace = true }
1920
approx = { workspace = true }
2021
indexmap = { workspace = true }
2122
geometry = { workspace = true }
23+
uniquify = { workspace = true }
2224
rgb = { workspace = true }
2325
thiserror = { workspace = true }
2426
toml = { workspace = true }
2527
regex = { workspace = true }
28+
tracing = { workspace = true }
2629

2730
[dev-dependencies]
28-
gds21 = "0.2"
31+
const_format = "0.2"
2932

3033
[build-dependencies]
3134
lrpar = { version = "0.13", features = ["serde"] }

core/compiler/src/gds.rs

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
use std::{io::BufReader, ops::Deref, path::Path};
2+
3+
use anyhow::{Result, anyhow};
4+
use gds21::{
5+
GdsBoundary, GdsElement, GdsLayerSpec, GdsLibrary, GdsPoint, GdsStrans, GdsStruct, GdsStructRef,
6+
};
7+
use indexmap::IndexMap;
8+
use regex::Regex;
9+
use tracing::trace;
10+
use uniquify::Names;
11+
12+
use crate::compile::{CellId, CompileOutput, CompiledData, ExecErrorCompileOutput, SolvedValue};
13+
14+
pub struct GdsMap {
15+
layers: IndexMap<String, GdsLayerSpec>,
16+
}
17+
18+
struct GdsExporter {
19+
lib: GdsLibrary,
20+
map: GdsMap,
21+
names: Names<CellId>,
22+
}
23+
24+
impl GdsExporter {
25+
fn new(name: impl Into<String>, map: GdsMap) -> Self {
26+
Self {
27+
lib: GdsLibrary::new(name),
28+
map,
29+
names: Names::new(),
30+
}
31+
}
32+
}
33+
34+
impl FromIterator<(String, GdsLayerSpec)> for GdsMap {
35+
fn from_iter<T: IntoIterator<Item = (String, GdsLayerSpec)>>(iter: T) -> Self {
36+
Self {
37+
layers: IndexMap::from_iter(iter),
38+
}
39+
}
40+
}
41+
42+
impl Deref for GdsMap {
43+
type Target = IndexMap<String, GdsLayerSpec>;
44+
45+
fn deref(&self) -> &Self::Target {
46+
&self.layers
47+
}
48+
}
49+
50+
impl GdsMap {
51+
pub fn from_lyp(path: impl AsRef<Path>) -> Result<Self> {
52+
let lyp = klayout_lyp::from_reader(BufReader::new(std::fs::File::open(path)?))?;
53+
Ok(GdsMap::from_iter(
54+
lyp.layers
55+
.into_iter()
56+
.map(|layer_prop| {
57+
let re = Regex::new(r"(\d*)/(\d*)@\d*")?;
58+
let caps = re
59+
.captures(&layer_prop.source)
60+
.ok_or_else(|| anyhow!("parse error"))?;
61+
let layer = caps
62+
.get(1)
63+
.ok_or_else(|| anyhow!("parse error"))?
64+
.as_str()
65+
.parse()?;
66+
let datatype = caps
67+
.get(2)
68+
.ok_or_else(|| anyhow!("parse error"))?
69+
.as_str()
70+
.parse()?;
71+
Ok((
72+
layer_prop.name,
73+
GdsLayerSpec {
74+
layer,
75+
xtype: datatype,
76+
},
77+
))
78+
})
79+
.collect::<Result<Vec<_>>>()?,
80+
))
81+
}
82+
}
83+
84+
impl CompileOutput {
85+
pub fn to_gds(&self, map: GdsMap, out_path: impl AsRef<Path>) -> Result<()> {
86+
let out_path = out_path.as_ref();
87+
trace!("Exporting to gds at {out_path:?}");
88+
let mut exporter = GdsExporter::new("TOP", map);
89+
if let CompileOutput::Valid(output)
90+
| CompileOutput::ExecErrors(ExecErrorCompileOutput {
91+
errors: _,
92+
output: Some(output),
93+
}) = self
94+
{
95+
output.cell_to_gds(&mut exporter, output.top)?;
96+
}
97+
if let Some(parent) = out_path.parent() {
98+
std::fs::create_dir_all(parent)?;
99+
}
100+
exporter.lib.save(out_path).map_err(|e| anyhow!("{e}"))?;
101+
102+
Ok(())
103+
}
104+
}
105+
106+
impl CompiledData {
107+
fn cell_to_gds(&self, exporter: &mut GdsExporter, id: CellId) -> Result<()> {
108+
trace!("Exporting cell {id}");
109+
let cell = &self.cells[&id];
110+
let name = &cell.scopes[&cell.root].name;
111+
let re = Regex::new(r".*cell ([a-zA-Z0-9_]*)")?;
112+
let caps = re.captures(name).ok_or_else(|| anyhow!("parse error"))?;
113+
let name = caps.get(1).ok_or_else(|| anyhow!("parse error"))?.as_str();
114+
let name = exporter.names.assign_name(id, name);
115+
let mut ocell = GdsStruct::new(name.to_string());
116+
for (_, obj) in &cell.objects {
117+
match obj {
118+
SolvedValue::Rect(rect) => {
119+
if rect.construction {
120+
continue;
121+
}
122+
if let Some(layer) = &rect.layer {
123+
let GdsLayerSpec {
124+
layer,
125+
xtype: datatype,
126+
} = exporter.map[layer];
127+
let x0 = rect.x0.0 as i32;
128+
let x1 = rect.x1.0 as i32;
129+
let y0 = rect.y0.0 as i32;
130+
let y1 = rect.y1.0 as i32;
131+
ocell.elems.push(GdsElement::GdsBoundary(GdsBoundary {
132+
layer,
133+
datatype,
134+
xy: vec![
135+
GdsPoint::new(x0, y0),
136+
GdsPoint::new(x0, y1),
137+
GdsPoint::new(x1, y1),
138+
GdsPoint::new(x1, y0),
139+
],
140+
..Default::default()
141+
}));
142+
}
143+
}
144+
SolvedValue::Instance(i) => {
145+
self.cell_to_gds(exporter, i.cell)?;
146+
ocell.elems.push(GdsElement::GdsStructRef(GdsStructRef {
147+
name: exporter.names.name(&i.cell).unwrap().to_string(),
148+
xy: GdsPoint::new(i.x as i32, i.y as i32),
149+
strans: Some(GdsStrans {
150+
reflected: i.reflect,
151+
abs_mag: false,
152+
abs_angle: false,
153+
mag: None,
154+
angle: Some(i.angle.degrees()),
155+
}),
156+
..Default::default()
157+
}));
158+
}
159+
_ => {}
160+
}
161+
}
162+
exporter.lib.structs.push(ocell);
163+
Ok(())
164+
}
165+
}

0 commit comments

Comments
 (0)