Compare commits

...

123 Commits

Author SHA1 Message Date
Joachim Strömbergson 0454e023cd
Ignore application_fpga_par.json
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2024-04-25 11:29:47 +02:00
Joachim Strömbergson e961f46e79
Update Verilog version to 2005 for linting
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2024-04-24 08:44:08 +02:00
Joachim Strömbergson f655196af7
Clarify the functional description of the touch_sense core
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2024-04-22 16:03:08 +02:00
dehanj a5e30f1203
CI: Divide into separate jobs.
- Gives a better overview of CI and the different checks, without going
  into the logs too deeply.
- Cache: use a unique key for each run, and remove 'restore key' since it
  could potentially retrieve the wrong bitstream. The stragegy should be
  to fail if a cache is not present, not fetch a bitstream from a
  different build.
2024-04-19 12:16:41 +02:00
dehanj d7b8bb26a9
CI: move check-hash to separate job.
- This makes it easier to see if CI fails on hashes (which might be
  expected during development) or something else.
2024-04-17 12:10:28 +02:00
Michael Cardell Widerkrantz 3cf218469c
hw/tool: UDI/UDS storage
Describe how the UDI and UDS are actually stored in the FPGA, how they
are accessed, and how they are initialled by the patch_uds_udi.py
script.

Co-authored-by: Joachim Strömbergson <joachim@assured.se>
2024-04-03 11:27:00 +02:00
dehanj 1c90b1aa3d
Add release notes for TK1-24.03
Clarifying earlier release notes.
2024-03-26 13:34:54 +01:00
dehanj 574e17f26a
Update hash of bitstream and firmware 2024-03-26 13:09:06 +01:00
dehanj 4bd249816a
fw: Remove unused header includes 2024-03-26 13:09:06 +01:00
dehanj 3a6a60ff26
fw: Protect zeroisation against compiler optimisation.
The memset() responsible for the zeroisation of the secure_ctx under
the compute_cdi() function in FW's main.c, was optimised away by the
compiler. Instead of using memset(), secure_wipe() is introduced
which uses a volatile keyword to prevent the compiler to try to
optimise it. Secure_wipe() is now used on all locations handling
removal of sensitive data.
2024-03-26 13:09:01 +01:00
dehanj c85b5311cd
Change filename personalize.py to patch_uds_udi.py
Also adding a more detailed explaination of what the script intends to
do
2024-03-26 13:07:11 +01:00
Michael Cardell Widerkrantz 88c6036215
Add mitigations to threat model
Describe under each release what kind of threat mitigations we have
added.
2024-03-25 17:27:00 +01:00
dehanj 0e166e4159
Build tp1 firmware in CI 2024-03-22 11:43:39 +01:00
dehanj 92136983c5
Update hash of bitstream and firmware 2024-03-22 11:25:40 +01:00
Michael Cardell Widerkrantz 09c1f3f549
Silence splint somewhat
The only real changes are some unitialized variables and that we now
make explicit that we don't care about the return value from memset().
2024-03-22 11:03:13 +01:00
Michael Cardell Widerkrantz b0efcf019e
Include static analysis in CI
- Exclude splint from CI, so we make another target for it "splint",
  which we might include in the "check" target later.

- Move the analysis runs earlier in CI so they, including indentation
  checks, fail first.

- Include printouts of hashen in check-binary-hashes to easier see
  what the digest are if it fails in CI.
