mirror of
https://github.com/TinyTapeout/tt-support-tools.git
synced 2026-11-03 04:36:09 +01:00
164 lines
4.7 KiB
Python
164 lines
4.7 KiB
Python
import argparse
|
|
import os
|
|
|
|
import gdstk
|
|
from cairosvg import svg2png
|
|
from PIL import Image
|
|
|
|
PRBOUNDARY_LAYER = (0, 0)
|
|
METAL_LAYERS = [
|
|
(34, 0), # Metal1
|
|
(36, 0), # Metal2
|
|
(42, 0), # Metal3
|
|
(46, 0), # Metal4
|
|
(81, 0), # Metal5
|
|
]
|
|
NOFILL_LAYER = (152, 5)
|
|
|
|
TR_NOFILL_POLY_XY = [
|
|
[121.76, 5.27],
|
|
[121.76, 28.54],
|
|
[96.94, 28.54],
|
|
[96.94, 51.80],
|
|
[78.02, 51.80],
|
|
[78.02, 75.38],
|
|
[57.85, 75.38],
|
|
[57.85, 96.16],
|
|
[38.93, 96.16],
|
|
[38.93, 119.12],
|
|
[17.84, 119.12],
|
|
[17.84, 205.36],
|
|
[101.90, 205.36],
|
|
[101.90, 175.89],
|
|
[123.93, 175.89],
|
|
[123.93, 160.62],
|
|
[150.29, 160.62],
|
|
[150.29, 201.63],
|
|
[166.43, 201.63],
|
|
[166.43, 219.63],
|
|
[216.39, 219.63],
|
|
[216.39, 98.09],
|
|
[192.48, 98.09],
|
|
[192.48, 5.27],
|
|
]
|
|
|
|
|
|
class LogoGenerator:
|
|
def __init__(self, variant: str):
|
|
assert variant in ("tr", "tl")
|
|
self.variant = variant
|
|
self.macro_name = f"tt_logo_corner_{variant}"
|
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
png_file = os.path.join(script_dir, f"tt_logo_corner_{variant}.png")
|
|
svg2png(
|
|
url=f"{script_dir}/tt_logo_corner_{variant}.svg",
|
|
write_to=png_file,
|
|
)
|
|
self.img = Image.open(png_file).convert("L")
|
|
self.pixel_size = 1
|
|
if variant == "tl":
|
|
self.pixel_size = 0.82 # 164 um
|
|
self.width = self.img.width * self.pixel_size
|
|
self.height = self.img.height * self.pixel_size
|
|
|
|
def gen_gds(self, gds_file: str):
|
|
lib = gdstk.Library()
|
|
cell = lib.new_cell(self.macro_name)
|
|
boundary = gdstk.rectangle(
|
|
(0, 0),
|
|
(self.width, self.height),
|
|
layer=PRBOUNDARY_LAYER[0],
|
|
datatype=PRBOUNDARY_LAYER[1],
|
|
)
|
|
cell.add(boundary)
|
|
|
|
img = self.img
|
|
pixels = []
|
|
for y in range(img.height):
|
|
for x in range(img.width):
|
|
color: int = img.getpixel((x, y)) # type: ignore
|
|
if color < 16:
|
|
flipped_y = img.height - y - 1 # flip vertically
|
|
x1 = x * self.pixel_size
|
|
y1 = flipped_y * self.pixel_size
|
|
x2 = (x + 1) * self.pixel_size
|
|
y2 = (flipped_y + 1) * self.pixel_size
|
|
pixels += [gdstk.Polygon([(x1, y1), (x2, y1), (x2, y2), (x1, y2)])]
|
|
|
|
for layer in METAL_LAYERS:
|
|
merged_pixels = gdstk.offset(
|
|
pixels,
|
|
0,
|
|
use_union=True,
|
|
layer=layer[0],
|
|
datatype=layer[1],
|
|
)
|
|
cell.add(*merged_pixels)
|
|
|
|
if self.variant == "tr":
|
|
nofill_poly = gdstk.Polygon(
|
|
TR_NOFILL_POLY_XY, layer=NOFILL_LAYER[0], datatype=NOFILL_LAYER[1]
|
|
)
|
|
cell.add(nofill_poly)
|
|
else:
|
|
nofill_rect = gdstk.rectangle(
|
|
(0, 0),
|
|
(self.width, self.height),
|
|
layer=NOFILL_LAYER[0],
|
|
datatype=NOFILL_LAYER[1],
|
|
)
|
|
cell.add(nofill_rect)
|
|
|
|
lib.write_gds(gds_file)
|
|
|
|
def gen_verilog(self, verilog_file: str):
|
|
verilog_lines = [
|
|
"`default_nettype none",
|
|
"",
|
|
f"module {self.macro_name} ();",
|
|
"endmodule",
|
|
]
|
|
|
|
with open(verilog_file, "w") as f:
|
|
f.write("\n".join(verilog_lines) + "\n")
|
|
|
|
def gen_lef(self, lef_file: str):
|
|
lef_lines = [
|
|
f"VERSION 5.7 ;",
|
|
f" NOWIREEXTENSIONATPIN ON ;",
|
|
f' DIVIDERCHAR "/" ;',
|
|
f' BUSBITCHARS "[]" ;',
|
|
f"MACRO {self.macro_name}",
|
|
f" CLASS BLOCK ;",
|
|
f" FOREIGN {self.macro_name} ;",
|
|
f" ORIGIN 0.000 0.000 ;",
|
|
f" SIZE {self.width:.3f} BY {self.height:.3f} ;",
|
|
f"END {self.macro_name}",
|
|
f"END LIBRARY",
|
|
]
|
|
|
|
with open(lef_file, "w") as f:
|
|
f.write("\n".join(lef_lines) + "\n")
|
|
|
|
def gen_logo(self, dir):
|
|
self.gen_gds(f"{dir}/gds/{self.macro_name}.gds")
|
|
self.gen_lef(f"{dir}/lef/{self.macro_name}.lef")
|
|
self.gen_verilog(f"{dir}/verilog/{self.macro_name}.v")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
parser = argparse.ArgumentParser(description="TT GF corner logo generator")
|
|
parser.add_argument(
|
|
"--output-dir",
|
|
default=".",
|
|
help="Directory to write the logo files to",
|
|
)
|
|
args = parser.parse_args()
|
|
dir = args.output_dir
|
|
os.makedirs(f"{dir}/gds", exist_ok=True)
|
|
os.makedirs(f"{dir}/lef", exist_ok=True)
|
|
os.makedirs(f"{dir}/verilog", exist_ok=True)
|
|
LogoGenerator("tr").gen_logo(dir)
|
|
LogoGenerator("tl").gen_logo(dir)
|