feat(docs): add new datasheet generation method (#123)

(cherry picked from commit c36badfb60)
This commit is contained in:
Kristaps Jurkans
2025-11-14 22:16:17 +02:00
committed by Uri Shaked
parent bef483ab40
commit 6e576d6de6
37 changed files with 2751 additions and 205 deletions
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+52
View File
@@ -0,0 +1,52 @@
#import "../src/lib.typ": annotated_qrcode
#let call_to_action_page(qrcode_colour: black) = [
#align(center)[
#heading(level: 1)[Where is #emph(underline("your")) design?]
*Go from idea to chip design in minutes, without breaking the bank.*
]
Interested and want to get your own design manufactured? Visit our website and
check out our educational material and previous submissions!
#align(center, heading(level: 2, outlined: false)[How?])
New to this? Use our basic Wokwi template to see what's possible. If you're ready for more,
use our advanced Wokwi template and unlock some extra pins.
Know Verilog and CocoTB? Get stuck in with our HDL templates.
#align(center, heading(level: 2, outlined: false)[When?])
Multiple shuttles are run per year, meaning you've got an opportunity to manufacture your design
at any time.
#align(center, heading(level: 2, outlined: false)[Stuck? Need help? Want inspiration?])
Come chat to us and our community on Discord! Scan the QR code below.
#v(1cm)
#grid(
columns: (1fr, 1fr, 1fr),
rows: 1,
column-gutter: 1em,
align: center,
inset: 8pt,
fill: white,
annotated_qrcode(
"https://tinytapeout.com",
"Website",
tiaoma_args: ("scale": 2.0, "fg-color": qrcode_colour)
),
annotated_qrcode(
"https://tinytapeout.com/digital_design",
"Digital design guide",
tiaoma_args: ("scale": 1.75, "fg-color": qrcode_colour)
),
annotated_qrcode(
"https://tinytapeout.com/discord",
"Discord server",
tiaoma_args: ("scale": 2.0, "fg-color": qrcode_colour)
)
)
]
+144
View File
@@ -0,0 +1,144 @@
#let caravel = {
align(center,
table(
columns: 4,
align: left,
table.header(
[mprj_io_pin], [Function], [Signal], [QFN64 pin]
),
`0`, [Input], [`ui_in[0]`], [`31`],
`1`, [Input], [`ui_in[1]`], [`32`],
`2`, [Input], [`ui_in[2]`], [`33`],
`3`, [Input], [`ui_in[3]`], [`34`],
`4`, [Input], [`ui_in[4]`], [`35`],
`5`, [Input], [`ui_in[5]`], [`36`],
`6`, [Input], [`ui_in[6]`], [`37`],
`7`, [Analog], [`analog[0]`], [`41`],
`8`, [Analog], [`analog[1]`], [`42`],
`9`, [Analog], [`analog[2]`], [`43`],
`10`, [Analog], [`analog[3]`], [`44`],
`11`, [Analog], [`analog[4]`], [`45`],
`12`, [Analog], [`analog[5]`], [`46`],
`13`, [Input], [`ui_in[7]`], [48],
`14`, [Input], [`clk` $dagger$], [50],
`15`, [Input], [`rst_n` $dagger$], [`51`],
`16`, [Bidirectional], [`uio[0]`], [`53`],
`17`, [Bidirectional], [`uio[1]`], [`54`],
`18`, [Bidirectional], [`uio[2]`], [`55`],
`19`, [Bidirectional], [`uio[3]`], [`57`],
`20`, [Bidirectional], [`uio[4]`], [`58`],
`21`, [Bidirectional], [`uio[5]`], [`59`],
`22`, [Bidirectional], [`uio[6]`], [`60`],
`23`, [Bidirectional], [`uio[7]`], [`61`],
`24`, [Output], [`uo_out[0]`], [`62`],
`25`, [Output], [`uo_out[1]`], [`2`],
`26`, [Output], [`uo_out[2]`], [`3`],
`27`, [Output], [`uo_out[3]`], [`4`],
`28`, [Output], [`uo_out[4]`], [`5`],
`29`, [Output], [`uo_out[5]`], [`6`],
`30`, [Output], [`uo_out[6]`], [`7`],
`31`, [Output], [`uo_out[7]`], [`8`],
`32`, [Analog], [`analog[6]`], [`11`],
`33`, [Analog], [`analog[7]`], [`12`],
`34`, [Analog], [`analog[8]`], [`13`],
`35`, [Analog], [`analog[9]`], [`14`],
`36`, [Analog], [`analog[10]`], [`15`],
`37`, [Analog], [`analog[11]`], [`16`],
`38`, [Mux Control], [`ctrl_ena`], [`22`],
`39`, [Mux Control], [`ctrl_sel_inc`], [`24`],
`40`, [Mux Control], [`ctrl_sel_rst_n`], [`25`],
`41`, [Reserved], [(none)], [`26`],
`42`, [Reserved], [(none)], [`27`],
`43`, [Reserved], [(none)], [`28`],
)
)
[
$dagger$ Internally, there's no difference between `clk`, `rst_n` and `ui_in` pins. They are all just bits in the
`pad_ui_in` bus. However, we use different names to make it easier to understand the purpose of each signal.
]
}
#let openframe = {
align(center,
table(
columns: 3,
align: left,
table.header(
[QFN64 Pin], [Function], [Signal]
),
`1`, [Mux Control], [`ctrl_ena`],
`2`, [Mux Control], [`ctrl_sel_inc`],
`3`, [Mux Control], [`ctrl_sel_rst_n`],
`4`, [Reserved], [(none)],
`5`, [Reserved], [(none)],
`6`, [Reserved], [(none)],
`7`, [Reserved], [(none)],
`8`, [Reserved], [(none)],
`9`, [Output], [`uo_out[0]`],
`10`, [Output], [`uo_out[1]`],
`11`, [Output], [`uo_out[2]`],
`12`, [Output], [`uo_out[3]`],
`13`, [Output], [`uo_out[4]`],
`14`, [Output], [`uo_out[5]`],
`15`, [Output], [`uo_out[6]`],
`16`, [Output], [`uo_out[7]`],
`17`, [Power], [VDD IO],
`18`, [Ground], [GND IO],
`19`, [Analog], [`analog[0]`],
`20`, [Analog], [`analog[1]`],
`21`, [Analog], [`analog[2]`],
`22`, [Analog], [`analog[3]`],
`23`, [Power], [VAA Analog],
`24`, [Ground], [GND Analog],
`25`, [Analog], [`analog[4]`],
`26`, [Analog], [`analog[5]`],
`27`, [Analog], [`analog[6]`],
`28`, [Analog], [`analog[7]`],
`29`, [Ground], [VDD Core],
`30`, [Power], [VDD Core],
`31`, [Ground], [GND IO],
`32`, [Power], [VDD IO],
`33`, [Bidirectional], [`uio[0]`],
`34`, [Bidirectional], [`uio[1]`],
`35`, [Bidirectional], [`uio[2]`],
`36`, [Bidirectional], [`uio[3]`],
`37`, [Bidirectional], [`uio[4]`],
`38`, [Bidirectional], [`uio[5]`],
`39`, [Bidirectional], [`uio[6]`],
`40`, [Bidirectional], [`uio[7]`],
`41`, [Input], [`ui_in[0]`],
`42`, [Input], [`ui_in[1]`],
`43`, [Input], [`ui_in[2]`],
`44`, [Input], [`ui_in[3]`],
`45`, [Input], [`ui_in[4]`],
`46`, [Input], [`ui_in[5]`],
`47`, [Input], [`ui_in[6]`],
`48`, [Input], [`ui_in[7]`],
`49`, [Input], [`rst_n` $dagger$],
`50`, [Input], [`clk` $dagger$],
`51`, [Ground], [GND IO],
`52`, [Power], [VDD IO],
`53`, [Analog], [`analog[8]`],
`54`, [Analog], [`analog[9]`],
`55`, [Analog], [`analog[10]`],
`56`, [Analog], [`analog[11]`],
`57`, [Ground], [GND Analog],
`58`, [Power], [VDD Analog],
`59`, [Analog], [`analog[12]`],
`60`, [Analog], [`analog[13]`],
`61`, [Analog], [`analog[14]`],
`62`, [Analog], [`analog[15]`],
`63`, [Ground], [GND Core],
`64`, [Power], [VDD Core]
)
)
[
$dagger$ Internally, there's no difference between `clk`, `rst_n` and `ui_in` pins. They are all just bits in the
`pad_ui_in` bus. However, we use different names to make it easier to understand the purpose of each signal.
]
}
+9
View File
@@ -0,0 +1,9 @@
= Pinout
The chip is packaged in a 64-pin QFN package. The pinout is shown below.
#align(center, image("../resources/images/tt-qfn-64.svg"))
Note: You will receive the chip mounted on a breakout board
(#link("https://github.com/tinytapeout/breakout-pcb")[github.com/tinytapeout/breakout-pcb]).
The pinout is provided for advanced users, as most users will not need to solder the chip directly.
+21
View File
@@ -0,0 +1,21 @@
= Team
Tiny Tapeout would not be possible without a lot of people helping. We would especially like to thank:
- *Uri Shaked* for #link("https://wokwi.com")[Wokwi] development and lots more
- #link("https://psychogenic.com/")[*Patrick Deegan*] for PCBs, software, documentation and lots more
- #link("https://twitter.com/tnt")[*Sylvain Munaut*] for help with scan chain improvements
- #link("https://www.linkedin.com/in/michael-thompson-0a581a/")[*Mike Thompson*] and
#link("https://www.linkedin.com/in/mitch-bailey-8ba0b45/")[*Mitch Bailey*] for verification expertise
- #link("https://www.linkedin.com/in/tim-edwards-4376a18/")[*Tim Edwards*] and
#link("https://www.linkedin.com/in/harald-pretl-4911ba10/")[*Harald Pretl*] for ASIC expertise
- #link("https://twitter.com/jix_")[*Jix*] for formal verification support
- #link("https://twitter.com/proppy")[*Proppy*] for help with GitHub actions
- #link("https://twitter.com/maxiborga")[*Maximo Balestrini*] for all the amazing renders and the interactive GDS viewer
- *James Rosenthal* for coming up with digital design examples
- All the *people who took part in TinyTapeout 01* and volunteered time to improve docs and test the flow
- The #link("https://www.yosyshq.com/")[*team at YosysHQ*] and *all the other open source EDA tool makes*
- *Jeff* and the #link("https://efabless.com/")[*Efabless Team*] for running the shuttles and providing OpenLane and
sponsorship
- #link("https://www.youtube.com/watch?v=EczW2IWdnOM")[*Tim Ansell* and *Google*] for supporting the open source silicon
movement
- #link("https://zerotoasiccourse.com/")[*Zero to ASIC course community*] for all your support
- *Jeremy Birch* for help with STA
+102
View File
@@ -0,0 +1,102 @@
= The Tiny Tapeout Multiplexer
== Overview
The Tiny Tapeout Multiplexer distributes a single set of user IOs to multiple user designs. It is the backbone of the
Tiny Tapeout chip.
It has the following features:
- 10 dedicated inputs
- 8 dedicated outputs
- 8 bidirectional outputs
- Supports up to 512 user designs (32 mux units, each with up to 16 designs)
- Designs can have different sizes. The basic unit is called a tile, and each design can occupy up to 16 tiles.
== Operation
The multiplexer consists of three main units:
1. The controller $dash.em$ used to set the address of the active design
2. The spine $dash.em$ a bus that connects the controller with all the mux units
3. Mux units $dash.em$ connects the spine to individual user designs
=== The Controller
The mux controller has 3 input lines:
#align(center)[
#table(
columns: 2, rows: 4,
table.header(
[Input], [Description]
),
`ena`, [Sent as-is (buffered) to the downstream mux units],
`sel_rst_n`, [Resets the internal address counter to 0 (active low)],
`sel_inc`, [Increments the internal address counter by 1]
)
]
It outputs the address of the currently selected design on the `si_sel` port of the spine (see below).
For instance, to select the design at address 12, you need to pulse `sel_rst_n` low, and then pulse `sel_inc` 12 times:
#figure(
caption: [Mux signals for activating the design at address 12],
align(center)[
#image("../resources/images/mux_select_addr_12.svg")
]
)
#figure(
caption: [Mux Diagram],
align(center)[
#image("../resources/images/mux_diagram.svg", height: 55%)
]
)
#figure(
caption: [Mux Controller Diagram],
align(center)[
#image("../resources/images/mux_controller.png")
]
)
Internally, the controller is just a chain of 10 D-flip-flops. The `sel_inc` signal is connected to the clock of the
first flip-flop, and the output of each flip-flop is connected to the clock of the next flip-flop. The `sel_rst_n`
signal is connected to the reset of all flip-flops.
The following Wokwi project demonstrates this setup:
#link("https://wokwi.com/projects/36434780766")[wokwi.com/projects/36434780766].
It contains an Arduino Nano that decodes the currently selected mux address and displays it on a 7-segment display.
Click on the button labeled `RST_N` to reset the counter, and click on the button labeled `INC` to increment the counter.
=== The Spine
The controller and all muxes are connected together through the spine. The spine has the following signals going to it:
*From controller to mux*:
- `si_ena` $dash.em$ the `ena` input
- `si_sel` $dash.em$ selected design address (10 bits)
- `ui_in` $dash.em$ user clock, user `rst_n`, user_inputs (10 bits)
- `uio_in` $dash.em$ bidirectional I/O inputs (8 bits)
*From mux to controller*:
- `uo_out` $dash.em$ user outputs (8 bits)
- `uio_oe` $dash.em$ bidirectional I/O output enable (8 bits)
- `uio_out` $dash.em$ bidirectional I/O outputs (8 bits)
The only signal which is actually generated by the controller is `si_sel` (using `sel_rst_n` and `sel_inc`, as explained
above). The other signals are just going through from/to chip I/O pads.
=== The Multiplexer
Each mux branch is connected to up to 16 designs. It also has 5 bits of a hard-coded address (each unit gets assigned
a different address, based on its position on the die).
The mux implements the following logic:
If `si_ena` is 1, and `si_sel` matches the mux address, we know the mux is active. Then, it activates the specific
user design port that matches the remaining bits of `si_sel`.
*For the active design*:
- `clk`, `rst_n`, `ui_in`, `uio_in` are connected to the respective pins coming from the spine (through a buffer)
- `uo_out`, `uio_oe`, `uio_out` are connected to the respective pins going out to the spine (through a tristate buffer)
*For all others, inactive designs* (including all designs in inactive muxes):
- `clk`, `rst_n`, `ui_in`, `uio_in` are all tied to zero
- `uo_out`, `uio_oe`, `uio_out` are disconnected from the spine (the tristate buffer output enable is disabled)
== Pinout
// this pinout table must be populated from within the datasheet template itself
@@ -0,0 +1,92 @@
#import "../src/lib.typ": badge, callout
#import "../src/colours.typ"
= Using This Datasheet
== Structure
Projects are ordered by their mux address, in ascending order. Documentation is user-provided from their GitHub
repositories and are merged into the final shuttle once the deadline is reached.
In general, each project should contain:
- The user-provided title & a list of authors
- A link to the GitHub repository used for submission
- A link to the Wokwi project (if applicable)
- A "How it works" section
- A "How to test" section
- An "External hardware" section (if applicable)
- A pinout table for both digital & analog designs
== Badges
This datasheet uses "badges" to quickly convey some information about the content. These badges are explained in the
table below.
#let example_address_badge = box(baseline: 0.4em, badge(colours.BADGE_TEAL, strong(raw("-123"))))
#let example_microtile_addr_badge = box(baseline: 0.4em, badge(colours.BADGE_TEAL, strong(raw("-423/2"))))
#let example_clock_badge = box(baseline: 0.4em, badge(colours.BADGE_BLUE, strong(raw("25.175 MHz"))))
#let example_proj_wokwi = box(baseline: 0.4em, badge(colours.BADGE_PINK, strong(raw("Wokwi Project"))))
#let example_proj_hdl = box(baseline: 0.4em, badge(colours.BADGE_PINK, strong(raw("HDL Project"))))
#let example_proj_analog = box(baseline: 0.4em, badge(colours.BADGE_PINK, strong(raw("Analog Project"))))
#let example_proj_analog = box(baseline: 0.4em, badge(colours.BADGE_PINK, strong(raw("Analog Project"))))
#let example_medium_danger = box(baseline: 0.4em, badge(colours.WARNING_STRONG, strong(raw("Medium Danger"))))
#let example_high_danger = box(baseline: 0.4em, badge(colours.DANGER_STRONG, strong(raw("High Danger"))))
#let example_artwork = box(baseline: 0.4em, badge(colours.BADGE_PURPLE, strong(raw("Artwork"))))
#table(
columns: 2,
inset: 6pt,
align: (center + horizon, left),
table.header(
[Badge], [Description]
),
example_artwork, [Used to showcase artwork from our community.],
[#example_address_badge \ #example_microtile_addr_badge], [Mux address of the project, in decimal. For microtile
designs, their sub-address is placed after the forward slash. In this example, it would be `2`.],
example_clock_badge, [Clock frequency of the project. May be truncated from actual value or omitted completely.],
[#example_proj_hdl \ #example_proj_wokwi \ #example_proj_analog], [Project type, indicating if it was made with a HDL,
Wokwi, or if it is analog.],
[#example_medium_danger \ #example_high_danger], [Indicates the risk that the project presents to the ASIC. Medium
danger projects can damage the ASIC under certain conditions, whilst high danger projects _will_ damage the ASIC.]
)
== Callouts
In addition to #example_medium_danger and #example_high_danger badges being used, a callout is placed before the project
documentation begins to alert the user.
A callout for #example_medium_danger may look something like:
#callout("warning",
`This project will damage the ASIC under certain conditions.`,
`There is an error in the schematic which may lead to ASIC failure under certain clocking conditions.`
)
Similarly, a callout for #example_high_danger may look something like:
#callout("danger",
`This project will damage the ASIC.`,
`There is an error in the schematic which may cause permanent damage when powered on in a certain configuration.`
)
Should there be a project that poses a danger, the callout will explain the reasoning behind the danger level.
Callouts may also provide some additional information, and look something like so:
#callout("info",
`Information`,
raw("Silicon melts at 1414°C, and boils at 3265°C. Don't let your chip get too hot!")
)
== Figures & Footnotes
Numbering for figures and footnotes within the "Project" chapter is formed by combining the address of the project with
the current figure number. For example, the second figure for a project with an address of 256 will be captioned with
"Figure 256.2". Likewise, the third footnote for a project of address 128 will be shown as "128.3".
The numbering outside of the "Project" chapter resumes as normal, being formatted with a simple number, e.g. "Figure 3".
== Updates
This datasheet is intended to be a living and breathing document. Please update your projects' datasheet with new
information if you have it, by creating a pull request against the shuttle repository.
@@ -0,0 +1,93 @@
Copyright 2021 The Martian Mono Project Authors (https://github.com/evilmartians/mono)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://openfontlicense.org
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -0,0 +1,95 @@
Martian Mono Variable Font
==========================
This download contains Martian Mono as both a variable font and static fonts.
Martian Mono is a variable font with these axes:
wdth
wght
This means all the styles are contained in a single file:
Martian_Mono/MartianMono-VariableFont_wdth,wght.ttf
If your app fully supports variable fonts, you can now pick intermediate styles
that aren’t available as static fonts. Not all apps support variable fonts, and
in those cases you can use the static font files for Martian Mono:
Martian_Mono/static/MartianMono_Condensed-Thin.ttf
Martian_Mono/static/MartianMono_Condensed-ExtraLight.ttf
Martian_Mono/static/MartianMono_Condensed-Light.ttf
Martian_Mono/static/MartianMono_Condensed-Regular.ttf
Martian_Mono/static/MartianMono_Condensed-Medium.ttf
Martian_Mono/static/MartianMono_Condensed-SemiBold.ttf
Martian_Mono/static/MartianMono_Condensed-Bold.ttf
Martian_Mono/static/MartianMono_Condensed-ExtraBold.ttf
Martian_Mono/static/MartianMono_SemiCondensed-Thin.ttf
Martian_Mono/static/MartianMono_SemiCondensed-ExtraLight.ttf
Martian_Mono/static/MartianMono_SemiCondensed-Light.ttf
Martian_Mono/static/MartianMono_SemiCondensed-Regular.ttf
Martian_Mono/static/MartianMono_SemiCondensed-Medium.ttf
Martian_Mono/static/MartianMono_SemiCondensed-SemiBold.ttf
Martian_Mono/static/MartianMono_SemiCondensed-Bold.ttf
Martian_Mono/static/MartianMono_SemiCondensed-ExtraBold.ttf
Martian_Mono/static/MartianMono-Thin.ttf
Martian_Mono/static/MartianMono-ExtraLight.ttf
Martian_Mono/static/MartianMono-Light.ttf
Martian_Mono/static/MartianMono-Regular.ttf
Martian_Mono/static/MartianMono-Medium.ttf
Martian_Mono/static/MartianMono-SemiBold.ttf
Martian_Mono/static/MartianMono-Bold.ttf
Martian_Mono/static/MartianMono-ExtraBold.ttf
Martian_Mono/static/MartianMono_SemiExpanded-Thin.ttf
Martian_Mono/static/MartianMono_SemiExpanded-ExtraLight.ttf
Martian_Mono/static/MartianMono_SemiExpanded-Light.ttf
Martian_Mono/static/MartianMono_SemiExpanded-Regular.ttf
Martian_Mono/static/MartianMono_SemiExpanded-Medium.ttf
Martian_Mono/static/MartianMono_SemiExpanded-SemiBold.ttf
Martian_Mono/static/MartianMono_SemiExpanded-Bold.ttf
Martian_Mono/static/MartianMono_SemiExpanded-ExtraBold.ttf
Get started
-----------
1. Install the font files you want to use
2. Use your app's font picker to view the font family and all the
available styles
Learn more about variable fonts
-------------------------------
https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts
https://variablefonts.typenetwork.com
https://medium.com/variable-fonts
In desktop apps
https://theblog.adobe.com/can-variable-fonts-illustrator-cc
https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts
Online
https://developers.google.com/fonts/docs/getting_started
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide
https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts
Installing fonts
MacOS: https://support.apple.com/en-us/HT201749
Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux
Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows
Android Apps
https://developers.google.com/fonts/docs/android
https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts
License
-------
Please read the full license text (OFL.txt) to understand the permissions,
restrictions and requirements for usage, redistribution, and modification.
You can use them in your products & projects – print or digital,
commercial or otherwise.
This isn't legal advice, please consider consulting a lawyer and see the full
license for all details.
@@ -0,0 +1,93 @@
Copyright 2024 The Montserrat.Git Project Authors (https://github.com/JulietaUla/Montserrat.git)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://openfontlicense.org
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -0,0 +1,81 @@
Montserrat Variable Font
========================
This download contains Montserrat as both variable fonts and static fonts.
Montserrat is a variable font with this axis:
wght
This means all the styles are contained in these files:
Montserrat/Montserrat-VariableFont_wght.ttf
Montserrat/Montserrat-Italic-VariableFont_wght.ttf
If your app fully supports variable fonts, you can now pick intermediate styles
that aren’t available as static fonts. Not all apps support variable fonts, and
in those cases you can use the static font files for Montserrat:
Montserrat/static/Montserrat-Thin.ttf
Montserrat/static/Montserrat-ExtraLight.ttf
Montserrat/static/Montserrat-Light.ttf
Montserrat/static/Montserrat-Regular.ttf
Montserrat/static/Montserrat-Medium.ttf
Montserrat/static/Montserrat-SemiBold.ttf
Montserrat/static/Montserrat-Bold.ttf
Montserrat/static/Montserrat-ExtraBold.ttf
Montserrat/static/Montserrat-Black.ttf
Montserrat/static/Montserrat-ThinItalic.ttf
Montserrat/static/Montserrat-ExtraLightItalic.ttf
Montserrat/static/Montserrat-LightItalic.ttf
Montserrat/static/Montserrat-Italic.ttf
Montserrat/static/Montserrat-MediumItalic.ttf
Montserrat/static/Montserrat-SemiBoldItalic.ttf
Montserrat/static/Montserrat-BoldItalic.ttf
Montserrat/static/Montserrat-ExtraBoldItalic.ttf
Montserrat/static/Montserrat-BlackItalic.ttf
Get started
-----------
1. Install the font files you want to use
2. Use your app's font picker to view the font family and all the
available styles
Learn more about variable fonts
-------------------------------
https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts
https://variablefonts.typenetwork.com
https://medium.com/variable-fonts
In desktop apps
https://theblog.adobe.com/can-variable-fonts-illustrator-cc
https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts
Online
https://developers.google.com/fonts/docs/getting_started
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide
https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts
Installing fonts
MacOS: https://support.apple.com/en-us/HT201749
Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux
Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows
Android Apps
https://developers.google.com/fonts/docs/android
https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts
License
-------
Please read the full license text (OFL.txt) to understand the permissions,
restrictions and requirements for usage, redistribution, and modification.
You can use them in your products & projects – print or digital,
commercial or otherwise.
This isn't legal advice, please consider consulting a lawyer and see the full
license for all details.
+32
View File
@@ -0,0 +1,32 @@
// callouts
#let WARNING_STRONG = rgb("#ff6b21")
#let WARNING_WEAK = rgb("#fd8448")
#let DANGER_STRONG = rgb("#ff0000")
#let DANGER_WEAK = rgb("#ff4747")
#let INFO_STRONG = rgb("#2766ef")
#let INFO_WEAK = rgb("#4b7be2")
// misc document items
#let LINK_DEFAULT = rgb("#4646cd")
#let TABLE_GREY = rgb("#2b2b2b")
#let ARTWORK_GREY_INFO = rgb("#2b2b2bda")
#let HORIZONTAL_RULE_GREY = rgb("#c4c4c4c4")
// badges
#let BADGE_TEAL = rgb("#009696")
#let BADGE_MUTED_TEAL = rgb("#007474")
#let BADGE_BLUE = rgb("#3e71e7")
#let BADGE_PINK = rgb("#db44b2")
#let BADGE_PURPLE = rgb("#a952ff")
// themes
#let THEME_PLUM = rgb("#9c6fb6")
#let THEME_TT06_PINK = rgb("#ec789d")
#let THEME_SKY_BLUE = rgb("#0c66ab")
// unused colours for safekeeping
#let UNUSED_GOLD = rgb("#ffc936")
#let UNUSED_PURPLE_1 = rgb("#9123ff")
#let UNUSED_PURPLE_2 = rgb("#a041ff")
+622
View File
@@ -0,0 +1,622 @@
#import "@preview/tiaoma:0.3.0"
#import "lib.typ": badge, callout, annotated_qrcode, get_image_by_id
#import "colours.typ"
#import "../chapters/pinout-tables.typ" as pins
#import "../chapters/call-to-action.typ": call_to_action_page
#let _funding_content = state("_funding_content", [])
#let _funding_alt_title = state("_funding_alt_title", [])
#let _flip_footer_ordering = state("_flip_footer_ordering", false)
#let _chip_render_content = state("_chip_render_content", none)
#let _chip_render_sponsor_text = state("_chip_render_sponsor_text", none)
#let _chip_render_sponsor_logo = state("_chip_render_sponsor_logo", none)
#let styling(body) = {
set page(paper: "a4", margin: auto)
set text(font: "Montserrat", size: 12pt)
show raw: set text(font: "Martian Mono", weight: "light")
// style headings
show heading.where(level: 1): this => {
text(size: 28pt, this)
v(0.1cm)
}
show heading.where(level: 2): set text(size: 22pt)
show heading.where(level: 3): set text(size: 16pt)
// indent numbered and bullet point lists
set enum(indent: 1em)
set list(indent: 1em)
// format table so that empty cells show dark grey em dash
show table.cell: this => {
if this.body == [] {
align(center + horizon, text(fill: colours.TABLE_GREY)[$dash.em$])
} else {
this
}
}
// set quote styling
// used for project description
show quote: set align(center)
show quote: set pad(x: 1em)
show quote: set block(above: 1.75em)
body
}
#let styling_set_par(body) = {
// justify text, except for in tables
set par(justify: true)
show table: this => {
set par(justify: false)
this
}
body
}
#let _footer(shuttle, invert_text_colour: false, display_pg_as: "1", flip_ordering: false) = {
// setup
set text(size: 10pt)
set text(white) if invert_text_colour
let logo = box(baseline: 0.25em, {
if invert_text_colour {
image("../resources/logos/tt-logo-white.svg", height: 25%)
} else {
image("../resources/logos/tt-logo-black.svg", height: 25%)
}
})
// get the title of the current chapter
let title = context query(selector(heading.where(level: 1)).before(here())).last().body
let pg_num = context counter(page).display(display_pg_as)
let TITLE_SPACING = 0.5cm
let LOGO_SPACING = 0.25cm
let set_1 = {strong(pg_num); h(TITLE_SPACING); emph(title); h(1fr); emph(shuttle); h(LOGO_SPACING); logo}
let set_2 = {logo; h(LOGO_SPACING); emph(shuttle); h(1fr); emph(title); h(TITLE_SPACING); strong(pg_num)}
// actual styling
context {
// alternate odd-even pages
if calc.even(counter(page).get().first()) {
if flip_ordering {set_2} else {set_1}
} else {
if flip_ordering {set_1} else {set_2}
}
}
}
#let project(
title: "Title",
author: ("Author 1", "Author 2"),
repo_link: "!!! missing repository link !!!",
description: "!!! Missing description !!!",
address: "----",
clock: "No Clock",
type: "HDL",
wokwi_id: none,
danger_level: none,
danger_reason: none,
body
) = {
show: styling;
show: styling_set_par;
// make fake heading - this is the one that gets shown in the table of contents
// which has the nice address marker next to it
let fake_heading = block(
heading(level: 2, outlined: true, bookmarked: false)[
#box(baseline: 0.4em, badge(colours.BADGE_TEAL, strong(raw(address))))
#title
]
)
// move fake heading so it doesn't affect layout
place(top + left, hide(fake_heading))
// make heading thats seen on the project page
heading(level: 2, outlined: false, bookmarked: true, title)
// display author names
// if 1, it is displayed as is
// if 2, it is displayed as "a & b"
// if >2, it is displayed as "a, b & c"
let author_text = []
author_text += [by *#author.at(0)*]
if author.len() == 2 {
author_text += [ & *#author.at(1)*]
} else if author.len() > 2 {
let names = author.slice(1, author.len()-1)
for name in names {
author_text += [, *#name*]
}
author_text += [ & *#author.at(author.len()-1)*]
}
author_text
// makes badges array, add address first
let badges = (badge(colours.BADGE_TEAL, strong(raw(address))),)
if clock != "No Clock" {badges.push(badge(colours.BADGE_BLUE, strong(raw(clock))))}
badges.push(badge(colours.BADGE_PINK, strong(raw(type + " Project"))))
// add asic danger callout if necessary
let danger_callout
if danger_level != none {
if danger_level == "medium" {
badges.push(badge(colours.WARNING_STRONG, strong(raw("Medium Danger"))))
danger_callout = callout(
"warning",
raw("This project can damage the ASIC under certain conditions."),
raw(danger_reason)
)
} else if danger_level == "high" {
badges.push(badge(colours.DANGER_STRONG, strong(raw("High Danger"))))
danger_callout = callout(
"danger",
raw("This project will damage the ASIC."),
raw(danger_reason)
)
} else {
panic([unexpected danger_level value (#danger_level)])
}
}
// add badges to page, unpack badge array
grid(columns: badges.len(), column-gutter: 1em, ..badges)
// hardcode these repo/wokwi links to be black and to not follow link-override-colour
link(repo_link, text(black, raw(repo_link.trim("https://", at: start))))
if wokwi_id != none {
let wokwi_link = "https://wokwi.com/projects/" + wokwi_id
parbreak()
link(wokwi_link, text(black, raw(wokwi_link.trim("https://", at: start))))
}
// add description and danger callout to page
quote(block: true, quotes: true, emph(description))
danger_callout
set heading(offset: 2)
// ensure each figure and footnote is only counted within its project
// format numbering as "<project_address>.<figure_count>"
let project_numbering(count) = {address.trim("-", at: start) + "." + str(count)}
counter(figure.where(kind: image)).update(0)
counter(footnote).update(0)
set figure(numbering: project_numbering)
set footnote(numbering: project_numbering)
body
pagebreak(weak: true)
}
#let splash_chapter_page(
title,
page_colour: white,
invert_text_colour: false,
footer_text: none,
additional_content: none
) = {
page(
fill: page_colour,
footer: context {
_footer(
footer_text,
invert_text_colour: invert_text_colour,
flip_ordering: _flip_footer_ordering.final()
)
},
// page body - center title and add additional content if necessary
{
set text(white) if invert_text_colour
// make headings
align(center + horizon, block(text(size: 100pt, strong(title))))
place(top + left, hide(heading(level: 1, title)))
// make info box if needed
if additional_content != none {
set text(black)
place(center + bottom, block(fill: white, inset: 10pt, additional_content))
}
}
)
}
// make a tiling logo page
#let tiling_logo_page() = {
let pattern = tiling(
size: (3cm, 3cm),
spacing: (1cm, 1cm),
image("../resources/logos/tt-logo-light-grey.svg")
)
page(
background: rect(width: 110%, height: 105%, inset: 0pt, outset: 0pt, stroke: none, fill: pattern),
[] // empty page
)
}
#let datasheet(
shuttle_id: none,
shuttle_name: none,
repo_link: none,
theme: "classic",
projects: none,
show_pinouts: "openframe",
theme_override_colour: none,
date: datetime.today(),
link_disable_colour: false,
link_override_colour: none,
chip_viewer_link: none,
qrcode_follows_theme: false,
body
) = {
set document(
title: [#shuttle_name Datasheet],
author: "Tiny Tapeout & Contributors",
description: [The official Tiny Tapeout datasheet for #shuttle_id. Template by Kristaps Jurkans (bluesky/\@krisj.dev)]
)
show: styling;
let date_str = date.display("[month repr:long] [day padding:none], [year]")
// contains title, repo link and compilation date
let cover_text = align(center)[
#text(size: 32pt, strong[#shuttle_name Datasheet])
#link(
repo_link,
text(
size: 14pt,
font: "Martian Mono",
repo_link.trim("https://", at: start)
)
)
#v(2.5cm)
#text(size: 16pt, weight: "medium", date_str)
]
// configure theme variables
let selected_theme_colour = colours.THEME_PLUM // default fill
if theme_override_colour != none {selected_theme_colour = theme_override_colour}
let qrcode_colour = black
if qrcode_follows_theme and theme == "bold" {qrcode_colour = selected_theme_colour}
// make titlepage
if theme == "classic" {
image("../resources/logos/tt-logo-colourful.png")
cover_text
} else if theme == "bold" {
set page(
background: image("../resources/backgrounds/colourful-background-gds-o10-bw.png", height: 100%),
fill: selected_theme_colour
)
align(
center + horizon,
image("../resources/logos/tt-logo-white.svg", height: 60%)
)
set text(white)
cover_text
} else if theme == "monochrome" {
align(
center + horizon,
image("../resources/logos/tt-logo-black.svg", height: 60%)
)
cover_text
}
// style link colour
// moved after title page since theme-override-colour would cause it to blend in with the background
let link_colour = luma(0%)
if not link_disable_colour {
// if override colour specified, set it to that
// else fall back to default link colour
if link_override_colour != none {
link_colour = link_override_colour
} else {
link_colour = colours.LINK_DEFAULT
}
}
show link: set text(link_colour)
// add tiling logo page (this is pg2 of the datasheet)
tiling_logo_page()
show: styling_set_par;
// setup for table of contents
set page(footer: _footer(shuttle_id, invert_text_colour: false, display_pg_as: "i"))
counter(page).update(1)
// add spacing for each H1, and make H1 bold
show outline.entry.where(level: 1): set block(above: 1em)
show outline.entry.where(level: 1): strong
// make actual table of contents
outline(
depth: 2,
title: heading(level: 1, outlined: false, bookmarked: true, "Table of Contents")
)
pagebreak(weak: true)
// determine whether we need to flip the footer ordering depending on if the table fo contents
// ended on an odd or even page
context {
_flip_footer_ordering.update(calc.even(counter(page).get().last()))
}
set page(footer: context {_footer(
shuttle_id, display_pg_as: "1", flip_ordering: _flip_footer_ordering.final()
)})
// reset page counter so that it starts counting actual content now
counter(page).update(1)
// make chip render pages
context {
let chip_renders = _chip_render_content.final()
if chip_renders != none {
let qr
let qr_grid
if chip_viewer_link != none {
qr_grid = annotated_qrcode(
chip_viewer_link, "Online chip viewer",
tiaoma_args: ("scale": 2.0, "fg-color": qrcode_colour)
)
}
let sponsor_grid
if _chip_render_sponsor_text.final() != none and _chip_render_sponsor_logo.final() != none {
sponsor_grid = grid(
columns: 1,
rows: 3,
align: center + horizon,
row-gutter: 1em,
_chip_render_sponsor_text.final(),
_chip_render_sponsor_logo.final(),
[] // added for padding
)
}
let content
let content_arr = ()
if sponsor_grid != none {
content_arr.push(sponsor_grid)
}
if qr_grid != none {
content_arr.push(qr_grid)
}
if content_arr.len() >= 1 {
content = grid(
columns: content_arr.len(),
rows: 1,
column-gutter: 1em, row-gutter: 1em,
align: center + horizon,
..content_arr
)
}
if theme == "bold" {
splash_chapter_page(
"Chip Renders",
page_colour: selected_theme_colour,
invert_text_colour: true,
footer_text: shuttle_id,
additional_content: content
)
} else {
splash_chapter_page(
"Chip Renders",
invert_text_colour: false,
footer_text: shuttle_id,
additional_content: content
)
}
// display chip renders
chip_renders
}
}
// make project splash page + show all projects
if projects != none {
if theme == "bold" {
splash_chapter_page(
"Projects",
page_colour: selected_theme_colour,
invert_text_colour: true,
footer_text: shuttle_id
)
} else {
splash_chapter_page(
"Projects",
footer_text: shuttle_id
)
}
projects
}
// reset counters back to 0, to be used in the info section of the datasheet
counter(figure.where(kind: image)).update(0)
counter(footnote).update(0)
body
// add informational content
// chip pinout diagram
page(include "../chapters/pinout.typ")
// multiplexer infrastructure explanation
page({
include "../chapters/tt-multiplexer.typ"
if show_pinouts == "caravel" {
pins.caravel
} else if show_pinouts == "openframe" {
pins.openframe
} else {
panic([unknown pinout table referenced (#show_pinouts)])
}
})
// add funding/sponsor page
page(context {
let funding_content = _funding_content.final()
let alt_title = _funding_alt_title.final()
if funding_content != [] {
if alt_title != none {
heading(level: 1, alt_title)
} else {
heading(level: 1, "Funding")
}
}
funding_content
})
page(include "../chapters/team.typ")
page(include "../chapters/using-this-datasheet.typ")
// add call to action page
if theme == "classic" or theme == "monochrome" {
page(call_to_action_page())
} else if theme == "bold" {
page(
fill: selected_theme_colour,
footer: none,
{
set text(white)
call_to_action_page(qrcode_colour: black)
}
)
}
}
#let funding(doc, alt_title: none) = {
context {
_funding_content.update(doc)
_funding_alt_title.update(alt_title)
}
}
#let renders(sponsor_text: none, sponsor_logo: none, doc) = {
context {
_chip_render_content.update(doc)
_chip_render_sponsor_text.update(sponsor_text)
_chip_render_sponsor_logo.update(sponsor_logo)
}
}
#let art(id, rot: 90deg) = {
// all artwork is assumed to be external (hosted in a separate repo)
let art_img = get_image_by_id("artwork", id, height: 100%)
let info = yaml("../resources/external/manifest.yaml").at("artwork").at(id)
let attribution = strong[
#info.title $dash.fig$
#if info.at("designer", default: none) != none [Designed by #info.designer.]
Illustrated by #info.artist.
]
// heading shown in table of contents
let art_heading = [#box(baseline: 0.4em, badge(colours.BADGE_PURPLE, strong(`Artwork`))) #info.title]
set text(fill: white, size: 10pt)
page(
paper: "a4",
margin: 0pt,
footer: none,
// add artwork as background
background: rotate(rot, reflow: true, art_img),
{
// make fake & read heading
// first is shown in ToC, the second in the PDF list
place(top, hide(heading(level: 2, outlined: true, bookmarked: false, art_heading)))
place(top, hide(heading(level: 2, outlined: false, bookmarked: true)[(Artwork) #info.title]))
// determine position for artwork attribution
context {
let attribution_placement = bottom + left
// if even
if calc.even(counter(page).get().first()) {
// but flipped
if _flip_footer_ordering.final() {
attribution_placement = bottom + right
} else {
attribution_placement = bottom + left
}
// if odd
} else {
if _flip_footer_ordering.final() {
attribution_placement = bottom + left
} else {
attribution_placement = bottom + right
}
}
// add artwork attribution
place(
attribution_placement,
block(
fill: colours.ARTWORK_GREY_INFO,
inset: 4pt,
attribution
)
)
}
}
)
}
#let add_render(title, subtitle: none, img) = {
page(
align(center, grid(
columns: 1,
row-gutter: 10pt,
align: center,
heading(level: 2, title),
subtitle,
img
)
)
)
}
+178
View File
@@ -0,0 +1,178 @@
#import "@preview/tiaoma:0.3.0"
#import "colours.typ" as colours
/// Create a badge with a given colour and text
///
/// NOTE: This function will replace any instances of a hyphen ("-")
/// with a coloured zero digit. This is intended, and is used for
/// the address badge.
/// - colour (color): Colour of the badge
/// - doc (content, str): Text to display within the badge
/// -> content
#let badge(colour, body) = {
set text(white)
show "-": text(colours.BADGE_MUTED_TEAL, "0")
rect(fill: colour, body)
}
/// Create a callout to display important information
///
/// - type (): Callout type (warning, danger, info, custom)
/// - title (str): Title of the callout
/// - custom_title_colour (color): Colour to use for the title of the custom callout
/// - custom_body_colour (color): Colour to use for the body of the custom callout
/// - body (content, str): Content to display in the body of the callout
/// -> content
#let callout(
type,
title,
custom_title_colour: none,
custom_body_colour: none,
body
) = {
set par(justify: false)
let title_colour
let body_colour
if type == "warning" {
title_colour = colours.WARNING_STRONG
body_colour = colours.WARNING_WEAK
} else if type == "danger" {
title_colour = colours.DANGER_STRONG
body_colour = colours.DANGER_WEAK
} else if type == "info" {
title_colour = colours.INFO_STRONG
body_colour = colours.INFO_WEAK
} else if type == "custom" {
title_colour = custom_title_colour
body_colour = custom_body_colour
} else {
panic([unknown callout type (#type)])
}
set text(white)
// make body first
block(
fill: body_colour,
width: 100%,
inset: 8pt,
{
// make title
block(fill: title_colour, width: 100%, outset: 8pt, strong(title))
body
}
)
}
/// Create an annotated QR code
///
/// An annotated QR code consists of a title, the QR code, and the link to the website.
/// They are stacked on top of each other.
///
/// - url (str): Link to a website
/// - title (str): Title of the QR code
/// - title_colour (color): Colour of the title of the QR code
/// - url_colour (color): Colour of the link
/// - tiaoma_args (dict): Arguments to pass to the tiaoma package
/// -> grid
#let annotated_qrcode(
url,
title,
title_colour: black,
url_colour: black,
tiaoma_args: (:)
) = {
let qr = tiaoma.qrcode(url, options: tiaoma_args)
grid(
columns: 1,
rows: 3,
align: center + horizon,
row-gutter: 1em,
text(fill: title_colour, title),
qr,
// make url be the width of the QR code
context {
block(
width: measure(qr).width + 1cm,
height: auto,
breakable: false,
link(url, text(url_colour, url.trim("https://", at: start))))
}
)
}
/// Retrieve an image from via an ID
///
/// The artwork repo must be cloned into resources/external, and its `manifest.yaml`
/// must be present for this function to work.
///
/// - type (str): Type of image to fetch (must be a key in one of the manifests)
/// - id (str): ID of image to fetch
/// - args (arguments): Arguments to supply to `image()`
/// -> content
#let get_image_by_id(type, id, ..args) = {
// external manifest is used for artwork repo
// since large photos would bloat the template size
let external_manifest = yaml("../resources/external/manifest.yaml")
let local_manifest = yaml("../resources/manifest.yaml")
let combined_manifest = (:)
// combine the two
for (k, v) in local_manifest.pairs() {
combined_manifest.insert(k, v)
}
for (k, v) in external_manifest.pairs() {
combined_manifest.insert(k, v)
}
if type not in combined_manifest {
panic("type not in either local or external manifest")
}
let root_path = "../resources"
if type in external_manifest {
root_path += "/external"
}
let img_details = combined_manifest.at(type).at(id)
// make image
image(root_path + "/" + type + "/" + img_details.file, ..args)
}
/// Create a horizontal line
///
/// Used for `pandoc` compatability
///
/// -> content
#let horizontalrule() = {
line(
length: 100%,
stroke: 2pt + colours.HORIZONTAL_RULE_GREY
)
}
/// Create a block quote
///
/// Used for `pandoc` compatability
///
/// - body (content): Body of the block quote
/// -> content
#let blockquote(body) = {
quote(
block: true,
body
)
}
+3
View File
@@ -0,0 +1,3 @@
#import "lib.typ" as lib
#import "datasheet.typ" as datasheet
#import "colours.typ" as colours
+10
View File
@@ -0,0 +1,10 @@
[package]
name = "tt-docs"
version = "1.0.0"
authors = ["Kristaps Jurkans <kris.jurkans@gmail.com>"]
license = "Apache-2.0"
description = "Tiny Tapeout Docs"
repository = "?"
keywords = ["TinyTapeout"]
entrypoint = "src/tt.typ"
exclude = ["images"]