2024-03-22 11:03:13 +01:00
Michael Cardell Widerkrantz d10c4972d7
Use tkey-builder:4 2024-03-22 10:54:33 +01:00
Michael Cardell Widerkrantz da40edfc51
tkey-builder: Include clang-tidy & splint
To be able to run statical analysis on source, include clang-tidy and
splint (see make check) in tkey-builder.
2024-03-21 15:03:08 +01:00
Michael Cardell Widerkrantz 48324fe5b3
tp1 fw: Update pico-sdk to 1.5.1 2024-03-21 14:17:01 +01:00
dehanj 2ff2e9a91d
fw: remove duplicate defines in tk1_mem.h 2024-03-21 10:28:51 +01:00
Michael Cardell Widerkrantz 661a6458c8
fw: Add missing TK1_MMIO_BASE
TK1_MMIO_BASE and _SIZE needed by at least qemu.
2024-03-21 10:09:38 +01:00
dehanj 57a6ee2a12
Use tkey-builder:3 as default when building 2024-03-20 17:19:59 +01:00
dehanj 8ca4241ade
Disable non-zero exit for verilog linter in CI, see issue 182. 2024-03-20 16:39:53 +01:00
Joachim Strömbergson de668a0244
Clean up code and silence warnings after linting
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2024-03-20 16:39:53 +01:00
Joachim Strömbergson f364b523cf
Change UDS address to three bits to match input port connection 'addr'
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2024-03-20 16:39:53 +01:00
Joachim Strömbergson bbde62d3f5
Add PINMISSING lint ignore for I1 and I2 SB_LUT4 cells
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2024-03-20 16:39:52 +01:00
Joachim Strömbergson 8731908cb1
Support incremental builds for the bitstream.
By patching the UDS and UDI into an already built bitstream, it is now
not necessary to rebuild the entire build flow when changing the UDS
and the UDI. This lowers re-build times significantly.

Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2024-03-20 16:39:45 +01:00
Joachim Strömbergson 29fd8338a7
Update the bitstream hash
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2024-03-20 14:36:56 +01:00
Joachim Strömbergson 8784a24b33
Change cpu_monitor to security_monitor and to also check RAM
Change name of cpu_monitor to security_monitor and increase its
functionality to include RAM access violations. If addresses in RAM
but outside of physical RAM is accessed in any way the
security_monitor traps the CPU in the same way as it already did for
execution violations.
2024-03-20 14:36:55 +01:00
Joachim Strömbergson 3fb6d66cf3
Add set-only register for the force_trap signal to ensure
that the device must be reset to get out of trap. This
change also breaks a critical path.

Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2024-03-20 14:36:55 +01:00
Joachim Strömbergson 4c3e210a00
Only set ram_we to cpu_wstrb in RAM_PREFIX
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2024-03-20 14:36:55 +01:00
Joachim Strömbergson e48c0fc7d9
Implement cs0 and cs1 as logic equations, not muxes
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2024-03-20 14:36:55 +01:00
Michael Cardell Widerkrantz 0590445f3d
Add testbench targets on top-level
The testbenches live in their own Makefiles under
hw/application_fpga/core/*/toolruns (except picorv32). Let's add a
top-level target to build and run them.

In order to run core testbenches, use

  cd hw/application_fpga
  make tb

or if using Podman:

  cd contrib
  make run-tb

to run the same target in a container.
2024-03-20 13:47:12 +01:00
Joachim Strömbergson ea9271292c
Add Icarus Verilog compiler, simulator used by testbenches
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2024-03-20 13:47:12 +01:00
dehanj 159b5b052b
Updated readme and docs to point at dev.tillitis.se. 2024-03-19 17:06:34 +01:00
Michael Cardell Widerkrantz 4d4db70590
fw: Change ASLR name in MMIO
Use _RAM_ADDR_RAND instead of _RAM_ASLR since this is not OS-level
ASLR we're talking about. It's address randomization as seen from
outside of the CPU, not from the process running inside it. Ordinary
ASLR is visible from the CPU.
2024-03-19 14:36:31 +01:00
Michael Cardell Widerkrantz f40987b138
fw: Change license for use with qemu
This file is also included in at least qemu (GPL-2.0-or-later) besides
tillitis-key1 (GPL-2.0-only) and tkey-libs (GPL-2.0-only) so it's
licensed as GPL v2 or later even if the rest of the project is -only.
2024-03-19 14:36:31 +01:00
Michael Cardell Widerkrantz c48724e115
fw: Change memory constants to defines
Instead of putting  memory constant into an enum we use defines.

Use the direct memory address instead of ORing constants together to
compute the address.

An enum in ISO C is a signed int. Some of are memory addresses are to
large to fit in a signed int. This is not a problem since we're not
using ISO C (-std=gnu99) but it doesn't look very nice if you turn on
pedantic warnings. Also, if someone would use another compiler which
at least supports the inline assembly we use, but possible not other
GNU extensions, things would probably break.
2024-03-19 14:36:20 +01:00
dehanj 1e34ddcfa6
Update linter to Verilog-2005 2024-03-19 10:45:37 +01:00
Michael Cardell Widerkrantz 746d7f0e0d
Use pedantic warnings
Use pedantic warnings but still allow inline assembly, so turn off
language-extension-token warnings.
2024-03-19 09:25:37 +01:00
Michael Cardell Widerkrantz e085d0ebd0
Add void to function signatures meant to be used without args 2024-03-19 08:41:39 +01:00
Michael Cardell Widerkrantz 046343e525
Change memory constants to defines
Instead of putting  memory constant into an enum we use defines.

Use the direct memory address instead of ORing constants together to
compute the address.

An enum in ISO C is a signed int. Some of are memory addresses are to
large to fit in a signed int. This is not a problem since we're not
using ISO C (-std=gnu99) but it doesn't look very nice if you turn on
pedantic warnings. Also, if someone would use another compiler which
at least supports the inline assembly we use, but possible not other
GNU extensions, things would probably break.
2024-03-19 08:40:04 +01:00
Michael Cardell Widerkrantz e2bd38c540
fw: Remove unusued forever_redflash()
Since we now use assert() and feed the CPU an unimplemented
instruction we have no need for this.
2024-03-18 16:19:59 +01:00
dehanj 9d36acde08
FW: Force the CPU to hang on errors 2024-03-14 15:48:10 +01:00
Michael Cardell Widerkrantz fcccee8ec8
Tkey-builder: Use Ubuntu-23.10, yosys-0.36 & nextpnr-0.6 2024-03-14 14:22:57 +01:00
dehanj d83f235fd3
Add injection molded plastic case 2023-12-11 13:48:39 +01:00
dehanj 7019cd9048
remove whitespaces and tabs 2023-12-07 17:16:31 +01:00
dehanj 2014923966
Isolate ringbuffer index, copy inbound usb data to new buffer 2023-12-07 17:15:24 +01:00
dehanj 6d5da25321
Translate + clean up 2023-11-07 10:59:21 +01:00
dehanj f83abed4e4
Add gpio for debug purpose 2023-11-06 12:19:00 +01:00
dehanj 7f2efb68f9
Inclulde the latest release tk1-23.03-2-Bellatrix 2023-09-06 13:29:58 +02:00
Joachim Strömbergson bc661536dc
Updating threat model with new section on TKey Unlocked
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-09-06 13:29:53 +02:00
dehanj a453aae031
New plastic clip and update BOM for TP1 2023-09-01 13:41:05 +02:00
Michael Cardell Widerkrantz 5f0a9bec9a
Add flash make podman target
Use the iceprog in the tkey-builder image to program the SPI flash in
the TKey.
2023-09-01 13:39:25 +02:00
Daniel Lublin 7cd085a17e
Avoid confusing errors by checking for programmer and stick first
Signed-off-by: Daniel Lublin <daniel@lublin.se>
2023-08-30 11:37:03 +02:00
blaufish 426b56ebf5
Verilog 2001 rule; use wires for assignments, not registers. (#139) 2023-08-16 10:44:18 +02:00
blaufish cced6aec31
Explicity make uart_core.rx_data a wire (#140) 2023-08-16 10:43:04 +02:00
Joachim Strömbergson 1ab36c7c83
Fix link to system_description
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:29 +02:00
Joachim Strömbergson 9ee4ce5a23
Try and fix the broken link in the threat model
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:29 +02:00
Joachim Strömbergson 022bf0bbf9
Change name of pin constraint file to match tk1 pcb
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:29 +02:00
Joachim Strömbergson 17ddb1f84a
Minor fix of ackronyms in the README
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:29 +02:00
Joachim Strömbergson 3e75818879
Fix spelling of toolruns dir
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:29 +02:00
Joachim Strömbergson 5e34802d1c
Update readme with info on API, status, usage and performance
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:28 +02:00
Joachim Strömbergson 361381210e
Add an initial testcase. Hard to simulate entropy
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:28 +02:00
Joachim Strömbergson a76fc19c65
Add Makefile, testbench and support module needed to build som target
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:28 +02:00
Joachim Strömbergson a517552c85
Update README with info about the core functions
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:28 +02:00
Joachim Strömbergson bc7dfea9c4
Add test9: EXE monitor control and detection
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:28 +02:00
Joachim Strömbergson 4644c79cbd
Adding test 8: GPIO test
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:28 +02:00
Joachim Strömbergson 394e437c91
Add test7: Control of LED RGB outputs.
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:27 +02:00
Joachim Strömbergson 480f4e3d45
Add test6: Test that RAM ASLR and SCRAMBLE registers can be set by fw
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:27 +02:00
Joachim Strömbergson d70937c11b
Improved messaging from the testbench
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:27 +02:00
Joachim Strömbergson 59af60bdd5
Add test4: writing and reading blake2s entry point
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:27 +02:00
Joachim Strömbergson dc2903a5b4
Update test3 to check that writing to CDI works when in fw mode
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:27 +02:00
Joachim Strömbergson 16a91bfdd5
Adding test 3: Reading out the CDI
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:27 +02:00
Joachim Strömbergson 1f47991ac2
Add test2: Read out UDI
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:27 +02:00
Joachim Strömbergson 6d9890d050
Add test1: Read out name and version
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:26 +02:00
Joachim Strömbergson 49eac9d101
Complete init of DUT and input, output display
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:26 +02:00
Joachim Strömbergson 1909833952
Add header with info and license
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:26 +02:00
Joachim Strömbergson b1993742bb
Fix testbench buik including DUT instantiation
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:26 +02:00
Joachim Strömbergson 2fb61bba73
Add UDI used during simulation
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:26 +02:00
Joachim Strömbergson cb2fd573b3
Add dummy LED macro driver module needed for simulation
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:26 +02:00
Joachim Strömbergson 61598f57e5
Add initial version of testbench annd Makfile for building sim target
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:26 +02:00
Joachim Strömbergson 97e3e25d98
Update the UART README with info about the core and its API
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:25 +02:00
Joachim Strömbergson 704d67c8ab
Add Makefile to build sim. Debug sim build
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:25 +02:00
Joachim Strömbergson 819b93deff
Complete testbench and update README with API info
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:25 +02:00
Joachim Strömbergson bbff7576df
Fix markdown syntax for API listing
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:25 +02:00
Joachim Strömbergson e6eaad87dc
Update README with info about the timer API
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:25 +02:00
Joachim Strömbergson 4c54b4b60b
Add info about the API in the README
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:25 +02:00
Joachim Strömbergson 18bb9b8599
Making the testbench self checking
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:25 +02:00
Joachim Strömbergson 1d2a71ec0c
Change file extension to markdown
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:24 +02:00
Joachim Strömbergson 1e97e27e66
Updated README, completed testcase and cleaned up the testbench
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:24 +02:00
Joachim Strömbergson de7f273f71
Fixed nits in word
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:24 +02:00
Joachim Strömbergson 526df27bae
Clarify what locked down means and orogin of the UDS in Bellatrix
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:24 +02:00
Joachim Strömbergson 9d188a2f7f
Add more info about how the timer works
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:24 +02:00
Joachim Strömbergson 7c9dfaf45a
Add testcase for the timer top level wrapper and clean up the tb
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:24 +02:00
Joachim Strömbergson c185849ae4
Minor cleanup of README, testbench and Makefile
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:24 +02:00
Michael Cardell Widerkrantz e0e871c730
Include debug symbols in the ELF 2023-07-04 09:04:23 +02:00
Daniel Lublin ea7d64c29f
doc: update to refs to in-tree TP-1 firmware
Signed-off-by: Daniel Lublin <daniel@lublin.se>
2023-07-04 09:04:23 +02:00
Daniel Lublin 65e3ea015d
Revise terminology; it's device app and client app
Signed-off-by: Daniel Lublin <daniel@lublin.se>
2023-07-04 09:04:23 +02:00
Joachim Strömbergson 3d787886b6
Clarify warm boot attack mitigtions and scope for Bellatrix
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:23 +02:00
Joachim Strömbergson 6d0a761e65
Make memeq function side channel silent
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:23 +02:00
Daniel Lublin 2ddd523c29
Use tkey-builder:2; add hashes & checks for bitstream & fw bins
Signed-off-by: Daniel Lublin <daniel@lublin.se>
2023-07-04 09:04:23 +02:00
Joachim Strömbergson aac03357e9
Add note about clearing stray touch events
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-07-04 09:04:23 +02:00
dehanj 8a5d1b3518
Doc: release notes 2023-07-04 09:04:22 +02:00
Monrad-Aas 33abc7fcfe
pdf printed 2023-07-04 09:04:22 +02:00
Monrad-Aas a964d3bb89
Replaced Cap w. spring contacts
Signed-off-by: Monrad-Aas <isak.monrad-aas@sigma.se>
2023-07-04 09:04:22 +02:00
Daniel Lublin 47c7e55cba
doc: release notes
Signed-off-by: Daniel Lublin <daniel@lublin.se>
2023-03-29 17:08:33 +02:00
Daniel Lublin ff71f796e3
toolchain: use new image by default
Signed-off-by: Daniel Lublin <daniel@lublin.se>
2023-03-29 17:03:53 +02:00
Daniel Lublin 508d044430
toolchain: revise Makefile for container builds
Use podman primarily. Default to using the fully qualified image from
ghcr.io

Signed-off-by: Daniel Lublin <daniel@lublin.se>
2023-03-29 11:45:43 +02:00
Daniel Lublin fae06116dd
toolchain: pin yosys to latest tag, icestorm to recent commit, use newer nextpnr
The icebram and nextpnr issues have been resolved.

Signed-off-by: Daniel Lublin <daniel@lublin.se>
2023-03-29 11:45:43 +02:00
Daniel Lublin 2991dcef68
doc: harmonize w dev-tillitis
Signed-off-by: Daniel Lublin <daniel@lublin.se>
2023-03-29 11:45:18 +02:00
Daniel Lublin 9aece67a41
testfw: test read bytes from CDI
Signed-off-by: Daniel Lublin <daniel@lublin.se>
2023-03-28 11:44:13 +02:00
Daniel Lublin eeed342b96
testfw: make output slightly more readable
Signed-off-by: Daniel Lublin <daniel@lublin.se>
2023-03-28 11:32:56 +02:00
Daniel Lublin aa86c9d58c
testfw: compare UDS correctly, correct byte-order
Also don't let fwram success overwrite anyfailed

Signed-off-by: Daniel Lublin <daniel@lublin.se>
2023-03-28 11:32:56 +02:00
Daniel Lublin dcc6351f79
testfw: use a func for fail prints
Now testfw fits again (when built with -Os)

Signed-off-by: Daniel Lublin <daniel@lublin.se>
2023-03-28 11:32:56 +02:00
Daniel Lublin bcac8eeaf4
testfw: update check for new known UDS; correctly and always print UDS
Signed-off-by: Daniel Lublin <daniel@lublin.se>
2023-03-28 11:32:56 +02:00
Joachim Strömbergson 909b95cdaa
Clarify access behaviour of the UDS
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-03-28 10:02:57 +02:00
Joachim Strömbergson 688910bee4
Use different byte values in test UDS words
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
2023-03-28 09:26:23 +02:00
Michael Cardell Widerkrantz c126199a41
fw: UDS not byte-readable
Since UDS is not byte-readable we copy it by word to local_uds. Now
UDS lives for a short while in local_uds on the stack in FW_RAM and in
the internal buffer of the blake2s context (also in FW_RAM) but is
very soon overwritten.
2023-03-27 16:24:02 +02:00
Michael Cardell Widerkrantz fae2447344
testfw: Test UDS against known good 2023-03-27 16:24:02 +02:00
Daniel Lublin e3ee7c5bab
doc: adjust to 128-byte framelen 2023-03-27 10:58:20 +02:00
Michael Cardell Widerkrantz cefb6ca9c1
fw: Change max frame size to 128 bytes 2023-03-27 10:58:16 +02:00
Daniel Lublin 29c5ab1108
doc: correct deps
Signed-off-by: Daniel Lublin <daniel@lublin.se>
2023-03-27 10:31:23 +02:00
90 changed files with 125044 additions and 47730 deletions

View File

@ -10,13 +10,64 @@ on:
workflow_dispatch: {}
jobs:
ci:
check-firmware:
runs-on: ubuntu-latest
container:
image: ghcr.io/tillitis/tkey-builder:1
image: ghcr.io/tillitis/tkey-builder:4
steps:
- name: checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
# fetch-depth: 0
persist-credentials: false
- name: fix
# https://github.com/actions/runner-images/issues/6775
run: |
git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: check indentation in firmware C code
working-directory: hw/application_fpga
run: |
make -C fw/tk1 checkfmt
make -C fw/testfw checkfmt
- name: run static analysis on firmware C code
working-directory: hw/application_fpga
run: |
make check
- name: compile firmware and testfw
working-directory: hw/application_fpga
run: make firmware.bin testfw.bin
check-verilog:
runs-on: ubuntu-latest
container:
image: ghcr.io/tillitis/tkey-builder:4
steps:
- name: checkout
uses: actions/checkout@v4
with:
# fetch-depth: 0
persist-credentials: false
- name: fix
# https://github.com/actions/runner-images/issues/6775
run: |
git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: lint verilog using verilator
working-directory: hw/application_fpga
run: make lint
build-other-firmwares:
runs-on: ubuntu-latest
container:
image: ghcr.io/tillitis/tkey-builder:4
steps:
- name: checkout
uses: actions/checkout@v4
with:
# fetch-depth: 0
persist-credentials: false
@ -30,29 +81,68 @@ jobs:
working-directory: hw/boards/mta1-usb-v1/ch552_fw
run: make
- name: compile tp1 firmware
working-directory: hw/boards/tp1/firmware
run: ./build.sh
build-bitstream:
outputs:
commit_sha: ${{ github.sha }}
runs-on: ubuntu-latest
container:
image: ghcr.io/tillitis/tkey-builder:4
steps:
- name: checkout
uses: actions/checkout@v4
with:
# fetch-depth: 0
persist-credentials: false
- name: fix
# https://github.com/actions/runner-images/issues/6775
run: |
git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: make production test gateware
working-directory: hw/production_test/application_fpga_test_gateware
run: make
- name: compile firmware and testfw
working-directory: hw/application_fpga
run: make firmware.bin testfw.bin
- name: check fmt of our firmware C code
working-directory: hw/application_fpga
run: |
make -C fw/tk1 checkfmt
make -C fw/testfw checkfmt
- name: lint verilog using verilator
working-directory: hw/application_fpga
run: make lint
# doing this last as it takes long time
- name: make application FPGA gateware
working-directory: hw/application_fpga
run: make all
- name: Cache binaries
uses: actions/cache@v4
with:
path: |
hw/application_fpga/application_fpga.bin
hw/application_fpga/firmware.bin
key: build-${{ github.run_number }}-${{ github.sha }}-${{ github.run_attempt }}
check-hashes:
needs: build-bitstream
runs-on: ubuntu-latest
container:
image: ghcr.io/tillitis/tkey-builder:4
steps:
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Retrieve binaries from cache
uses: actions/cache@v4
with:
path: |
hw/application_fpga/application_fpga.bin
hw/application_fpga/firmware.bin
key: build-${{ github.run_number }}-${{ needs.build-bitstream.outputs.commit_sha }}-${{ github.run_attempt }}
- name: check matching hashes for firmware.bin & application_fpga.bin
working-directory: hw/application_fpga
run: make check-binary-hashes
# TODO? first deal with hw/boards/ and hw/production_test/
# - name: check for SPDX tags
# run: ./LICENSES/spdx-ensure

1
.gitignore vendored
View File

@ -62,3 +62,4 @@ fp-info-cache
*.ses
__pycache__
application_fpga_par.json

View File

@ -28,6 +28,8 @@ contrib/99-tillitis.rules
contrib/Dockerfile
contrib/Makefile
dco.md
hw/application_fpga/application_fpga.bin.sha256
hw/application_fpga/config.vlt
hw/application_fpga/core/timer/README.md
hw/application_fpga/core/tk1/README.md
hw/application_fpga/core/touch_sense/README.md
@ -35,6 +37,7 @@ hw/application_fpga/core/trng/README.md
hw/application_fpga/core/uds/README.txt
hw/application_fpga/data/udi.hex
hw/application_fpga/data/uds.hex
hw/application_fpga/firmware.bin.sha512
hw/application_fpga/fw/.clang-format
hw/application_fpga/fw/testfw/Makefile
hw/application_fpga/fw/tk1/Makefile

View File

@ -43,41 +43,48 @@ security-critical operations.
*The TK1 PCB, the first implementation of the TKey.*
## Documentation
## Getting started
The official website is [tillitis.se](https://tillitis.se).
### Getting started
The Tkey can be purchased at
[shop.tillitis.se](https://shop.tillitis.se).
* [tillitis-key1-apps repository](https://github.com/tillitis/tillitis-key1-apps),
with apps and host programs for using the TKey
* [Quickstart](doc/quickstart.md) to initial programming of the TKey
(only required for the DevKit)
* [Toolchain setup](doc/toolchain_setup.md)
* [Release Notes](doc/release_notes.md)
All documentation concerning the TKey has been migrated to [TKey
Developer Handbook](https://dev.tillitis.se).
### In-depth technical information
* [System Description](doc/system_description/system_description.md)
## Tkey Device Apps
Offically supported apps can be found at
[tillitis.se](https://tillitis.se/download/)
The source and other projects from us can be found here at our
[GitHub](https://github.com/tillitis).
Other known (but not all) projects can be found at
[dev.tillitis.se](https://dev.tillitis.se/projects/).
### Other noteworthy links
* [Threat Model](doc/threat_model/threat_model.md)
* [Framing Protocol](doc/framing_protocol/framing_protocol.md)
* [Boards](doc/system_description/boards.md)
* [FPGA](doc/system_description/fpga.md)
* [Software](doc/system_description/software.md)
* [QEMU](https://github.com/tillitis/qemu/tree/tk1) (branch `tk1` in
separate repository)
* [Release Notes](doc/release_notes.md)
* [Quickstart for the DevKit](doc/quickstart.md). Initial programming
if you have the "old" DevKit.
Note that development is ongoing. For example, changes might be made
to the measuring and derivation of key material, causing the
public/private keys of a signer app to change. To avoid unexpected
changes, please use a tagged release. Read the [Release
Note that development is ongoing. To avoid unexpected changes of
derived key material, please use a tagged release. Read the [Release
Notes](doc/release_notes.md) to keep up to date with changes and new
releases.
## About this repository
This repository contains hardware, software and utilities written as
This repository contains hardware, firmware and utilities written as
part of the TKey. It is structured as monolithic repository, or
"monorepo", where all components live in one repository.
Device and client applications, however, are kept in other
repositories here at our [GitHub](https://github.com/tillitis).
## Licensing
See [LICENSES](./LICENSES/README.md) for more information about

View File

@ -1,4 +1,4 @@
FROM docker.io/library/ubuntu:22.10 as base
FROM docker.io/library/ubuntu:23.10 as base
RUN apt-get -qq update -y \
&& DEBIAN_FRONTEND=noninteractive \
@ -8,12 +8,14 @@ RUN apt-get -qq update -y \
ca-certificates \
clang \
clang-format \
clang-tidy \
cmake \
flex \
gawk \
git \
golang \
graphviz \
iverilog \
less \
libboost-dev \
libboost-filesystem-dev \
@ -40,6 +42,7 @@ RUN apt-get -qq update -y \
vim \
xdot \
sdcc \
splint \
cmake \
gcc-arm-none-eabi \
libnewlib-arm-none-eabi \
@ -51,10 +54,10 @@ FROM base as toolsbuilder
RUN git clone https://github.com/YosysHQ/icestorm /src
WORKDIR /src
RUN git checkout 45f5e5f3889afb07907bab439cf071478ee5a2a5 \
RUN git checkout d20a5e9001f46262bf0cef220f1a6943946e421d \
&& make -j$(nproc --ignore=2) \
&& make install
RUN git >/usr/local/repo-commit-icestorm describe --tags --always --dirty
RUN git >/usr/local/repo-commit-icestorm describe --all --always --long --dirty
WORKDIR /
RUN rm -rf /src
@ -63,39 +66,34 @@ RUN git clone -b interfaces --depth=1 https://github.com/tillitis/icestorm /src
WORKDIR /src/iceprog
RUN make -j$(nproc --ignore=2) \
&& make PROGRAM_PREFIX=tillitis- install
RUN git >/usr/local/repo-commit-tillitis--icestorm describe --tags --always --dirty
RUN git >/usr/local/repo-commit-tillitis--icestorm describe --all --always --long --dirty
WORKDIR /
RUN rm -rf /src
RUN git clone https://github.com/YosysHQ/yosys /src
RUN git clone -b yosys-0.36 --depth=1 https://github.com/YosysHQ/yosys /src
WORKDIR /src
# Avoiding current issue with yosys & icebram, filed in:
# https://github.com/YosysHQ/yosys/issues/3478
RUN git checkout 06ef3f264afaa3eaeab45cc0404d8006c15f02b1 \
RUN make -j$(nproc --ignore=2) \
&& make install
RUN git >/usr/local/repo-commit-yosys describe --all --always --long --dirty
WORKDIR /
RUN rm -rf /src
RUN git clone -b nextpnr-0.6 --depth=1 https://github.com/YosysHQ/nextpnr /src
WORKDIR /src
RUN cmake -DARCH=ice40 -DCMAKE_INSTALL_PREFIX=/usr/local . \
&& make -j$(nproc --ignore=2) \
&& make install
RUN git >/usr/local/repo-commit-yosys describe --tags --always --dirty
RUN git >/usr/local/repo-commit-nextpnr describe --all --always --long --dirty
WORKDIR /
RUN rm -rf /src
RUN git clone https://github.com/YosysHQ/nextpnr /src
WORKDIR /src
# Use nextpnr-0.4. Aa few commits later we got issues, like on f4e6bbd383f6c43.
RUN git checkout nextpnr-0.4 \
&& cmake -DARCH=ice40 -DCMAKE_INSTALL_PREFIX=/usr/local . \
&& make -j$(nproc --ignore=2) \
&& make install
RUN git >/usr/local/repo-commit-nextpnr describe --tags --always --dirty
WORKDIR /
RUN rm -rf /src
RUN git clone --branch 1.5.0 --depth 1 https://github.com/raspberrypi/pico-sdk.git /usr/local/pico-sdk
RUN git clone --branch 1.5.1 --depth 1 https://github.com/raspberrypi/pico-sdk.git /usr/local/pico-sdk
WORKDIR /usr/local/pico-sdk
RUN git submodule update --init
RUN git >/usr/local/repo-commit-picosdk describe --tags --always --dirty
RUN git >/usr/local/repo-commit-picosdk describe --all --always --long --dirty
WORKDIR /
FROM base
LABEL org.opencontainers.image.description="Toolchain for building TKey FPGA bitstream, firmware, apps"
LABEL org.opencontainers.image.description="Toolchain for building TKey FPGA bitstream, firmware, apps, programmer firmware"
COPY --from=toolsbuilder /usr/local/ /usr/local

View File

@ -1,26 +1,67 @@
all:
@echo "Build targets: "
@echo "build Build an image for building tools with Docker"
@echo "run Run a shell using the above image with Docker"
@echo "podman-pull Pull in the podman tkey builder"
@echo "podman-build Build an image with podman"
@echo "podman-run Run a shell using above image with podman"
@echo "podman-run-make Run the above image with podman and build the FPGA bitstream"
# Copyright (C) 2024 - Tillitis AB
# SPDX-License-Identifier: GPL-2.0-only
build:
docker build -t tkey-builder .
# image produced by build-image targets
BUILDIMAGE=tkey-builder-local
# default image used when running a container
IMAGE=ghcr.io/tillitis/tkey-builder:4
all:
@echo "Targets:"
@echo "run Run a shell using image '$(IMAGE)' (Podman)"
@echo "run-make Build the FPGA bitstream using image '$(IMAGE)' (Podman)"
@echo "run-tb Run all the testbenches using image '$(IMAGE)' (Podman)"
@echo "run-make-no-clean Like run-make but without cleaning first, useful for iterative firmware dev"
@echo "run-make-clean_fw Like run-make but cleans only firmware"
@echo "flash Program the SPI flash on the TKey - needs an existing bitstream"
@echo "pull Pull down the image '$(IMAGE)' (Podman)"
@echo "build-image Build a toolchain image named '$(BUILDIMAGE)' (Podman)"
@echo " A newly built image can be used like: make IMAGE=$(BUILDIMAGE) run"
@echo "docker-run Run a shell using image '$(IMAGE)' (Docker)"
@echo "docker-build-image Build a toolchain image named '$(BUILDIMAGE)' (Docker)"
run:
docker run --rm --mount type=bind,source="`pwd`/../",target=/build -w /build -it tkey-builder /usr/bin/bash
podman run --rm --mount type=bind,source="`pwd`/../",target=/build -w /build -it \
$(IMAGE) /usr/bin/bash
podman-pull:
podman pull ghcr.io/tillitis/tkey-builder:1
docker-run:
docker run --rm --mount type=bind,source="`pwd`/../",target=/build -w /build -it \
$(IMAGE) /usr/bin/bash
podman-build:
podman build -t tkey-builder .
run-make:
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
$(IMAGE) make clean application_fpga.bin
podman-run:
podman run --rm --mount type=bind,source="`pwd`/../",target=/build -w /build -it tkey-builder /usr/bin/bash
run-tb:
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
$(IMAGE) make tb
podman-run-make:
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it tkey-builder make
run-make-testfw:
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
$(IMAGE) make clean application_fpga_testfw.bin
run-make-no-clean:
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
$(IMAGE) make application_fpga.bin
run-make-clean_fw:
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
$(IMAGE) make clean_fw application_fpga.bin
flash:
podman run --rm \
--device /dev/bus/usb/$(lsusb | grep -m 1 1209:8886 | awk '{ printf "%s/%s", $2, substr($4,1,3) }') \
--mount type=bind,source="`pwd`/../hw/application_fpga",target=/build \
-w /build/hw/application_fpga \
-it $(IMAGE) tillitis-iceprog /build/application_fpga.bin
pull:
podman pull $(IMAGE)
build-image:
podman build -t $(BUILDIMAGE) .
docker-build-image:
docker build -t $(BUILDIMAGE) .

View File

@ -1,5 +1,8 @@
# Framing Protocol
**NOTE:** Documentation migrated to dev.tillitis.se, this is kept for
history. This is likely to be outdated.
#### Version
* Version: Draft 1.3
* 2021-12-20
@ -114,10 +117,10 @@ The bits in the command header byte should be interpreted as:
* Bits [6..5] (2 bits). Frame ID tag.
* Bits [4..3] (2 bits). Endpoint number.
0. HW in interface_fpga
0. HW in interface_fpga (unused)
1. HW in application_fpga
2. FW in application_fpga
3. SW (application) in application_fpga
3. SW (device application) in application_fpga
* Bit [2] (1 bit). Unused. MUST be zero.
@ -125,12 +128,12 @@ The bits in the command header byte should be interpreted as:
0. 1 byte
1. 4 bytes
2. 32 bytes
3. 512 bytes
3. 128 bytes
Note that the number of bytes indicated by the command data length field
does **not** include the command header byte. This means that a complete
command frame, with a header indicating a data length of 512 bytes, is
512+1 bytes in length.
command frame, with a header indicating a data length of 128 bytes, is
128+1 bytes in length.
Note that the host sets the frame ID tag. The ID tag in a given command
MUST be preserved in the corresponding response to the command.
@ -148,7 +151,7 @@ Some examples to clarify endpoints and commands:
data. The single byte could indicate action such as reading from the
TRNG or resetting the application_fpga.
* 0x13: A command to the FW in the application_fpga with 512 bytes of
* 0x13: A command to the FW in the application_fpga with 128 bytes of
data. The data could for example be parts of an application binary to
be loaded into the program memory.
@ -166,10 +169,10 @@ The bits in the response header byte should be interpreted as:
* Bits [6..5] (2 bits). Frame ID tag.
* Bits [4..3] (2 bits). Endpoint number.
0. HW in interface_fpga
0. HW in interface_fpga (unused)
1. HW in application_fpga
2. FW in application_fpga
3. SW (application) in application_fpga
3. SW (device application) in application_fpga
* Bit [2] (1 bit). Response status.
0. OK
@ -179,13 +182,13 @@ The bits in the response header byte should be interpreted as:
0. 1 byte
1. 4 bytes
2. 32 bytes
3. 512 bytes
3. 128 bytes
Note that the number of bytes indicated by the response data length field
does **not** include the response header byte. This means that a complete
response frame, with a header indicating a data length of 512 bytes, is
512+1 bytes in length.
response frame, with a header indicating a data length of 128 bytes, is
128+1 bytes in length.
Note that the ID in a response MUST be the same ID as was present in the
header of the command being responded to.
@ -205,7 +208,7 @@ less available for the "payload" of the response.
responds with a single byte of data.
* 0x1b: A successful command to the application running in the
application_fpga. The response contains 512 bytes of data, for example
application_fpga. The response contains 128 bytes of data, for example
an EdDSA Ed25519 signature.

View File

@ -1,5 +1,9 @@
# Tillitis TKey Quickstart
**NOTE:** Documentation migrated to dev.tillitis.se, this is kept for
history. This is likely to be outdated, and are only relevant if you
have an "older" DevKit, typically handed out during OSFC 2022.
This document describes how to build the FPGA bitstream, including the
firmware, and get this programmed onto the flash memory of the
Tillitis TKey USB device.

View File

@ -3,6 +3,102 @@
Descriptions of the tagged TKey releases.
## TK1-24.03
This is an official release of the "Bellatrix" version of the Tillitis'
TKey. This version is ready for general use.
Using OCI image `ghcr.io/tillitis/tkey-builder:4`, built from
`../contrib/Dockerfile`, and the generic
`../hw/application_fpga/data/uds.hex` and
`../hw/application_fpga/data/udi.hex`, a clean build should generate
the following digest:
```
321924aa3b26507f2a02325750e63c83b306c7831f8e2c87e8d198cecf8cc1c1 application_fpga.bin
```
### FPGA
- Security Monitor now prevents access to RAM outside of the physical
memory. If it detects an access outside of the RAM address space, it
will halt the CPU.
- CPU Monitor changes name to Security monitor, which CPU Monitor is a
part of. Prepare for more functions in the future.
- Support incremental builds for the bitstream, when changing UDS/UDI
between builds. Requires tkey-builder:3 or higher.
- Update Verilog linter to Verilog-2005 and fixed warnings.
- Complete testbenches and add 9 tests for the FPGA cores.
### Firmware
- Protect zeroisation against compiler optimisation by using
secure_wipe(), fixing a memset() that was removed during
compilation.
- Make memeq() function side channel silent.
- Change memory constants to defines instead of an enum, to be
compatible with ISO C.
- Deprecate TK1_MMIO_TK1_RAM_ASLR and introduce
TK1_MMIO_TK1_RAM_ADDR_RAND instead to distinguish from OS-level
ASLR.
- Use pedantic warnings while building firmware and fixed warnings.
- Use clang-tidy in CI.
- Fix warnings from splint.
### TP1
- New plastic clip o and update of BOM.
- Build TP1 firmware in CI.
### CH552
- Fixed a bug where a byte of data could in some rare circumstances be
dropped, causing a client app to hang.
- General clean-up of code, translated all comments to English.
### TK1
- New injection moulded plastic case
### tkey-builder
- Updated to version 3. Bumping Ubuntu to 23.10, Yosys to 0.36 and
nextpnr to 0.6.
- Updated to version 4. Bumping pico-sdk to 1.5.1, adding clang-tidy
and splint.
### Docs
- Fixing broken links, cleaning up docs and READMEs.
- Clarify warm boot attack mitigations and scope for Bellatrix in
threat model.
For full change log [see](https://github.com/tillitis/tillitis-key1/compare/TK1-23.03.2...TK1-24.03)
## TK1-23.03.2
This is the official release of the "Bellatrix" version of the
Tillitis TKey device. This version is ready for general use.
This release only contains a hardware update to tk1. Capacitor C8 is
not populated. A PCB spring contact, U11, is insted placed on the
footprint of C8.
## TK1-23.03.1
This is the official release of the "Bellatrix" version of
the Tillitis TKey device. This version is ready for general
use.
Given the OCI image `ghcr.io/tillitis/tkey-builder:2` built from
`../contrib/Dockerfile` and the generic UDS.hex and UDI.hex, a clean
build should generate the following digest:
```
sha256sum application_fpga.bin
d2970828269b3ba7f09fb73b8592b08814dfe8c8087b00b0659feb516bb00f33 application_fpga.bin
```
This bug fix release contains the following changes:
- Change the firmware protocol max frame size back to 128 bytes
- Correct a bug with the reading out of UDS
## TK1-23.03
This is the official release of the "Bellatrix" version of
the Tillitis TKey device. This version is ready for general
@ -58,12 +154,12 @@ f11d6b0f57c5405598206dcfea284008413391a2c51f124a2e2ae8600cb78f0b application_fp
will start flashing red. Note that the CPU will stay in the trap
state until the TKey device is disconnected.
- (HW) The RAM memory now includes an initial adress and scrambling
mechanism to make it harder to find assets generated by and
stored in the RAM by applications. The address space layout
randomizarion (ASLR) and data value scrambling is set up by the
firmware before the application is loaded, and does not affect
how applications executes.
- (HW) The RAM memory now includes an address randomisation and data
scrambling mechanism to make it harder for someone outside of the
CPU to find assets generated by and stored in the RAM by
applications. This randomisation and scrambling is set up by
firmware before the application is loaded, and does not affect how
applications executes.
- (HW) The UART Rx FIFO now allows applications to read out the
number of bytes received and not yet consumed by the application.
@ -113,8 +209,8 @@ f11d6b0f57c5405598206dcfea284008413391a2c51f124a2e2ae8600cb78f0b application_fp
PicoRV32. Please compile your programs with the Zmmul extension,
`-march=rv32iczmmul` for `clang`.
- (HW) The UDI is locked down and can now only be accessed by
firmware, not applications.
- (HW) The UDI is locked down and can only be accessed by firmware, to
prevent applications from tracking a particular TKey.
- (HW) The timer MMIO API now takes separate start and stop bits for
triggering the respective action, mitigating a time-of-check to

View File

@ -67,9 +67,14 @@ use the RAM during loading and measurement of the application.
Unique Device Secret memory.
A 256 bit memory implemented using separate registers. The
registers can only be accessed once between power cycling.
Only the firmware can access the UDS memory core.
A 256 bit memory implemented using eight 32-bit registers. The
registers can only be accessed once between power cycling. This means
that the UDS **must** be read as u32. If read as u8, only the first
byte from a given address will be correct, subsequent bytes will be
zero.
The UDS can only be read in FW mode. Reading from the UDS in APP mode
will return all zeros.
#### Application RAM
@ -139,6 +144,10 @@ TKey device. Using the core, the firmware and applications can
get information about touch events and manage detection of
events.
It is recommended that SW start by acknowledge any stray events prior
to signal the user that a touch event is expected and then start
waiting for an event.
The touch sensor is available to use by firmware and applications.

View File

@ -1,5 +1,8 @@
# Tillitis TKey software
**NOTE:** Documentation migrated to dev.tillitis.se, this is kept for
history. This is likely to be outdated.
## Introduction
This text is both an introduction to and a requirement specification
@ -22,12 +25,13 @@ constrained environment, the application mode.
The firmware and application uses a memory mapped input/output (MMIO)
for communication with the hardware. The memory map is constrained
when running in application mode, e.g. UDS isn't readable, and the
`APP_{ADDR, SIZE}` are not writable for the application.
when running in application mode, e.g. FW-RAM and UDS isn't readable,
and several MMIO addresses are either not readable or not writable for
the application.
See table in the [System
Description](system_description.md#memory-mapped-hardware-functions)
for details about the memory system and MMIO.
for details about access rules control in the memory system and MMIO.
The firmware (and optionally all software) on the TKey can communicate
to the host via the `UART_{RX,TX}_{STATUS,DATA}` registers, using the
@ -308,10 +312,10 @@ Response to `FW_CMD_LOAD_APP`
| *name* | *size (bytes)* | *comment* |
|--------|----------------|---------------------|
| data | 511 | Raw binary app data |
| data | 127 | Raw binary app data |
Load 511 bytes of raw app binary into device RAM. Should be sent
consecutively over the complete raw binary. (512 == largest frame
Load 127 bytes of raw app binary into device RAM. Should be sent
consecutively over the complete raw binary. (128 == largest frame
length minus the command byte).
#### `FW_RSP_LOAD_APP_DATA` (0x06)
@ -377,9 +381,9 @@ host <-
```
host ->
u8 CMD[1 + 512];
u8 CMD[1 + 128];
CMD[0].len = 512 // command frame format
CMD[0].len = 128 // command frame format
CMD[1] = 0x03 // FW_CMD_LOAD_APP
CMD[2..6] = APP_SIZE
@ -398,14 +402,14 @@ host <-
RSP[3..] = 0
repeat ceil(APP_SIZE / 511) times:
repeat ceil(APP_SIZE / 127) times:
host ->
u8 CMD[1 + 512];
u8 CMD[1 + 128];
CMD[0].len = 512 // command frame format
CMD[0].len = 128 // command frame format
CMD[1] = 0x05 // FW_CMD_LOAD_APP_DATA
CMD[2..] = APP_DATA (511 bytes of app data, pad with zeros)
CMD[2..] = APP_DATA (127 bytes of app data, pad with zeros)
host <-
u8 RSP[1 + 4]
@ -422,9 +426,9 @@ Except response from last chunk of app data which is:
```
host <-
u8 RSP[1 + 512]
u8 RSP[1 + 128]
RSP[0].len = 512 // command frame format
RSP[0].len = 128 // command frame format
RSP[1] = 0x07 // FW_RSP_LOAD_APP_DATA_READY
RSP[2] = STATUS

View File

@ -1,5 +1,8 @@
# System Description
**NOTE:** Documentation migrated to dev.tillitis.se, this is kept for
history. This is likely to be outdated.
## Purpose and Revision
The purpose of this document is to provide a description of the
@ -242,15 +245,15 @@ Assigned core prefixes:
| `TIMER_STATUS` | r | r | | | | TIMER_STATUS_RUNNING_BIT is 1 when the timer is running. |
| `TIMER_PRESCALER` | r/w | r/w | 4B | | | Prescaler init value. Write blocked when running. |
| `TIMER_TIMER` | r/w | r/w | 4B | | | Timer init or current value while running. Write blocked when running. |
| `UDS_FIRST` | r[^3] | invisible | 4B | u8[32] | | First word of Unique Device Secret key. |
| `UDS_LAST` | | invisible | | | | The last word of the UDS |
| `UDS_FIRST` | r[^3] | invisible | 4B | u8[32] | | First word of Unique Device Secret key. Note: Read once per power up. |
| `UDS_LAST` | | invisible | | | | The last word of the UDS. Note: Read once per power up. |
| `UART_BITRATE` | r/w | | | | | TBD |
| `UART_DATABITS` | r/w | | | | | TBD |
| `UART_STOPBITS` | r/w | | | | | TBD |
| `UART_RX_STATUS` | r | r | 1B | u8 | | Non-zero when there is data to read |
| `UART_RX_DATA` | r | r | 1B | u8 | | Data to read. Only LSB contains data |
| `UART_RX_BYTES` | r | r | 4B | u32 | | Number of bytes received from the host and not yet read by SW, FW. |
| `UART_TX_STATUS` | r | r | 1B | u8 | | Non-zero when it's OK to write data |
| `UART_TX_STATUS` | r | r | 1B | u8 | | Non-zero when it's OK to write data to send. |
| `UART_TX_DATA` | w | w | 1B | u8 | | Data to send. Only LSB contains data |
| `TOUCH_STATUS` | r/w | r/w | | | | TOUCH_STATUS_EVENT_BIT is 1 when touched. After detecting a touch |
| | | | | | | event (reading a 1), write anything here to acknowledge it. |

View File

@ -11,11 +11,10 @@ client app as needed to solve different use cases.
This document describes the threat model for the Tillitis TKey device
and the device app. Based on [the system
description](system_description.md) and use cases, the threat model
tries to capture and describe the threats that needs to be mitigated
in order for the device app to work in a secure and trustworthy
manner.
description](../system_description/system_description.md) and use
cases, the threat model tries to capture and describe the threats that
needs to be mitigated in order for the device app to work in a secure
and trustworthy manner.
## Assumptions
@ -29,7 +28,7 @@ manner.
fabric besides the configuration circuit.
* There exist a possible warm boot attack against the Lattice iCE40
UltraPlus FPGAs which allows an attacker with physical access to
UltraPlus FPGAs, which allows an attacker with physical access to
load a FPGA configuration even though the NVCM has been programmed
and locked.
@ -171,22 +170,94 @@ perform without the user discovering the missing device.
## TKey Release specific scope
This threat model will be updated for each release of the TKey device.
For each version we description what threats are in scope, what threats
For each version we describe what threats are in scope, what threats
are out of scope and what mitigations are in place.
### TK1-23.03
### TKey Unlocked
This is the first general release of the TKey TK1 device. In this
device the FPGA bitstream is stored and locked into the NVCM. The UDS
and UDI assets are stored as part of the FPGA bitstream. The FPGA
design contain some mechanisms for execution protection, execution
monitoring as well as functionality designed to make evil maid attacks
harder to successfully perform, i.e. take longer time.
Note that the threat model and the mitigations per release (see below)
applies to TKey Unlocked devices too as long as they have been
provisioned with:
- the bitstream from the release,
- A unique, random UDS
- A unique UDI
The configuration must have been written into the NVCM and
locked by blowing the fuses.
### TK1-24.03-Bellatrix
#### Mitigations
- USB port attacks - boot protocol:
- Instead of exiting to an eternal loop on errors, firmware now
forces a CPU trap state that requires a reboot.
- Software attacks:
Access outside of physical RAM forces the CPU into a trap state
that requires a reboot.
### TK1-23.03.2-Bellatrix
This release contains a BOM update to the Tkey hardware for the touch
capabilites, hence the specific scope for TK1-23.03-1-Bellatrix is
valid for this release.
### TK1-23.03.1-Bellatrix
This is the first general release of the TKey TK1 end user device. In this
device the FPGA bitstream is stored and locked into the NVCM. This means
that the bitstream can't be changed or read out from the device.
The UDS and UDI assets are generated during provisioning by Tillitis, and
are stored as part of the FPGA bitstream. The UDS is generated using
the tpt tool and is not stored by Tillitis after generation.
The FPGA design contain some mechanisms for execution protection,
execution monitoring as well as functionality designed to make warm
boot based evil maid attacks harder to successfully perform, i.e. take
longer time. Moreover the transparent TKey casing is glued together
which makes it harder to open up without leaving physical marks
indicating tamper attempts.
The FPGA design as well as the firmware has been audited, and
hardening of these has been performed to some degree. For more
information, see the [Release Notes](/doc/release_notes.md)
#### Mitigations
- To protect the UDS the hardware design allows only one read per word
of the UDS per power-cycle.
- USB port attacks - boot protocol:
- The firmware has a more strict protocol state machine and exits out
to an eternal loop on any errors.
- Firmware stack is protected by hardware for execution.
- Software attacks:
- Firmware uses its own FW_RAM for sensitive computations which is
not available in app mode.
- Device apps can protect arbitrarly parts of RAM, typically heap +
stack, with hardware support.
- Hardware attacks:
- The reading and handling of the UDS is randomized so it doesn't
always occur on the same cycle.
- Firmware turns on hardware assisted RAM address and data
scrambling mechanisms. It makes it harder for an outside attacker
to find assets generated by and stored in the RAM by applications.
Note that this mitigates an attack from outside the CPU, not from
an exploit towards applications running on it.
#### Known possible weakneses
The CH552 MCU providing USB host communication contains firmware that
@ -201,10 +272,10 @@ modification of the firmware CH552.
#### In scope
- SW attacks from the host against the firmware in the FPGA, and the
FPGA design itself via the USB host interface.
- SW attacks from the host against the firmware in the FPGA as well as
the FPGA design itself via the USB host interface.
- Timing attacks on the firmware in the FPGA.
- Timing attacks on the firmware and the FPGA design.
#### Out of scope
@ -212,7 +283,11 @@ modification of the firmware CH552.
- Faulting of the execution by the CPU in the FPGA and the CH552 MCU
- EM leakage
- Attacks on the TKey device apps
- Warm boot attacks. It should be hard to successfully perform against
the TKey, but the attack is not yet fully mitigated.
- Attacks on the TKey device apps.
### engineering-release-1

View File

@ -1,5 +1,8 @@
# Toolchain setup
**NOTE:** Documentation migrated to dev.tillitis.se, this is kept for
history. This is likely to be outdated.
Here are instructions for setting up the tools required to build the
project. Tested on Ubuntu 22.10.
@ -8,7 +11,7 @@ project. Tested on Ubuntu 22.10.
The following is intended to be a complete list of the packages that
are required for doing all of the following:
- building and developing [TKey host programs and
- building and developing [TKey device and client
apps](https://github.com/tillitis/tillitis-key1-apps)
- building our [QEMU machine](https://github.com/tillitis/qemu/tree/tk1)
(useful for apps dev)
@ -25,8 +28,8 @@ sudo apt install build-essential clang lld llvm bison flex libreadline-dev \
libboost-iostreams-dev cmake libusb-1.0-0-dev \
ninja-build libglib2.0-dev libpixman-1-dev \
golang clang-format \
gcc-arm-none-eabi libnewlib-arm-none-eabi \
libstdc++-arm-none-eabi-newlib
gcc-arm-none-eabi libnewlib-arm-none-eabi \
libstdc++-arm-none-eabi-newlib
```
## Device permissions
@ -80,15 +83,15 @@ install other versions of these tools locally, they could conflict
git clone https://github.com/YosysHQ/icestorm
cd icestorm
git checkout 45f5e5f3889afb07907bab439cf071478ee5a2a5
git checkout d20a5e9001f46262bf0cef220f1a6943946e421d
make -j$(nproc)
sudo make install
cd ..
# Custom iceprog for the RPi 2040-based programmer (will be upstreamed).
# Note: tillitis-iceprog depends on libusb-1.0.0.
# On Ubuntu install with 'sudo apt install libusb-1.0.0'
git clone -b interfaces https://github.com/tillitis/icestorm tillitis--icestorm
# Note: install dependencies for building tillitis-iceprog on Ubuntu:
# sudo apt install libftdi-dev libusb-1.0-0-dev
git clone -b interfaces https://github.com/tillitis/icestorm tillitis--icestorm
cd tillitis--icestorm/iceprog
make
sudo make PROGRAM_PREFIX=tillitis- install
@ -96,17 +99,14 @@ install other versions of these tools locally, they could conflict
git clone https://github.com/YosysHQ/yosys
cd yosys
# Avoiding current issue with yosys & icebram, filed in:
# https://github.com/YosysHQ/yosys/issues/3478
git checkout 06ef3f264afaa3eaeab45cc0404d8006c15f02b1
git checkout yosys-0.26
make -j$(nproc)
sudo make install
cd ..
git clone https://github.com/YosysHQ/nextpnr
cd nextpnr
# Use nextpnr-0.4. Aa few commits later we got issues, like on f4e6bbd383f6c43.
git checkout nextpnr-0.4
git checkout nextpnr-0.5
cmake -DARCH=ice40 -DCMAKE_INSTALL_PREFIX=/usr/local .
make -j$(nproc)
sudo make install
@ -144,32 +144,32 @@ The circuit board designs were all created in [KiCad
## MTA1-USB-V1 and TP-1 programming board firmware
The programmer boards are running a custom firmware developed by
Blinkinlabs. The source code for this firnware is available on
Github: https://github.com/Blinkinlabs/ice40_flasher
There is also a pre built firmware binary available for the
programmer board:
https://github.com/Blinkinlabs/ice40_flasher/tree/main/bin
The TP-1 programming boards runs a custom firmware developed by
Blinkinlabs. Source code for this firmware can be found at
[hw/boards/tp1/firmware/](../hw/boards/tp1/firmware/). There is also a
pre-built firmware binary at
[hw/boards/tp1/firmware/bin/main.uf2](../hw/boards/tp1/firmware/bin/main.uf2).
To update the firmware on the programmer board, either build the file
"main.uf2", or download the pre built file to your host computer.
Then do the following:
`main.uf2` (more instructions below), or get the pre-built file to
your host computer. Then do the following:
1. Disconnect the programming board from the host computer
2. Press and hold the "BOOTSEL" button on the RPi2040 sub board on
the programming board
2. Press and hold the "BOOTSEL" button on the RPi2040 sub-board on the
programming board
3. Reconnect the programming board to the host computer
4. Release the "BOOTSEL" button after connecting the programming
board to the host. The board should now appear to the host as a
USB connected storage device
5. Open the storage device and drop the firmware file ("main.uf2")
into the storage device
4. Release the "BOOTSEL" button after connecting the programming board
to the host. The board should now appear to the host as a USB
connected storage device
5. Open the storage device and drop the firmware file `main.uf2` into
the storage device
The programmer will update its firmware with the file and restart
itself. After reboot the storage device will automatically be
disconnected.
### Building the TP-1 firmware
The firmware requires the Raspberry Pi Pico SDK:
cd ~
@ -177,10 +177,13 @@ The firmware requires the Raspberry Pi Pico SDK:
cd pico-sdk
git submodule update --init
Note that the Docker image places the pico-sdk directory in
Note that our container image places the pico-sdk directory in
/usr/local. For normal development, it is usually left in the
users home directory.
See
[hw/boards/tp1/firmware/README.md](../hw/boards/tp1/firmware/README.md)
for further instructions.
## CH552 USB to Serial firmware

View File

@ -6,9 +6,13 @@
# HW targets as well as its firmware.
#
#
# Copyright (C) 2022, 2023 - Tillitis AB
# Copyright (C) 2022-2024 - Tillitis AB
# SPDX-License-Identifier: GPL-2.0-only
#
#
# Please note: When creating a new cores and adding more testbenches,
# please update the tb target below to include it as well.
#
#=======================================================================
#-------------------------------------------------------------------
@ -26,7 +30,7 @@ ICESTORM_PATH ?=
# bits wide; an EBR is 128 32-bits words)
BRAM_FW_SIZE ?= 1536
PIN_FILE ?= application_fpga_mta1_usb_v1.pcf
PIN_FILE ?= application_fpga_tk1.pcf
SIZE ?= llvm-size
OBJCOPY ?= llvm-objcopy
@ -36,7 +40,7 @@ CC = clang
CFLAGS = -target riscv32-unknown-none-elf -march=rv32iczmmul -mabi=ilp32 \
-static -std=gnu99 -O2 -ffast-math -fno-common -fno-builtin-printf \
-fno-builtin-putchar -fno-builtin-memcpy -nostdlib -mno-relax -Wall \
-flto -DNOCONSOLE
-Wpedantic -Wno-language-extension-token -flto -g -DNOCONSOLE
AS = clang
ASFLAGS = -target riscv32-unknown-none-elf -march=rv32iczmmul -mabi=ilp32 -mno-relax
@ -61,8 +65,10 @@ VERILOG_SRCS = \
$(P)/core/timer/rtl/timer_core.v \
$(P)/core/timer/rtl/timer.v \
$(P)/core/uds/rtl/uds.v \
$(P)/core/uds/rtl/uds_rom.v \
$(P)/core/touch_sense/rtl/touch_sense.v \
$(P)/core/tk1/rtl/tk1.v \
$(P)/core/tk1/rtl/udi_rom.v \
$(P)/core/uart/rtl/uart_core.v \
$(P)/core/uart/rtl/uart_fifo.v \
$(P)/core/uart/rtl/uart.v \
@ -143,6 +149,9 @@ firmware.elf: $(FIRMWARE_OBJS) $(P)/fw/tk1/firmware.lds
.PHONY: check
check:
clang-tidy -header-filter=.* -checks=cert-* $(FIRMWARE_SOURCES) -- $(CFLAGS)
.PHONY: splint
splint:
splint -nolib -predboolint +boolint -nullpass -unrecog -infloops -initallelements -type -unreachable -unqualifiedtrans -fullinitblock $(FIRMWARE_SOURCES)
testfw.elf: $(TESTFW_OBJS) $(P)/fw/tk1/firmware.lds
@ -157,6 +166,13 @@ firmware.hex: firmware.bin firmware_size_mismatch
testfw.hex: testfw.bin testfw_size_mismatch
python3 $(P)/tools/makehex/makehex.py $< $(BRAM_FW_SIZE) > $@
.PHONY: check-binary-hashes
check-binary-hashes:
sha512sum firmware.bin
sha256sum application_fpga.bin
sha512sum -c firmware.bin.sha512
sha256sum -c application_fpga.bin.sha256
%.bin: %.elf
$(SIZE) $<
@test "$$($(SIZE) $< | awk 'NR==2{print $$2, $$3}')" = "0 0" \
@ -169,7 +185,7 @@ testfw.hex: testfw.bin testfw_size_mismatch
# Source linting.
#-------------------------------------------------------------------
LINT=verilator
LINT_FLAGS = +1364-2001ext+ --lint-only -Wall -Wno-DECLFILENAME \
LINT_FLAGS = +1364-2005ext+ --lint-only -Wall -Wno-DECLFILENAME \
--timescale 1ns/1ns -DNO_ICE40_DEFAULT_ASSIGNMENTS
lint: $(FPGA_SRC) $(VERILOG_SRCS) $(ICE40_SIM_CELLS)
@ -182,7 +198,9 @@ lint: $(FPGA_SRC) $(VERILOG_SRCS) $(ICE40_SIM_CELLS)
config.vlt $^ \
>lint_issues.txt 2>&1 \
&& { rm -f lint_issues.txt; exit 0; } \
|| { cat lint_issues.txt; exit 1; }
|| { cat lint_issues.txt; exit 0; }
echo "Non-zero exit temporarily removed, see issue 182."
#|| { cat lint_issues.txt; exit 1; }
.PHONY: lint
@ -202,22 +220,35 @@ verilator: $(VERILATOR_FPGA_SRC) $(VERILOG_SRCS) firmware.hex $(ICE40_SIM_CELLS)
make -C verilated -f Vapplication_fpga.mk
.PHONY: verilator
#-------------------------------------------------------------------
# Run all testbenches
#-------------------------------------------------------------------
tb:
make -C core/timer/toolruns sim-top
make -C core/tk1/toolruns sim-top
make -C core/touch_sense/toolruns sim-top
make -C core/trng/toolruns sim-top
make -C core/uart/toolruns sim-top
make -C core/uds/toolruns sim-top
.PHONY: tb
#-------------------------------------------------------------------
# Main FPGA build flow.
# Synthesis. Place & Route. Bitstream generation.
#-------------------------------------------------------------------
synth.json: $(FPGA_SRC) $(VERILOG_SRCS) bram_fw.hex $(P)/data/uds.hex $(P)/data/udi.hex
synth.json: $(FPGA_SRC) $(VERILOG_SRCS) bram_fw.hex
$(YOSYS_PATH)yosys -v3 -l synth.log -DBRAM_FW_SIZE=$(BRAM_FW_SIZE) \
-DFIRMWARE_HEX=\"$(P)/bram_fw.hex\" \
-DUDS_HEX=\"$(P)/data/uds.hex\" \
-DUDI_HEX=\"$(P)/data/udi.hex\" \
-p 'synth_ice40 -dsp -top application_fpga -json $@; write_verilog -attr2comment synth.v' \
$(filter %.v, $^)
application_fpga.asc: synth.json $(P)/data/$(PIN_FILE)
application_fpga_par.json: synth.json $(P)/data/$(PIN_FILE)
$(NEXTPNR_PATH)nextpnr-ice40 --ignore-loops --up5k --package sg48 --json $< \
--pcf $(P)/data/$(PIN_FILE) --asc $@
--pcf $(P)/data/$(PIN_FILE) --write $@
application_fpga.asc: application_fpga_par.json $(P)/data/uds.hex $(P)/data/udi.hex
UDS_HEX="$(P)/data/uds.hex" UDI_HEX="$(P)/data/udi.hex" OUT_ASC=$@ $(NEXTPNR_PATH)nextpnr-ice40 --up5k --package sg48 --ignore-loops --json $< --run tools/patch_uds_udi.py
application_fpga.bin: application_fpga.asc bram_fw.hex firmware.hex
$(ICESTORM_PATH)icebram -v bram_fw.hex firmware.hex < $< > $<.tmp
@ -267,14 +298,21 @@ route_sim_vcd: route_tb.vvp
# FPGA device programming.
#-------------------------------------------------------------------
prog_flash: application_fpga.bin
sudo tillitis-iceprog $<
prog_flash: check-hardware application_fpga.bin
sudo tillitis-iceprog application_fpga.bin
.PHONY: prog_flash
prog_flash_testfw: application_fpga_testfw.bin
sudo tillitis-iceprog $<
prog_flash_testfw: check-hardware application_fpga_testfw.bin
sudo tillitis-iceprog application_fpga_testfw.bin
.PHONY: prog_flash_testfw
check-hardware:
@sudo tillitis-iceprog -t >/dev/null 2>&1 || \
{ echo "Programmer not plugged in or not accessible"; false; }
@if sudo tillitis-iceprog -t 2>&1 | grep -qi "^flash.id:\( 0x\(00\|ff\)\)\{4\}"; then \
echo "No USB stick in the programmer?"; false; else true; fi
.PHONY: check-hardware
#-------------------------------------------------------------------
# Post build analysis.
#-------------------------------------------------------------------
@ -292,6 +330,7 @@ clean: clean_fw
rm -f bram_fw.hex
rm -f synth.{log,v,json} route.v application_fpga.{asc,bin,vcd} application_fpga_testfw.bin
rm -f tb_application_fpga.vvp synth_tb.vvp route_tb.vvp
rm -f application_fpga_par.json
rm -f *.vcd
rm -f lint_issues.txt
rm -rf verilated
@ -316,11 +355,14 @@ help:
@echo "Supported targets:"
@echo "------------------"
@echo "all Build all targets."
@echo "check Run static analysis on firmware."
@echo "splint Run splint static analysis on firmware."
@echo "firmware.elf Build firmware ELF file."
@echo "firmware.hex Build firmware converted to hex, to be included in bitstream."
@echo "bram_fw.hex Build a fake BRAM file that will be filled in later after place-n-route."
@echo "verilator Build Verilator simulation program"
@echo "lint Run lint on Verilog source files."
@echo "tb Run all testbenches"
@echo "prog_flash Program device flash with FGPA bitstream including firmware (using the RPi Pico-based programmer)."
@echo "prog_flash_testfw Program device flash as above, but with testfw."
@echo "clean Delete all generated files."

View File

@ -0,0 +1 @@
321924aa3b26507f2a02325750e63c83b306c7831f8e2c87e8d198cecf8cc1c1 application_fpga.bin

View File

@ -1,5 +1,37 @@
# timer
A simple timer with prescaler written in Verilog.
A simple timer with prescaler.
## Introduction
This core implements a simple timer with a prescaler. The purpose of the prescaler is to more easily time durations rather than cycles. If for example setting the timer to the clock frequency, the timer can cound seconds.
This core implements a simple timer with a prescaler. The prescaler
allows measurement of time durations rather than cycles. If for
example setting the prescaler to the clock frequency in Hertz, the
timer will count seconds.
## API
The following addresses define the API for the timer:
```
ADDR_CTRL: 0x08
CTRL_START_BIT: 0
CTRL_STOP_BIT: 1
ADDR_STATUS: 0x09
STATUS_RUNNING_BIT: 0
ADDR_PRESCALER: 0x0a
ADDR_TIMER: 0x0b
```
## Details
The core consists of the timer_core module (in timer_core.v) and a top
level wrapper, timer (in timer.v). The top level wrapper implements
the API, while the timer_core implements the actual timer
functionality.
The timer counter and the prescaler counter are both 32 bits.
When enabled the counter counts down one integer value per cycle.
The timer will stop when reaching final zero (given by prescaler times the initial value of the timer)
and the running flag will be lowered.

View File

@ -24,29 +24,16 @@ module tb_timer();
parameter CLK_HALF_PERIOD = 1;
parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD;
localparam ADDR_NAME0 = 8'h00;
localparam ADDR_NAME1 = 8'h01;
localparam ADDR_VERSION = 8'h02;
localparam ADDR_CTRL = 8'h08;
localparam CTRL_START_BIT = 0;
localparam CTRL_STOP_BIT = 1;
localparam ADDR_CTRL = 8'h08;
localparam CTRL_NEXT_BIT = 0;
localparam ADDR_STATUS = 8'h09;
localparam STATUS_RUNNING_BIT = 0;
localparam ADDR_STATUS = 8'h09;
localparam STATUS_READY_BIT = 0;
localparam ADDR_PRESCALER = 8'h0a;
localparam ADDR_TIMER = 8'h0b;
localparam ADDR_CONFIG = 8'h0a;
localparam CONFIG_ENCDEC_BIT = 0;
localparam ADDR_KEY0 = 8'h10;
localparam ADDR_KEY1 = 8'h11;
localparam ADDR_KEY2 = 8'h12;
localparam ADDR_KEY3 = 8'h13;
localparam ADDR_BLOCK0 = 8'h20;
localparam ADDR_BLOCK1 = 8'h21;
localparam ADDR_RESULT0 = 8'h30;
localparam ADDR_RESULT1 = 8'h31;
//----------------------------------------------------------------
// Register and Wire declarations.
@ -63,6 +50,7 @@ module tb_timer();
reg [7 : 0] tb_address;
reg [31 : 0] tb_write_data;
wire [31 : 0] tb_read_data;
wire tb_ready;
reg [31 : 0] read_data;
@ -79,7 +67,8 @@ module tb_timer();
.address(tb_address),
.write_data(tb_write_data),
.read_data(tb_read_data)
.read_data(tb_read_data),
.ready(tb_ready)
);
@ -123,6 +112,16 @@ module tb_timer();
$display("------------");
$display("Cycle: %08d", cycle_ctr);
$display("");
$display("Inputs and outputs:");
$display("cs: 0x%1x, we: 0x%1x, address: 0x%02x, write_data: 0x%08x, read_data: 0x%08x, ready: 0x%1x",
tb_cs, tb_we, tb_address, tb_write_data, tb_read_data, tb_ready);
$display("");
$display("Internal state:");
$display("prescaler_reg: 0x%08x, timer_reg: 0x%08x", dut.prescaler_reg, dut.timer_reg);
$display("start_reg: 0x%1x, stop_reg: 0x%1x", dut.start_reg, dut.stop_reg);
$display("core_running: 0x%1x, core_curr_timer: 0x%08x", dut.core_running, dut.core_curr_timer);
$display("");
$display("");
end
endtask // dump_dut_state
@ -251,14 +250,39 @@ module tb_timer();
//----------------------------------------------------------------
// test1()
// Set timer and scaler and then start the timer. Wait
// for the ready flag to be asserted again.
//----------------------------------------------------------------
task test1;
begin
begin : test1
reg [31 : 0] time_start;
reg [31 : 0] time_stop;
tc_ctr = tc_ctr + 1;
tb_monitor = 0;
$display("");
$display("--- test1: started.");
write_word(ADDR_PRESCALER, 8'h02);
write_word(ADDR_TIMER, 8'h10);
time_start = cycle_ctr;
write_word(ADDR_CTRL, 8'h01);
#(2 * CLK_PERIOD);
read_word(ADDR_STATUS);
while (read_data) begin
read_word(ADDR_STATUS);
end
time_stop = cycle_ctr;
write_word(CTRL_START_BIT, 8'h02);
$display("--- test1: Cycles between start and stop: %d", (time_stop - time_start));
#(CLK_PERIOD);
tb_monitor = 0;
$display("--- test1: completed.");
$display("");
end
@ -281,8 +305,8 @@ module tb_timer();
display_test_result();
$display("");
$display(" -= Testbench for timer started =-");
$display(" =============================");
$display(" -= Testbench for timer completed =-");
$display(" ===============================");
$display("");
$finish;
end // timer_test

View File

@ -222,7 +222,7 @@ module tb_timer_core();
//----------------------------------------------------------------
initial
begin : timer_core_test
$display("--- Simulation of TIMER core started.");
$display("--- Simulation of timer core started.");
$display("");
init_sim();

View File

@ -21,7 +21,7 @@ CC = iverilog
CC_FLAGS = -Wall
LINT = verilator
LINT_FLAGS = +1364-2001ext+ --lint-only -Wall -Wno-fatal -Wno-DECLFILENAME
LINT_FLAGS = +1364-2005ext+ --lint-only -Wall -Wno-fatal -Wno-DECLFILENAME
all: top.sim core.sim
@ -57,7 +57,7 @@ clean:
help:
@echo "Build system for simulation of Prince core"
@echo "Build system for simulation of timer core"
@echo ""
@echo "Supported targets:"
@echo "------------------"
@ -67,7 +67,7 @@ help:
@echo "sim-top: Run top level simulation."
@echo "sim-core: Run core level simulation."
@echo "lint-core: Lint core rtl source files."
@echo "lint-core: Lint top rtl source files."
@echo "lint-top: Lint top rtl source files."
@echo "clean: Delete all built files."
#===================================================================

View File

@ -1,6 +1,198 @@
# tk1
## Introduction
The tk1 core provides design informantion as well as control of TKey specific
functionlity such as execution mode, SW controlled stack protection, memory
scrambling, handling of illegal instructions.
The tk1 core is where information, control and monitoring
functionality unique to the TKey1 can be found. This means that it
provides more than one distinct functionality accessible via the core
API.
## API
### Access to device information
```
ADDR_NAME0: 0x00
ADDR_NAME1: 0x01
ADDR_VERSION: 0x02
```
These addresses provide read only information about the name (type)
and version of the device. They can be read by FW as well as
applications.
### Control of execution mode
```
ADDR_SWITCH_APP: 0x08
```
This register controls if the device is executing in FW mode or in App
mode. The register can be written once between power cycles, and only
by FW. If set the device is in app mode.
### Control of RGB LED
```
ADDR_LED: 0x09
LED_B_BIT: 0
LED_G_BIT: 1
LED_R_BIT: 2
```
This register control the RGB LED on the TKey device. Setting a bit to
one turns the corresponding color on. It can be read and written by FW
as well as by Apps.
### Control and status of GPIO
```
ADDR_GPIO: 0x0a
GPIO1_BIT: 0
GPIO2_BIT: 1
GPIO3_BIT: 2
GPIO4_BIT: 3
```
This register control and provide status access to the four GPIOs on
the TKey. GPIO one and two are inputs. They will sample the input
level and present it to SW. GPIO three and four are outputs. They will
emit either high or low voltage level depending on if the
corresponding register is one or zero.
### Application introspection
```
ADDR_APP_START: 0x0c
ADDR_APP_SIZE: 0x0d
```
These registers provide read only information to the loaded app to
itself - where it was loaded and its size. The values are written by
FW as part of the loading of the app. The registers can't be written
when the ADDR_SWITCH_APP has been set.
### Access to Blake2s
```
ADDR_BLAKE2S: 0x10
```
This register provides the 32-bit function pointer address to the
Blake2s hash function in the FW. It is written by FW during boot. The
register can't be written to when the ADDR_SWITCH_APP has been set.
### Access to CDI
```
ADDR_CDI_FIRST: 0x20
ADDR_CDI_LAST: 0x27
```
These registers provide access to the 256-bit compound device secret
calculated by the FW as part of loading an application. The registers
are written by the FW. The register can't be written to when the
ADDR_SWITCH_APP has been set. Apps can read the CDI and is it as base
secret for any secrets it needs to perform its intended use case.
### Access to UDI
```
ADDR_UDI_FIRST: 0x30
ADDR_UDI_LAST: 0x31
```
These read-only registers provide access to the 64-bit Unique Device
Identity (UDI).
The two UDI words are stored using 32 named SB\_LUT4 FPGA multiplexer
(MUX) instances, identified in the source code as "udi\_rom\_idx". One
instance for each bit in core read_data output bus.
Each SB\_LUT4 MUX is able to store 16 bits of data, in total 512 bits.
But since the UDI is 64 bits, we only use the two LSBs in each MUX.
Note that only the LSB address of the SB_LUT4 instances are connected
to the CPU address. This means that only the two LSBs in each MUX can
be addressed.
During build of the FPGA design, the UDI is set to a known bit
pattern, which means that the SB_LUT4 instantiations are initialized
to a fixed bit pattern.
The tool 'patch\_uds\_udi.py' is used to replace the fixed bit pattern
with a unique bit pattern before generating the per device unique FPGA
bitstream. This allows us to generate these device unique FPGA
bitstreams without having to do a full FPGA build.
### RAM memory protecion
```
ADDR_RAM_ASLR: 0x40
ADDR_RAM_SCRAMBLE: 0x41
```
These write only registers control how the data in the RAM is
scrambled as a way of protecting the data. The ADDR_RAM_ASLR control
how the addresses are scrambled. The ADDR_RAM_SCRAMBLE control how the
data itself is scrambled. FW writes random values to these registers
during boot.
### Security monitor
```
ADDR_CPU_MON_CTRL: 0x60
ADDR_CPU_MON_FIRST:0x61
ADDR_CPU_MON_LAST: 0x62
```
Monitors events and state changes in the SoC and handles security
violations. Currently checks for:
1. Trying to execute instructions in FW_RAM. *Always enabled.*
2. Trying to access RAM outside of the physical memory. *Always enabled*
3. Trying to execute instructions from a memory area in RAM defined by
the application.
Number 1 and 2 are always enabled. Number 3 is set and enabled by the
device application. Once enabled, by writing to ADDR_CPU_MON_CTRL, the
memory defined by ADDR_CPU_MON_FIRST and ADDR_CPU_MON_LAST will be
protected against execution. Typically the application developer will
set this protection to cover the application stack and/or heap.
An application can write to these registers to define the area and
then enable the monitor. Once enabled the monitor can't be disabled,
and the ADDR_CPU_MON_FIRST and ADDR_CPU_MON_LAST registers can't be
changed. This means that an application that wants to use the monitor
must define the area first before enabling the monitor.
Once enabled, if the CPU tries to read an instruction from the defined
area, the core will force the CPU to instead read an all zero, which
is an illegal instruction. This illegal instruction will trigger the
CPU to enter its TRAP state, from which it can't return unless the
TKey is power cycled.
The firmware will not write to these registers as part of loading an
app. The app developer must define the area and enable the monitor to
get the protection.
One feature not obvious from the API is that when the CPU traps the
core will detect that and start flashing the status LED with a red
light indicating that the CPU is in a trapped state and no further
execution is possible.
## Implementation
The core is implemented as a single module. Future versions will
probably be separated into separate modules.
---

View File

@ -61,8 +61,10 @@ module tk1(
localparam LED_B_BIT = 0;
localparam ADDR_GPIO = 8'h0a;
/* verilator lint_off UNUSED */
localparam GPIO1_BIT = 0;
localparam GPIO2_BIT = 1;
/* verilator lint_on UNUSED */
localparam GPIO3_BIT = 2;
localparam GPIO4_BIT = 3;
@ -99,9 +101,6 @@ module tk1(
reg [31 : 0] cdi_mem [0 : 7];
reg cdi_mem_we;
reg [31 : 0] udi_mem [0 : 1];
initial $readmemh(`UDI_HEX, udi_mem);
reg switch_app_reg;
reg switch_app_we;
@ -142,6 +141,9 @@ module tk1(
reg [31 : 0] cpu_mon_last_reg;
reg cpu_mon_last_we;
reg force_trap_reg;
reg force_trap_set;
//----------------------------------------------------------------
// Wires.
@ -149,11 +151,11 @@ module tk1(
/* verilator lint_off UNOPTFLAT */
reg [31 : 0] tmp_read_data;
reg tmp_ready;
reg tmp_force_trap;
/* verilator lint_on UNOPTFLAT */
reg [2 : 0] muxed_led;
wire [31:0] udi_rdata;
//----------------------------------------------------------------
// Concurrent connectivity for ports etc.
@ -163,7 +165,7 @@ module tk1(
assign fw_app_mode = switch_app_reg;
assign force_trap = tmp_force_trap;
assign force_trap = force_trap_reg;
assign gpio3 = gpio3_reg;
assign gpio4 = gpio4_reg;
@ -194,6 +196,12 @@ module tk1(
/* verilator lint_on PINMISSING */
udi_rom rom_i(
.addr(address[0]),
.data(udi_rdata)
);
//----------------------------------------------------------------
// reg_update
//----------------------------------------------------------------
@ -224,6 +232,7 @@ module tk1(
cpu_mon_last_reg <= 32'h0;
ram_aslr_reg <= 15'h0;
ram_scramble_reg <= 32'h0;
force_trap_reg <= 1'h0;
end
else begin
@ -290,6 +299,10 @@ module tk1(
if (cpu_mon_last_we) begin
cpu_mon_last_reg <= write_data;
end
if (force_trap_set) begin
force_trap_reg <= 1'h1;
end
end
end // reg_update
@ -318,22 +331,39 @@ module tk1(
//----------------------------------------------------------------
// cpu_monitor
// security_monitor
//
// Monitor events and state changes in the SoC, and handle
// security violations. We currently check for:
//
// Any access to RAM but outside of the size of the physical mem.
//
// Trying to execute instructions in FW-RAM.
//
// Trying to execute code in mem area set to be data access only.
// This requires execution monitor to have been setup and
// enabled.
//----------------------------------------------------------------
always @*
begin : cpu_monitor
tmp_force_trap = 1'h0;
begin : security_monitor
force_trap_set = 1'h0;
if (cpu_valid && cpu_instr) begin
if ((cpu_addr >= FW_RAM_FIRST) &&
(cpu_addr <= FW_RAM_LAST)) begin
tmp_force_trap = 1'h1;
if (cpu_valid) begin
if (cpu_addr[31 : 30] == 2'h01 & |cpu_addr[29 : 17]) begin
force_trap_set = 1'h1;
end
if (cpu_mon_en_reg) begin
if ((cpu_addr >= cpu_mon_first_reg) &&
(cpu_addr <= cpu_mon_last_reg)) begin
tmp_force_trap = 1'h1;
if (cpu_instr) begin
if ((cpu_addr >= FW_RAM_FIRST) &&
(cpu_addr <= FW_RAM_LAST)) begin
force_trap_set = 1'h1;
end
if (cpu_mon_en_reg) begin
if ((cpu_addr >= cpu_mon_first_reg) &&
(cpu_addr <= cpu_mon_last_reg)) begin
force_trap_set = 1'h1;
end
end
end
end
@ -476,7 +506,7 @@ module tk1(
if ((address >= ADDR_UDI_FIRST) && (address <= ADDR_UDI_LAST)) begin
if (!switch_app_reg) begin
tmp_read_data = udi_mem[address[0]];
tmp_read_data = udi_rdata;
end
end
end

View File

@ -0,0 +1,37 @@
//======================================================================
//
// udi_rom.v
// ---------
// UDI rom generated by instatiating named SB_LUT4 resources.
// Note: This makes the design tech specicific.
//
//
// Author: Claire Xiena Wolf.
// Copyright (C) 2023 - Tillitis AB
// SPDX-License-Identifier: GPL-2.0-only
//
//======================================================================
module udi_rom (
input wire [0:0] addr,
output wire [31:0] data
);
generate
genvar ii;
/* verilator lint_off PINMISSING */
for (ii = 0; ii < 32; ii = ii + 1'b1)
begin: luts
(* udi_rom_idx=ii, keep *) SB_LUT4 #(.LUT_INIT({2'h1})
) lut_i (
.I0(addr[0]),
.O(data[ii])
);
/* verilator lint_on PINMISSING */
end
endgenerate
endmodule
//======================================================================
// EOF udi_rom.v
//======================================================================

View File

@ -0,0 +1,42 @@
//======================================================================
//
// SB_RGBA_DRV.v
// -------------
// Dummy version of the SB_RGBA_DRV hard macro in Lattice iCE40 UP
// devices. This is just to be able to build the testbench. The only
// functionality we need is to be able to set the LEDs.
//
//
// Author: Joachim Strombergson
// Copyright (C) 2023 - Tillitis AB
// SPDX-License-Identifier: GPL-2.0-only
//
//======================================================================
`default_nettype none
module SB_RGBA_DRV (
output wire RGB0,
output wire RGB1,
output wire RGB2,
input wire RGBLEDEN,
input wire RGB0PWM,
input wire RGB1PWM,
input wire RGB2PWM,
input wire CURREN
);
parameter CURRENT_MODE = 1;
parameter RGB0_CURRENT = 8'h0;
parameter RGB1_CURRENT = 8'h0;
parameter RGB2_CURRENT = 8'h0;
assign RGB0 = RGB0PWM;
assign RGB1 = RGB1PWM;
assign RGB2 = RGB2PWM;
endmodule // SB_RGBA_DRV
//======================================================================
// EOF SB_RGBA_DRV.v
//======================================================================

View File

@ -0,0 +1,654 @@
//======================================================================
//
// tb_tk1.v
// --------
// Testbench for the TK1 core.
//
//
// Author: Joachim Strombergson
// Copyright (C) 2023 - Tillitis AB
// SPDX-License-Identifier: GPL-2.0-only
//
//======================================================================
`default_nettype none
module tb_tk1();
//----------------------------------------------------------------
// Internal constant and parameter definitions.
//----------------------------------------------------------------
parameter DEBUG = 1;
parameter CLK_HALF_PERIOD = 1;
parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD;
localparam ADDR_NAME0 = 8'h00;
localparam ADDR_NAME1 = 8'h01;
localparam ADDR_VERSION = 8'h02;
localparam ADDR_SWITCH_APP = 8'h08;
localparam ADDR_LED = 8'h09;
localparam LED_R_BIT = 2;
localparam LED_G_BIT = 1;
localparam LED_B_BIT = 0;
localparam ADDR_GPIO = 8'h0a;
localparam GPIO1_BIT = 0;
localparam GPIO2_BIT = 1;
localparam GPIO3_BIT = 2;
localparam GPIO4_BIT = 3;
localparam ADDR_APP_START = 8'h0c;
localparam ADDR_APP_SIZE = 8'h0d;
localparam ADDR_BLAKE2S = 8'h10;
localparam ADDR_CDI_FIRST = 8'h20;
localparam ADDR_CDI_LAST = 8'h27;
localparam ADDR_UDI_FIRST = 8'h30;
localparam ADDR_UDI_LAST = 8'h31;
localparam ADDR_RAM_ASLR = 8'h40;
localparam ADDR_RAM_SCRAMBLE = 8'h41;
localparam ADDR_CPU_MON_CTRL = 8'h60;
localparam ADDR_CPU_MON_FIRST = 8'h61;
localparam ADDR_CPU_MON_LAST = 8'h62;
//----------------------------------------------------------------
// Register and Wire declarations.
//----------------------------------------------------------------
reg [31 : 0] cycle_ctr;
reg [31 : 0] error_ctr;
reg [31 : 0] tc_ctr;
reg tb_monitor;
reg tb_clk;
reg tb_reset_n;
reg tb_cpu_trap;
wire tb_fw_app_mode;
reg [31 : 0] tb_cpu_addr;
reg tb_cpu_instr;
reg tb_cpu_valid;
wire tb_force_trap;
wire [14 : 0] tb_ram_aslr;
wire [31 : 0] tb_ram_scramble;
wire tb_led_r;
wire tb_led_g;
wire tb_led_b;
reg tb_gpio1;
reg tb_gpio2;
wire tb_gpio3;
wire tb_gpio4;
reg tb_cs;
reg tb_we;
reg [7 : 0] tb_address;
reg [31 : 0] tb_write_data;
wire [31 : 0] tb_read_data;
wire tb_ready;
//----------------------------------------------------------------
// Device Under Test.
//----------------------------------------------------------------
tk1 dut(
.clk(tb_clk),
.reset_n(tb_reset_n),
.cpu_trap(tb_cpu_trap),
.fw_app_mode(tb_fw_app_mode),
.cpu_addr(tb_cpu_addr),
.cpu_instr(tb_cpu_instr),
.cpu_valid(tb_cpu_valid),
.force_trap(tb_force_trap),
.ram_aslr(tb_ram_aslr),
.ram_scramble(tb_ram_scramble),
.led_r(tb_led_r),
.led_g(tb_led_g),
.led_b(tb_led_b),
.gpio1(tb_gpio1),
.gpio2(tb_gpio2),
.gpio3(tb_gpio3),
.gpio4(tb_gpio4),
.cs(tb_cs),
.we(tb_we),
.address(tb_address),
.write_data(tb_write_data),
.read_data(tb_read_data),
.ready(tb_ready)
);
//----------------------------------------------------------------
// clk_gen
//
// Always running clock generator process.
//----------------------------------------------------------------
always
begin : clk_gen
#CLK_HALF_PERIOD;
tb_clk = !tb_clk;
end // clk_gen
//----------------------------------------------------------------
// sys_monitor()
//
// An always running process that creates a cycle counter and
// conditionally displays information about the DUT.
//----------------------------------------------------------------
always
begin : sys_monitor
cycle_ctr = cycle_ctr + 1;
#(CLK_PERIOD);
if (tb_monitor)
begin
dump_dut_state();
end
end
//----------------------------------------------------------------
// dump_dut_state()
//
// Dump the state of the dump when needed.
//----------------------------------------------------------------
task dump_dut_state;
begin : dump_dut_state
$display("State of DUT at cycle: %08d", cycle_ctr);
$display("------------");
$display("Inputs and outputs:");
$display("tb_cpu_trap: 0x%1x, fw_app_mode: 0x%1x", tb_cpu_trap, tb_fw_app_mode);
$display("cpu_addr: 0x%08x, cpu_instr: 0x%1x, cpu_valid: 0x%1x, force_tap: 0x%1x",
tb_cpu_addr, tb_cpu_instr, tb_cpu_valid, tb_force_trap);
$display("ram_aslr: 0x%08x, ram_scramble: 0x%08x", tb_ram_aslr, tb_ram_scramble);
$display("led_r: 0x%1x, led_g: 0x%1x, led_b: 0x%1x", tb_led_r, tb_led_g, tb_led_b);
$display("ready: 0x%1x, cs: 0x%1x, we: 0x%1x, address: 0x%02x", tb_ready, tb_cs, tb_we, tb_address);
$display("write_data: 0x%08x, read_data: 0x%08x", tb_write_data, tb_read_data);
$display("");
$display("Internal state:");
$display("tmp_read_ready: 0x%1x, tmp_read_data: 0x%08x", dut.tmp_ready, dut.tmp_read_data);
$display("");
$display("");
end
endtask // dump_dut_state
//----------------------------------------------------------------
// reset_dut()
//
// Toggle reset to put the DUT into a well known state.
//----------------------------------------------------------------
task reset_dut;
begin
$display("--- Toggle reset.");
tb_reset_n = 0;
#(2 * CLK_PERIOD);
tb_reset_n = 1;
end
endtask // reset_dut
//----------------------------------------------------------------
// display_test_result()
//
// Display the accumulated test results.
//----------------------------------------------------------------
task display_test_result;
begin
if (error_ctr == 0)
begin
$display("--- All %02d test cases completed successfully", tc_ctr);
end
else
begin
$display("--- %02d tests completed - %02d test cases did not complete successfully.",
tc_ctr, error_ctr);
end
end
endtask // display_test_result
//----------------------------------------------------------------
// init_sim()
//
// Initialize all counters and testbed functionality as well
// as setting the DUT inputs to defined values.
//----------------------------------------------------------------
task init_sim;
begin
cycle_ctr = 0;
error_ctr = 0;
tc_ctr = 0;
tb_monitor = 0;
tb_clk = 1'h0;
tb_reset_n = 1'h1;
tb_cpu_addr = 32'h0;
tb_cpu_instr = 1'h0;
tb_cpu_valid = 1'h0;
tb_cpu_trap = 1'h0;
tb_gpio1 = 1'h0;
tb_gpio2 = 1'h0;
tb_cs = 1'h0;
tb_we = 1'h0;
tb_address = 8'h0;
tb_write_data = 32'h0;
end
endtask // init_sim
//----------------------------------------------------------------
// write_word()
//
// Write the given word to the DUT using the DUT interface.
//----------------------------------------------------------------
task write_word(input [11 : 0] address,
input [31 : 0] word);
begin
if (DEBUG)
begin
$display("--- Writing 0x%08x to 0x%02x.", word, address);
$display("");
end
tb_address = address;
tb_write_data = word;
tb_cs = 1;
tb_we = 1;
#(2 * CLK_PERIOD);
tb_cs = 0;
tb_we = 0;
end
endtask // write_word
//----------------------------------------------------------------
// read_word()
//
// Read a data word from the given address in the DUT.
// the word read will be available in the global variable
// read_data.
//----------------------------------------------------------------
task read_word(input [11 : 0] address, input [31 : 0] expected);
begin : read_word
reg [31 : 0] read_data;
tb_address = address;
tb_cs = 1'h1;
#(CLK_HALF_PERIOD);
read_data = tb_read_data;
#(CLK_HALF_PERIOD);
tb_cs = 1'h0;
if (DEBUG)
begin
if (read_data == expected) begin
$display("--- Reading 0x%08x from 0x%02x.", read_data, address);
end else begin
$display("--- Error: Got 0x%08x when reading from 0x%02x, expected 0x%08x",
read_data, address, expected);
error_ctr = error_ctr + 1;
end
$display("");
end
end
endtask // read_word
//----------------------------------------------------------------
// test1()
// Read out name and version.
//----------------------------------------------------------------
task test1;
begin
tc_ctr = tc_ctr + 1;
$display("");
$display("--- test1: Read out name and version started.");
read_word(ADDR_NAME0, 32'h746B3120);
read_word(ADDR_NAME1, 32'h6d6b6466);
read_word(ADDR_VERSION, 32'h00000005);
$display("--- test1: completed.");
$display("");
end
endtask // test1
//----------------------------------------------------------------
// test2()
// Read out UDI.
//----------------------------------------------------------------
task test2;
begin
tc_ctr = tc_ctr + 1;
$display("");
$display("--- test2: Read out UDI started.");
read_word(ADDR_UDI_FIRST, 32'h00010203);
read_word(ADDR_UDI_LAST, 32'h04050607);
$display("--- test2: completed.");
$display("");
end
endtask // test2
//----------------------------------------------------------------
// test3()
// Read out CDI.
//----------------------------------------------------------------
task test3;
begin
tc_ctr = tc_ctr + 1;
$display("");
$display("--- test3: Write and read CDI started.");
$display("--- test3: Write CDI.");
write_word(ADDR_CDI_FIRST + 0, 32'hf0f1f2f3);
write_word(ADDR_CDI_FIRST + 1, 32'he0e1e2e3);
write_word(ADDR_CDI_FIRST + 2, 32'hd0d1d2d3);
write_word(ADDR_CDI_FIRST + 3, 32'hc0c1c2c3);
write_word(ADDR_CDI_FIRST + 4, 32'ha0a1a2a3);
write_word(ADDR_CDI_FIRST + 5, 32'h90919293);
write_word(ADDR_CDI_FIRST + 6, 32'h80818283);
write_word(ADDR_CDI_FIRST + 7, 32'h70717273);
$display("--- test3: Read CDI.");
read_word(ADDR_CDI_FIRST + 0, 32'hf0f1f2f3);
read_word(ADDR_CDI_FIRST + 1, 32'he0e1e2e3);
read_word(ADDR_CDI_FIRST + 2, 32'hd0d1d2d3);
read_word(ADDR_CDI_FIRST + 3, 32'hc0c1c2c3);
read_word(ADDR_CDI_FIRST + 4, 32'ha0a1a2a3);
read_word(ADDR_CDI_FIRST + 5, 32'h90919293);
read_word(ADDR_CDI_FIRST + 6, 32'h80818283);
read_word(ADDR_CDI_LAST + 0, 32'h70717273);
$display("--- test3: Switch to app mode.");
write_word(ADDR_SWITCH_APP, 32'hdeadbeef);
$display("--- test3: Try to write CDI again.");
write_word(ADDR_CDI_FIRST + 0, 32'hfffefdfc);
write_word(ADDR_CDI_FIRST + 1, 32'hefeeedec);
write_word(ADDR_CDI_FIRST + 2, 32'hdfdedddc);
write_word(ADDR_CDI_FIRST + 3, 32'hcfcecdcc);
write_word(ADDR_CDI_FIRST + 4, 32'hafaeadac);
write_word(ADDR_CDI_FIRST + 5, 32'h9f9e9d9c);
write_word(ADDR_CDI_FIRST + 6, 32'h8f8e8d8c);
write_word(ADDR_CDI_FIRST + 7, 32'h7f7e7d7c);
$display("--- test3: Read CDI again.");
read_word(ADDR_CDI_FIRST + 0, 32'hf0f1f2f3);
read_word(ADDR_CDI_FIRST + 1, 32'he0e1e2e3);
read_word(ADDR_CDI_FIRST + 2, 32'hd0d1d2d3);
read_word(ADDR_CDI_FIRST + 3, 32'hc0c1c2c3);
read_word(ADDR_CDI_FIRST + 4, 32'ha0a1a2a3);
read_word(ADDR_CDI_FIRST + 5, 32'h90919293);
read_word(ADDR_CDI_FIRST + 6, 32'h80818283);
read_word(ADDR_CDI_LAST + 0, 32'h70717273);
$display("--- test3: completed.");
$display("");
end
endtask // test3
//----------------------------------------------------------------
// test4()
// Write and read blake2s entry point.
//----------------------------------------------------------------
task test4;
begin
tc_ctr = tc_ctr + 1;
$display("");
$display("--- test4: Write and read blake2s entry point in fw mode started.");
$display("--- test4: Reset DUT to switch to fw mode.");
reset_dut();
$display("--- test4: Write Blake2s entry point.");
write_word(ADDR_BLAKE2S, 32'hcafebabe);
$display("--- test4: Read Blake2s entry point.");
read_word(ADDR_BLAKE2S, 32'hcafebabe);
$display("--- test4: Switch to app mode.");
write_word(ADDR_SWITCH_APP, 32'hf00ff00f);
$display("--- test4: Write Blake2s entry point again.");
write_word(ADDR_BLAKE2S, 32'hdeadbeef);
$display("--- test4: Read Blake2s entry point again");
read_word(ADDR_BLAKE2S, 32'hcafebabe);
$display("--- test4: completed.");
$display("");
end
endtask // test4
//----------------------------------------------------------------
// test5()
// Write and read APP start address end size.
//----------------------------------------------------------------
task test5;
begin
tc_ctr = tc_ctr + 1;
$display("");
$display("--- test5: Write and read app start and size in fw mode started.");
$display("--- test5: Reset DUT to switch to fw mode.");
reset_dut();
$display("--- test5: Write app start address and size.");
write_word(ADDR_APP_START, 32'h13371337);
write_word(ADDR_APP_SIZE, 32'h47114711);
$display("--- test5: Read app start address and size.");
read_word(ADDR_APP_START, 32'h13371337);
read_word(ADDR_APP_SIZE, 32'h47114711);
$display("--- test5: Switch to app mode.");
write_word(ADDR_SWITCH_APP, 32'hf000000);
$display("--- test5: Write app start address and size again.");
write_word(ADDR_APP_START, 32'hdeadbeef);
write_word(ADDR_APP_SIZE, 32'hf00ff00f);
$display("--- test5: Read app start address and size.");
read_word(ADDR_APP_START, 32'h13371337);
read_word(ADDR_APP_SIZE, 32'h47114711);
$display("--- test5: completed.");
$display("");
end
endtask // test5
//----------------------------------------------------------------
// test6()
// Write and RAM scrambling in fw mode.
//----------------------------------------------------------------
task test6;
begin
tc_ctr = tc_ctr + 1;
$display("");
$display("--- test6: Write RAM scrambling in fw mode.");
$display("--- test6: Reset DUT to switch to fw mode.");
reset_dut();
$display("--- test6: Write RAM ASLR and RAM SCRAMBLE.");
write_word(ADDR_RAM_ASLR, 32'h13371337);
write_word(ADDR_RAM_SCRAMBLE, 32'h47114711);
$display("--- test6: Check value in dut RAM ASLR and SCRAMBLE registers.");
$display("--- test6: ram_aslr_reg: 0x%04x, ram_scramble_reg: 0x%08x", dut.ram_aslr_reg, dut.ram_scramble_reg);
$display("--- test6: Switch to app mode.");
write_word(ADDR_SWITCH_APP, 32'hf000000);
$display("--- test6: Write RAM ASLR and SCRAMBLE again.");
write_word(ADDR_RAM_ASLR, 32'hdeadbeef);
write_word(ADDR_RAM_SCRAMBLE, 32'hf00ff00f);
$display("--- test6: Check value in dut RAM ASLR and SCRAMBLE registers.");
$display("--- test6: ram_aslr_reg: 0x%04x, ram_scramble_reg: 0x%08x", dut.ram_aslr_reg, dut.ram_scramble_reg);
$display("--- test6: completed.");
$display("");
end
endtask // test6
//----------------------------------------------------------------
// test7()
// LED control.
//----------------------------------------------------------------
task test7;
begin
tc_ctr = tc_ctr + 1;
$display("");
$display("--- test7: LED control started.");
$display("--- test7: LEDs R: 0x%1x, G: 0x%1x, B: 0x%1x", tb_led_r, tb_led_g, tb_led_g);
$display("--- test7: Writing to LED control address to invert LED output.");
write_word(ADDR_LED, 32'h0);
$display("--- test7: LEDs R: 0x%1x, G: 0x%1x, B: 0x%1x", tb_led_r, tb_led_g, tb_led_g);
$display("--- test7: completed.");
$display("");
end
endtask // test7
//----------------------------------------------------------------
// test8()
// GPIO control.
//----------------------------------------------------------------
task test8;
begin
tc_ctr = tc_ctr + 1;
$display("");
$display("--- test8: GPIO control started.");
$display("--- test8: Set Inputs for GPIO 1 and 2 high.");
tb_gpio1 = 1'h1;
tb_gpio2 = 1'h1;
#(2 * CLK_PERIOD);
$display("--- test8: Check that we can read GPIO 1 and 2 as high.");
read_word(ADDR_GPIO, 32'h3);
$display("--- test8: Set GPIO 3 and 4 high by writing to the registers.");
write_word(ADDR_GPIO, 32'hf);
$display("--- test8: gpio3: 0x%1x, gpio4: 0x%1x", tb_gpio3, tb_gpio4);
$display("--- test8: completed.");
$display("");
end
endtask // test8
//----------------------------------------------------------------
// test9()
// EXE monitor control and detection.
//----------------------------------------------------------------
task test9;
begin
tc_ctr = tc_ctr + 1;
$display("");
$display("--- test9: EXE monitor control and detection started.");
$display("--- test9: Define and enable a memory area.");
write_word(ADDR_CPU_MON_FIRST, 32'h10000000);
write_word(ADDR_CPU_MON_LAST, 32'h20000000);
write_word(ADDR_CPU_MON_CTRL, 32'h1);
$display("--- test9: cpu_mon_first_reg: 0x%08x, cpu_mon_last_reg: 0x%08x",
dut.cpu_mon_first_reg, dut.cpu_mon_last_reg);
$display("--- test9: Try to redefine memory area after enabling monitor.");
write_word(ADDR_CPU_MON_FIRST, 32'hdeadbabe);
write_word(ADDR_CPU_MON_LAST, 32'hdeadcafe);
$display("--- test9: cpu_mon_first_reg: 0x%08x, cpu_mon_last_reg: 0x%08x",
dut.cpu_mon_first_reg, dut.cpu_mon_last_reg);
$display("--- test9: force_trap before illegal access: 0x%1x", tb_force_trap);
$display("--- test9: Creating an illegal access.");
tb_cpu_addr = 32'h13371337;
tb_cpu_instr = 1'h1;
tb_cpu_valid = 1'h1;
#(2 * CLK_PERIOD);
$display("--- test9: cpu_addr: 0x%08x, cpu_instr: 0x%1x, cpu_valid: 0x%1x",
tb_cpu_addr, tb_cpu_instr, tb_cpu_valid);
$display("--- test9: force_trap: 0x%1x", tb_force_trap);
$display("--- test9: completed.");
$display("");
end
endtask // test8
//----------------------------------------------------------------
// tk1_test
//----------------------------------------------------------------
initial
begin : tk1_test
$display("");
$display(" -= Testbench for tk1 started =-");
$display(" ===========================");
$display("");
init_sim();
reset_dut();
test1();
test2();
test3();
test4();
test5();
test6();
test7();
test8();
test9();
display_test_result();
$display("");
$display(" -= Testbench for tk1 completed =-");
$display(" =============================");
$display("");
$finish;
end // tk1_test
endmodule // tb_tk1
//======================================================================
// EOF tb_tk1.v
//======================================================================

View File

@ -0,0 +1,2 @@
00010203
04050607

View File

@ -0,0 +1,55 @@
#===================================================================
#
# Makefile
# --------
# Makefile for building the TK1 core simulation target.
#
#
# Author: Joachim Strombergson
# Copyright (C) 2023 - Tillitis AB
# SPDX-License-Identifier: GPL-2.0-only
#
#===================================================================
TOP_SRC=../rtl/tk1.v
TB_TOP_SRC =../tb/tb_tk1.v ../tb/sb_rgba_drv.v
CC = iverilog
CC_FLAGS = -Wall
LINT = verilator
LINT_FLAGS = +1364-2005ext+ --lint-only -Wall -Wno-fatal -Wno-DECLFILENAME
all: top.sim
top.sim: $(TB_TOP_SRC) $(TOP_SRC)
$(CC) $(CC_FLAGS) -o top.sim $(TB_TOP_SRC) $(TOP_SRC) -DUDI_HEX=\"../tb/udi.hex\"
sim-top: top.sim
./top.sim
lint-top: $(TOP_SRC)
$(LINT) $(LINT_FLAGS) $(TOP_SRC)
clean:
rm -f top.sim
help:
@echo "Build system for simulation of TK1 core"
@echo ""
@echo "Supported targets:"
@echo "------------------"
@echo "top.sim: Build top level simulation target."
@echo "sim-top: Run top level simulation."
@echo "lint-top: Lint top rtl source files."
@echo "clean: Delete all built files."
#===================================================================
# EOF Makefile
#===================================================================

View File

@ -1,5 +1,29 @@
# touch_sense
Core that handles touch senor events and provides them via an API.
Core that handles touch sensor events and provides them to the SW via
an API.
## Introduction
This core implements a touch sensor handler. The core detects and holds events for SW to read. The user must lift the finger between touch events.
This core implements a touch sensor handler. The core detects and
holds events for SW to read. The touch sensor input is expected to be
a change in level from low (0) to high (1). When an event is seen, the
core will set a status bit that SW can read.
SW must clear the captured event by writing to the status
register. The core will wait for the sensor input to become low again
before being able to detect another event.
## API
The API has a single address, and a single bit in that address:
```
ADDR_STATUS: 0x09
STATUS_EVENT_BIT: 0
```
SW should clear any stray attempts before signalling to the user that
a touch event is expected. Clearing an event is done by writing the
the status address, the value written does not matter.

View File

@ -18,16 +18,12 @@ module tb_touch_sense();
//----------------------------------------------------------------
// Internal constant and parameter definitions.
//----------------------------------------------------------------
parameter DEBUG = 0;
parameter DEBUG = 1;
parameter DUMP_WAIT = 0;
parameter CLK_HALF_PERIOD = 1;
parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD;
localparam ADDR_NAME0 = 8'h00;
localparam ADDR_NAME1 = 8'h01;
localparam ADDR_VERSION = 8'h02;
localparam ADDR_STATUS = 8'h09;
localparam STATUS_READY_BIT = 0;
@ -174,7 +170,7 @@ module tb_touch_sense();
//
// Write the given word to the DUT using the DUT interface.
//----------------------------------------------------------------
task write_word(input [11 : 0] address,
task write_word(input [7 : 0] address,
input [31 : 0] word);
begin
if (DEBUG)
@ -200,7 +196,7 @@ module tb_touch_sense();
// the word read will be available in the global variable
// read_data.
//----------------------------------------------------------------
task read_word(input [11 : 0] address);
task read_word(input [7 : 0] address);
begin
tb_address = address;
tb_cs = 1;
@ -233,7 +229,10 @@ module tb_touch_sense();
//----------------------------------------------------------------
// test1()
// test1.
// Create a touch event check that it is accessible from the
// API. Clear the event from the API and check that it is
// really cleared.
//----------------------------------------------------------------
task test1;
begin
@ -242,10 +241,45 @@ module tb_touch_sense();
$display("");
$display("--- test1: started.");
// Set touch event to low:
tb_touch_event = 1'h0;
// Clear the event handler.
$display("--- test1: Clearing any stray event.");
write_word(8'h09, 32'h0);
// Check status.
#(CLK_PERIOD);
read_word(8'h09);
// Set touch event input to high.
$display("--- test1: Creating a touch event.");
tb_touch_event = 1'h1;
$display("--- test1: Waiting for the event to be caught.");
wait_ready();
$display("--- test1: Event has been seen.");
$display("--- test1: Dropping the event input.");
tb_touch_event = 1'h0;
#(CLK_PERIOD);
$display("--- test1: Clearing the event.");
write_word(8'h09, 32'h0);
#(CLK_PERIOD);
// Check that the event is now removed.
read_word(8'h09);
#(CLK_PERIOD);
$display("--- test1: Event has been cleared.");
read_word(8'h09);
#(CLK_PERIOD);
$display("--- test1: completed.");
$display("");
end
endtask // tes1
endtask // test1
//----------------------------------------------------------------
@ -260,6 +294,7 @@ module tb_touch_sense();
init_sim();
reset_dut();
test1();
display_test_result();

View File

@ -18,7 +18,7 @@ CC = iverilog
CC_FLAGS = -Wall
LINT = verilator
LINT_FLAGS = +1364-2001ext+ --lint-only -Wall -Wno-fatal -Wno-DECLFILENAME
LINT_FLAGS = +1364-2005ext+ --lint-only -Wall -Wno-fatal -Wno-DECLFILENAME
all: top.sim

View File

@ -1,57 +1,91 @@
# trng
Implementation of the Tillitis True Random Number Generator (TRNG).
## Introduction
Applications running on the Tillitis TKey device may have a need of random numbers.
As unpredictable initial vectors, as challnges, random tokens etc.
The Tillitis TRNG supports these applications by providing a hardware based
source of entropy (digital noise) with a uniform distribution.
Applications running on the Tillitis TKey device may have a need of
random numbers. For unpredictable initial vectors, challnges, random
tokens etc.
Note that the data provided by the TRNG is entropy, not processed random numbers.
The data should NOT be used directly, but used as seed for a (cryptographically safe)
random number generator algorithm.
The Tillitis TRNG supports these applications by providing a hardware
based source of entropy (digital noise) with a uniform distribution.
Note that the data provided by the TRNG is entropy, not processed
random numbers. The data should NOT be used directly, but used as
seed for a (cryptographically safe) random number generator (CSPRNG)
algorithm.
## Status
First version completed. In testing. Use with caution.
## How to use
The ready bit in the status register indicates that there is a new word of
entropy available to read out. Applications requiring multiple words of
entropy MUST wait for the ready bit to be set before reading ut
subseqent words. Not waiting for the ready bit to be set will lead to reading out
the same entropy data more than once.
First version of TKey completed. The TRNG has been tested and provides
good entropy suitable as seed for a CSPRNG (also known as a Digital
Random Bit Generator - DRBG).
Applications that need cryptographically safe random number should use the output
from the TRNG as seed to a Digital Random Bit Generator (DRBG), for example a Hash_DRBG.
## API
The TRNG API provides to readable addresses:
```
ADDR_STATUS: 0x09
STATUS_READY_BIT: 0
ADDR_ENTROPY: 0x20
```
The STATUS_READY_BIT in the status register indicates that there is a
new word of entropy available to read out. When the word is read from
ADDR_ENTROPY register, the ready bit is cleared.
Applications requiring multiple words of entropy MUST wait for the
ready bit to be set again before reading ut subseqent words. Not
waiting for the ready bit to be set will lead to reading out (at least
parts of) the same entropy data more than once.
Applications that need cryptographically safe random number should use
the output from the TRNG as seed to a CSPRNG, , for example a
Hash_DRBG.
## Implementation details
The implementation is based on free running digital oscillators. The implementation creates
two sets of oscillators by instantiating a number if LCs configured as one bit inverter gates,
where the output of the inverter is connected to its own input. The oscillators will have a toggle
rate based on the given internal gate delay and the wire delay through given by the feedback
circuit.
After a given number of clock cycles the outputs from the oscillators in each group are
XOR combined and sampled into two separate registers. This process is repeated a second time,
producing two more bits, one for each group. These two sets of two bits are then XOR combined
to produce a single entropy bit. This means that an entropy bit is the XOR combined result
from two oscillator groups over two sampling events.
The implementation is based on free running digital oscillators. The
implementation creates two sets of oscillators by instantiating a
number if LCs configured as one bit inverter gates, where the output
of the inverter is connected to its own input. The oscillators will
have a toggle rate based on the given internal gate delay and the wire
delay through given by the feedback circuit.
Entropy bits are collected into an entropy word. When at least 32 bits have been collected,
the ready bit is set, indicating to SW that a new entropy word is available.
After a given number of clock cycles (4096) the outputs from the
oscillators in each group are XOR combined and sampled into two
separate registers. This process is repeated a second time, producing
two more bits, one for each group. These two sets of two bits are then
XOR combined to produce a single entropy bit. This means that an
entropy bit is the XOR combined result from two oscillator groups over
two sampling events.
Note that the entropy word is not held for the SW to read out. Sampling and collection is running
continuosly, and the word read by SW will contain the latest 32 bits collected. Entropy bits
not read by SW will be discarded at the same rate as new bits are collected.
Entropy bits are collected into an entropy word. When at least 32 bits
have been collected, the ready bit is set, indicating to SW that a new
entropy word is available.
Currently the following build time parameters are used to configure the implementation:
Note that the entropy word is not held for the SW to read
out. Sampling and collection is running continuosly, and the word read
by SW will contain the latest 32 bits collected. Entropy bits not read
by SW will be discarded at the same rate as new bits are collected.
Currently the following build time parameters are used to configure
the implementation:
- 4096 cycles between sampling
- 16 oscillators in each group
- 64 bits collected before setting the ready flag
With the TKey device running at 18 MHz this means that we sample bits
at 4.3 kbps. Since we sample twice to produce a single bit, the
effective raw bitrate is 2.1 kbps.
The 64 bits collected means that there is a separation of at least 32
collected entropy bits between bits in the words read out.
---

View File

@ -36,7 +36,6 @@ module rosc(
//----------------------------------------------------------------
// API
localparam ADDR_STATUS = 8'h09;
localparam STATUS_READY_BIT = 0;
localparam ADDR_ENTROPY = 8'h20;
// Total number of ROSCs will be 2 x NUM_ROSC.
@ -115,10 +114,12 @@ module rosc(
for(i = 0 ; i < NUM_ROSC ; i = i + 1)
begin: oscillators
/* verilator lint_off PINMISSING */
/* verilator lint_off UNOPTFLAT */
(* keep *) SB_LUT4 #(.LUT_INIT(16'h1)) osc_inv_f (.I0(f[i]), .O(f[i]));
(* keep *) SB_LUT4 #(.LUT_INIT(16'h1)) osc_inv_g (.I0(g[i]), .O(g[i]));
/* verilator lint_off PINMISSING */
/* verilator lint_on UNOPTFLAT */
/* verilator lint_on PINMISSING */
end
endgenerate

View File

@ -0,0 +1,29 @@
//======================================================================
//
// SB_LUT4.v
// ---------
// Simulation model of the SB_LUT4 macro used to buil the sim target.
//
//
// Author: Joachim Strombergson
// Copyright (C) 2023 - Tillitis AB
// SPDX-License-Identifier: GPL-2.0-only
//
//======================================================================
`default_nettype none
module SB_LUT4 (
input wire I0,
output wire O
);
parameter LUT_INIT = 16'h0;
assign O = ~I0;
endmodule // SB_LUT4
//======================================================================
// EOF SB_LUT4.v
//======================================================================

View File

@ -0,0 +1,255 @@
//======================================================================
//
// tb_trng.v
// -----------
// Testbench for the TRNG core.
//
//
// Author: Joachim Strombergson
// Copyright (C) 2022 - Tillitis AB
// SPDX-License-Identifier: GPL-2.0-only
//
//======================================================================
`default_nettype none
module tb_trng();
//----------------------------------------------------------------
// Internal constant and parameter definitions.
//----------------------------------------------------------------
parameter DEBUG = 1;
parameter CLK_HALF_PERIOD = 1;
parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD;
// API
localparam ADDR_STATUS = 8'h09;
localparam STATUS_READY_BIT = 0;
localparam ADDR_ENTROPY = 8'h20;
//----------------------------------------------------------------
// Register and Wire declarations.
//----------------------------------------------------------------
reg [31 : 0] cycle_ctr;
reg [31 : 0] error_ctr;
reg [31 : 0] tc_ctr;
reg tb_monitor;
reg tb_clk;
reg tb_reset_n;
reg tb_cs;
reg tb_we;
reg [7 : 0] tb_address;
reg [31 : 0] tb_write_data;
wire [31 : 0] tb_read_data;
wire tb_ready;
//----------------------------------------------------------------
// Device Under Test.
//----------------------------------------------------------------
rosc dut(
.clk(tb_clk),
.reset_n(tb_reset_n),
.cs(tb_cs),
.we(tb_cs),
.address(tb_address),
.write_data(tb_write_data),
.read_data(tb_read_data),
.ready(tb_ready)
);
//----------------------------------------------------------------
// clk_gen
//
// Always running clock generator process.
//----------------------------------------------------------------
always
begin : clk_gen
#CLK_HALF_PERIOD;
tb_clk = !tb_clk;
end // clk_gen
//----------------------------------------------------------------
// sys_monitor()
//
// An always running process that creates a cycle counter and
// conditionally displays information about the DUT.
//----------------------------------------------------------------
always
begin : sys_monitor
cycle_ctr = cycle_ctr + 1;
#(CLK_PERIOD);
if (tb_monitor)
begin
dump_dut_state();
end
end
//----------------------------------------------------------------
// dump_dut_state()
//
// Dump the state of the dump when needed.
//----------------------------------------------------------------
task dump_dut_state;
begin : dump_dut_state
integer i;
$display("State of DUT at cycle: %08d", cycle_ctr);
$display("------------");
$display("Inputs and outputs:");
$display("cs: 0x%1x, address: 0x%02x, read_data: 0x%08x", tb_cs, tb_address, tb_read_data);
$display("");
$display("Internal state:");
$display("tmp_read_ready: 0x%1x, tmp_read_data: 0x%08x", dut.tmp_ready, dut.tmp_read_data);
$display("cycle_ctr_done: 0x%1x, cycle_ctr_rst: 0x%1x, cycle_ctr: 0x%04x",
dut.cycle_ctr_done, dut.cycle_ctr_rst, dut.cycle_ctr_reg);
$display("bit_ctr: 0x%02x", dut.bit_ctr_reg);
$display("");
$display("");
end
endtask // dump_dut_state
//----------------------------------------------------------------
// reset_dut()
//
// Toggle reset to put the DUT into a well known state.
//----------------------------------------------------------------
task reset_dut;
begin
$display("--- Toggle reset.");
tb_reset_n = 0;
#(2 * CLK_PERIOD);
tb_reset_n = 1;
end
endtask // reset_dut
//----------------------------------------------------------------
// display_test_result()
//
// Display the accumulated test results.
//----------------------------------------------------------------
task display_test_result;
begin
if (error_ctr == 0)
begin
$display("--- All %02d test cases completed successfully", tc_ctr);
end
else
begin
$display("--- %02d tests completed - %02d test cases did not complete successfully.",
tc_ctr, error_ctr);
end
end
endtask // display_test_result
//----------------------------------------------------------------
// init_sim()
//
// Initialize all counters and testbed functionality as well
// as setting the DUT inputs to defined values.
//----------------------------------------------------------------
task init_sim;
begin
cycle_ctr = 0;
error_ctr = 0;
tc_ctr = 0;
tb_monitor = 0;
tb_clk = 1'h0;
tb_reset_n = 1'h1;
tb_cs = 1'h0;
tb_cs = 1'h0;
tb_address = 8'h0;
tb_write_data = 32'h0;
end
endtask // init_sim
//----------------------------------------------------------------
// read_word()
//
// Read a data word from the given address in the DUT.
// the word read will be available in the global variable
// read_data.
//----------------------------------------------------------------
task read_word(input [11 : 0] address, input [31 : 0] expected);
begin : read_word
reg [31 : 0] read_data;
tb_address = address;
tb_cs = 1'h1;
#(CLK_HALF_PERIOD);
read_data = tb_read_data;
#(CLK_HALF_PERIOD);
tb_cs = 1'h0;
if (DEBUG)
begin
if (read_data == expected) begin
$display("--- Reading 0x%08x from 0x%02x.", read_data, address);
end else begin
$display("--- Error: Got 0x%08x when reading from 0x%02x, expected 0x%08x",
read_data, address, expected);
error_ctr = error_ctr + 1;
end
$display("");
end
end
endtask // read_word
//----------------------------------------------------------------
// test1()
//----------------------------------------------------------------
task test1;
begin
tc_ctr = tc_ctr + 1;
tb_monitor = 1;
$display("");
$display("--- test1: started.");
read_word(ADDR_STATUS, 32'h0);
$display("--- test1: completed.");
$display("");
end
endtask // test1
//----------------------------------------------------------------
// trng_test
//----------------------------------------------------------------
initial
begin : trng_test
$display("");
$display(" -= Testbench for trng started =-");
$display(" ============================");
$display("");
init_sim();
reset_dut();
test1();
display_test_result();
$display("");
$display(" -= Testbench for trng completed =-");
$display(" ==============================");
$display("");
$finish;
end // trng_test
endmodule // tb_trng
//======================================================================
// EOF tb_trng.v
//======================================================================

View File

@ -0,0 +1,55 @@
#===================================================================
#
# Makefile
# --------
# Makefile for building the trng core.
#
#
# Author: Joachim Strombergson
# Copyright (C) 2023 - Tillitis AB
# SPDX-License-Identifier: GPL-2.0-only
#
#===================================================================
TOP_SRC=../rtl/rosc.v
TB_TOP_SRC =../tb/tb_trng.v ../tb/SB_LUT4.v
CC = iverilog
CC_FLAGS = -Wall
LINT = verilator
LINT_FLAGS = +1364-2005ext+ --lint-only -Wall -Wno-fatal -Wno-DECLFILENAME
all: top.sim
top.sim: $(TB_TOP_SRC) $(TOP_SRC)
$(CC) $(CC_FLAGS) -o top.sim $(TB_TOP_SRC) $(TOP_SRC)
sim-top: top.sim
./top.sim
lint-top: $(TOP_SRC)
$(LINT) $(LINT_FLAGS) $(TOP_SRC)
clean:
rm -f top.sim
help:
@echo "Build system for simulation of trng core"
@echo ""
@echo "Supported targets:"
@echo "------------------"
@echo "top.sim: Build top level simulation target."
@echo "sim-top: Run top level simulation."
@echo "lint-top: Lint top rtl source files."
@echo "clean: Delete all built files."
#===================================================================
# EOF Makefile
#===================================================================

View File

@ -2,8 +2,41 @@ uart
====
A simple universal asynchronous receiver/transmitter (UART) core
implemented in Verilog.
implemented in Verilog. The core is completed and has been used in
several FPGA designs.
# Status
The core is completed and has been used in several FPGA designs.
## Introduction
The UART core is used as main communication channel between the TKey
device System on Chip (SoC) and the TKey client. The UART contains a
512 byte receive buffer, allowing the SW running on the SoC to not
have to wait for bytes and poll them as soon as they are received. The
number of bytes in the FIFO is also exposed to the SW through the
ADDR_RX_BYTES address.
The number of data and data bits can be set by SW. The default is
eight data bits and one stop bit.
The default bit rate is based on target clock frequency divided by the
bit rate times in order to hit the center of the bits. I.e. Clock: 18
MHz, 62500 bps Divisor = 18E6 / 62500 = 288
## API
```
ADDR_BIT_RATE: 0x10
ADDR_DATA_BITS: 0x11
ADDR_STOP_BITS: 0x12
ADDR_RX_STATUS: 0x20
ADDR_RX_DATA: 0x21
ADDR_RX_BYTES: 0x22
ADDR_TX_STATUS: 0x40
ADDR_TX_DATA: 0x41
```
## Implementation notes.
The FIFO allocates a single block RAM (EBR).

View File

@ -61,7 +61,7 @@ module uart_core(
// Internal receive interface.
output wire rxd_syn,
output [7 : 0] rxd_data,
output wire [7 : 0] rxd_data,
input wire rxd_ack,
// Internal transmit interface.

View File

@ -59,19 +59,12 @@ module tb_uart();
reg tb_reset_n;
reg tb_rxd;
wire tb_txd;
wire tb_rxd_syn;
wire [7 : 0] tb_rxd_data;
wire tb_rxd_ack;
wire tb_txd_syn;
wire [7 : 0] tb_txd_data;
wire tb_txd_ack;
reg tb_cs;
reg tb_we;
reg [7 : 0] tb_address;
reg [31 : 0] tb_write_data;
wire [31 : 0] tb_read_data;
wire tb_error;
wire [7 : 0] tb_debug;
wire tb_ready;
reg txd_state;
@ -86,33 +79,19 @@ module tb_uart();
.rxd(tb_rxd),
.txd(tb_txd),
.rxd_syn(tb_rxd_syn),
.rxd_data(tb_rxd_data),
.rxd_ack(tb_rxd_ack),
// Internal transmit interface.
.txd_syn(tb_txd_syn),
.txd_data(tb_txd_data),
.txd_ack(tb_txd_ack),
// API interface.
.cs(tb_cs),
.we(tb_we),
.address(tb_address),
.write_data(tb_write_data),
.read_data(tb_read_data),
.error(tb_error),
.debug(tb_debug)
.ready(tb_ready)
);
//----------------------------------------------------------------
// Concurrent assignments.
//----------------------------------------------------------------
// We connect the internal facing ports on the dut together.
assign tb_txd_syn = tb_rxd_syn;
assign tb_txd_data = tb_rxd_data;
assign tb_rxd_ack = tb_txd_ack;
//----------------------------------------------------------------
@ -223,9 +202,6 @@ module tb_uart();
//----------------------------------------------------------------
task dump_tx_state;
begin
$display("txd = 0x%01x, txd_reg = 0x%01x, txd_byte_reg = 0x%01x, txd_bit_ctr_reg = 0x%01x, txd_bitrate_ctr_reg = 0x%02x, txd_ack = 0x%01x, etx_ctrl_reg = 0x%02x",
dut.core.txd, dut.core.txd_reg, dut.core.txd_byte_reg, dut.core.txd_bit_ctr_reg,
dut.core.txd_bitrate_ctr_reg, dut.core.txd_ack, dut.core.etx_ctrl_reg);
end
endtask // dump_dut_state
@ -260,8 +236,8 @@ module tb_uart();
tb_rxd = 1;
tb_cs = 0;
tb_we = 0;
tb_address = 8'h00;
tb_write_data = 32'h00000000;
tb_address = 8'h0;
tb_write_data = 32'h0;
txd_state = 1;
end

View File

@ -0,0 +1,55 @@
#===================================================================
#
# Makefile
# --------
# Makefile for building the UART core.
#
#
# Author: Joachim Strombergson
# Copyright (C) 2022 - Tillitis AB
# SPDX-License-Identifier: GPL-2.0-only
#
#===================================================================
TOP_SRC=../rtl/uart.v ../rtl/uart_core.v ../rtl/uart_fifo.v
TB_TOP_SRC =../tb/tb_uart.v
CC = iverilog
CC_FLAGS = -Wall
LINT = verilator
LINT_FLAGS = +1364-2005ext+ --lint-only -Wall -Wno-fatal -Wno-DECLFILENAME
all: top.sim
top.sim: $(TB_TOP_SRC) $(TOP_SRC)
$(CC) $(CC_FLAGS) -o top.sim $(TB_TOP_SRC) $(TOP_SRC)
sim-top: top.sim
./top.sim
lint-top: $(TOP_SRC)
$(LINT) $(LINT_FLAGS) $(TOP_SRC)
clean:
rm -f top.sim
help:
@echo "Build system for simulation of UART core"
@echo ""
@echo "Supported targets:"
@echo "------------------"
@echo "top.sim: Build top level simulation target."
@echo "sim-top: Run top level simulation."
@echo "lint-top: Lint top rtl source files."
@echo "clean: Delete all built files."
#===================================================================
# EOF Makefile
#===================================================================

View File

@ -0,0 +1,62 @@
# uds
Unique Device Secret core
## Introduction
This core store and protect the Unique Device Secret (UDS) asset. The
UDS can be accessed as eight separate 32-bit words. The words can only
be accessed as long as the fw_app_mode input is low, implying that the
CPU is executing the FW.
The UDS words can be accessed in any order, but a given word can only
be accessed once between reset cycles. This read once functionality is
implemented with a companion read bit for each word. The read bit is
set when the word is first accessed. The read bit controls if the real
UDS word is returned or not.
This means that the even if the chip select (cs) control
input is forced high, the content will become all zero when the read
bit has been set after one cycle.
## API
There are eight addresses in the API. These are defined by the
two values ADDR_UDS_FIRST and ADDR_UDS_LAST:
```
ADDR_UDS_FIRST: 0x10
ADDR_UDS_LAST: 0x17
```
These addresses are read only and read once between reset.
Any access to another address will be ignored by the core.
## Implementation
These read-only registers provide read access to the 256-bit UDS.
The eight UDS words are stored using 32 named SB\_LUT4 FPGA
multiplexer (MUX) instances, identified in the source code as
"uds\_rom\_idx". One instance for each bit in the core read\_data
output bus.
During build of the FPGA design, the UDS is set to a known bit
pattern, which means that the SB\_LUT4 instantiations are initialized
to a fixed bit pattern.
The tool 'patch\_uds\_udi.py' is used to replace the fixed bit pattern
with a unique bit pattern before generating the per device unique FPGA
bitstream. This allows us to generate these device unique FPGA
bitstreams without haveing to do a full FPGA build.
Each SB\_LUT4 MUX is able to store 16 bits of data, in total 512 bits.
But since the UDS is 256 bits, we only use the eight LSBs in each MUX.
The eighth MSBs in each MUX will be initialized to zero. The read
access bit (se description above) for a given word is used as the
highest address bit to the MUXes. This forces any subsequent accesses
to a UDS word to read from the MUX MSBs, not the LSBs where the UDS is
stored.

View File

@ -1,7 +0,0 @@
# uds
Unique Device Secret core
## Introduction
This core store and protect the Unique Device Secret. The
storage is implemented in discrete registers. The contents can be read once between chip reset, and only if the system is in not in application access mode.

View File

@ -20,25 +20,15 @@ module uds(
input wire fw_app_mode,
input wire cs,
input wire [7 : 0] address,
input wire [2 : 0] address,
output wire [31 : 0] read_data,
output wire ready
);
//----------------------------------------------------------------
// Internal constant and parameter definitions.
//----------------------------------------------------------------
localparam ADDR_UDS_FIRST = 8'h10;
localparam ADDR_UDS_LAST = 8'h17;
//----------------------------------------------------------------
// Registers including update variables and write enable.
//----------------------------------------------------------------
reg [31 : 0] uds_reg [0 : 7];
initial $readmemh(`UDS_HEX, uds_reg);
reg uds_rd_reg [0 : 7];
reg uds_rd_we;
@ -57,6 +47,17 @@ module uds(
assign ready = tmp_ready;
//----------------------------------------------------------------
// uds rom instance.
//----------------------------------------------------------------
uds_rom rom_i(
.addr(address),
.re(uds_rd_we),
.data(tmp_read_data)
);
//----------------------------------------------------------------
// reg_update
//----------------------------------------------------------------
@ -85,23 +86,18 @@ module uds(
always @*
begin : api
uds_rd_we = 1'h0;
tmp_read_data = 32'h0;
tmp_ready = 1'h0;
if (cs) begin
tmp_ready = 1'h1;
if ((address >= ADDR_UDS_FIRST) && (address <= ADDR_UDS_LAST)) begin
if (!fw_app_mode) begin
if (uds_rd_reg[address[2 : 0]] == 1'h0) begin
tmp_read_data = uds_reg[address[2 : 0]];
uds_rd_we = 1'h1;
end
end
end
if (!fw_app_mode) begin
if (uds_rd_reg[address[2 : 0]] == 1'h0) begin
uds_rd_we = 1'h1;
end
end
end
end
endmodule // uds
//======================================================================

View File

@ -0,0 +1,39 @@
//======================================================================
//
// uds_rom.v
// ---------
// UDS rom. Generated by instantiating named SB_LUT4 resources.
// Note: This makes the design technology specific.
//
//
// Author: Claire Xenia Wolf
// Copyright (C) 2023 - YosysHQ, Tillitis AB
// SPDX-License-Identifier: GPL-2.0-only
//
//======================================================================
`default_nettype none
module uds_rom(
input wire [2:0] addr,
input wire re,
output wire [31:0] data
);
generate
genvar ii;
for (ii = 0; ii < 32; ii = ii + 1'b1) begin: luts
(* uds_rom_idx=ii, keep *) SB_LUT4
#(
.LUT_INIT({8'ha6 ^ ii[7:0], 8'h00})
) lut_i (
.I0(addr[0]), .I1(addr[1]), .I2(addr[2]), .I3(re),
.O(data[ii])
);
end
endgenerate
endmodule // uds_rom
//======================================================================
// EOF uds_rom.v
//======================================================================

View File

@ -19,26 +19,21 @@ module tb_uds();
// Internal constant and parameter definitions.
//----------------------------------------------------------------
parameter DEBUG = 1;
parameter DUMP_WAIT = 0;
parameter CLK_HALF_PERIOD = 1;
parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD;
localparam ADDR_NAME0 = 8'h00;
localparam ADDR_NAME1 = 8'h01;
localparam ADDR_VERSION = 8'h02;
localparam ADDR_UDS_FIRST = 8'h10;
localparam ADDR_UDS_LAST = 8'h17;
localparam ADDR_UDS_FIRST = 8'h10;
localparam ADDR_UDS_LAST = 8'h17;
//----------------------------------------------------------------
// Register and Wire declarations.
//----------------------------------------------------------------
reg [31 : 0] cycle_ctr;
reg [31 : 0] error_ctr;
reg [31 : 0] tc_ctr;
reg tb_monitor;
reg [31 : 0] cycle_ctr;
reg [31 : 0] error_ctr;
reg [31 : 0] tc_ctr;
reg tb_monitor;
reg tb_clk;
reg tb_reset_n;
@ -47,8 +42,6 @@ module tb_uds();
reg [7 : 0] tb_address;
wire [31 : 0] tb_read_data;
reg [31 : 0] read_data;
//----------------------------------------------------------------
// Device Under Test.
@ -102,13 +95,19 @@ module tb_uds();
task dump_dut_state;
begin : dump_dut_state
integer i;
$display("State of DUT");
$display("State of DUT at cycle: %08d", cycle_ctr);
$display("------------");
$display("Cycle: %08d", cycle_ctr);
$display("Inputs and outputs:");
$display("fw_app_mode: 0x%1x", tb_fw_app_mode);
$display("cs: 0x%1x, address: 0x%02x, read_data: 0x%08x", tb_cs, tb_address, tb_read_data);
$display("");
$display("Internal state:");
$display("tmp_read_ready: 0x%1x, tmp_read_data: 0x%08x", dut.tmp_ready, dut.tmp_read_data);
for (i = 0 ; i < 8 ; i = i + 1) begin
$display("uds_reg[%1d]: 0x%08x, uds_rd_reg[%1d]: 0x%1x",
i, dut.uds_reg[i], i, dut.uds_rd_reg[i]);
$display("uds_reg[%1d]: 0x%08x, uds_rd_reg[%1d]: 0x%1x", i, dut.uds_reg[i], i, dut.uds_rd_reg[i]);
end
$display("");
$display("");
end
@ -179,17 +178,28 @@ module tb_uds();
// the word read will be available in the global variable
// read_data.
//----------------------------------------------------------------
task read_word(input [11 : 0] address);
begin
tb_address = address;
tb_cs = 1;
#(CLK_PERIOD);
task read_word(input [11 : 0] address, input [31 : 0] expected);
begin : read_word
reg [31 : 0] read_data;
tb_address = address;
tb_cs = 1'h1;
#(CLK_HALF_PERIOD);
read_data = tb_read_data;
tb_cs = 0;
#(CLK_HALF_PERIOD);
tb_cs = 1'h0;
if (DEBUG)
begin
$display("--- Reading 0x%08x from 0x%02x.", read_data, address);
if (read_data == expected) begin
$display("--- Reading 0x%08x from 0x%02x.", read_data, address);
end else begin
$display("--- Error: Got 0x%08x when reading from 0x%02x, expected 0x%08x",
read_data, address, expected);
error_ctr = error_ctr + 1;
end
$display("");
end
end
@ -202,72 +212,95 @@ module tb_uds();
task test1;
begin
tc_ctr = tc_ctr + 1;
tb_monitor = 1'h0;
$display("");
$display("--- test1: started.");
$display("--- test1: Filling uds with known values.");
dut.uds_reg[0] = 32'hf0f0f0f0;
dut.uds_reg[1] = 32'he1e1e1e1;
dut.uds_reg[2] = 32'hd2d2d2d2;
dut.uds_reg[3] = 32'hc3c3c3c3;
dut.uds_reg[4] = 32'hb4b4b4b4;
dut.uds_reg[5] = 32'ha5a5a5a5;
dut.uds_reg[6] = 32'h96969696;
dut.uds_reg[7] = 32'h87878787;
$display("--- test1: Dumping DUT state to show UDS contents");
dump_dut_state();
$display("--- test1: Reading UDS words.");
read_word(ADDR_UDS_FIRST + 0);
read_word(ADDR_UDS_FIRST + 1);
read_word(ADDR_UDS_FIRST + 2);
read_word(ADDR_UDS_FIRST + 0, 32'hf0f0f0f0);
read_word(ADDR_UDS_FIRST + 1, 32'he1e1e1e1);
read_word(ADDR_UDS_FIRST + 2, 32'hd2d2d2d2);
$display("--- test1: Dumping state again to see read bits.");
dump_dut_state();
$display("--- test1: Reading rest of the words.");
read_word(ADDR_UDS_FIRST + 3);
read_word(ADDR_UDS_FIRST + 4);
read_word(ADDR_UDS_FIRST + 5);
read_word(ADDR_UDS_FIRST + 6);
read_word(ADDR_UDS_FIRST + 7);
read_word(ADDR_UDS_FIRST + 3, 32'hc3c3c3c3);
read_word(ADDR_UDS_FIRST + 4, 32'hb4b4b4b4);
read_word(ADDR_UDS_FIRST + 5, 32'ha5a5a5a5);
read_word(ADDR_UDS_FIRST + 6, 32'h96969696);
read_word(ADDR_UDS_FIRST + 7, 32'h87878787);
$display("--- test1: Dumping state again to see read bits.");
dump_dut_state();
$display("--- test1: Reading UDS words again.");
read_word(ADDR_UDS_FIRST + 0);
read_word(ADDR_UDS_FIRST + 1);
read_word(ADDR_UDS_FIRST + 2);
read_word(ADDR_UDS_FIRST + 3);
read_word(ADDR_UDS_FIRST + 4);
read_word(ADDR_UDS_FIRST + 5);
read_word(ADDR_UDS_FIRST + 6);
read_word(ADDR_UDS_FIRST + 7);
$display("--- test1: This should return all zeros.");
read_word(ADDR_UDS_FIRST + 0, 32'h0);
read_word(ADDR_UDS_FIRST + 1, 32'h0);
read_word(ADDR_UDS_FIRST + 2, 32'h0);
read_word(ADDR_UDS_FIRST + 3, 32'h0);
read_word(ADDR_UDS_FIRST + 4, 32'h0);
read_word(ADDR_UDS_FIRST + 5, 32'h0);
read_word(ADDR_UDS_FIRST + 6, 32'h0);
read_word(ADDR_UDS_FIRST + 7, 32'h0);
$display("--- test1: Resetting DUT.");
$display("--- test1: This should allow access again.");
reset_dut();
$display("--- test1: Filling uds with new known values.");
dut.uds_reg[0] = 32'h0f0f0f0f;
dut.uds_reg[1] = 32'h1e1e1e1e;
dut.uds_reg[2] = 32'h2d2d2d2d;
dut.uds_reg[3] = 32'h3c3c3c3c;
dut.uds_reg[4] = 32'h4b4b4b4b;
dut.uds_reg[5] = 32'h5a5a5a5a;
dut.uds_reg[6] = 32'h69696969;
dut.uds_reg[7] = 32'h78787878;
$display("--- test1: Dumping state again to see read bits.");
dump_dut_state();
$display("--- test1: Reading UDS words.");
read_word(ADDR_UDS_FIRST + 0);
read_word(ADDR_UDS_FIRST + 1);
read_word(ADDR_UDS_FIRST + 2);
read_word(ADDR_UDS_FIRST + 3);
read_word(ADDR_UDS_FIRST + 4);
read_word(ADDR_UDS_FIRST + 5);
read_word(ADDR_UDS_FIRST + 6);
read_word(ADDR_UDS_FIRST + 7);
$display("--- test1: Reading UDS words in changed order.");
read_word(ADDR_UDS_FIRST + 7, 32'h78787878);
read_word(ADDR_UDS_FIRST + 6, 32'h69696969);
read_word(ADDR_UDS_FIRST + 4, 32'h4b4b4b4b);
read_word(ADDR_UDS_FIRST + 3, 32'h3c3c3c3c);
read_word(ADDR_UDS_FIRST + 1, 32'h1e1e1e1e);
read_word(ADDR_UDS_FIRST + 0, 32'h0f0f0f0f);
read_word(ADDR_UDS_FIRST + 5, 32'h5a5a5a5a);
read_word(ADDR_UDS_FIRST + 2, 32'h2d2d2d2d);
$display("--- test1: Reading UDS words again.");
read_word(ADDR_UDS_FIRST + 0);
read_word(ADDR_UDS_FIRST + 1);
read_word(ADDR_UDS_FIRST + 2);
read_word(ADDR_UDS_FIRST + 3);
read_word(ADDR_UDS_FIRST + 4);
read_word(ADDR_UDS_FIRST + 5);
read_word(ADDR_UDS_FIRST + 6);
read_word(ADDR_UDS_FIRST + 7);
$display("--- test1: This should return all zeros.");
read_word(ADDR_UDS_FIRST + 0, 32'h0);
read_word(ADDR_UDS_FIRST + 1, 32'h0);
read_word(ADDR_UDS_FIRST + 2, 32'h0);
read_word(ADDR_UDS_FIRST + 3, 32'h0);
read_word(ADDR_UDS_FIRST + 4, 32'h0);
read_word(ADDR_UDS_FIRST + 5, 32'h0);
read_word(ADDR_UDS_FIRST + 6, 32'h0);
read_word(ADDR_UDS_FIRST + 7, 32'h0);
$display("--- test1: completed.");
$display("");
end
endtask // tes1
endtask // test1
//----------------------------------------------------------------
@ -286,8 +319,8 @@ module tb_uds();
display_test_result();
$display("");
$display(" -= Testbench for uds started =-");
$display(" ===========================");
$display(" -= Testbench for uds completed =-");
$display(" =============================");
$display("");
$finish;
end // uds_test

View File

@ -18,7 +18,7 @@ CC = iverilog
CC_FLAGS = -Wall
LINT = verilator
LINT_FLAGS = +1364-2001ext+ --lint-only -Wall -Wno-fatal -Wno-DECLFILENAME
LINT_FLAGS = +1364-2005ext+ --lint-only -Wall -Wno-fatal -Wno-DECLFILENAME
all: top.sim

View File

@ -1,9 +1,9 @@
#=======================================================================
#
# application_fpga_usb_v1.pcf
# ---------------------------
# application_fpga_tk1.pcf
# ------------------------
# Pin constraints file for the Application FPGA design to be used
# on the MTA1-USB-V1 board with the CH552 MCU used as a USB-serial chip.
# on the tk1 board with the CH552 MCU used as a USB-serial chip.
#
#
# Copyright (C) 2022 - Tillitis AB
@ -35,5 +35,5 @@ set_io led_g 40
set_io led_b 41
#=======================================================================
# EOF application_fpga_ch552.pcf
# EOF application_fpga_tk1.pcf
#=======================================================================

View File

@ -1,8 +1,8 @@
80808080
91919191
a2a2a2a2
b3b3b3b3
c4c4c4c4
d5d5d5d5
e6e6e6e6
f7f7f7f7
80818283
94959697
a0a1a2a3
b4b5b6b7
c0c1c2c3
d4d5d6d7
e0e1e2e3
f4f5f6f7

View File

@ -0,0 +1 @@
06d0aafcc763307420380a8c5a324f3fccfbba6af7ff6fe0facad684ebd69dd43234c8531a096c77c2dc3543f8b8b629c94136ca7e257ca560da882e4dbbb025 firmware.bin

View File

@ -106,7 +106,7 @@ uint32_t wait_timer_tick(uint32_t last_timer)
}
}
void zero_fwram()
void zero_fwram(void)
{
for (int i = 0; i < TK1_MMIO_FW_RAM_SIZE; i++) {
fw_ram[i] = 0x00;
@ -142,7 +142,14 @@ int check_fwram_zero_except(unsigned int offset, uint8_t expected_val)
return failed;
}
int main()
void failmsg(char *s)
{
puts("FAIL: ");
puts(s);
puts("\r\n");
}
int main(void)
{
// Function pointer to blake2s()
volatile int (*fw_blake2s)(void *, unsigned long, const void *,
@ -150,11 +157,24 @@ int main()
blake2s_ctx *);
uint8_t in;
// Hard coded test UDS in ../../data/uds.hex
// clang-format off
uint32_t uds_test[8] = {
0x80818283,
0x94959697,
0xa0a1a2a3,
0xb4b5b6b7,
0xc0c1c2c3,
0xd4d5d6d7,
0xe0e1e2e3,
0xf4f5f6f7,
};
// clang-format on
// Wait for terminal program and a character to be typed
in = readbyte();
puts("I'm testfw on:");
puts("\r\nI'm testfw on:");
// Output the TK1 core's NAME0 and NAME1
uint32_t name;
wordcpy_s(&name, 1, (void *)tk1name0, 1);
@ -176,14 +196,24 @@ int main()
// Should get non-empty UDS
wordcpy_s(uds_local, UDS_WORDS, (void *)uds, UDS_WORDS);
if (memeq(uds_local, zeros, UDS_WORDS * 4)) {
puts("FAIL: UDS empty\r\n");
failmsg("UDS empty");
anyfailed = 1;
}
puts("\r\nUDS: ");
for (int i = 0; i < UDS_WORDS * 4; i++) {
puthex(((uint8_t *)uds_local)[i]);
}
puts("\r\n");
if (!memeq(uds_local, uds_test, UDS_WORDS * 4)) {
failmsg("UDS not equal to test UDS");
anyfailed = 1;
}
// Should NOT be able to read from UDS again
wordcpy_s(uds_local, UDS_WORDS, (void *)uds, UDS_WORDS);
if (!memeq(uds_local, zeros, UDS_WORDS * 4)) {
puts("FAIL: Read UDS a second time\r\n");
failmsg("Read UDS a second time");
anyfailed = 1;
}
@ -191,7 +221,7 @@ int main()
// Should get non-empty UDI
wordcpy_s(udi_local, UDI_WORDS, (void *)udi, UDI_WORDS);
if (memeq(udi_local, zeros, UDI_WORDS * 4)) {
puts("FAIL: UDI empty\r\n");
failmsg("UDI empty");
anyfailed = 1;
}
@ -204,22 +234,32 @@ int main()
wordcpy_s((void *)cdi, CDI_WORDS, cdi_writetest, CDI_WORDS);
wordcpy_s(cdi_readback, CDI_WORDS, (void *)cdi, CDI_WORDS);
if (!memeq(cdi_writetest, cdi_readback, CDI_WORDS * 4)) {
puts("FAIL: Can't write CDI in fw mode\r\n");
failmsg("Can't write CDI in fw mode");
anyfailed = 1;
}
// Should be able to read bytes from CDI.
uint8_t cdi_readback_bytes[CDI_WORDS * 4];
memcpy(cdi_readback_bytes, (void *)cdi, CDI_WORDS * 4);
if (!memeq(cdi_writetest, cdi_readback_bytes, CDI_WORDS * 4)) {
failmsg("Can't read bytes from CDI");
anyfailed = 1;
}
// Test FW_RAM.
puts("Testing FW_RAM (takes 15s on hw)...\r\n");
puts("\r\nTesting FW_RAM (takes 15s on hw)...\r\n");
for (unsigned int i = 0; i < TK1_MMIO_FW_RAM_SIZE; i++) {
zero_fwram();
*(volatile uint8_t *)(TK1_MMIO_FW_RAM_BASE + i) = 0x42;
anyfailed = check_fwram_zero_except(i, 0x42);
int fwram_fail = check_fwram_zero_except(i, 0x42);
if (fwram_fail) {
anyfailed = 1;
}
}
puts("\r\n");
uint32_t sw = *switch_app;
if (sw != 0) {
puts("FAIL: switch_app is not 0 in fw mode\r\n");
failmsg("switch_app is not 0 in fw mode");
anyfailed = 1;
}
@ -233,21 +273,21 @@ int main()
sw = *switch_app;
if (sw != 0xffffffff) {
puts("FAIL: switch_app is not 0xffffffff in app mode\r\n");
failmsg("switch_app is not 0xffffffff in app mode");
anyfailed = 1;
}
// Should NOT be able to read from UDS in app-mode.
wordcpy_s(uds_local, UDS_WORDS, (void *)uds, UDS_WORDS);
if (!memeq(uds_local, zeros, UDS_WORDS * 4)) {
puts("FAIL: Read from UDS in app-mode\r\n");
failmsg("Read from UDS in app-mode");
anyfailed = 1;
}
// Should NOT be able to read from UDI in app-mode.
wordcpy_s(udi_local, UDI_WORDS, (void *)udi, UDI_WORDS);
if (!memeq(udi_local, zeros, UDI_WORDS * 4)) {
puts("FAIL: Read from UDI in app-mode\r\n");
failmsg("Read from UDI in app-mode");
anyfailed = 1;
}
@ -259,18 +299,18 @@ int main()
wordcpy_s((void *)cdi, CDI_WORDS, zeros, CDI_WORDS);
wordcpy_s(cdi_local2, CDI_WORDS, (void *)cdi, CDI_WORDS);
if (!memeq(cdi_local, cdi_local2, CDI_WORDS * 4)) {
puts("FAIL: Write to CDI in app-mode\r\n");
failmsg("Write to CDI in app-mode");
anyfailed = 1;
}
// Test FW_RAM.
*fw_ram = 0x21;
if (*fw_ram == 0x21) {
puts("FAIL: Write and read FW RAM in app-mode\r\n");
failmsg("Write and read FW RAM in app-mode");
anyfailed = 1;
}
puts("Testing timer... 3");
puts("\r\nTesting timer... 3");
// Matching clock at 18 MHz, giving us timer in seconds
*timer_prescaler = 18 * 1000000;
@ -297,12 +337,12 @@ int main()
puts(" 1. done.\r\n");
if (*timer_status & (1 << TK1_MMIO_TIMER_STATUS_RUNNING_BIT)) {
puts("FAIL: Timer didn't stop\r\n");
failmsg("Timer didn't stop");
anyfailed = 1;
}
if (*timer != 10) {
puts("FAIL: Timer didn't reset to 10\r\n");
failmsg("Timer didn't reset to 10");
anyfailed = 1;
}
@ -321,18 +361,19 @@ int main()
blake2s(&digest0[0], 32, NULL, 0, &msg, 17, &b2s_ctx);
fw_blake2s(&digest1[0], 32, NULL, 0, &msg, 17, &b2s_ctx);
puts("digest #0: \r\n");
puts("\r\ndigest #0: \r\n");
hexdump((uint8_t *)digest0, 32);
puts("digest #1: \r\n");
hexdump((uint8_t *)digest1, 32);
if (!memeq(digest0, digest1, 32)) {
puts("FAIL: Digests not the same\r\n");
failmsg("Digests not the same");
anyfailed = 1;
}
// Check and display test results.
puts("\r\n--> ");
if (anyfailed) {
puts("Some test FAILED!\r\n");
} else {

View File

@ -4,7 +4,6 @@
*/
#include "assert.h"
#include "led.h"
#include "lib.h"
void assert_fail(const char *assertion, const char *file, unsigned int line,
@ -20,6 +19,11 @@ void assert_fail(const char *assertion, const char *file, unsigned int line,
htif_puts(function);
htif_lf();
forever_redflash();
#ifndef S_SPLINT_S
// Force illegal instruction to halt CPU
asm volatile("unimp");
#endif
// Not reached
__builtin_unreachable();
}

View File

@ -13,15 +13,3 @@ void set_led(uint32_t led_value)
{
*led = led_value;
}
void forever_redflash()
{
int led_on = 0;
for (;;) {
*led = led_on ? LED_RED : LED_BLACK;
for (volatile int i = 0; i < 800000; i++) {
}
led_on = !led_on;
}
}

View File

@ -18,5 +18,4 @@
// clang-format on
void set_led(uint32_t led_value);
void forever_redflash();
#endif

View File

@ -104,6 +104,7 @@ void *memset(void *dest, int c, unsigned n)
for (; n; n--, s++)
*s = (uint8_t)c;
/*@ -temptrans @*/
return dest;
}
@ -117,6 +118,11 @@ void memcpy_s(void *dest, size_t destsize, const void *src, size_t n)
uint8_t *dest_byte = (uint8_t *)dest;
for (size_t i = 0; i < n; i++) {
/*@ -nullderef @*/
/* splint complains that dest_byte and src_byte can be
* NULL, but it seems it doesn't understand assert.
* See above.
*/
dest_byte[i] = src_byte[i];
}
}
@ -139,12 +145,20 @@ int memeq(void *dest, const void *src, size_t n)
{
uint8_t *src_byte = (uint8_t *)src;
uint8_t *dest_byte = (uint8_t *)dest;
int res = -1;
for (size_t i = 0; i < n; i++) {
if (dest_byte[i] != src_byte[i]) {
return 0;
res = 0;
}
}
return -1;
return res;
}
void secure_wipe(void *v, size_t n)
{
volatile uint8_t *p = (volatile uint8_t *)v;
while (n--)
*p++ = 0;
}

View File

@ -28,5 +28,5 @@ void *memset(void *dest, int c, unsigned n);
void memcpy_s(void *dest, size_t destsize, const void *src, size_t n);
void wordcpy_s(void *dest, size_t destsize, const void *src, size_t n);
int memeq(void *dest, const void *src, size_t n);
void secure_wipe(void *v, size_t n);
#endif

View File

@ -6,7 +6,6 @@
#include "../tk1_mem.h"
#include "assert.h"
#include "blake2s/blake2s.h"
#include "led.h"
#include "lib.h"
#include "proto.h"
#include "state.h"
@ -29,7 +28,7 @@ static volatile uint32_t *timer = (volatile uint32_t *)TK1_MMIO_TIMER_
static volatile uint32_t *timer_prescaler = (volatile uint32_t *)TK1_MMIO_TIMER_PRESCALER;
static volatile uint32_t *timer_status = (volatile uint32_t *)TK1_MMIO_TIMER_STATUS;
static volatile uint32_t *timer_ctrl = (volatile uint32_t *)TK1_MMIO_TIMER_CTRL;
static volatile uint32_t *ram_aslr = (volatile uint32_t *)TK1_MMIO_TK1_RAM_ASLR;
static volatile uint32_t *ram_rand = (volatile uint32_t *)TK1_MMIO_TK1_RAM_ADDR_RAND;
static volatile uint32_t *ram_scramble = (volatile uint32_t *)TK1_MMIO_TK1_RAM_SCRAMBLE;
// clang-format on
@ -42,9 +41,9 @@ struct context {
uint8_t uss[32]; // User Supplied Secret, if any
};
static void print_hw_version();
static void print_hw_version(void);
static void print_digest(uint8_t *md);
static uint32_t rnd_word();
static uint32_t rnd_word(void);
static void compute_cdi(const uint8_t *digest, const uint8_t use_uss,
const uint8_t *uss);
static void copy_name(uint8_t *buf, const size_t bufsiz, const uint32_t word);
@ -55,9 +54,9 @@ static enum state loading_commands(const struct frame_header *hdr,
const uint8_t *cmd, enum state state,
struct context *ctx);
static void run(const struct context *ctx);
static void scramble_ram();
static void scramble_ram(void);
static void print_hw_version()
static void print_hw_version(void)
{
htif_puts("Hello, I'm firmware with");
htif_puts(" tk1_name0:");
@ -81,7 +80,7 @@ static void print_digest(uint8_t *md)
htif_lf();
}
static uint32_t rnd_word()
static uint32_t rnd_word(void)
{
while ((*trng_status & (1 << TK1_MMIO_TRNG_STATUS_READY_BIT)) == 0) {
}
@ -92,7 +91,8 @@ static uint32_t rnd_word()
static void compute_cdi(const uint8_t *digest, const uint8_t use_uss,
const uint8_t *uss)
{
uint32_t local_cdi[8];
uint32_t local_uds[8] = {0};
uint32_t local_cdi[8] = {0};
blake2s_ctx secure_ctx = {0};
uint32_t rnd_sleep = 0;
int blake2err = 0;
@ -112,7 +112,9 @@ static void compute_cdi(const uint8_t *digest, const uint8_t use_uss,
// Update hash with UDS. This means UDS will live for a short
// while on the firmware stack which is in the special fw_ram.
blake2s_update(&secure_ctx, (const void *)uds, 32);
wordcpy_s(local_uds, 8, (void *)uds, 8);
blake2s_update(&secure_ctx, (const void *)local_uds, 32);
(void)secure_wipe(local_uds, sizeof(local_uds));
// Update with TKey program digest
blake2s_update(&secure_ctx, digest, 32);
@ -127,7 +129,7 @@ static void compute_cdi(const uint8_t *digest, const uint8_t use_uss,
// Clear secure_ctx of any residue of UDS. Don't want to keep
// that for long even though fw_ram is cleared later.
(void)memset(&secure_ctx, 0, sizeof(secure_ctx));
(void)secure_wipe(&secure_ctx, sizeof(secure_ctx));
// CDI only word writable
wordcpy_s((void *)cdi, 8, &local_cdi, 8);
@ -188,7 +190,7 @@ static enum state initial_commands(const struct frame_header *hdr,
uint32_t local_app_size;
htif_puts("cmd: load-app(size, uss)\n");
if (hdr->len != 512) {
if (hdr->len != 128) {
// Bad length
state = FW_STATE_FAIL;
break;
@ -253,19 +255,21 @@ static enum state loading_commands(const struct frame_header *hdr,
switch (cmd[0]) {
case FW_CMD_LOAD_APP_DATA:
htif_puts("cmd: load-app-data\n");
if (hdr->len != 512) {
if (hdr->len != 128) {
// Bad length
state = FW_STATE_FAIL;
break;
}
if (ctx->left > (512 - 1)) {
nbytes = 512 - 1;
if (ctx->left > (128 - 1)) {
nbytes = 128 - 1;
} else {
nbytes = ctx->left;
}
memcpy_s(ctx->loadaddr, ctx->left, cmd + 1, nbytes);
/*@-mustfreeonly@*/
ctx->loadaddr += nbytes;
/*@+mustfreeonly@*/
ctx->left -= nbytes;
if (ctx->left == 0) {
@ -359,14 +363,14 @@ static void run(const struct context *ctx)
__builtin_unreachable();
}
static void scramble_ram()
static void scramble_ram(void)
{
uint32_t *ram = (uint32_t *)(TK1_RAM_BASE);
uint32_t rnd = rnd_word();
uint32_t rnd_incr = rnd_word();
// Set RAM address and data scrambling values
*ram_aslr = rnd_word();
*ram_rand = rnd_word();
*ram_scramble = rnd_word();
// Fill RAM with random data (FW does not use RAM, has its stack in
@ -377,11 +381,11 @@ static void scramble_ram()
}
// Set new scrambling values, for all use of RAM by app
*ram_aslr = rnd_word();
*ram_rand = rnd_word();
*ram_scramble = rnd_word();
}
int main()
int main(void)
{
struct context ctx = {0};
struct frame_header hdr = {0};
@ -393,7 +397,12 @@ int main()
// Let the app know the function adddress for blake2s()
*fw_blake2s_addr = (uint32_t)blake2s;
/*@-mustfreeonly@*/
/* Yes, splint, this points directly to RAM and we don't care
* about freeing anything was pointing to 0x0 before.
*/
ctx.loadaddr = (uint8_t *)TK1_RAM_BASE;
/*@+mustfreeonly@*/
ctx.use_uss = FALSE;
scramble_ram();
@ -428,10 +437,12 @@ int main()
htif_puts("firmware state 0x");
htif_puthex(state);
htif_lf();
forever_redflash();
assert(1 == 2);
break; // Not reached
}
}
/*@ -compdestroy @*/
/* We don't care about memory leaks here. */
return (int)0xcafebabe;
}

View File

@ -5,6 +5,7 @@
#include "proto.h"
#include "../tk1_mem.h"
#include "assert.h"
#include "led.h"
#include "lib.h"
#include "state.h"
@ -22,6 +23,7 @@ static uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status,
static int parseframe(uint8_t b, struct frame_header *hdr);
static void write(uint8_t *buf, size_t nbytes);
static int read(uint8_t *buf, size_t bufsize, size_t nbytes);
static int bytelen(enum cmdlen cmdlen);
static uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status,
enum cmdlen len)
@ -71,25 +73,7 @@ static int parseframe(uint8_t b, struct frame_header *hdr)
hdr->id = (b & 0x60) >> 5;
hdr->endpoint = (b & 0x18) >> 3;
// Length
switch (b & 0x3) {
case LEN_1:
hdr->len = 1;
break;
case LEN_4:
hdr->len = 4;
break;
case LEN_32:
hdr->len = 32;
break;
case LEN_512:
hdr->len = 512;
break;
default:
// Unknown length
return -1;
}
hdr->len = bytelen(b & 0x3);
return 0;
}
@ -104,27 +88,22 @@ void fwreply(struct frame_header hdr, enum fwcmd rspcode, uint8_t *buf)
switch (rspcode) {
case FW_RSP_NAME_VERSION:
len = LEN_32;
nbytes = 32;
break;
case FW_RSP_LOAD_APP:
len = LEN_4;
nbytes = 4;
break;
case FW_RSP_LOAD_APP_DATA:
len = LEN_4;
nbytes = 4;
break;
case FW_RSP_LOAD_APP_DATA_READY:
len = LEN_512;
nbytes = 512;
len = LEN_128;
break;
case FW_RSP_GET_UDI:
len = LEN_32;
nbytes = 32;
break;
default:
@ -134,6 +113,8 @@ void fwreply(struct frame_header hdr, enum fwcmd rspcode, uint8_t *buf)
return;
}
nbytes = bytelen(len);
// Frame Protocol Header
writebyte(genhdr(hdr.id, hdr.endpoint, 0x0, len));
@ -161,7 +142,7 @@ static void write(uint8_t *buf, size_t nbytes)
}
}
uint8_t readbyte()
uint8_t readbyte(void)
{
for (;;) {
if (*can_rx) {
@ -182,3 +163,33 @@ static int read(uint8_t *buf, size_t bufsize, size_t nbytes)
return 0;
}
// bytelen returns the number of bytes a cmdlen takes
static int bytelen(enum cmdlen cmdlen)
{
int len = 0;
switch (cmdlen) {
case LEN_1:
len = 1;
break;
case LEN_4:
len = 4;
break;
case LEN_32:
len = 32;
break;
case LEN_128:
len = 128;
break;
default:
// Shouldn't happen
assert(1 == 2);
}
return len;
}

View File

@ -19,10 +19,10 @@ enum cmdlen {
LEN_1,
LEN_4,
LEN_32,
LEN_512
LEN_128
};
#define CMDLEN_MAXBYTES 512
#define CMDLEN_MAXBYTES 128
// clang-format off
enum fwcmd {
@ -50,8 +50,9 @@ struct frame_header {
enum cmdlen len;
};
/*@ -exportlocal @*/
void writebyte(uint8_t b);
uint8_t readbyte();
uint8_t readbyte(void);
void fwreply(struct frame_header hdr, enum fwcmd rspcode, uint8_t *buf);
int readcommand(struct frame_header *hdr, uint8_t *cmd, int state);
#endif

View File

@ -1,102 +1,144 @@
/*
* QEMU RISC-V Board Compatible with Tillitis TK1 platform
* Tillitis TKey Memory Map
*
* Copyright (c) 2022, 2023 Tillitis AB
* SPDX-License-Identifier: GPL-2.0-only
* Copyright (c) 2022, 2023, 2024 Tillitis AB
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Note that this file is also included in at least qemu
* (GPL-2.0-or-later) besides tillitis-key1 (GPL-2.0-only) and
* tkey-libs (GPL-2.0-only) so it's licensed as GPL v2 or later.
*/
// clang-format off
#ifndef TK1_MEM_H
#define TK1_MEM_H
#ifndef TKEY_TK1_MEM_H
#define TKEY_TK1_MEM_H
// The canonical location of this file is:
// repo: https://github.com/tillitis/tillitis-key1
// path: /hw/application_fpga/fw/tk1_mem.h
/*
// The contents are derived from the Verilog code. For use by QEMU model,
// firmware, and apps.
The canonical location of this file is in:
enum {
TK1_ROM_BASE = 0x00000000, // 0b00000000...
TK1_RAM_BASE = 0x40000000, // 0b01000000...
TK1_RAM_SIZE = 0x20000, // 128 KB
TK1_RESERVED_BASE = 0x80000000, // 0b10000000...
TK1_MMIO_BASE = 0xc0000000, // 0b11000000...
TK1_MMIO_SIZE = 0xffffffff - TK1_MMIO_BASE,
https://github.com/tillitis/tillitis-key1
TK1_APP_MAX_SIZE = TK1_RAM_SIZE,
/hw/application_fpga/fw/tk1_mem.h
TK1_MMIO_TRNG_BASE = TK1_MMIO_BASE | 0x00000000,
TK1_MMIO_TIMER_BASE = TK1_MMIO_BASE | 0x01000000,
TK1_MMIO_UDS_BASE = TK1_MMIO_BASE | 0x02000000,
TK1_MMIO_UART_BASE = TK1_MMIO_BASE | 0x03000000,
TK1_MMIO_TOUCH_BASE = TK1_MMIO_BASE | 0x04000000,
TK1_MMIO_FW_RAM_BASE = TK1_MMIO_BASE | 0x10000000,
TK1_MMIO_FW_RAM_SIZE = 2048,
// This "core" only exists in QEMU
TK1_MMIO_QEMU_BASE = TK1_MMIO_BASE | 0x3e000000,
TK1_MMIO_TK1_BASE = TK1_MMIO_BASE | 0x3f000000, // 0xff000000
The contents are derived from the Verilog code. For use by QEMU model,
firmware, and apps.
TK1_NAME0_SUFFIX = 0x00,
TK1_NAME1_SUFFIX = 0x04,
TK1_VERSION_SUFFIX = 0x08,
Memory map
TK1_MMIO_TRNG_STATUS = TK1_MMIO_TRNG_BASE | 0x24,
TK1_MMIO_TRNG_STATUS_READY_BIT = 0,
TK1_MMIO_TRNG_ENTROPY = TK1_MMIO_TRNG_BASE | 0x80,
Top level prefix, the first 2 bits in a 32-bit address:
TK1_MMIO_TIMER_CTRL = TK1_MMIO_TIMER_BASE | 0x20,
TK1_MMIO_TIMER_CTRL_START_BIT = 0,
TK1_MMIO_TIMER_CTRL_STOP_BIT = 1,
TK1_MMIO_TIMER_STATUS = TK1_MMIO_TIMER_BASE | 0x24,
TK1_MMIO_TIMER_STATUS_RUNNING_BIT = 0,
TK1_MMIO_TIMER_PRESCALER = TK1_MMIO_TIMER_BASE | 0x28,
TK1_MMIO_TIMER_TIMER = TK1_MMIO_TIMER_BASE | 0x2c,
name prefix address length
--------------------------------------------------------
ROM 0b00 30 bit address
RAM 0b01 30 bit address
Reserved 0b10
MMIO 0b11 6 bits for core select, 24 bits rest
TK1_MMIO_UDS_FIRST = TK1_MMIO_UDS_BASE | 0x40,
TK1_MMIO_UDS_LAST = TK1_MMIO_UDS_BASE | 0x5c, // Address of last 32-bit word of UDS
Address Prefix, the first 8 bits in a 32-bit address:
TK1_MMIO_UART_BIT_RATE = TK1_MMIO_UART_BASE | 0x40,
TK1_MMIO_UART_DATA_BITS = TK1_MMIO_UART_BASE | 0x44,
TK1_MMIO_UART_STOP_BITS = TK1_MMIO_UART_BASE | 0x48,
TK1_MMIO_UART_RX_STATUS = TK1_MMIO_UART_BASE | 0x80,
TK1_MMIO_UART_RX_DATA = TK1_MMIO_UART_BASE | 0x84,
TK1_MMIO_UART_RX_BYTES = TK1_MMIO_UART_BASE | 0x88,
TK1_MMIO_UART_TX_STATUS = TK1_MMIO_UART_BASE | 0x100,
TK1_MMIO_UART_TX_DATA = TK1_MMIO_UART_BASE | 0x104,
name prefix
--------------------
ROM 0x00
RAM 0x40
MMIO 0xc0
MMIO TRNG 0xc0
MMIO TIMER 0xc1
MMIO UDS 0xc2
MMIO UART 0xc3
MMIO TOUCH 0xc4
MMIO FW_RAM 0xd0
MMIO QEMU 0xfe Not used in real hardware
MMIO TK1 0xff
*/
TK1_MMIO_TOUCH_STATUS = TK1_MMIO_TOUCH_BASE | 0x24,
TK1_MMIO_TOUCH_STATUS_EVENT_BIT = 0,
#define TK1_ROM_BASE 0x00000000
#define TK1_RAM_BASE 0x40000000
#define TK1_RAM_SIZE 0x20000
// This will only ever exist in QEMU:
TK1_MMIO_QEMU_DEBUG = TK1_MMIO_QEMU_BASE | 0x1000,
#define TK1_MMIO_BASE 0xc0000000
#define TK1_MMIO_SIZE 0x3fffffff
TK1_MMIO_TK1_NAME0 = TK1_MMIO_TK1_BASE | TK1_NAME0_SUFFIX,
TK1_MMIO_TK1_NAME1 = TK1_MMIO_TK1_BASE | TK1_NAME1_SUFFIX,
TK1_MMIO_TK1_VERSION = TK1_MMIO_TK1_BASE | TK1_VERSION_SUFFIX,
TK1_MMIO_TK1_SWITCH_APP = TK1_MMIO_TK1_BASE | 0x20,
TK1_MMIO_TK1_LED = TK1_MMIO_TK1_BASE | 0x24,
TK1_MMIO_TK1_LED_R_BIT = 2,
TK1_MMIO_TK1_LED_G_BIT = 1,
TK1_MMIO_TK1_LED_B_BIT = 0,
TK1_MMIO_TK1_GPIO = TK1_MMIO_TK1_BASE | 0x28,
TK1_MMIO_TK1_GPIO1_BIT = 0,
TK1_MMIO_TK1_GPIO2_BIT = 1,
TK1_MMIO_TK1_GPIO3_BIT = 2,
TK1_MMIO_TK1_GPIO4_BIT = 3,
TK1_MMIO_TK1_APP_ADDR = TK1_MMIO_TK1_BASE | 0x30,
TK1_MMIO_TK1_APP_SIZE = TK1_MMIO_TK1_BASE | 0x34,
TK1_MMIO_TK1_BLAKE2S = TK1_MMIO_TK1_BASE | 0x40,
TK1_MMIO_TK1_CDI_FIRST = TK1_MMIO_TK1_BASE | 0x80,
TK1_MMIO_TK1_CDI_LAST = TK1_MMIO_TK1_BASE | 0x9c, // Address of last 32-bit word of CDI.
TK1_MMIO_TK1_UDI_FIRST = TK1_MMIO_TK1_BASE | 0xc0,
TK1_MMIO_TK1_UDI_LAST = TK1_MMIO_TK1_BASE | 0xc4, // Address of last 32-bit word of UDI.
TK1_MMIO_TK1_RAM_ASLR = TK1_MMIO_TK1_BASE | 0x100,
TK1_MMIO_TK1_RAM_SCRAMBLE = TK1_MMIO_TK1_BASE | 0x104,
TK1_MMIO_TK1_CPU_MON_CTRL = TK1_MMIO_TK1_BASE | 0x180,
TK1_MMIO_TK1_CPU_MON_FIRST = TK1_MMIO_TK1_BASE | 0x184,
TK1_MMIO_TK1_CPU_MON_LAST = TK1_MMIO_TK1_BASE | 0x188,
};
#define TK1_APP_MAX_SIZE 0x20000
#define TK1_MMIO_FW_RAM_BASE 0xd0000000
// FW_RAM is 2048 bytes
#define TK1_MMIO_FW_RAM_SIZE 0x800
#define TK1_MMIO_TRNG_BASE 0xc0000000
#define TK1_MMIO_TRNG_STATUS 0xc0000024
#define TK1_MMIO_TRNG_STATUS_READY_BIT 0
#define TK1_MMIO_TRNG_ENTROPY 0xc0000080
#define TK1_MMIO_TIMER_BASE 0xc1000000
#define TK1_MMIO_TIMER_CTRL 0xc1000020
#define TK1_MMIO_TIMER_CTRL_START_BIT 0
#define TK1_MMIO_TIMER_CTRL_STOP_BIT 1
#define TK1_MMIO_TIMER_STATUS 0xc1000024
#define TK1_MMIO_TIMER_STATUS_RUNNING_BIT 0
#define TK1_MMIO_TIMER_PRESCALER 0xc1000028
#define TK1_MMIO_TIMER_TIMER 0xc100002c
#define TK1_MMIO_UDS_BASE 0xc2000000
#define TK1_MMIO_UDS_FIRST 0xc2000040
#define TK1_MMIO_UDS_LAST 0xc200005c
#define TK1_MMIO_UART_BASE 0xc3000000
#define TK1_MMIO_UART_BIT_RATE 0xc3000040
#define TK1_MMIO_UART_DATA_BITS 0xc3000044
#define TK1_MMIO_UART_STOP_BITS 0xc3000048
#define TK1_MMIO_UART_RX_STATUS 0xc3000080
#define TK1_MMIO_UART_RX_DATA 0xc3000084
#define TK1_MMIO_UART_RX_BYTES 0xc3000088
#define TK1_MMIO_UART_TX_STATUS 0xc3000100
#define TK1_MMIO_UART_TX_DATA 0xc3000104
#define TK1_MMIO_TOUCH_BASE 0xc4000000
#define TK1_MMIO_TOUCH_STATUS 0xc4000024
#define TK1_MMIO_TOUCH_STATUS_EVENT_BIT 0
// This only exists in QEMU, not real hardware
#define TK1_MMIO_QEMU_BASE 0xfe000000
#define TK1_MMIO_QEMU_DEBUG 0xfe001000
#define TK1_MMIO_TK1_BASE 0xff000000
#define TK1_MMIO_TK1_NAME0 0xff000000
#define TK1_MMIO_TK1_NAME1 0xff000004
#define TK1_MMIO_TK1_VERSION 0xff000008
#define TK1_MMIO_TK1_SWITCH_APP 0xff000020
#define TK1_MMIO_TK1_LED 0xff000024
#define TK1_MMIO_TK1_LED_R_BIT 2
#define TK1_MMIO_TK1_LED_G_BIT 1
#define TK1_MMIO_TK1_LED_B_BIT 0
#define TK1_MMIO_TK1_GPIO 0xff000028
#define TK1_MMIO_TK1_GPIO1_BIT 0
#define TK1_MMIO_TK1_GPIO2_BIT 1
#define TK1_MMIO_TK1_GPIO3_BIT 2
#define TK1_MMIO_TK1_GPIO4_BIT 3
#define TK1_MMIO_TK1_APP_ADDR 0xff000030
#define TK1_MMIO_TK1_APP_SIZE 0xff000034
#define TK1_MMIO_TK1_BLAKE2S 0xff000040
#define TK1_MMIO_TK1_CDI_FIRST 0xff000080
#define TK1_MMIO_TK1_CDI_LAST 0xff00009c
#define TK1_MMIO_TK1_UDI_FIRST 0xff0000c0
#define TK1_MMIO_TK1_UDI_LAST 0xff0000c4
// Deprecated - use _ADDR_RAND instead
#define TK1_MMIO_TK1_RAM_ASLR 0xff000100
#define TK1_MMIO_TK1_RAM_ADDR_RAND 0xff000100
#define TK1_MMIO_TK1_RAM_SCRAMBLE 0xff000104
#define TK1_MMIO_TK1_CPU_MON_CTRL 0xff000180
#define TK1_MMIO_TK1_CPU_MON_FIRST 0xff000184
#define TK1_MMIO_TK1_CPU_MON_LAST 0xff000188
#endif

View File

@ -71,18 +71,16 @@ module application_fpga(
wire clk;
wire reset_n;
/* verilator lint_off UNOPTFLAT */
wire cpu_trap;
wire cpu_valid;
wire cpu_instr;
wire [03 : 0] cpu_wstrb;
/* verilator lint_off UNUSED */
wire [31 : 0] cpu_addr;
/* verilator lint_on UNUSED */
wire [31 : 0] cpu_wdata;
/* verilator lint_off UNOPTFLAT */
reg rom_cs;
/* verilator lint_on UNOPTFLAT */
reg [11 : 0] rom_address;
wire [31 : 0] rom_read_data;
wire rom_ready;
@ -94,60 +92,46 @@ module application_fpga(
wire [31 : 0] ram_read_data;
wire ram_ready;
/* verilator lint_off UNOPTFLAT */
reg trng_cs;
/* verilator lint_on UNOPTFLAT */
reg trng_we;
reg [7 : 0] trng_address;
reg [31 : 0] trng_write_data;
wire [31 : 0] trng_read_data;
wire trng_ready;
/* verilator lint_off UNOPTFLAT */
reg timer_cs;
/* verilator lint_on UNOPTFLAT */
reg timer_we;
reg [7 : 0] timer_address;
reg [31 : 0] timer_write_data;
wire [31 : 0] timer_read_data;
wire timer_ready;
/* verilator lint_off UNOPTFLAT */
reg uds_cs;
/* verilator lint_on UNOPTFLAT */
reg [7 : 0] uds_address;
reg [2 : 0] uds_address;
wire [31 : 0] uds_read_data;
wire uds_ready;
/* verilator lint_off UNOPTFLAT */
reg uart_cs;
/* verilator lint_on UNOPTFLAT */
reg uart_we;
reg [7 : 0] uart_address;
reg [31 : 0] uart_write_data;
wire [31 : 0] uart_read_data;
wire uart_ready;
/* verilator lint_off UNOPTFLAT */
reg fw_ram_cs;
/* verilator lint_on UNOPTFLAT */
reg [3 : 0] fw_ram_we;
reg [8 : 0] fw_ram_address;
reg [31 : 0] fw_ram_write_data;
wire [31 : 0] fw_ram_read_data;
wire fw_ram_ready;
/* verilator lint_off UNOPTFLAT */
reg touch_sense_cs;
/* verilator lint_on UNOPTFLAT */
reg touch_sense_we;
reg [7 : 0] touch_sense_address;
wire [31 : 0] touch_sense_read_data;
wire touch_sense_ready;
/* verilator lint_off UNOPTFLAT */
reg tk1_cs;
/* verilator lint_on UNOPTFLAT */
reg tk1_we;
reg [7 : 0] tk1_address;
reg [31 : 0] tk1_write_data;
@ -157,6 +141,7 @@ module application_fpga(
wire force_trap;
wire [14 : 0] ram_aslr;
wire [31 : 0] ram_scramble;
/* verilator lint_on UNOPTFLAT */
//----------------------------------------------------------------
@ -211,6 +196,9 @@ module application_fpga(
rom rom_inst(
.clk(clk),
.reset_n(reset_n),
.cs(rom_cs),
.address(rom_address),
.read_data(rom_read_data),
@ -384,7 +372,7 @@ module application_fpga(
rom_address = cpu_addr[13 : 2];
ram_cs = 1'h0;
ram_we = cpu_wstrb;
ram_we = 4'h0;
ram_address = cpu_addr[16 : 2] ^ ram_aslr;
ram_write_data = cpu_wdata ^ ram_scramble ^ {2{cpu_addr[15 : 0]}};
@ -404,7 +392,7 @@ module application_fpga(
timer_write_data = cpu_wdata;
uds_cs = 1'h0;
uds_address = cpu_addr[9 : 2];
uds_address = cpu_addr[4 : 2];
uart_cs = 1'h0;
uart_we = |cpu_wstrb;
@ -434,10 +422,11 @@ module application_fpga(
end
RAM_PREFIX: begin
ram_cs = 1'h1;
ram_cs = 1'h1;
ram_we = cpu_wstrb;
muxed_rdata_new = ram_read_data ^ ram_scramble ^ {2{cpu_addr[15 : 0]}};
muxed_ready_new = ram_ready;
end
end
RESERVED_PREFIX: begin
muxed_rdata_new = 32'h0;

View File

@ -35,7 +35,7 @@ module fw_ram(
reg [31 : 0] mem_read_data0;
reg [31 : 0] mem_read_data1;
reg ready_reg;
reg fw_app_cs;
wire fw_app_cs;
reg bank0;
reg bank1;

View File

@ -125,14 +125,12 @@ module ram(
//----------------------------------------------------------------
always @*
begin : mem_mux
cs0 = 1'h0;
cs1 = 1'h0;
cs0 = ~address[14] & cs;
cs1 = address[14] & cs;
if (address[14]) begin
cs1 = cs;
muxed_read_data = read_data1;
end else begin
cs0 = cs;
muxed_read_data = read_data0;
end
end

View File

@ -15,6 +15,9 @@
`default_nettype none
module rom(
input wire clk,
input wire reset_n,
input wire cs,
/* verilator lint_off UNUSED */
input wire [11 : 0] address,
@ -42,15 +45,28 @@ module rom(
initial $readmemh(`FIRMWARE_HEX, memory);
reg [31 : 0] rom_rdata;
reg rom_ready;
reg ready_reg;
//----------------------------------------------------------------
// Concurrent assignments of ports.
//----------------------------------------------------------------
assign read_data = rom_rdata;
assign ready = rom_ready;
assign ready = ready_reg;
//----------------------------------------------------------------
// reg_update
//----------------------------------------------------------------
always @ (posedge clk)
begin : reg_update
if (!reset_n) begin
ready_reg <= 1'h0;
end
else begin
ready_reg <= cs;
end
end // reg_update
//----------------------------------------------------------------
@ -58,11 +74,9 @@ module rom(
//----------------------------------------------------------------
always @*
begin : rom_logic
/* verilator lint_off WIDTH */
rom_rdata = memory[address];
/* verilator lint_on WIDTH */
rom_ready = cs;
end
endmodule // rom

View File

@ -0,0 +1,89 @@
# -*- coding: utf-8 -*-
#=======================================================================
#
# Copyright (C) 2023 Tillitis AB
# Written by Myrtle Shah <gatecat@ds0.me>
# SPDX-License-Identifier: GPL-2.0-only
#
# Script to patch in a Unique Device Secret (UDS) and a Unique Device
# Identifier (UDI) from files into a bitstream.
#
# It's supposed to be run like this:
#
# nextpnr-ice40 --up5k --package sg48 --ignore-loops \
# --json application_fpga_par.json --run patch_uds_udi.py
#
# with this environment:
#
# - UDS_HEX: path to the UDS file, typically the path to
# ../data/uds.hex
# - UDI_HEX: path to the UDI file, typically the path to ../data/udi.hex
# - OUT_ASC: path to the ASC output that is then used by icebram and icepack.
#
# The script changes the UDS and UDI that are stored in named 4-bit
# LUT instances in the JSON file so we can generate device
# unique bitstreams without running the complete flow just to change
# UDS and UDI. Then we can just run the final bitstream generation
# from the ASC file.
#
# We represent our UDI and UDS values as a number of 32 bit words:
#
# - UDI: 2 words.
# - UDS: 8 words.
#
# We reserve 32 named 4-bit LUTs *each* to store the data: UDS in
# "uds_rom_idx" and UDI in "udi_rom_idx".
#
# The script repeats the value in the LUTs so we don't have to care
# about the value of the unused address bits.
#
# See documentation in their implementation in ../core/uds/README.md
# and ../core/tk1/README.md
import os
def parse_hex(file, length):
data = []
with open(file, "r") as f:
for line in f:
l = line.strip()
if len(l) > 0:
data.append(int(l, 16))
assert len(data) == length, len(data)
return data
def rewrite_lut(lut, idx, data, has_re=False):
# each LUT provides one bit per 32-bit word out of 64/256 bits total
new_init = 0
for i, word in enumerate(data):
if (word >> idx) & 0x1:
# repeat so we don't have to care about inputs above
# address
repeat = (16 // len(data))
for k in range(repeat):
# UDS also has a read enable
# LUT output is zero if this isn't asserted
if has_re and k < (repeat // 2):
continue
new_init |= (1 << (k * len(data) + i))
lut.setParam("LUT_INIT", f"{new_init:016b}")
uds = parse_hex(os.environ["UDS_HEX"], 8)
udi = parse_hex(os.environ["UDI_HEX"], 2)
uds_lut_count = 0
udi_lut_count = 0
for cell_name, cell in ctx.cells:
if "uds_rom_idx" in cell.attrs:
index = int(cell.attrs["uds_rom_idx"], 2)
rewrite_lut(cell, index, uds, True)
uds_lut_count += 1
if "udi_rom_idx" in cell.attrs:
index = int(cell.attrs["udi_rom_idx"], 2)
rewrite_lut(cell, index, udi, False)
udi_lut_count += 1
assert uds_lut_count == 32, uds_lut_count
assert udi_lut_count == 32, udi_lut_count
write_bitstream(ctx, os.environ["OUT_ASC"])

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
(footprint "1674954-1" (version 20211014) (generator pcbnew)
(layer "F.Cu")
(tedit 0)
(descr "1674954-1")
(tags "Undefined or Miscellaneous")
(attr smd)
(fp_text reference "U**" (at -2.733 -0.184) (layer "F.SilkS")
(effects (font (size 1.27 1.27) (thickness 0.254)))
(tstamp e149e0b1-47fa-4b20-b36e-2d51ee1e85c3)
)
(fp_text value "1674954-1" (at -2.733 -0.184) (layer "F.SilkS") hide
(effects (font (size 1.27 1.27) (thickness 0.254)))
(tstamp e68c5170-03c3-4a20-abd0-ad610c43d035)
)
(fp_text user "${REFERENCE}" (at -2.733 -0.184) (layer "F.Fab")
(effects (font (size 1.27 1.27) (thickness 0.254)))
(tstamp 81c041f3-483e-477d-9475-d108280de2a9)
)
(fp_line (start 0 -1.3) (end 0 1.3) (layer "F.SilkS") (width 0.1) (tstamp 5994a946-119f-4db4-aafe-00ae73b5b800))
(fp_line (start 0 -1.3) (end -0.25 -1.3) (layer "F.SilkS") (width 0.1) (tstamp b680b4a7-6cb0-40b5-a7ec-a02910a0daa4))
(fp_line (start 0 1.3) (end -0.25 1.3) (layer "F.SilkS") (width 0.1) (tstamp c5a1761e-3391-4e74-90c9-947fd66e1fc6))
(fp_line (start 0 -1.3) (end 0 1.3) (layer "F.Fab") (width 0.1) (tstamp 08e2d62f-f99a-4268-8b33-617dfcc63e75))
(fp_line (start -4.5 -1.3) (end 0 -1.3) (layer "F.Fab") (width 0.1) (tstamp 92e8f8c3-0985-4c0d-8e38-92cbbf365409))
(fp_line (start 0 1.3) (end -4.5 1.3) (layer "F.Fab") (width 0.1) (tstamp eaef1172-3351-417c-bfc4-74a598f141cb))
(fp_line (start -4.5 1.3) (end -4.5 -1.3) (layer "F.Fab") (width 0.1) (tstamp f6ee98b5-4773-4eeb-a825-33c1705abace))
(pad "1" smd rect (at -2.45 0 90) (size 2.6 4.1) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp a1c7b1f5-f895-4192-9484-2357882c73e0))
(model "1674954-1.stp"
(offset (xyz 0 0 0))
(scale (xyz 1 1 1))
(rotate (xyz -90 0 -90))
)
)

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
CH554 main frequency modification, delay function definition
                     Serial port 0 and serial port 1 initialization
                     Serial port 0 and serial port 1 transceiver subfunctions
                     Watchdog initialization
                     Watchdog initialization
*******************************************************************************/
#include <stdint.h>
@ -20,8 +20,8 @@
* Description : CH554 clock selection and configuration function, Fsys 6MHz is used by default, FREQ_SYS can be passed
                 CLOCK_CFG configuration, the formula is as follows:
                 Fsys = (Fosc * 4 / (CLOCK_CFG & MASK_SYS_CK_SEL); the specific clock needs to be configured by yourself
*******************************************************************************/
void CfgFsys( )
*******************************************************************************/
void CfgFsys( )
{
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA;
@ -31,19 +31,19 @@ void CfgFsys( )
#if FREQ_SYS == 32000000
CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x07; // 32MHz
#elif FREQ_SYS == 24000000
CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x06; // 24MHz
CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x06; // 24MHz
#elif FREQ_SYS == 16000000
CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x05; // 16MHz
CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x05; // 16MHz
#elif FREQ_SYS == 12000000
CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x04; // 12MHz
#elif FREQ_SYS == 6000000
CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x03; // 6MHz
CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x03; // 6MHz
#elif FREQ_SYS == 3000000
CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x02; // 3MHz
CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x02; // 3MHz
#elif FREQ_SYS == 750000
CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x01; // 750KHz
CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x01; // 750KHz
#elif FREQ_SYS == 187500
CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x00; // 187.5MHz
CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x00; // 187.5MHz
#else
#warning FREQ_SYS invalid or not set
#endif
@ -59,7 +59,7 @@ void CfgFsys( )
* Input : UNIT16 n
* Output : None
* Return : None
*******************************************************************************/
*******************************************************************************/
void mDelayuS( uint16_t n ) // Delay in uS
{
#ifdef FREQ_SYS
@ -129,7 +129,7 @@ void mDelaymS( uint16_t n ) //
#endif
-- n;
}
}
}
#if SDCC < 370
void putchar(char c)
@ -160,3 +160,44 @@ int getchar() {
return SBUF;
}
#endif
// Set pin p1.4 and p1.5 to GPIO output mode.
void gpio_init(){
// p1.4
P1_MOD_OC &= ~0x10;
P1_DIR_PU |= 0x10;
// p1.5
P1_MOD_OC &= ~0x20;
P1_DIR_PU |= 0x20;
}
void gpio_set(uint8_t pin) {
switch (pin)
{
case 0x10: // p1.4
P1 |= 0x10;
break;
case 0x20: // p1.5
P1 |= 0x20;
break;
default: // do nothing, unsupported pin.
break;
}
}
void gpio_unset(uint8_t pin) {
switch (pin)
{
case 0x10:
P1 &= ~0x10;
break;
case 0x20:
P1 &= ~0x20;
break;
default: // do nothing, unsupported pin.
break;
}
}

View File

@ -102,7 +102,7 @@ inline void UART1Setup()
U1SM0 = 0; //UART1选择8位数据位
U1SMOD = 1; //快速模式
U1REN = 1; //使能接收
// should correct for rounding in SBAUD1 calculation
// should correct for rounding in SBAUD1 calculation
SBAUD1 = 256 - FREQ_SYS/16/UART1_BAUD;
}
@ -177,3 +177,8 @@ inline void CH554WDTFeed(uint8_t tim)
WDOG_COUNT = tim; // Watchdog counter assignment
}
// Set pin p1.4 and p1.5 to GPIO output mode.
void gpio_init();
void gpio_set(uint8_t pin);
void gpio_unset(uint8_t pin);

View File

@ -40,7 +40,7 @@ __code uint8_t DevDesc[] = {0x12,0x01,0x10,0x01,0x02,0x00,0x00,DEFAULT_ENDP0_SIZ
__code uint8_t CfgDesc[] ={
0x09,0x02,0x43,0x00,0x02,0x01,0x00,0xa0,0x32, //Configuration descriptor (two interfaces)
// The following is the interface 0 (CDC interface) descriptor
    0x09,0x04,0x00,0x00,0x01,0x02,0x02,0x01,0x00, // CDC interface descriptor (one endpoint)
0x09,0x04,0x00,0x00,0x01,0x02,0x02,0x01,0x00, // CDC interface descriptor (one endpoint)
//The following is the function descriptor
0x05,0x24,0x00,0x10,0x01, //Function descriptor (header)
0x05,0x24,0x01,0x00,0x00, //Management descriptor (no data interface) 03 01
@ -173,40 +173,39 @@ void DeviceInterrupt(void) __interrupt (INT_NO_USB) //USB
{
switch (USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP))
{
case UIS_TOKEN_IN | 1: //endpoint 1# 端点中断上传
case UIS_TOKEN_IN | 1: //endpoint 1# Endpoint interrupts upload
UEP1_T_LEN = 0;
UEP1_CTRL = UEP1_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK; //默认应答NAK
UEP1_CTRL = UEP1_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK; //Default answer NAK
break;
case UIS_TOKEN_IN | 2: //endpoint 2# 端点批量上传
case UIS_TOKEN_IN | 2: //endpoint 2# Endpoint bulk upload
{
UEP2_T_LEN = 0; //预使用发送长度一定要清空
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK; //默认应答NAK
UpPoint2_Busy = 0; //清除忙标志
UEP2_T_LEN = 0; //The pre-used sending length must be cleared
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK; //Default answer NAK
UpPoint2_Busy = 0; //clear busy flag
}
break;
case UIS_TOKEN_OUT | 2: //endpoint 3# 端点批量下传
if ( U_TOG_OK ) // 不同步的数据包将丢弃
case UIS_TOKEN_OUT | 2: //endpoint 3# Endpoint batch download
if ( U_TOG_OK ) // Out-of-sync packets will be dropped
{
USBByteCount = USB_RX_LEN; // Grads length of recieved data
USBBufOutPoint = 0; //Get data pointer reset
USBByteCount = USB_RX_LEN; // Grads length of recieved data
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_R_RES | UEP_R_RES_NAK; //NAK after receiving a packet of data, the main function finishes processing, and the main function modifies the response mode
}
break;
case UIS_TOKEN_SETUP | 0: //SETUP事务
case UIS_TOKEN_SETUP | 0: //SETUP routine
len = USB_RX_LEN;
if(len == (sizeof(USB_SETUP_REQ)))
{
SetupLen = ((uint16_t)UsbSetupBuf->wLengthH<<8) | (UsbSetupBuf->wLengthL);
len = 0; // 默认为成功并且上传0长度
len = 0; // Defaults to success and uploading 0 length
SetupReq = UsbSetupBuf->bRequest;
if ( ( UsbSetupBuf->bRequestType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )//非标准请求
if ( ( UsbSetupBuf->bRequestType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )// non-standard request
{
switch( SetupReq )
{
case GET_LINE_CODING: //0x21 currently configured
pDescr = LineCoding;
len = sizeof(LineCoding);
len = SetupLen >= DEFAULT_ENDP0_SIZE ? DEFAULT_ENDP0_SIZE : SetupLen; // 本次传输长度
len = SetupLen >= DEFAULT_ENDP0_SIZE ? DEFAULT_ENDP0_SIZE : SetupLen; // The length of this transmission
memcpy(Ep0Buffer,pDescr,len);
SetupLen -= len;
pDescr += len;
@ -227,12 +226,12 @@ void DeviceInterrupt(void) __interrupt (INT_NO_USB) //USB
case USB_GET_DESCRIPTOR:
switch(UsbSetupBuf->wValueH)
{
case 1: //设备描述符
pDescr = DevDesc; //把设备描述符送到要发送的缓冲区
case 1: // device descriptor
pDescr = DevDesc; //Send the device descriptor to the buffer to be sent
len = sizeof(DevDesc);
break;
case 2: //配置描述符
pDescr = CfgDesc; //把设备描述符送到要发送的缓冲区
case 2: //configuration descriptor
pDescr = CfgDesc; //Send the device descriptor to the buffer to be sent
len = sizeof(CfgDesc);
break;
case 3:
@ -292,19 +291,19 @@ void DeviceInterrupt(void) __interrupt (INT_NO_USB) //USB
{
if( CfgDesc[ 7 ] & 0x20 )
{
/* 唤醒 */
/* Wake */
}
else
{
len = 0xFF; /* 操作失败 */
len = 0xFF; /* operation failed */
}
}
else
{
len = 0xFF; /* 操作失败 */
len = 0xFF; /* operation failed */
}
}
else if ( ( UsbSetupBuf->bRequestType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )// 端点
else if ( ( UsbSetupBuf->bRequestType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )// endpoint
{
switch( UsbSetupBuf->wIndexL )
{
@ -327,25 +326,25 @@ void DeviceInterrupt(void) __interrupt (INT_NO_USB) //USB
UEP1_CTRL = UEP1_CTRL & ~ ( bUEP_R_TOG | MASK_UEP_R_RES ) | UEP_R_RES_ACK;
break;
default:
len = 0xFF; // 不支持的端点
len = 0xFF; // Unsupported endpoint
break;
}
}
else
{
len = 0xFF; // 不是端点不支持
len = 0xFF; // It's not that the endpoint doesn't support it
}
break;
case USB_SET_FEATURE: /* Set Feature */
if( ( UsbSetupBuf->bRequestType & 0x1F ) == USB_REQ_RECIP_DEVICE ) /* 设置设备 */
if( ( UsbSetupBuf->bRequestType & 0x1F ) == USB_REQ_RECIP_DEVICE ) /* Set up the device */
{
if( ( ( ( uint16_t )UsbSetupBuf->wValueH << 8 ) | UsbSetupBuf->wValueL ) == 0x01 )
{
if( CfgDesc[ 7 ] & 0x20 )
{
/* 休眠 */
/* hibernate */
#ifdef DE_PRINTF
printf( "suspend\n" ); //睡眠状态
printf( "suspend\n" ); //sleep state
#endif
while ( XBUS_AUX & bUART0_TX )
{
@ -353,58 +352,58 @@ void DeviceInterrupt(void) __interrupt (INT_NO_USB) //USB
}
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA;
WAKE_CTRL = bWAK_BY_USB | bWAK_RXD0_LO | bWAK_RXD1_LO; //USB或者RXD0/1有信号时可被唤醒
PCON |= PD; //睡眠
WAKE_CTRL = bWAK_BY_USB | bWAK_RXD0_LO | bWAK_RXD1_LO; //USB or RXD0/1 can be woken up when there is a signal
PCON |= PD; // sleep
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA;
WAKE_CTRL = 0x00;
}
else
{
len = 0xFF; /* 操作失败 */
len = 0xFF; /* operation failed */
}
}
else
{
len = 0xFF; /* 操作失败 */
len = 0xFF; /* operation failed */
}
}
else if( ( UsbSetupBuf->bRequestType & 0x1F ) == USB_REQ_RECIP_ENDP ) /* 设置端点 */
else if( ( UsbSetupBuf->bRequestType & 0x1F ) == USB_REQ_RECIP_ENDP ) /* Set endpoint */
{
if( ( ( ( uint16_t )UsbSetupBuf->wValueH << 8 ) | UsbSetupBuf->wValueL ) == 0x00 )
{
switch( ( ( uint16_t )UsbSetupBuf->wIndexH << 8 ) | UsbSetupBuf->wIndexL )
{
case 0x83:
UEP3_CTRL = UEP3_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* 设置端点3 IN STALL */
UEP3_CTRL = UEP3_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* Set endpoint 3 IN STALL */
break;
case 0x03:
UEP3_CTRL = UEP3_CTRL & (~bUEP_R_TOG) | UEP_R_RES_STALL;/* 设置端点3 OUT Stall */
UEP3_CTRL = UEP3_CTRL & (~bUEP_R_TOG) | UEP_R_RES_STALL;/* Set endpoint 3 OUT Stall */
break;
case 0x82:
UEP2_CTRL = UEP2_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* 设置端点2 IN STALL */
UEP2_CTRL = UEP2_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* Set endpoint 2 IN STALL */
break;
case 0x02:
UEP2_CTRL = UEP2_CTRL & (~bUEP_R_TOG) | UEP_R_RES_STALL;/* 设置端点2 OUT Stall */
UEP2_CTRL = UEP2_CTRL & (~bUEP_R_TOG) | UEP_R_RES_STALL;/* Set endpoint 2 OUT Stall */
break;
case 0x81:
UEP1_CTRL = UEP1_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* 设置端点1 IN STALL */
UEP1_CTRL = UEP1_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* Set endpoint 1 IN STALL */
break;
case 0x01:
UEP1_CTRL = UEP1_CTRL & (~bUEP_R_TOG) | UEP_R_RES_STALL;/* 设置端点1 OUT Stall */
UEP1_CTRL = UEP1_CTRL & (~bUEP_R_TOG) | UEP_R_RES_STALL;/* Set endpoint 1 OUT Stall */
default:
len = 0xFF; /* 操作失败 */
len = 0xFF; /* operation failed */
break;
}
}
else
{
len = 0xFF; /* 操作失败 */
len = 0xFF; /* operation failed */
}
}
else
{
len = 0xFF; /* 操作失败 */
len = 0xFF; /* operation failed */
}
break;
case USB_GET_STATUS:
@ -420,67 +419,67 @@ void DeviceInterrupt(void) __interrupt (INT_NO_USB) //USB
}
break;
default:
len = 0xff; //操作失败
len = 0xff; //operation failed
break;
}
}
}
else
{
len = 0xff; //包长度错误
len = 0xff; //Packet length error
}
if(len == 0xff)
{
SetupReq = 0xFF;
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL;//STALL
}
else if(len <= DEFAULT_ENDP0_SIZE) //上传数据或者状态阶段返回0长度包
else if(len <= DEFAULT_ENDP0_SIZE) //Upload data or status phase returns 0 length packet
{
UEP0_T_LEN = len;
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA1返回应答ACK
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;//The default packet is DATA1Return response ACK
}
else
{
UEP0_T_LEN = 0; //虽然尚未到状态阶段但是提前预置上传0长度数据包以防主机提前进入状态阶段
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA1,返回应答ACK
UEP0_T_LEN = 0; //Although it has not yet reached the status stage, it is preset to upload 0-length data packets in advance to prevent the host from entering the status stage early.
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK; //The default data packet is DATA1, and the response ACK is returned
}
break;
case UIS_TOKEN_IN | 0: //endpoint0 IN
switch(SetupReq)
{
case USB_GET_DESCRIPTOR:
len = SetupLen >= DEFAULT_ENDP0_SIZE ? DEFAULT_ENDP0_SIZE : SetupLen; //本次传输长度
memcpy( Ep0Buffer, pDescr, len ); //加载上传数据
len = SetupLen >= DEFAULT_ENDP0_SIZE ? DEFAULT_ENDP0_SIZE : SetupLen; //The length of this transmission
memcpy( Ep0Buffer, pDescr, len ); //Load upload data
SetupLen -= len;
pDescr += len;
UEP0_T_LEN = len;
UEP0_CTRL ^= bUEP_T_TOG; //同步标志位翻转
UEP0_CTRL ^= bUEP_T_TOG; //Sync flag flip
break;
case USB_SET_ADDRESS:
USB_DEV_AD = USB_DEV_AD & bUDA_GP_BIT | SetupLen;
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
break;
default:
UEP0_T_LEN = 0; //状态阶段完成中断或者是强制上传0长度数据包结束控制传输
UEP0_T_LEN = 0; //The status phase is completed and interrupted or the 0-length data packet is forced to be uploaded to end the control transmission.
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
break;
}
break;
case UIS_TOKEN_OUT | 0: // endpoint0 OUT
if(SetupReq ==SET_LINE_CODING) //设置串口属性
if(SetupReq ==SET_LINE_CODING) // Set serial port properties
{
if( U_TOG_OK )
{
memcpy(LineCoding,UsbSetupBuf,USB_RX_LEN);
Config_Uart1(LineCoding);
UEP0_T_LEN = 0;
UEP0_CTRL |= UEP_R_RES_ACK | UEP_T_RES_ACK; // 准备上传0包
UEP0_CTRL |= UEP_R_RES_ACK | UEP_T_RES_ACK; // Prepare to upload 0 packages
}
}
else
{
UEP0_T_LEN = 0;
UEP0_CTRL |= UEP_R_RES_ACK | UEP_T_RES_NAK; //状态阶段对IN响应NAK
UEP0_CTRL |= UEP_R_RES_ACK | UEP_T_RES_NAK; // Status phase, responds to IN with NAK
}
break;
@ -489,12 +488,12 @@ void DeviceInterrupt(void) __interrupt (INT_NO_USB) //USB
default:
break;
}
UIF_TRANSFER = 0; //写0清空中断
UIF_TRANSFER = 0; //Writing 0 clears the interrupt
}
if(UIF_BUS_RST) //设备模式USB总线复位中断
if(UIF_BUS_RST) //Device mode USB bus reset interrupt
{
#ifdef DE_PRINTF
printf( "reset\n" ); //睡眠状态
printf( "reset\n" ); //sleep state
#endif
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
UEP1_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK;
@ -502,37 +501,37 @@ void DeviceInterrupt(void) __interrupt (INT_NO_USB) //USB
USB_DEV_AD = 0x00;
UIF_SUSPEND = 0;
UIF_TRANSFER = 0;
UIF_BUS_RST = 0; //清中断标志
Uart_Input_Point = 0; //循环缓冲区输入指针
Uart_Output_Point = 0; //循环缓冲区读出指针
UartByteCount = 0; //当前缓冲区剩余待取字节数
USBByteCount = 0; //USB端点收到的长度
UsbConfig = 0; //清除配置值
UIF_BUS_RST = 0; //clear interrupt flag
Uart_Input_Point = 0; //Circular buffer input pointer
Uart_Output_Point = 0; //Circular buffer read pointer
UartByteCount = 0; //The number of bytes remaining in the current buffer to be fetched
USBByteCount = 0; //USB endpoint received length
UsbConfig = 0; //Clear configuration values
UpPoint2_Busy = 0;
}
if (UIF_SUSPEND) //USB总线挂起/唤醒完成
if (UIF_SUSPEND) //USB bus suspend/wake completed
{
UIF_SUSPEND = 0;
if ( USB_MIS_ST & bUMS_SUSPEND ) //挂起
if ( USB_MIS_ST & bUMS_SUSPEND ) //hang
{
#ifdef DE_PRINTF
printf( "suspend\n" ); //睡眠状态
printf( "suspend\n" ); //sleep state
#endif
while ( XBUS_AUX & bUART0_TX )
{
; //等待发送完成
; //Wait for sending to complete
}
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA;
WAKE_CTRL = bWAK_BY_USB | bWAK_RXD0_LO | bWAK_RXD1_LO; //USB或者RXD0/1有信号时可被唤醒
PCON |= PD; //睡眠
WAKE_CTRL = bWAK_BY_USB | bWAK_RXD0_LO | bWAK_RXD1_LO; //Can be woken up when there is a signal from USB or RXD0/1
PCON |= PD; //sleep
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA;
WAKE_CTRL = 0x00;
}
}
else { //意外的中断,不可能发生的情况
USB_INT_FG = 0xFF; //清中断标志
else { //Unexpected interruption, impossible situation
USB_INT_FG = 0xFF; //clear interrupt flag
}
}
@ -542,22 +541,35 @@ void DeviceInterrupt(void) __interrupt (INT_NO_USB) //USB
*******************************************************************************/
void Uart1_ISR(void) __interrupt (INT_NO_UART1)
{
if(U1RI) //收到数据
if(U1RI) //data received
{
Receive_Uart_Buf[Uart_Input_Point++] = SBUF1;
UartByteCount++; //Number of bytes remaining in the current buffer
if(Uart_Input_Point>=UART_REV_LEN)
if(Uart_Input_Point>=UART_REV_LEN) {
Uart_Input_Point = 0; //Write pointer
U1RI =0;
}
U1RI = 0;
}
}
//主函数
uint8_t uart_byte_count() {
uint8_t in = Uart_Input_Point;
uint8_t out = Uart_Output_Point;
if (in < out) {
in = in + UART_REV_LEN;
}
return in - out;
}
//main function
main()
{
uint8_t length;
uint8_t Uart_Timeout = 0;
uint8_t recievedData[MAX_PACKET_SIZE] ="";
uint8_t USB_output_buffer[64] = {0};
uint8_t USB_output_buffer_remain = 0;
CfgFsys( ); // CH559 clock selection configuration
mDelaymS(5); // Modify the main frequency and wait for the internal crystal to stabilize, which must be added
mInitSTDIO( ); // Serial port 0, can be used for debugging
@ -572,23 +584,39 @@ main()
UEP0_T_LEN = 0;
UEP1_T_LEN = 0; //Pre-use send length must be cleared
UEP2_T_LEN = 0; //Pre-use send length must be cleared
// Enable GPIO debugging on p1.4 and p1.5
// gpio_init();
// gpio_unset(0x10);
// gpio_unset(0x20);
while(1)
{
if(UsbConfig)
{
if(USBByteCount) // USB receiving endpoint has data
{
CH554UART1SendByte(Ep2Buffer[USBBufOutPoint++]);
recievedData[USBBufOutPoint] = Ep2Buffer[USBBufOutPoint];
USBByteCount--;
if(USBByteCount==0)
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_R_RES | UEP_R_RES_ACK;
memcpy(USB_output_buffer, Ep2Buffer, USBByteCount);
USB_output_buffer_remain = USBByteCount;
USBBufOutPoint = 0;
USBByteCount = 0;
}
if(UartByteCount)
if(USB_output_buffer_remain)
{
CH554UART1SendByte(USB_output_buffer[USBBufOutPoint++]);
USB_output_buffer_remain--;
if(USB_output_buffer_remain==0) {
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_R_RES | UEP_R_RES_ACK;
}
}
UartByteCount = uart_byte_count();
if(UartByteCount) {
Uart_Timeout++;
}
if(!UpPoint2_Busy) // The endpoint is not busy (the first packet of data after idle, only used to trigger upload)
{
length = UartByteCount;
@ -596,22 +624,36 @@ main()
{
if(length>39 || Uart_Timeout>100)
{
Uart_Timeout = 0;
if(Uart_Output_Point+length>UART_REV_LEN)
// if we reach a wrap-around, just transmit from index to end of buffer.
// The rest goes in next packet, i.e., not handling wrap-around.
if(Uart_Output_Point+length>UART_REV_LEN) {
length = UART_REV_LEN-Uart_Output_Point;
UartByteCount -= length;
}
// write upload endpoint
memcpy(Ep2Buffer+MAX_PACKET_SIZE,&Receive_Uart_Buf[Uart_Output_Point],length);
Uart_Output_Point+=length;
if (Uart_Output_Point>=UART_REV_LEN)
                            Uart_Output_Point = 0;
                        UEP2_T_LEN = length; // Pre-use send length must be cleared
                        UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK; // Answer ACK
                        UpPoint2_Busy = 1;
                    }
                }
if (Uart_Output_Point>=UART_REV_LEN) {
Uart_Output_Point = 0;
}
UEP2_T_LEN = length; // Pre-use send length must be cleared
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK; // Answer ACK
UpPoint2_Busy = 1;
// Should according to the USB-spec check if
// length == 64, if so we should send a
// zero-length USB packet. This is very
// unlikley to happen.
}
}
}
// Should have a timeout if the transfer for some reason
// fails to reset UpPoint2_Busy. But does not seem to
// happen.
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,26 @@
"Source:","C:\Users\matt\Other-Repos\tillitis-key1\hw\boards\tk1\tk1.kicad_sch"
"Date:","11/15/2022 2:04:00 PM"
"Tool:","Eeschema (6.0.4)"
"Generator:","C:\Program Files\KiCad\6.0\bin\scripting\plugins/bom_csv_grouped_by_extended_value.py"
"Component Count:","47"
"Ref","Qnty","Value","Footprint","Description","Manufacturer","Manufacturer Part Number","Supplier","Supplier Part Number"
"C1,C2,C3,C4,C5,C6,C25","7","10uF,10V,X5R,20%","mta1:CAPC1608X09L","Unpolarized capacitor","Any/not critical","","",""
"C7,C13,C16,C17,C18,C19,C20,C21,C22,C23,C26","11","0.10uF,16V,X5R,20%","mta1:CAPC1005X06L","Unpolarized capacitor","Any/not critical","","",""
"C8","1","1uF,50V,X7R,10%,1.6mm thickness","Capacitor_SMD:C_1206_3216Metric","Unpolarized capacitor","TDK Corporation","C3216X7R1H105K160AE","Digikey","445-8904-2-ND"
"C27","1","1pF,16V,X5R,20%","mta1:CAPC1005X06L","Unpolarized capacitor","Any/not critical","","",""
"D1","1","0402 indicator LED, blue","LED_SMD:LED_0402_1005Metric","Light emitting diode","Foshan NationStar","NCD0402B1","LCSC","C130724"
"D3","1","LED_ARGB","mta1:0402rgb-1010","","Foshan NationStar","FC-B1010RGBT-HG","LCSC","C158099"
"FB3","1","BLM18KG300TN1D","mta1:Ferritbead_0603_1608Metric","","Murata","BLM18KG300TN1D","Digikey","490-5447-1-ND"
"P1","1","USB_C_Plug","mta1:U261-241N-4BS60","USB Type-C Plug connector","XKB","U261-241N-4BS60","LCSC","C319150"
"R1,R2,R19,R20,R22,R23,R24,R25,R26","9","10k,1/16W,5%","mta1:ERJ2G(0402)_L","Resistor","Any/not critical","","",""
"R3,R16,R17,R18","4","1k,1/16W,5%","mta1:ERJ2G(0402)_L","Resistor","Any/not critical","","",""
"R29","1","5.1k,1/16W,1%","mta1:ERJ2G(0402)_L","Resistor","Any/not critical","","",""
"R30","1","2k,1/16W,1%","mta1:ERJ2G(0402)_L","Resistor","Any/not critical","","",""
"U1","1","MCP1824T-2502EOT","Package_TO_SOT_SMD:SOT-23-5","IC REG LINEAR 2.5V 300MA SOT23-5","Microchip","MCP1824T-2502EOT","Digikey","MCP1824T-2502E/OTCT-ND"
"U2","1","MIC5258-1.2YM5","Package_TO_SOT_SMD:SOT-23-5","IC REG LINEAR 1.2V 150MA SOT23-5","Micrel Inc.","MIC5258-1.2YM5","Digikey","2156-MIC5258-1.2YM5-ND"
"U3","1","CH552E","Package_SO:MSOP-10_3x3mm_P0.5mm","8-bit enhanced USB microcontroller CH552","WCH","CH552E","LCSC","C967938"
"U5","1","USBLC6-2SC6","Package_TO_SOT_SMD:SOT-23-6","Very low capacitance ESD protection diode, 2 data-line, SOT-23-6","ST","USBLC6-2SC6","Digikey","497-5235-1-ND"
"U6","1","ICE40UP5K-SG48ITR","Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.6x5.6mm","iCE40 UltraPlus FPGA, 5280 LUTs, 1.2V, 48-pin QFN","Lattice","ICE40UP5K-SG48ITR","Digikey","220-2145-2-ND"
"U8","1","W25Q80DVUXIE","mta1:W25Q80DVUXIE","IC FLASH 8MBIT SPI 104MHZ 8USON","Winbond Electronics","W25Q80DVUXIE","Digikey","W25Q80DVUXIETR-ND"
"U9","1","NCP752BSN33T1G","mta1:NCP752BSN33T1G","IC REG LINEAR 3.3V 200MA 5TSOP","onsemi","NCP752BSN33T1G","Digikey","NCP752BSN33T1GOSCT-ND"
"U10","1","PT2043AT6","Package_TO_SOT_SMD:SOT-23-6","SOT-23-6 Touch Sensors ROHS","PinTeng","PT2043AT6","LCSC","C2914233"
"Source:","C:\Users\72417946\Documents\GitHub\tillitis-key1\hw\boards\tk1\tk1.kicad_sch"
"Date:","2023-03-17 11:49:31"
"Tool:","Eeschema (6.0.4)"
"Generator:","C:\Program Files\KiCad\6.0\bin\scripting\plugins/bom_csv_grouped_by_value_with_fp.py"
"Component Count:","47"
"Ref","Qnty","Value","Cmp name","Footprint","Description","Vendor"
"C1, C2, C3, C4, C5, C6, C25, ","7","10uF","C","mta1:CAPC1608X09L","Unpolarized capacitor",""
"C7, C13, C16, C17, C18, C19, C20, C21, C22, C23, C26, ","11","0.10uF","C","mta1:CAPC1005X06L","Unpolarized capacitor",""
"C27, ","1","1pF","C","mta1:CAPC1005X06L","Unpolarized capacitor",""
"D1, ","1","0402 indicator LED, blue","LED","LED_SMD:LED_0402_1005Metric","Light emitting diode",""
"D3, ","1","LED_ARGB","FC-B1010RGBT-HG","mta1:0402rgb-1010","",""
"FB3, ","1","BLM18KG300TN1D","Ferrite_Bead-Device","mta1:Ferritbead_0603_1608Metric","",""
"P1, ","1","USB_C_Plug","USB_C_Plug","mta1:U261-241N-4BS60","USB Type-C Plug connector",""
"R1, R2, R19, R20, R22, R23, R24, R25, R26, ","9","10k","R","mta1:ERJ2G(0402)_L","Resistor",""
"R3, R16, R17, R18, ","4","1k","R","mta1:ERJ2G(0402)_L","Resistor",""
"R29, ","1","5.1k","R","mta1:ERJ2G(0402)_L","Resistor",""
"R30, ","1","2k","R","mta1:ERJ2G(0402)_L","Resistor",""
"U1, ","1","MCP1824T-2502EOT","MCP1824T-2502EOT","Package_TO_SOT_SMD:SOT-23-5","IC REG LINEAR 2.5V 300MA SOT23-5",""
"U2, ","1","MIC5258-1.2YM5","MIC5258-1.2YM5-TR","Package_TO_SOT_SMD:SOT-23-5","IC REG LINEAR 1.2V 150MA SOT23-5",""
"U3, ","1","CH552E","CH552E","Package_SO:MSOP-10_3x3mm_P0.5mm","8-bit enhanced USB microcontroller CH552",""
"U5, ","1","USBLC6-2SC6","USBLC6-2SC6","Package_TO_SOT_SMD:SOT-23-6","Very low capacitance ESD protection diode, 2 data-line, SOT-23-6",""
"U6, ","1","ICE40UP5K-SG48ITR","ICE40UP5K-SG48ITR","Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.6x5.6mm","iCE40 UltraPlus FPGA, 5280 LUTs, 1.2V, 48-pin QFN",""
"U8, ","1","W25Q80DVUXIE","W25Q80DVUXIE","mta1:W25Q80DVUXIE","IC FLASH 8MBIT SPI 104MHZ 8USON",""
"U9, ","1","NCP752BSN33T1G","NCP752BSN33T1G","mta1:NCP752BSN33T1G","IC REG LINEAR 3.3V 200MA 5TSOP",""
"U10, ","1","PT2043AT6","PT2043AT6","Package_TO_SOT_SMD:SOT-23-6","SOT-23-6 Touch Sensors ROHS",""
"U11, ","1","~","1674954-1","1674954-1","AMP - TE CONNECTIVITY - 1674954-1 - SPRING FINGER, MOBILE PHONES",""

Can't render this file because it has a wrong number of fields in line 6.

File diff suppressed because it is too large Load Diff

View File

@ -3,10 +3,12 @@
"active_layer": 49,
"active_layer_preset": "",
"auto_track_width": false,
"hidden_netclasses": [],
"hidden_nets": [],
"high_contrast_mode": 0,
"net_color_mode": 1,
"opacity": {
"images": 0.6,
"pads": 1.0,
"tracks": 1.0,
"vias": 1.0,
@ -62,7 +64,7 @@
35,
36
],
"visible_layers": "0021000_7ffffff8",
"visible_layers": "fffffff_ffffffff",
"zone_display_mode": 0
},
"meta": {

View File

@ -1,5 +1,6 @@
{
"board": {
"3dviewports": [],
"design_settings": {
"defaults": {
"board_outline_line_width": 0.049999999999999996,
@ -81,11 +82,7 @@
"courtyards_overlap|125050001|92563069|aff9b94a-3155-4d61-8287-3dc8c06c9c02|00000000-0000-0000-0000-000061552981",
"courtyards_overlap|125128899|96299999|a9dc0c59-b820-453f-94ad-ca6fe558a198|aff9b94a-3155-4d61-8287-3dc8c06c9c02",
"silk_over_copper|101399150|99725850|415e16b8-6b2d-45a0-8768-17340423ff22|f7241cad-2f53-4952-a61b-73042c7feb93",
"silk_over_copper|101399150|99725850|415e16b8-6b2d-45a0-8768-17340423ff22|fe6d9248-0cc4-46a4-ae8e-05e05dd2a86e",
"silk_overlap|107643750|90560000|43a44da6-8a26-4f6b-bfab-90bd54eff706|3380a407-9e97-471c-8138-3f5ae456a02d",
"silk_overlap|107643750|90560000|43f30d59-714f-4bad-98a3-5b688f75bff9|3380a407-9e97-471c-8138-3f5ae456a02d",
"silk_overlap|108525000|93825000|3fde9030-6d4b-46cf-94bc-1e2f098b7b7d|911835c1-7de3-4364-900a-69211931b2f3",
"silk_overlap|108525000|93825000|e93fedf4-2386-4d73-b28a-1d7d9e9c0354|911835c1-7de3-4364-900a-69211931b2f3"
"silk_over_copper|101399150|99725850|415e16b8-6b2d-45a0-8768-17340423ff22|fe6d9248-0cc4-46a4-ae8e-05e05dd2a86e"
],
"meta": {
"filename": "board_design_settings.json",
@ -94,20 +91,26 @@
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"connection_width": "warning",
"copper_edge_clearance": "error",
"copper_sliver": "warning",
"courtyards_overlap": "error",
"diff_pair_gap_out_of_range": "error",
"diff_pair_uncoupled_length_too_long": "error",
"drill_out_of_range": "error",
"duplicate_footprints": "warning",
"extra_footprint": "warning",
"footprint": "error",
"footprint_type_mismatch": "error",
"hole_clearance": "error",
"hole_near_hole": "error",
"invalid_outline": "error",
"isolated_copper": "warning",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"lib_footprint_issues": "warning",
"lib_footprint_mismatch": "warning",
"malformed_courtyard": "error",
"microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore",
@ -117,9 +120,14 @@
"padstack": "error",
"pth_inside_courtyard": "ignore",
"shorting_items": "error",
"silk_edge_clearance": "warning",
"silk_over_copper": "warning",
"silk_overlap": "warning",
"skew_out_of_range": "error",
"solder_mask_bridge": "error",
"starved_thermal": "error",
"text_height": "warning",
"text_thickness": "warning",
"through_hole_pad_without_hole": "error",
"too_many_vias": "error",
"track_dangling": "warning",
@ -128,7 +136,6 @@
"unconnected_items": "error",
"unresolved_variable": "error",
"via_dangling": "warning",
"zone_has_empty_net": "error",
"zones_intersect": "error"
},
"rule_severitieslegacy_courtyards_overlap": true,
@ -138,18 +145,63 @@
"allow_microvias": false,
"max_error": 0.005,
"min_clearance": 0.09999999999999999,
"min_connection": 0.0,
"min_copper_edge_clearance": 0.25,
"min_hole_clearance": 0.25,
"min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.19999999999999998,
"min_microvia_drill": 0.09999999999999999,
"min_resolved_spokes": 2,
"min_silk_clearance": 0.0,
"min_text_height": 0.7999999999999999,
"min_text_thickness": 0.08,
"min_through_hole_diameter": 0.25,
"min_track_width": 0.125,
"min_via_annular_width": 0.125,
"min_via_diameter": 0.6,
"solder_mask_to_copper_clearance": 0.0,
"use_height_for_length_calcs": true
},
"teardrop_options": [
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 5,
"td_on_pad_in_zone": false,
"td_onpadsmd": true,
"td_onroundshapesonly": false,
"td_ontrackend": false,
"td_onviapad": true
}
],
"teardrop_parameters": [
{
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_target_name": "td_round_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_target_name": "td_rect_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_target_name": "td_track_end",
"td_width_to_size_filter_ratio": 0.9
}
],
"track_widths": [
0.0,
0.125,
@ -170,7 +222,8 @@
"zones_allow_external_fillets": false,
"zones_use_no_outline": true
},
"layer_presets": []
"layer_presets": [],
"viewports": []
},
"boards": [],
"cvpcb": {
@ -354,18 +407,23 @@
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_label_syntax": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"conflicting_netclasses": "error",
"different_unit_footprint": "error",
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"endpoint_off_grid": "warning",
"extra_units": "error",
"global_label_dangling": "warning",
"hier_label_mismatch": "error",
"label_dangling": "error",
"lib_symbol_issues": "warning",
"missing_bidi_pin": "warning",
"missing_input_pin": "warning",
"missing_power_pin": "error",
"missing_unit": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
@ -375,6 +433,7 @@
"pin_to_pin": "warning",
"power_pin_not_driven": "error",
"similar_labels": "warning",
"simulation_model_issue": "error",
"unannotated": "error",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
@ -392,7 +451,7 @@
"net_settings": {
"classes": [
{
"bus_width": 12.0,
"bus_width": 12,
"clearance": 0.1,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
@ -406,10 +465,10 @@
"track_width": 0.1,
"via_diameter": 0.6,
"via_drill": 0.25,
"wire_width": 6.0
"wire_width": 6
},
{
"bus_width": 12.0,
"bus_width": 12,
"clearance": 0.1,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
@ -418,26 +477,20 @@
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "power",
"nets": [
"+1V2",
"+2V5",
"+3V3",
"+5V",
"/Application FPGA/APP_+1.2_PLL",
"GND"
],
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.2,
"via_diameter": 0.6,
"via_drill": 0.25,
"wire_width": 6.0
"wire_width": 6
}
],
"meta": {
"version": 2
"version": 3
},
"net_colors": null
"net_colors": null,
"netclass_assignments": null,
"netclass_patterns": []
},
"pcbnew": {
"last_paths": {
@ -453,6 +506,8 @@
"schematic": {
"annotate_start_num": 0,
"drawing": {
"dashed_lines_dash_length_ratio": 12.0,
"dashed_lines_gap_length_ratio": 3.0,
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
@ -484,7 +539,11 @@
"page_layout_descr_file": "C:\\Users\\matt\\Other-Repos\\tillitis-key1\\hw\\boards\\mta1-library\\CERN_OHL_S_drawing_sheet.kicad_wks",
"plot_directory": "./",
"spice_adjust_passive_values": false,
"spice_current_sheet_as_root": false,
"spice_external_command": "spice \"%I\"",
"spice_model_current_sheet_as_root": true,
"spice_save_all_currents": false,
"spice_save_all_voltages": false,
"subpart_first_id": 65,
"subpart_id_separator": 0
},

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<export version="E">
<design>
<source>C:\Users\matt\Other-Repos\tillitis-key1\hw\boards\tk1\tk1.kicad_sch</source>
<date>11/15/2022 2:04:00 PM</date>
<source>C:\Users\72417946\Documents\GitHub\tillitis-key1\hw\boards\tk1\tk1.kicad_sch</source>
<date>2023-03-17 11:49:31</date>
<tool>Eeschema (6.0.4)</tool>
<sheet number="1" name="/" tstamps="/">
<title_block>
@ -78,27 +78,6 @@
</sheet>
</design>
<components>
<comp ref="C8">
<value>1uF</value>
<footprint>Capacitor_SMD:C_1206_3216Metric</footprint>
<fields>
<field name="Extended Value">50V,X7R,10%,1.6mm thickness</field>
<field name="Manufacturer">TDK Corporation</field>
<field name="Manufacturer Part Number">C3216X7R1H105K160AE</field>
<field name="Supplier">Digikey</field>
<field name="Supplier Part Number">445-8904-2-ND</field>
</fields>
<libsource lib="Device" part="C" description="Unpolarized capacitor"/>
<property name="Extended Value" value="50V,X7R,10%,1.6mm thickness"/>
<property name="Manufacturer" value="TDK Corporation"/>
<property name="Manufacturer Part Number" value="C3216X7R1H105K160AE"/>
<property name="Supplier" value="Digikey"/>
<property name="Supplier Part Number" value="445-8904-2-ND"/>
<property name="Sheetname" value="Application FPGA"/>
<property name="Sheetfile" value="application_fpga.kicad_sch"/>
<sheetpath names="/Application FPGA/" tstamps="/00000000-0000-0000-0000-0000611cc101/"/>
<tstamps>0f8bd06f-60b1-4be8-90d9-1a7f1cd60020</tstamps>
</comp>
<comp ref="C16">
<value>0.10uF</value>
<footprint>mta1:CAPC1005X06L</footprint>
@ -511,6 +490,29 @@
<sheetpath names="/Application FPGA/" tstamps="/00000000-0000-0000-0000-0000611cc101/"/>
<tstamps>206cf77e-9615-45a1-84e2-dd89660f9255</tstamps>
</comp>
<comp ref="U11">
<value>~</value>
<datasheet>https://www.te.com/commerce/DocumentDelivery/DDEController?Action=srchrtrv&amp;DocNm=6-1773460-8_Spring_Fingers&amp;DocType=Data+Sheet&amp;DocLang=English&amp;PartCntxt=1674954-1&amp;DocFormat=pdf</datasheet>
<fields>
<field name="Description">AMP - TE CONNECTIVITY - 1674954-1 - SPRING FINGER, MOBILE PHONES</field>
<field name="Manufacturer_Name">TE Connectivity</field>
<field name="Manufacturer_Part_Number">1674954-1</field>
<field name="Mouser Part Number">571-1674954-1</field>
<field name="Mouser Price/Stock">https://www.mouser.co.uk/ProductDetail/TE-Connectivity/1674954-1?qs=o4qE4s2E%252BcyEbD%252ByxeI18A%3D%3D</field>
</fields>
<libsource lib="mta1" part="1674954-1" description="AMP - TE CONNECTIVITY - 1674954-1 - SPRING FINGER, MOBILE PHONES"/>
<property name="Description" value="AMP - TE CONNECTIVITY - 1674954-1 - SPRING FINGER, MOBILE PHONES"/>
<property name="Height" value=""/>
<property name="Mouser Part Number" value="571-1674954-1"/>
<property name="Mouser Price/Stock" value="https://www.mouser.co.uk/ProductDetail/TE-Connectivity/1674954-1?qs=o4qE4s2E%252BcyEbD%252ByxeI18A%3D%3D"/>
<property name="Manufacturer_Name" value="TE Connectivity"/>
<property name="Manufacturer_Part_Number" value="1674954-1"/>
<property name="Sheetname" value="Application FPGA"/>
<property name="Sheetfile" value="application_fpga.kicad_sch"/>
<property name="exclude_from_board"/>
<sheetpath names="/Application FPGA/" tstamps="/00000000-0000-0000-0000-0000611cc101/"/>
<tstamps>81172fbc-f24e-4173-965f-d88ed2c48035</tstamps>
</comp>
<comp ref="C7">
<value>0.10uF</value>
<footprint>mta1:CAPC1005X06L</footprint>
@ -981,6 +983,24 @@
<pin num="6" name="I/O1" type="passive"/>
</pins>
</libpart>
<libpart lib="mta1" part="1674954-1">
<description>AMP - TE CONNECTIVITY - 1674954-1 - SPRING FINGER, MOBILE PHONES</description>
<docs>https://www.te.com/commerce/DocumentDelivery/DDEController?Action=srchrtrv&amp;DocNm=6-1773460-8_Spring_Fingers&amp;DocType=Data+Sheet&amp;DocLang=English&amp;PartCntxt=1674954-1&amp;DocFormat=pdf</docs>
<fields>
<field name="Reference">U</field>
<field name="Value">1674954-1</field>
<field name="Footprint">1674954-1</field>
<field name="Datasheet">https://www.te.com/commerce/DocumentDelivery/DDEController?Action=srchrtrv&amp;DocNm=6-1773460-8_Spring_Fingers&amp;DocType=Data+Sheet&amp;DocLang=English&amp;PartCntxt=1674954-1&amp;DocFormat=pdf</field>
<field name="Description">AMP - TE CONNECTIVITY - 1674954-1 - SPRING FINGER, MOBILE PHONES</field>
<field name="Mouser Part Number">571-1674954-1</field>
<field name="Mouser Price/Stock">https://www.mouser.co.uk/ProductDetail/TE-Connectivity/1674954-1?qs=o4qE4s2E%252BcyEbD%252ByxeI18A%3D%3D</field>
<field name="Manufacturer_Name">TE Connectivity</field>
<field name="Manufacturer_Part_Number">1674954-1</field>
</fields>
<pins>
<pin num="1" name="1" type="passive"/>
</pins>
</libpart>
<libpart lib="mta1" part="CH552E">
<description>8-bit enhanced USB microcontroller CH552</description>
<fields>
@ -1193,7 +1213,7 @@
<uri>C:\Program Files\KiCad\6.0\share\kicad\symbols\/Power_Protection.kicad_sym</uri>
</library>
<library logical="mta1">
<uri>C:\Users\matt\Other-Repos\tillitis-key1\hw\boards\tk1/../mta1-library/mta1.kicad_sym</uri>
<uri>C:\Users\72417946\Documents\GitHub\tillitis-key1\hw\boards\tk1/../mta1-library/mta1.kicad_sym</uri>
</library>
</libraries>
<nets>
@ -1269,9 +1289,8 @@
<node ref="U8" pin="3" pinfunction="IO2" pintype="bidirectional"/>
</net>
<net code="8" name="/Application FPGA/TOUCH_PAD">
<node ref="C8" pin="1" pintype="passive"/>
<node ref="C8" pin="2" pintype="passive"/>
<node ref="R30" pin="2" pintype="passive"/>
<node ref="U11" pin="1" pinfunction="1" pintype="passive"/>
</net>
<net code="9" name="/USB to Serial converter/INT_USB_IN_D+">
<node ref="P1" pin="A6" pinfunction="D+" pintype="bidirectional"/>

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -7,8 +7,8 @@
"F1","1","50mA","Fuse:Fuse_1206_3216Metric","Resettable fuse, polymeric positive temperature coefficient, small symbol","Littelfuse","1206L005/60WR","Digikey","F8129TR-ND"
"FID1,FID2,FID3","3","Fiducial","Fiducial:Fiducial_1mm_Mask2mm","Fiducial Marker","","","",""
"FOOT1,FOOT2,FOOT3,FOOT4","4","Rubber Foot,8mm diameter x 2.8mm height, self-adhesive foot","","","3M","SJ5076","RS","120-6041"
"J3","1","BC-1-208","mta1:BC-1-208","","Disong","BC-1-208","",""
"J4","1","BC-1-701","mta1:BC-1-701","","Disong","BC-1-701","",""
"J3","1","Spring pin strips 1R, 2P 2mm pitch","mta1:BC-1-208","Spring pin, can use one 10P and cut","Mill-Max","836-22-002-30-001101","Mouser","575-8362200230001101"
"J4","1","Spring pin strips 1R, 7P 2mm pitch","mta1:BC-1-701","Spring pin, can use one 10P and cut","Mill-Max","836-22-007-30-001101","Mouser","575-8362200730001101"
"Q1","1","AO3400A","Package_TO_SOT_SMD:SOT-23","30V Vds, 5.7A Id, N-Channel MOSFET, SOT-23","Alpha & Omega","AO3400A","Digikey","785-1000-2-ND"
"Q2","1","AO3401A","Package_TO_SOT_SMD:SOT-23","-4.0A Id, -30V Vds, P-Channel MOSFET, SOT-23","Alpha & Omega","AO3401A","Digikey","785-1001-2-ND"
"R7,R8","2","10K,1/16W,5%","mta1:ERJ2G(0402)_L","Resistor","Any/not critical","","",""

Can't render this file because it has a wrong number of fields in line 6.