Compare commits
123 Commits
Author | SHA1 | Date |
---|---|---|
Joachim Strömbergson | 0454e023cd | |
Joachim Strömbergson | e961f46e79 | |
Joachim Strömbergson | f655196af7 | |
dehanj | a5e30f1203 | |
dehanj | d7b8bb26a9 | |
Michael Cardell Widerkrantz | 3cf218469c | |
dehanj | 1c90b1aa3d | |
dehanj | 574e17f26a | |
dehanj | 4bd249816a | |
dehanj | 3a6a60ff26 | |
dehanj | c85b5311cd | |
Michael Cardell Widerkrantz | 88c6036215 | |
dehanj | 0e166e4159 | |
dehanj | 92136983c5 | |
Michael Cardell Widerkrantz | 09c1f3f549 | |
Michael Cardell Widerkrantz | b0efcf019e | |
Michael Cardell Widerkrantz | d10c4972d7 | |
Michael Cardell Widerkrantz | da40edfc51 | |
Michael Cardell Widerkrantz | 48324fe5b3 | |
dehanj | 2ff2e9a91d | |
Michael Cardell Widerkrantz | 661a6458c8 | |
dehanj | 57a6ee2a12 | |
dehanj | 8ca4241ade | |
Joachim Strömbergson | de668a0244 | |
Joachim Strömbergson | f364b523cf | |
Joachim Strömbergson | bbde62d3f5 | |
Joachim Strömbergson | 8731908cb1 | |
Joachim Strömbergson | 29fd8338a7 | |
Joachim Strömbergson | 8784a24b33 | |
Joachim Strömbergson | 3fb6d66cf3 | |
Joachim Strömbergson | 4c3e210a00 | |
Joachim Strömbergson | e48c0fc7d9 | |
Michael Cardell Widerkrantz | 0590445f3d | |
Joachim Strömbergson | ea9271292c | |
dehanj | 159b5b052b | |
Michael Cardell Widerkrantz | 4d4db70590 | |
Michael Cardell Widerkrantz | f40987b138 | |
Michael Cardell Widerkrantz | c48724e115 | |
dehanj | 1e34ddcfa6 | |
Michael Cardell Widerkrantz | 746d7f0e0d | |
Michael Cardell Widerkrantz | e085d0ebd0 | |
Michael Cardell Widerkrantz | 046343e525 | |
Michael Cardell Widerkrantz | e2bd38c540 | |
dehanj | 9d36acde08 | |
Michael Cardell Widerkrantz | fcccee8ec8 | |
dehanj | d83f235fd3 | |
dehanj | 7019cd9048 | |
dehanj | 2014923966 | |
dehanj | 6d5da25321 | |
dehanj | f83abed4e4 | |
dehanj | 7f2efb68f9 | |
Joachim Strömbergson | bc661536dc | |
dehanj | a453aae031 | |
Michael Cardell Widerkrantz | 5f0a9bec9a | |
Daniel Lublin | 7cd085a17e | |
blaufish | 426b56ebf5 | |
blaufish | cced6aec31 | |
Joachim Strömbergson | 1ab36c7c83 | |
Joachim Strömbergson | 9ee4ce5a23 | |
Joachim Strömbergson | 022bf0bbf9 | |
Joachim Strömbergson | 17ddb1f84a | |
Joachim Strömbergson | 3e75818879 | |
Joachim Strömbergson | 5e34802d1c | |
Joachim Strömbergson | 361381210e | |
Joachim Strömbergson | a76fc19c65 | |
Joachim Strömbergson | a517552c85 | |
Joachim Strömbergson | bc7dfea9c4 | |
Joachim Strömbergson | 4644c79cbd | |
Joachim Strömbergson | 394e437c91 | |
Joachim Strömbergson | 480f4e3d45 | |
Joachim Strömbergson | d70937c11b | |
Joachim Strömbergson | 59af60bdd5 | |
Joachim Strömbergson | dc2903a5b4 | |
Joachim Strömbergson | 16a91bfdd5 | |
Joachim Strömbergson | 1f47991ac2 | |
Joachim Strömbergson | 6d9890d050 | |
Joachim Strömbergson | 49eac9d101 | |
Joachim Strömbergson | 1909833952 | |
Joachim Strömbergson | b1993742bb | |
Joachim Strömbergson | 2fb61bba73 | |
Joachim Strömbergson | cb2fd573b3 | |
Joachim Strömbergson | 61598f57e5 | |
Joachim Strömbergson | 97e3e25d98 | |
Joachim Strömbergson | 704d67c8ab | |
Joachim Strömbergson | 819b93deff | |
Joachim Strömbergson | bbff7576df | |
Joachim Strömbergson | e6eaad87dc | |
Joachim Strömbergson | 4c54b4b60b | |
Joachim Strömbergson | 18bb9b8599 | |
Joachim Strömbergson | 1d2a71ec0c | |
Joachim Strömbergson | 1e97e27e66 | |
Joachim Strömbergson | de7f273f71 | |
Joachim Strömbergson | 526df27bae | |
Joachim Strömbergson | 9d188a2f7f | |
Joachim Strömbergson | 7c9dfaf45a | |
Joachim Strömbergson | c185849ae4 | |
Michael Cardell Widerkrantz | e0e871c730 | |
Daniel Lublin | ea7d64c29f | |
Daniel Lublin | 65e3ea015d | |
Joachim Strömbergson | 3d787886b6 | |
Joachim Strömbergson | 6d0a761e65 | |
Daniel Lublin | 2ddd523c29 | |
Joachim Strömbergson | aac03357e9 | |
dehanj | 8a5d1b3518 | |
Monrad-Aas | 33abc7fcfe | |
Monrad-Aas | a964d3bb89 | |
Daniel Lublin | 47c7e55cba | |
Daniel Lublin | ff71f796e3 | |
Daniel Lublin | 508d044430 | |
Daniel Lublin | fae06116dd | |
Daniel Lublin | 2991dcef68 | |
Daniel Lublin | 9aece67a41 | |
Daniel Lublin | eeed342b96 | |
Daniel Lublin | aa86c9d58c | |
Daniel Lublin | dcc6351f79 | |
Daniel Lublin | bcac8eeaf4 | |
Joachim Strömbergson | 909b95cdaa | |
Joachim Strömbergson | 688910bee4 | |
Michael Cardell Widerkrantz | c126199a41 | |
Michael Cardell Widerkrantz | fae2447344 | |
Daniel Lublin | e3ee7c5bab | |
Michael Cardell Widerkrantz | cefb6ca9c1 | |
Daniel Lublin | 29c5ab1108 |
|
@ -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
|
||||
|
|
|
@ -62,3 +62,4 @@ fp-info-cache
|
|||
*.ses
|
||||
|
||||
__pycache__
|
||||
application_fpga_par.json
|
||||
|
|
|
@ -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
|
||||
|
|
49
README.md
49
README.md
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) .
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. |
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
321924aa3b26507f2a02325750e63c83b306c7831f8e2c87e8d198cecf8cc1c1 application_fpga.bin
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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."
|
||||
|
||||
#===================================================================
|
||||
|
|
|
@ -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.
|
||||
|
||||
---
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
//======================================================================
|
|
@ -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
|
||||
//======================================================================
|
|
@ -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
|
||||
//======================================================================
|
|
@ -0,0 +1,2 @@
|
|||
00010203
|
||||
04050607
|
|
@ -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
|
||||
#===================================================================
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
---
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
//======================================================================
|
|
@ -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
|
||||
//======================================================================
|
|
@ -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
|
||||
#===================================================================
|
|
@ -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).
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
#===================================================================
|
|
@ -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.
|
|
@ -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.
|
|
@ -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
|
||||
|
||||
//======================================================================
|
||||
|
|
|
@ -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
|
||||
//======================================================================
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
#=======================================================================
|
|
@ -1,8 +1,8 @@
|
|||
80808080
|
||||
91919191
|
||||
a2a2a2a2
|
||||
b3b3b3b3
|
||||
c4c4c4c4
|
||||
d5d5d5d5
|
||||
e6e6e6e6
|
||||
f7f7f7f7
|
||||
80818283
|
||||
94959697
|
||||
a0a1a2a3
|
||||
b4b5b6b7
|
||||
c0c1c2c3
|
||||
d4d5d6d7
|
||||
e0e1e2e3
|
||||
f4f5f6f7
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
06d0aafcc763307420380a8c5a324f3fccfbba6af7ff6fe0facad684ebd69dd43234c8531a096c77c2dc3543f8b8b629c94136ca7e257ca560da882e4dbbb025 firmware.bin
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,5 +18,4 @@
|
|||
// clang-format on
|
||||
|
||||
void set_led(uint32_t led_value);
|
||||
void forever_redflash();
|
||||
#endif
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 DATA1,Return 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
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -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
|
@ -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": {
|
||||
|
|
|
@ -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.
|
@ -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&DocNm=6-1773460-8_Spring_Fingers&DocType=Data+Sheet&DocLang=English&PartCntxt=1674954-1&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&DocNm=6-1773460-8_Spring_Fingers&DocType=Data+Sheet&DocLang=English&PartCntxt=1674954-1&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&DocNm=6-1773460-8_Spring_Fingers&DocType=Data+Sheet&DocLang=English&PartCntxt=1674954-1&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.
|
@ -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.
|
Loading…
Reference in New Issue