mirror of
https://github.com/TinyTapeout/tt-support-tools.git
synced 2026-11-03 04:36:09 +01:00
feat(datasheet): add typst datasheet flow
This is a squash of 5 commits in order to add the new datasheet flow. fix(datasheet): ensure datasheet can use images properly fix(datasheet): white page when funding was not specified This was caused by creating a page before first checking whether there was any content for that page beforehand, so it would result in a rogue white page with no content. fix(datasheet): missing analog pin tables fix(datasheet): tweak pandoc settings Switching from `gfm` to `markdown` should enable more formatting options. The extensions have been configured to be similar to `gfm` but provide some additional things, like `line_blocks` and `lists_without_preceding_blankline`s.
This commit is contained in:
@@ -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)
|
||||
)
|
||||
)
|
||||
]
|
||||
@@ -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.
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#import "../src/lib.typ": get_image_by_id
|
||||
|
||||
= Pinout
|
||||
|
||||
The chip is packaged in a 64-pin QFN package. The pinout is shown below.
|
||||
|
||||
#align(center, get_image_by_id("images", "chip_pinout_qfn64"))
|
||||
|
||||
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.
|
||||
@@ -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
|
||||
@@ -0,0 +1,97 @@
|
||||
#import "../src/lib.typ": get_image_by_id
|
||||
|
||||
= 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, get_image_by_id("images", "mux_address_select_waveform"))
|
||||
)
|
||||
|
||||
#figure(
|
||||
caption: [Mux Diagram],
|
||||
align(center, get_image_by_id("images", "mux_diagram", height: 55%))
|
||||
)
|
||||
|
||||
#figure(
|
||||
caption: [Mux Controller Diagram],
|
||||
align(center, get_image_by_id("images", "mux_controller"))
|
||||
)
|
||||
|
||||
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.
|
||||
Reference in New Issue
Block a user