diff --git a/docs/product/build.py b/docs/product/build.py index 3f7b9fd..b49b3e9 100644 --- a/docs/product/build.py +++ b/docs/product/build.py @@ -101,6 +101,69 @@ def prepare_table(name: str, table: dict) -> None: table["has_footnote"] = bool(table.get("footnote")) +def load_config(path: Path) -> dict: + """Parse the content YAML, reporting syntax errors against the offending line.""" + text = path.read_text(encoding="utf-8") + try: + return yaml.safe_load(text) + except yaml.YAMLError as error: + mark = getattr(error, "problem_mark", None) + detail = getattr(error, "problem", str(error)) + if mark is None: + raise SystemExit(f"{path}: {detail}") + line = ( + text.splitlines()[mark.line] if mark.line < len(text.splitlines()) else "" + ) + raise SystemExit( + f"{path}:{mark.line + 1}: {detail}\n" + f" {line.strip()}\n" + ' hint: inside a "quoted" value, HTML quotes must be escaped as \\"' + ) + + +def walk_strings(node, path: str = ""): + """Yield (dotted-path, text) for every string in the loaded config.""" + if isinstance(node, dict): + for key, value in node.items(): + yield from walk_strings(value, f"{path}.{key}" if path else str(key)) + elif isinstance(node, list): + for index, value in enumerate(node): + yield from walk_strings(value, f"{path}[{index}]") + elif isinstance(node, str): + yield path, node + + +def validate_markup(content: dict) -> None: + """Catch the two easy ways to write broken HTML in the config. + + YAML only processes \\" as an escape inside "quoted" values. In a >- folded + or plain value the backslash survives into the page and breaks the markup, + so a loaded string should never still contain one. + """ + problems = [] + for path, text in walk_strings(content): + if '\\"' in text: + problems.append( + f'{path}: contains a literal \\" — in a >- or plain value write ' + "the quote on its own, with no backslash" + ) + for tag in ("b", "a", "span"): + opened = len(re.findall(rf"<{tag}\b", text)) + closed = len(re.findall(rf"", text)) + if opened != closed: + problems.append( + f"{path}: {opened} <{tag}> but {closed} — unbalanced tag" + ) + # An unterminated href swallows the rest of the tag, which still leaves + # and balanced, so check the attribute closes its own quotes. + if len(re.findall(r"href=", text)) != len(re.findall(r'href="[^"]*"', text)): + problems.append( + f'{path}: malformed link — href="..." is missing its closing quote' + ) + if problems: + raise SystemExit("\n".join(f"{p}" for p in problems)) + + def as_data_uri_payload(path: Path) -> str: if not path.is_file(): raise SystemExit(f"missing asset: {path}") @@ -223,8 +286,8 @@ def main() -> None: level=logging.INFO, format="%(levelname)-8s %(message)s", stream=sys.stdout ) - with open(args.config, encoding="utf-8") as fh: - content = yaml.safe_load(fh) + content = load_config(args.config) + validate_markup(content) for key in TABLE_KEYS: if key not in content: diff --git a/docs/product/datasheet.html.mustache b/docs/product/datasheet.html.mustache index dfc7309..7fb0552 100644 --- a/docs/product/datasheet.html.mustache +++ b/docs/product/datasheet.html.mustache @@ -12,6 +12,8 @@ :root { --navy: {{theme.navy}}; --red: {{theme.red}}; + --tag-bg: {{theme.tag_bg}}; + --tag-fg: {{theme.tag_fg}}; --ink: {{theme.ink}}; --ink-mid: {{theme.ink_mid}}; --ink-faint: {{theme.ink_faint}}; @@ -88,8 +90,8 @@ body { .bar__tag { margin-left: auto; - background: var(--red); - color: #fff; + background: var(--tag-bg); + color: var(--tag-fg); font-size: var(--t-fine); font-weight: 700; letter-spacing: 0.16em; @@ -110,6 +112,10 @@ body { min-height: 0; } +/* Page 2 opens straight onto a section heading, so it needs the top margin + that page 1 gets from the hero's own padding. */ +.body--specs { padding-top: 5.5mm; } + .label { font-size: var(--t-micro); font-weight: 600; @@ -146,8 +152,7 @@ body { display: grid; grid-template-columns: 1.32fr 1fr; gap: 7mm; - padding: 4.6mm 0 4.2mm; - border-bottom: 2px solid var(--rule-hard); + padding: 4.6mm 0 5.4mm; } .hero h1 { @@ -167,8 +172,6 @@ body { max-width: 62ch; } -.hero .rule { height: 2px; background: var(--red); width: 22mm; margin-top: 3.2mm; } - .hero figure { margin: 0; display: flex; flex-direction: column; } .hero img { width: 100%; height: 44mm; object-fit: cover; display: block; } @@ -187,17 +190,11 @@ body { .features { display: grid; grid-template-columns: repeat(3, 1fr); - border-bottom: 2px solid var(--rule-hard); + column-gap: 7mm; + row-gap: 4.4mm; + padding: 0 0 5.4mm; } -.feature { - padding: 2.8mm 4mm 2.9mm 0; - border-right: 1px solid var(--rule); -} - -.feature:nth-child(3n) { border-right: 0; padding-right: 0; } -.feature:nth-child(n + 4) { border-top: 1px solid var(--rule); } - .feature h3 { margin: 1.6mm 0 1.4mm; font-size: var(--t-body); @@ -256,8 +253,8 @@ tbody tr:last-child td { border-bottom: 0; } /* ---------- pricing / faq blocks ---------- */ -.block { padding: 3.2mm 0; border-bottom: 2px solid var(--rule-hard); } -.block:last-of-type { border-bottom: 0; } +.block { padding: 0 0 5.4mm; } +.block:last-of-type { padding-bottom: 0; } .faq { display: grid; @@ -366,7 +363,7 @@ a:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }
{{> logo}} -
{{&doc.wordmark}}{{&doc.wordmark_sub}}
+
{{&doc.wordmark}}{{#doc.wordmark_sub}}{{&doc.wordmark_sub}}{{/doc.wordmark_sub}}
{{&doc.tag}}
{{&doc.ref}}
@@ -378,7 +375,6 @@ a:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }
{{&hero.eyebrow}}

{{&hero.heading}}

{{&hero.body}}

-
{{hero.photo_alt}} @@ -438,7 +434,7 @@ a:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }
{{&doc.page2_title}}
-
+
{{#process}}{{> secthead}}{{> table}}{{> footnote}}{{/process}} diff --git a/docs/product/datasheet.yaml b/docs/product/datasheet.yaml index 934ed5b..a5c175b 100644 --- a/docs/product/datasheet.yaml +++ b/docs/product/datasheet.yaml @@ -7,6 +7,10 @@ # Notes for editing: # - Every text field is rendered as raw HTML, so ,
and # work anywhere. Write a literal ampersand as &. +# - Inside a "quoted" value (the table rows), escape any double quote the HTML +# needs as \" — an unescaped one ends the value and breaks the YAML: +# "see the docs" +# Values written as plain or >- folded text need no escaping. # - Table `style` tokens set cell formatting, space separated: # name bold, no wrapping (first column of most tables) # mono bold + tabular figures (dimensions, values, signal names) @@ -20,8 +24,8 @@ doc: title: Tiny Tapeout — Datasheet wordmark: Tiny Tapeout - wordmark_sub: SHARED SILICON ASIC SHUTTLE - tag: DATASHEET + wordmark_sub: "" # strapline under the wordmark on page 1; blank to hide + tag: PRODUCT DATASHEET ref: DOC TT-DS-2026 · REV A page2_title: Electrical & Mechanical Specifications @@ -29,6 +33,11 @@ doc: theme: navy: "#040371" # header bars and table header rows red: "#ec3013" # accent: labels, rules, prices + # DATASHEET tag in the header bar. Official Tiny Tapeout brand colours: + # yellow #fef244 · cyan #3dfef7 · hot pink #f82381 · pink #fc9f9f · blue #040371 + # Set tag_fg to navy for the light colours, #ffffff for hot pink. + tag_bg: "#fef244" + tag_fg: "#040371" ink: "#141414" # body text ink_mid: "#55545f" # secondary text ink_faint: "#86858f" # captions, dashes @@ -48,10 +57,10 @@ assets: # -------------------------------------------------------------------------- hero: - eyebrow: Shared multi-project chip · SKY130 / SG13G2 / GF180MCU + eyebrow: Shared multi project chip · SKY130 / IHP SG13G2 / GF180MCU heading: From idea to chip design in minutes body: >- - Tiny Tapeout makes it more accessible than ever to get your designs manufactured on a real chip. + Tiny Tapeout makes it more accessible than ever to get designs manufactured on a real chip. Submit from a GitHub repository and we handle integration, tapeout, packaging and delivery. photo_alt: Tiny Tapeout ETR demoboard with a QFN-64 packaged ASIC on a breakout board @@ -66,7 +75,7 @@ features: - kicker: 02 · Languages title: HDL agnostic body: >- - Any language that can produce Verilog RTL. Project templates and CI are + Any language that can produce Verilog. Project templates and CI are supplied for Verilog, with community provided VHDL and Chisel. - kicker: 03 · I/O title: 26 pins, plus analog @@ -77,11 +86,11 @@ features: title: Three PDKs body: >- SkyWater SKY130, IHP sg13g2 and GlobalFoundries gf180mcu. Open-source PDKs - running multiple times per year. + running multiple times per year with no NDAs to sign. - kicker: 05 · Hardware title: Demoboard available body: >- - An optional RP2350-based demoboard carries your packaged chip and selects + An optional RP2350-based demoboard carries the packaged chip and selects any project on the die over USB. - kicker: 06 · Flexibility title: Bring your own flow @@ -104,12 +113,12 @@ pricing: "Multiplexed analog pad access for mixed signal designs. Minimum project size of 2 tiles applies.", "€100 / pin"] - ["Demoboard PCB", - "Optional add-on: your packaged chip, an RP2350 demoboard and a breakout board.", + "Optional add-on: packaged chip on an RP2350 powered demoboard.", "€100 first 80 boards for individuals are subsidised
€300 academic & industry"] footnote: >- Silicon area and the demoboard are billed separately. Buying area gets - your design manufactured on the wafer — on its own it does not get you a - physical chip. To hold your chip in your hand, add the demoboard PCB. Confirm + your design manufactured on the chip — on its own it does not get you a + physical chip. To receive a physical chip, add the demoboard PCB. Confirm current figures at app.tinytapeout.com/calculator. @@ -120,7 +129,7 @@ faq: - q: How long until I get my chip? a: >- Fabrication takes 6–9 months, then boards are assembled, tested and - shipped. Check tinytapeout.com/chips for the schedule.
. + shipped. Check tinytapeout.com/chips for the schedule. - q: Do I need chip design experience? a: >- No. Getting started documentation on the website and help on the Discord community helps beginners get started. @@ -140,7 +149,7 @@ faq: - q: What are the licence terms? a: >- Every design is published publicly under Apache-2.0. The minimum - submission is GDS + LEF, produced with any toolchain you like. + submission is GDS + LEF, produced with any toolchain you like. For full terms see tinytapeout.com/terms. institutions: label: Taught and used at @@ -163,15 +172,14 @@ process: heading: Process & fabrication note: TILE DIMENSIONS PER PDK columns: - - {label: PDK, width: "19%", style: name} - - {label: Foundry, width: "21%"} - - {label: Node, width: "17%", style: num} - - {label: 1×1 tile area, width: "25%", style: mono} - - {label: Package} + - {label: PDK, width: "22%", style: name} + - {label: Foundry, width: "26%"} + - {label: Node, width: "22%", style: num} + - {label: 1×1 tile area, style: mono} rows: - - ["SKY130A", "SkyWater", "130 nm", "161.00 × 111.52 µm", "QFN-64"] - - ["ihp-sg13g2", "IHP", "130 nm BiCMOS", "202.08 × 154.98 µm", "QFN-64"] - - ["gf180mcuD", "GlobalFoundries", "180 nm", "346.64 × 160.72 µm", "QFN-64"] + - ["SKY130A", "SkyWater", "130 nm", "161.00 × 111.52 µm"] + - ["ihp-sg13g2", "IHP", "130 nm BiCMOS", "202.08 × 154.98 µm"] + - ["gf180mcuD", "GlobalFoundries", "180 nm", "346.64 × 160.72 µm"] footnote: >- One tile holds approximately 1,000 standard cells. Larger designs are built from multi-tile blocks from 1×2 up to 8×4; the available sizes differ @@ -244,9 +252,11 @@ ordering: - {} rows: - ["Shuttle cadence", - "Several shuttles per year across the three processes. Check tinytapeout.com/chips for the schedule"] + "Several shuttles per year across the three processes. Check tinytapeout.com/chips for the schedule."] - ["Lead time", "6–9 months in fabrication, then assembly, test and fulfilment."] + - ["Volume discount", + "10% off orders over €10,000."] - ["Deliverable", "Silicon area only for remote or shared test, or area plus the demoboard kit: packaged chip, RP2350 demoboard and breakout board."] - ["Design tools", @@ -261,5 +271,5 @@ disclaimer: Electrical characteristics are quoted for the SKY130A process unless stated otherwise — consult tinytapeout.com/specs for the process you intend to use. Pricing is indicative; confirm current figures with the calculator before - ordering. Tiny Tapeout devices are educational and prototyping parts, and are - not qualified for safety-critical, medical or automotive use. + ordering. Full terms and conditions of sale are published at + tinytapeout.com/terms.