diff --git a/.github/autolabeler.yml b/.github/autolabeler.yml new file mode 100644 index 00000000..2391bac4 --- /dev/null +++ b/.github/autolabeler.yml @@ -0,0 +1,43 @@ +board-arty: ["targets/arty", "platforms/arty.py"] +board-atlys: ["targets/atlys", "platforms/atlys.py"] +board-basys3: ["targets/basys3", "platforms/basys3.py"] +board-cmod_a7: ["targets/cmod_a7", "platforms/cmod_a7.py"] +board-galatea: ["targets/galatea", "platforms/galatea.py"] +board-mimasv2: ["targets/mimasv2", "platforms/mimasv2.py"] +board-minispartan6: ["targets/minispartan6", "platforms/minispartan6.py"] +board-neso: ["targets/neso", "platforms/neso.py"] +board-netv2: ["targets/netv2", "platforms/netv2.py"] +board-nexys-video: ["targets/nexys-video", "platforms/nexys-video.py"] +board-opsis: ["targets/opsis", "platforms/opsis.py", "platforms/tofe_*.py"] +board-pipistrello: ["targets/pipistrello", "platforms/pipistrello.py"] +board-saturn: ["targets/saturn", "platforms/saturn.py"] +board-sim: ["targets/sim", "platforms/sim.py"] +board-waxwing: ["targets/waxwing", "platforms/waxwing.py"] +boards-all: ["targets/common/"] +boards-artix7: [ + "targets/arty", "platforms/arty.py", + "targets/basys3", "platforms/basys3.py", + "targets/cmod_a7", "platforms/cmod_a7.py", + "targets/neso", "platforms/neso.py", + "targets/netv2", "platforms/netv2.py", + "targets/nexys-video", "platforms/nexys-video.py" + ] +boards-spartan6: [ + "targets/atlys", "platforms/atlys.py", + "targets/galatea", "platforms/galatea.py", + "targets/mimasv2", "platforms/mimasv2.py", + "targets/minispartan6", "platforms/minispartan6.py", + "targets/opsis", "platforms/opsis.py", + "targets/pipstrello", "platforms/pipstrello.py", + "targets/saturn", "platforms/saturn.py", + "targets/waxwing", "platforms/waxwing.py" + ] +firmware-fpga: ["gateware/"] +firmware-softcpu: ["firmware/"] +hdmi2ethernet: ["targets/*/net.py", "targets/*/hdmi2eth.py", "firmware/uip/", "third_party/libuip/"] +hdmi2usb: ["targets/*/hdmi2usb.py", "gateware/encoder/"] +hdmi2***: ["targets/*/base.py"] +level-docs: ["docs/", "README.md", "*.md"] +level-firmware: ["gateware/", "firmware/"] +level-infrastructure: [".travis.yml", ".travis/", "scripts/", ".github/"] +level-software: ["software/"] diff --git a/.gitignore b/.gitignore index 6260aefc..360dc485 100644 --- a/.gitignore +++ b/.gitignore @@ -2,9 +2,12 @@ __pycache__ *.pyc *.egg-info *.vcd +firmware/hdmi_in[1-9].[ch] outgoing build *~ *.png third_party/qemu-litex third_party/micropython +third_party/linux +third_party/litex-devicetree diff --git a/.gitmodules b/.gitmodules index 856c0dc9..47e8b3b6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -31,3 +31,6 @@ [submodule "third_party/libmodem"] path = third_party/libmodem url = https://github.com/cr1901/libmodem +[submodule "third_party/migen"] + path = third_party/migen + url = https://github.com/m-labs/migen.git diff --git a/.travis.yml b/.travis.yml index cac740f1..0363f0c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ compiler: sudo: false addons: apt: + update: true packages: - build-essential - fxload @@ -26,6 +27,10 @@ env: global: - HDMI2USB_UDEV_IGNORE=1 - CLEAN_CHECK=1 + - PREBUILT_DIR="/tmp/HDMI2USB-firmware-prebuilt" + # Travis reports incorrect the hosts number of processors, override to 2 + # cores. + - JOBS=2 before_install: - wget https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip -O /tmp/ninja.zip @@ -34,14 +39,18 @@ before_install: - pip3 install --user meson install: - - export CPU="$C" - - export PLATFORMS="$P" - - export TARGETS="$T" + - export CPUS="$C" && echo "CPUS='$CPUS'" + - export PLATFORMS="$P" && echo "PLATFORMS='$PLATFORMS'" + - export TARGETS="$T" && echo "TARGETS='$TARGETS'" + - export FIRMWARE="$F" && echo "FIRMWARE='$FIRMWARE'" - $PWD/.travis/setup.sh script: - $PWD/.travis/build.sh +after_success: + - $PWD/.travis/update-prebuilt-list.sh + notifications: email: - hdmi2usb-spam@googlegroups.com @@ -85,6 +94,24 @@ jobs: - stage: Targets - Base env: C=lm32 P=pipistrello T="base" + - stage: Targets - Base + env: C=lm32 P=saturn T="base" + + - stage: Targets - Base + env: C=lm32 P=galatea T="base" + + - stage: Targets - Base + env: C=lm32 P=neso T="base" + + - stage: Targets - Base + env: C=lm32 P=waxwing T="base" + + - stage: Targets - Base + env: C=lm32 P=basys3 T="base" + + - stage: Targets - Base + env: C=lm32 P=cmod_a7 T="base" + # or1k base targets - stage: Targets - Base env: C=or1k P=arty T="base net" @@ -101,14 +128,19 @@ jobs: - stage: Targets - Base env: C=or1k P=pipistrello T="base" + # Linux Targets + #-------------------------------------------- + - stage: Targets - Base + env: C=or1k.linux F=linux P=arty T="net" + #-------------------------------------------- # Video Targets #-------------------------------------------- - stage: Targets - Video env: C=lm32 P=atlys T="video" - - stage: Targets - Video - env: C=lm32 P=netv2 T="video" + #- stage: Targets - Video + # env: C=lm32 P=netv2 T="video" - stage: Targets - Video env: C=lm32 P=nexys_video T="video" diff --git a/.travis/add-local-submodule.sh b/.travis/add-local-submodule.sh index d74772e0..906057ee 100755 --- a/.travis/add-local-submodule.sh +++ b/.travis/add-local-submodule.sh @@ -17,7 +17,7 @@ USER_SLUG="$1" SUBMODULE="$2" REV=$(git rev-parse HEAD) -echo "Submodule $SUBMODULE @ $REV" +echo "Submodule $SUBMODULE" # Get the pull request info REQUEST_USER="$(echo $USER_SLUG | perl -pe 's|^([^/]*)/.*|\1|')" @@ -27,16 +27,16 @@ echo "Request user is '$REQUEST_USER'". echo "Request repo is '$REQUEST_REPO'". # Get current origin from git -ORIGIN="$(git config -f .gitmodules submodule.$SUBMODULE.url)" -#ORIGIN="$(git remote get-url origin)" -if echo $ORIGIN | grep -q "github.com"; then +ORIGIN_URL="$(git config -f .gitmodules submodule.$SUBMODULE.url)" +#ORIGIN_URL="$(git remote get-url origin)" +if echo $ORIGIN_URL | grep -q "github.com"; then echo "Found github" else echo "Did not find github, skipping" exit 0 fi -ORIGIN_SLUG=$(echo $ORIGIN | perl -pe 's|.*github.com/(.*?)(.git)?$|\1|') +ORIGIN_SLUG=$(echo $ORIGIN_URL | perl -pe 's|.*github.com/(.*?)(.git)?$|\1|') echo "Origin slug is '$ORIGIN_SLUG'" ORIGIN_USER="$(echo $ORIGIN_SLUG | perl -pe 's|^([^/]*)/.*|\1|')" @@ -47,26 +47,36 @@ echo "Origin repo is '$ORIGIN_REPO'" USER_URL="git://github.com/$REQUEST_USER/$ORIGIN_REPO.git" -echo "Users repo would be '$USER_URL'" +# Check if the user's repo exists +echo -n "User's repo would be '$USER_URL' " +if git ls-remote --exit-code --heads "$USER_URL" > /dev/null 2>&1; then + echo "which exists!" +else + echo "which does *not* exist!" + USER_URL="$ORIGIN_URL" +fi +# If submodule doesn't exist, clone directly from the users repo if [ ! -e $SUBMODULE/.git ]; then - echo "Successfully cloned from user repo '$USER_URL'" - $(which git) clone $USER_URL $SUBMODULE --origin user || true - if [ -d $SUBMODULE/.git ]; then - echo "Successfully cloned from user repo '$ORIGIN_REPO'" - fi -fi -if [ -e $SUBMODULE/.git ]; then - ( - cd $SUBMODULE - git remote add user $USER_URL || git remote set-url user $USER_URL - $(which git) fetch user || git remote rm user - - git remote add origin $ORIGIN || git remote set-url origin $ORIGIN - $(which git) fetch origin - ) + echo "Cloning '$ORIGIN_REPO' from repo '$USER_URL'" + git clone $USER_URL $SUBMODULE --origin user fi +# If the submodule does exist, add a new remote. +( + cd $SUBMODULE + + git remote rm user >/dev/null 2>&1 || true + if [ "$USER_URL" != "$ORIGIN_URL" ]; then + git remote add user $USER_URL + git fetch user + fi + + git remote rm origin >/dev/null 2>&1 || true + git remote add origin $ORIGIN_URL + git fetch origin +) +# Checkout the submodule at the right revision git submodule update --init $SUBMODULE # Call ourselves recursively. diff --git a/.travis/build.sh b/.travis/build.sh index 74e072e8..043beb6d 100755 --- a/.travis/build.sh +++ b/.travis/build.sh @@ -1,19 +1,5 @@ #!/bin/bash -if [ -z "$PLATFORMS" ]; then - if [ -z "$SKIP_PLATFORMS" ]; then - SKIP_PLATFORMS="sim" - fi - if [ -z "$PLATFORM" ]; then - PLATFORMS=$(ls targets/ | grep -v ".py" | grep -v "common" | grep -v "$SKIP_PLATFORMS" | sed -e"s+targets/++") - else - PLATFORMS="$PLATFORM" - fi -fi -echo "Running with PLATFORMS='$PLATFORMS'" - -source scripts/enter-env.sh || exit 1 - # How long to wait for "make gateware" to finish. # Normal LiteX targets should take no longer than 20ish minutes on a modern # machine. We round up to 40mins. @@ -25,31 +11,62 @@ elif [ -x /usr/bin/timelimit ]; then export GATEWARE_TIMEOUT_CMD="/usr/bin/timelimit -T $GATEWARE_KILLOUT -t $GATEWARE_TIMEOUT" fi -ls -l $XILINX_DIR/opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64/xreport -if [ -f $XILINX_DIR/opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64/xreport ]; then - HAVE_XILINX_ISE=1 -else - HAVE_XILINX_ISE=0 -fi +# Check for the Xilinx toolchain being downloaded +export XILINX_LOCAL_USER_DATA=no + +GIT_REVISION=$TRAVIS_BRANCH/$(git describe) +ORIG_COMMITTER_NAME=$(git log -1 --pretty=%an) +ORIG_COMMITTER_EMAIL=$(git log -1 --pretty=%ae) set +x set -e +function filelist() { + find | sort | grep -v "__pycache__" | grep -v "conda" | grep -v third_party +} + function build() { - export PLATFORM=$1 + export FULL_PLATFORM=$1 export TARGET=$2 - export CPU=$3 + export FULL_CPU=$3 + + if [ x"$4" != x"" ]; then + FIRMWARE=$4 + else + unset $FIRMWARE + fi + export FIRMWARE - if [ -z "$PLATFORM" -o -z "$TARGET" -o -z "$CPU" ]; then - echo "usage: build PLATFORM TARGET CPU" - echo " got: build '$PLATFORM' '$TARGET' '$CPU'" + if [ -z "$FULL_PLATFORM" -o -z "$TARGET" -o -z "$FULL_CPU" ]; then + echo "usage: build FULL_PLATFORM TARGET FULL_CPU FIRMWARE" + echo " got: build '$FULL_PLATFORM' '$TARGET' '$FULL_CPU' '$FIRMWARE'" return 1 fi + ( + # Imports TARGET, PLATFORM, CPU and TARGET_BUILD_DIR from Makefile + source scripts/enter-env.sh || exit 1 + echo "" + echo "" + echo "" + echo "- make info" + echo "---------------------------------------------" + make info + echo "=============================================" + + echo "" + echo "" + echo "" + echo "- make clean" + echo "---------------------------------------------" + make clean + echo "=============================================" + # Create "clean" file list before build - find | sort | grep -v "__pycache__" > /tmp/filelist.before + filelist > /tmp/filelist.before + + TITLE="$FULL_PLATFORM $TARGET $FULL_CPU $FIRMWARE" - export TARGET_BUILD_DIR=$PWD/build/${PLATFORM}_${TARGET}_${CPU} export LOGFILE=$TARGET_BUILD_DIR/output.$(date +%Y%m%d-%H%M%S).log echo "Using logfile $LOGFILE" echo "" @@ -64,11 +81,11 @@ function build() { echo "" echo "" echo "=============================================" - echo "- $PLATFORM $TARGET $CPU" + echo "- $TITLE" echo "=============================================" # Output the commands available to make it easier to debug. echo "" - echo "- make help ($PLATFORM $TARGET $CPU)" + echo "- make help ($TITLE)" echo "---------------------------------------------" make help echo "=============================================" @@ -76,9 +93,9 @@ function build() { echo "" echo "" echo "" - echo "- make test ($PLATFORM $TARGET $CPU)" + echo "- make test ($TITLE)" echo "---------------------------------------------" - make test || return 1 + make test || exit 1 echo "=============================================" # We build the firmware first as it is very quick to build and @@ -87,9 +104,9 @@ function build() { echo "" echo "" echo "" - echo "- make firmware ($PLATFORM $TARGET $CPU) (prerun)" + echo "- make firmware check ($TITLE)" echo "---------------------------------------------" - make -j4 firmware || return 1 + make FIRMWARE=firmware firmware || exit 1 echo "- Firmware version data" echo "---------------------------------------------" VERSION_DATA="$(find $TARGET_BUILD_DIR -name version_data.c)" @@ -100,12 +117,12 @@ function build() { if grep -q -- "??" $VERSION_DATA; then echo "Repository had unknown files, failing to build!" -# return 1 + exit 1 fi if grep -q -- "-dirty" $VERSION_DATA; then echo "Repository was dirty, failing to build!" -# return 1 + exit 1 fi fi echo "=============================================" @@ -117,7 +134,7 @@ function build() { echo "" echo "" echo "" - echo "- make firmware-clean ($PLATFORM $TARGET $CPU) (prerun)" + echo "- make firmware-clean ($TITLE) (prerun)" echo "---------------------------------------------" make firmware-clean echo "=============================================" @@ -125,9 +142,9 @@ function build() { echo "" echo "" echo "" - echo "- make gateware ($PLATFORM $TARGET $CPU)" + echo "- make gateware ($TITLE)" echo "---------------------------------------------" - if [ $HAVE_XILINX_ISE -eq 0 ]; then + if [ $HAVE_XILINX_TOOLCHAIN -eq 0 ]; then echo "Skipping gateware" make gateware-fake else @@ -136,24 +153,46 @@ function build() { # FIXME: Should this be in the Makefile instead? echo "Using $GATEWARE_TIMEOUT timeout (with '$GATEWARE_TIMEOUT_CMD')." export FILTER=$PWD/.travis/run-make-gateware-filter.py - $GATEWARE_TIMEOUT_CMD time --verbose make gateware || return 1 + $GATEWARE_TIMEOUT_CMD time --verbose make gateware || exit 1 fi echo "=============================================" - echo "" - echo "" - echo "" - echo "- make firmware ($PLATFORM $TARGET $CPU)" - echo "---------------------------------------------" - make -j4 firmware || return 1 - echo "=============================================" + case "$FIRMWARE" in + linux) + echo "" + echo "" + echo "" + echo "- make firmware ($TITLE - $FIRMWARE)" + echo "---------------------------------------------" + ./scripts/build-linux.sh || exit 1 + echo "=============================================" + ;; + micropython) + echo "" + echo "" + echo "" + echo "- make firmware ($TITLE - $FIRMWARE)" + echo "---------------------------------------------" + ./scripts/build-micropython.sh || exit 1 + echo "=============================================" + ;; + *) + echo "" + echo "" + echo "" + echo "- make firmware ($TITLE - $FIRMWARE)" + echo "---------------------------------------------" + make firmware || exit 1 + echo "=============================================" + ;; + esac echo "" echo "" echo "" - echo "- make image ($PLATFORM $TARGET $CPU)" + echo "- make image ($TITLE)" echo "---------------------------------------------" - make image || true + make image echo "=============================================" if [ ! -z "$PROGS" ]; then @@ -161,7 +200,7 @@ function build() { echo "" echo "" echo "" - echo "- make load ($PROG $PLATFORM $TARGET $CPU)" + echo "- make load ($PROG $TITLE)" echo "---------------------------------------------" # Allow the programming to fail. PROG=$PROG make load || true @@ -170,17 +209,17 @@ function build() { # Save the resulting binaries into the prebuilt repo. The gateware # should always exist, but others might not. - if [ ! -z "$PREBUILT_DIR" ]; then - COPY_DEST="$PREBUILT_DIR/archive/$GIT_REVISION/$PLATFORM/$TARGET/$CPU/" + if [ -d "$PREBUILT_DIR" ]; then echo "" echo "" echo "" - echo "- Adding built files to github.com/$PREBUILT_REPO_OWNER/$PREBUILT_REPO" + echo "- Adding built files to $(cd $COPY_DEST; svn info | grep "Repository Root:")" echo "---------------------------------------------" - mkdir -p $COPY_DEST + COPY_DEST="$PREBUILT_DIR/archive/$GIT_REVISION/$FULL_PLATFORM/$TARGET/$FULL_CPU/" + + svn mkdir --parents $COPY_DEST - declare -a SAVE declare -a SAVE SAVE+="image*.bin" # Combined binary include gateware+bios+firmware # Gateware output for using @@ -215,6 +254,8 @@ function build() { cp $TARGET_BUILD_DIR/software/firmware/version_data.c $COPY_DEST/logs/version_data.c cp $TARGET_BUILD_DIR/output.*.log $COPY_DEST/logs/ + find $COPY_DEST -empty -delete + ( cd $COPY_DEST sha256sum $(find -type f) > sha256sum.txt @@ -226,14 +267,26 @@ function build() { export GIT_COMMITTER_NAME="TimVideos Robot" echo "" ( + cd $COPY_DEST + echo $PWD + ls -l -a . + svn add --parents * + ) + ( cd $PREBUILT_DIR - git add -A . - git commit -a \ - -m "Travis build #$TRAVIS_BUILD_NUMBER of $GIT_REVISION for PLATFORM=$PLATFORM TARGET=$TARGET CPU=$CPU" \ - -m "" \ - -m "From https://github.com/$TRAVIS_REPO_SLUG/tree/$TRAVIS_COMMIT" \ - -m "$TRAVIS_COMIT_MESSAGE" - git diff HEAD~1 --stat=1000,1000 + echo $PWD + COMMIT_MSG=$(tempfile -s .msg) + cat > $COMMIT_MSG < /tmp/filelist.after + filelist > /tmp/filelist.after echo "" echo "" echo "" @@ -271,183 +324,14 @@ function build() { echo "=============================================" cat /tmp/filelist.diff echo "=============================================" - return 1 + exit 1 fi fi - return 0 + ); return $? } -declare -a SUCCESSES -declare -a FAILURES - - -# Clone prebuilt repo to copy results into -if [ ! -z "$TRAVIS_PULL_REQUEST" -a "$TRAVIS_PULL_REQUEST" != "false" ]; then - # Don't do prebuilt for a pull request. - echo "" - echo "" - echo "" - echo "- Pull request, so no prebuilt pushing." -elif [ -z "$GH_TOKEN" ]; then - # Only if run by travis display error - if [ ! -z $TRAVIS_BUILD_NUMBER ]; then - echo "" - echo "" - echo "" - echo "- No Github token so unable to copy built files" - fi -elif [ -z "$TRAVIS_BRANCH" ]; then - echo "" - echo "" - echo "" - echo "- No branch name, unable to copy built files" -else - # Look at repo we are running in to determine where to try pushing to if in a fork - PREBUILT_REPO=HDMI2USB-firmware-prebuilt - PREBUILT_REPO_OWNER=$(echo $TRAVIS_REPO_SLUG|awk -F'/' '{print $1}') - GIT_REVISION=$TRAVIS_BRANCH/$(git describe) - ORIG_COMMITTER_NAME=$(git log -1 --pretty=%an) - ORIG_COMMITTER_EMAIL=$(git log -1 --pretty=%ae) - echo "" - echo "" - echo "" - echo "- Uploading built files to github.com/$PREBUILT_REPO_OWNER/$PREBUILT_REPO" - echo "---------------------------------------------" - export PREBUILT_DIR="/tmp/HDMI2USB-firmware-prebuilt" - ( - # Do a sparse, shallow checkout to keep disk space usage down. - mkdir -p $PREBUILT_DIR - cd $PREBUILT_DIR - git init > /dev/null - git config core.sparseCheckout true - git remote add origin https://$GH_TOKEN@github.com/$PREBUILT_REPO_OWNER/${PREBUILT_REPO}.git - cat > .git/info/sparse-checkout < /dev/null 2>&1 ; then - echo "Push success!" - else - echo "Push failed :-(" - fi - done - echo - echo "Push finished!" - ) -fi +export FUNC=build +. .travis/run.inc.sh echo "" echo "" diff --git a/.travis/copy-files.py b/.travis/copy-files.py new file mode 100755 index 00000000..a209b752 --- /dev/null +++ b/.travis/copy-files.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 + +import os.path +import shutil +import sys + +d = sys.argv[1] +assert d, d + +for l in sys.stdin.readlines(): + src = l.strip() + assert src, src + assert src.startswith('/'), src + out = os.path.join(d, src[1:]) + outdir = os.path.dirname(out) + src = src.replace('/opt/Xilinx/', '/opt/Xilinx.real/') + if not os.path.exists(outdir): + os.makedirs(outdir) + print("New pdir {}".format(outdir)) + + if os.path.isdir(src): + os.makedirs(out, exist_ok=False) + shutil.copystat(src, out) + print("New dir {}".format(out)) + else: + shutil.copy2(src, out, follow_symlinks=False) + print("New file {} -> {}".format(src, out)) diff --git a/.travis/download-prebuilt.sh b/.travis/download-prebuilt.sh new file mode 100755 index 00000000..73a3d4a9 --- /dev/null +++ b/.travis/download-prebuilt.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +# Script to clone prebuilt repo to copy results into. + +if [ ! -z "$TRAVIS" -a "$TRAVIS" = "true" ]; then + # Don't clone prebuilt on a pull request. + if [ ! -z "$TRAVIS_PULL_REQUEST" -a "$TRAVIS_PULL_REQUEST" != "false" ]; then + echo "" + echo "" + echo "" + echo "- Pull request, so no prebuilt pushing." + + # Don't clone if no github authentication + elif [ -z "$GH_TOKEN" ]; then + echo "" + echo "" + echo "" + echo "- No Github token (GH_TOKEN) so unable to push built files" + + # Don't clone if we don't know which branch we are on + elif [ -z "$TRAVIS_BRANCH" ]; then + echo "" + echo "" + echo "" + echo "- No branch name (\$TRAVIS_BRANCH), unable to copy built files" + + # Don't clone if we don't know which repo we are using + elif [ -z "$TRAVIS_REPO_SLUG" ]; then + echo "" + echo "" + echo "" + echo "- No repo slug name (\$TRAVIS_REPO_SLUG), unable to copy built files" + + else + # Look at repo we are running in to determine where to try pushing to if in a fork + PREBUILT_REPO=HDMI2USB-firmware-prebuilt + PREBUILT_REPO_OWNER=$(echo $TRAVIS_REPO_SLUG|awk -F'/' '{print $1}') + fi +fi + + +if [ -z "$PREBUILT_DIR" ]; then + echo "" + echo "" + echo "" + echo "- No PREBUILT_DIR value found." + +elif [ -z "$PREBUILT_REPO" ]; then + echo "" + echo "" + echo "" + echo "- No PREBUILT_REPO value found." + +elif [ -z "$PREBUILT_REPO_OWNER" ]; then + echo "" + echo "" + echo "" + echo "- No PREBUILT_REPO_OWNER value found." + +else + echo "" + echo "" + echo "" + echo "- Download built files from github.com/$PREBUILT_REPO_OWNER/$PREBUILT_REPO (to upload results)" + echo "---------------------------------------------" + ( + # Do a sparse, shallow checkout to keep disk space usage down. + #mkdir -p $PREBUILT_DIR + svn co --depth immediates https://github.com/$PREBUILT_REPO_OWNER/$PREBUILT_REPO/trunk/ $PREBUILT_DIR + cd $PREBUILT_DIR + SVN_REVISION=$(svnversion | sed -e's/P$//') + + for I in *; do + if [ "$I" == "archive" ]; then + continue + fi + svn update -r$SVN_REVISION --set-depth infinity $I + done + svn update -r$SVN_REVISION --set-depth immediates archive/$TRAVIS_BRANCH/ + echo "" + PREBUILT_DIR_DU=$(du -h -s . | sed -e's/[ \t]*\.$//') + echo "Prebuilt repo checkout is using $PREBUILT_DIR_DU" + ls -l $PWD + ls -l $PREBUILT_DIR/archive + ) + echo "=============================================" +fi diff --git a/.travis/fixup-git.sh b/.travis/fixup-git.sh new file mode 100755 index 00000000..efa91a23 --- /dev/null +++ b/.travis/fixup-git.sh @@ -0,0 +1,131 @@ +#!/bin/bash + +set -e + +# Disable prompting for passwords - works with git version 2.3 or above +export GIT_TERMINAL_PROMPT=0 +# Harder core version of disabling the username/password prompt. +GIT_CREDENTIAL_HELPER=$PWD/.git/git-credential-stop +cat > $GIT_CREDENTIAL_HELPER < $TRAVIS_COMMIT)" + echo "---------------------------------------------" + git log -n 5 --graph + echo "---------------------------------------------" + git fetch origin $TRAVIS_COMMIT + git branch -v + echo "---------------------------------------------" + git log -n 5 --graph + echo "---------------------------------------------" + git branch -D $TRAVIS_BRANCH || true + git checkout $TRAVIS_COMMIT -b $TRAVIS_BRANCH + git branch -v +fi +echo "" +echo "" +echo "" +echo "Git Revision" +echo "---------------------------------------------" +git status +echo "---------------------------------------------" +git describe +echo "=============================================" +GIT_REVISION=$(git describe) + +echo "" +echo "" +echo "" +echo "- Disk space free (after fixing git)" +echo "---------------------------------------------" +df -h +echo "" +DF_AFTER_GIT="$(($(stat -f --format="%a*%S" .)))" +awk "BEGIN {printf \"Git is using %.2f megabytes\n\",($DF_BEFORE_GIT-$DF_AFTER_GIT)/1024/1024}" diff --git a/.travis/generate-prebuilt-list.py b/.travis/generate-prebuilt-list.py new file mode 100755 index 00000000..0eeb23c2 --- /dev/null +++ b/.travis/generate-prebuilt-list.py @@ -0,0 +1,259 @@ +#!/usr/bin/env python3 + +import argparse +import csv +import os +import pprint +import sys +import tempfile +import urllib.request + +import subprocess + +slug = os.getenv("TRAVIS_REPO_SLUG", None) +prebuilt_repo_name = 'HDMI2USB-firmware-prebuilt' +if slug: + prebuilt_repo_owner = slug.split('/',1)[0] +else: + prebuilt_repo_owner = None + +parser = argparse.ArgumentParser( + description="""\ +Update the index files in the prebuilt repo.""") +parser.add_argument( + '--repo', default=prebuilt_repo_name) +parser.add_argument( + '--owner', default=prebuilt_repo_owner) +parser.add_argument( + '--branch', default=os.getenv('TRAVIS_BRANCH', None)) +parser.add_argument( + '--full-platform', default=os.getenv('FULL_PLATFORM', None)) +parser.add_argument( + '--target', default=os.getenv('TARGET', None)) +parser.add_argument( + '--full-cpu', default=os.getenv('FULL_CPU', None)) +parser.add_argument( + '--firmware', default=os.getenv('FIRMWARE', None)) +parser.add_argument( + '--gh-user', default=os.getenv('GH_USER', None)) +parser.add_argument( + '--gh-token', default=os.getenv('GH_TOKEN', None)) +parser.add_argument( + '--outdir', default=os.getenv('OUTDIR', None)) +args = parser.parse_args() + +assert args.repo +assert args.owner +assert args.branch == "master" + +assert args.gh_user +assert args.gh_token + +assert args.full_platform +assert args.target +assert args.full_cpu + +svn_base_url = "https://github.com/{}/{}/trunk/archive/{}".format( + args.owner, args.repo, args.branch) +pre_base_url = "https://github.com/{}/{}/branches/gh-pages".format( + args.owner, args.repo, args.branch) + +git_dir_url = "https://github.com/{}/{}/blob/master/archive/{}".format( + args.owner, args.repo, args.branch) +git_file_url = "https://github.com/{}/{}/blob/master/archive/{}".format( + args.owner, args.repo, args.branch) + +svn_args = '--non-interactive --username {} --password {}'.format( + args.gh_user, args.gh_token) + +print() +print("Looking at cpu '{}' in target '{}' for platform '{}' from '{}/{}'".format( + args.full_cpu, args.target, args.full_platform, args.owner, args.repo)) +print() +print("-"*75) +print() + +revs_data = subprocess.check_output( + "svn list {} {}".format(svn_args, svn_base_url).split()).decode('utf-8') + +revs = [v[:-1] for v in revs_data.splitlines()] +def parse_version(v): + if "-" not in v: + return v,0,'' + a,b,c = v.split('-') + return a,int(b),c +revs.sort(key=parse_version) + +def get_channel_spreadsheet(): + data = urllib.request.urlopen( + "https://docs.google.com/spreadsheets/d/e/2PACX-1vTmqEM-XXPW4oHrJMD7QrCeKOiq1CPng9skQravspmEmaCt04Kz4lTlQLFTyQyJhcjqzCc--eO2f11x/pub?output=csv" + ).read().decode('utf-8') + + rev_names = {} + for i in csv.reader(data.splitlines(), dialect='excel'): + if not i: + continue + if i[0] != "GitHub": + continue + + _, _, rev, name, conf, *_ = i + if not name: + continue + assert name not in rev_names, "{} is listed multiple times!".format( + name) + rev_names[name] = rev + + return rev_names + +_get_sha256sum_cache = {} +def get_sha256sum(rev, full_platform, target, full_cpu, svn_args=svn_args, svn_base_url=svn_base_url): + global _get_sha256sum_cache + full_path = "{rev}/{full_platform}/{target}/{full_cpu}/".format( + rev=rev, + full_platform=full_platform, + target=target, + full_cpu=full_cpu, + ) + try: + return _get_sha256sum_cache[full_path] + except KeyError: + try: + data = subprocess.check_output( + "svn cat {svn_args} {svn_base_url}/{full_path}/sha256sum.txt".format( + svn_args=svn_args, + svn_base_url=svn_base_url, + full_path=full_path, + ).split(), + stderr=subprocess.STDOUT, + ).decode('utf-8') + data = data.replace("./", "{}/{}".format(git_file_url, full_path)) + except subprocess.CalledProcessError: + print(" - Did not find {full_platform}/{target}/{full_cpu} at {rev}".format( + rev=rev, + full_platform=full_platform, + target=target, + full_cpu=full_cpu, + )) + data = None + _get_sha256sum_cache[full_path] = data + return data + +channels = {} + +# Find the unstable revision +print("Found {} revisions, 10 latest:\n * ".format(len(revs)), end="") +print("\n * ".join(reversed(revs[-10:]))) +urevs = list(revs) +while True: + rev = urevs.pop(-1) + if not get_sha256sum(rev, args.full_platform, args.target, args.full_cpu): + continue + channels['unstable'] = rev + break +print() + +# Get the stable/testing revisions +print("Getting other channels..") +channels.update(get_channel_spreadsheet()) + +# Get the sha254 files for each channel +output = {} +for channel, rev in sorted(channels.items()): + output[channel] = get_sha256sum( + rev, args.full_platform, args.target, args.full_cpu) +print() + +for channel, rev in sorted(channels.items()): + if not output[channel]: + rev = "unknown" + print("Channel {:10s} is at rev {}".format(channel, rev)) +print() + +# Download the gh-pages branch of the HDMI2USB-firmware-prebuilt repo +if args.outdir is None: + tmpdir = tempfile.mkdtemp() +else: + tmpdir = args.outdir + +os.makedirs(tmpdir, exist_ok=True) +print("Using {}".format(tmpdir)) +print() + +os.chdir(tmpdir) +print("Download github pages repo...") +if not os.path.exists("gh-pages"): + subprocess.check_call( + "svn checkout {} -q {}".format(svn_args, pre_base_url).split()) +print("Done.") +print("") +os.chdir("gh-pages") + +with open("revs.txt", "w") as f: + for rev in revs: + f.write("{}\n".format(rev)) + +out_dir = os.path.join(args.full_platform, args.target, args.full_cpu) +os.makedirs(out_dir, exist_ok=True) + +with open(os.path.join(out_dir, "channels.txt"), "w") as f: + for channel, rev in sorted(channels.items()): + gh_url = "{git_base_url}/{rev}/{full_platform}/{target}/{full_cpu}/".format( + git_base_url=git_dir_url, + rev=rev, + full_platform=args.full_platform, + target=args.target, + full_cpu=args.full_cpu) + f.write("{} {} {}\n".format(channel, rev, gh_url)) + +for channel, lines in sorted(output.items()): + if not lines: + continue + with open(os.path.join(out_dir, "{}.sha256sum".format(channel)), "w") as f: + f.write("".join(lines)) + +all_files = [] +for root, dirs, files in os.walk('.'): + skip_dirs = [] + for d in dirs: + if d.startswith('.'): + skip_dirs.append(d) + for d in skip_dirs: + dirs.remove(d) + for f in files: + if f == 'index.txt': + continue + all_files.append(os.path.join(root, f)) + +all_files.sort() + +with open('index.txt', 'w') as f: + subprocess.check_call(["sha256sum"]+all_files, stdout=f) + +print("Adding files...") +subprocess.check_call(["svn", "add", "--parents", "--force"]+all_files) +subprocess.check_call(["svn", "add", "--parents", "--force", "index.txt"]) +print() + +print("Current status...") +changes = subprocess.check_output("svn status -u --depth infinity".split(), stderr=subprocess.STDOUT).decode('utf-8') +print(changes) +subprocess.check_call("svn diff .".split(), stderr=subprocess.STDOUT) +print() + +if len(changes.splitlines()) == 1: + print("No changes to commit...") + print() +else: + print() + print("Committing changes...") + + with tempfile.NamedTemporaryFile() as f: + f.write("Updating channels (in Travis build {})\n".format(os.getenv("TRAVIS_BUILD_NUMBER", "None")).encode('utf-8')) + f.flush() + + subprocess.check_call("svn commit {} --file {}".format(svn_args, f.name).split()) + +print() +print("-"*75) +print("Done..") +print() diff --git a/.travis/package-xilinx-step2-create-tar.sh b/.travis/package-xilinx-step2-create-tar.sh index ecba0d6e..f4426a1c 100755 --- a/.travis/package-xilinx-step2-create-tar.sh +++ b/.travis/package-xilinx-step2-create-tar.sh @@ -31,20 +31,23 @@ if [ ! -f $STRACE_LOG ]; then fi STRACE_FILES=$BASE/strace.files.log -#cat $STRACE_LOG | python $SETUP_DIR/package-xilinx-filter-strace.py $PREFIX > $STRACE_FILES -$SETUP_DIR/package-xilinx-cluefs-filter.py $STRACE_LOG > $STRACE_FILES +if [ ! -f $STRACE_LOG ]; then + #cat $STRACE_LOG | python $SETUP_DIR/package-xilinx-filter-strace.py $PREFIX > $STRACE_FILES + $SETUP_DIR/package-xilinx-cluefs-filter.py $STRACE_LOG > $STRACE_FILES +fi XILINX_DIR=$BASE/xilinx-stripped if [ -d $XILINX_DIR ]; then - rm -rf $XILINX_DIR + rm -rf $XILINX_DIR fi echo "" echo "Creating directories" echo "--------------------------------------" mkdir -p $XILINX_DIR -cat $STRACE_FILES | xargs -d '\n' \ - cp -v --parents --no-dereference --preserve=all -t $XILINX_DIR || true +#cat $STRACE_FILES | xargs -d '\n' \ +# cp -v --parents --no-dereference --preserve=all -t $XILINX_DIR || true +cat $STRACE_FILES | $TOP_DIR/.travis/copy-files.py $XILINX_DIR echo "--------------------------------------" FILENAME="$BASE/xilinx-tools-$(git describe).tar.bz2" diff --git a/.travis/package-xilinx-step3-upload.sh b/.travis/package-xilinx-step3-upload.sh index 6950719c..aece070f 100755 --- a/.travis/package-xilinx-step3-upload.sh +++ b/.travis/package-xilinx-step3-upload.sh @@ -27,7 +27,7 @@ mkdir -p $BASE # Upload the tar bz $TB_COMMAND -s . --sync --pattern-match ".*\.gpg" # Upload the index file - md5sum *.gpg | sort -t- -k4,5n > index.txt + md5sum *.gpg | sort -t- -k3,3V -k4,4n > index.txt cat index.txt $TB_COMMAND -s . --sync --pattern-match "index.txt" ) diff --git a/.travis/prevent-condarc.sh b/.travis/prevent-condarc.sh new file mode 100755 index 00000000..9ad7b862 --- /dev/null +++ b/.travis/prevent-condarc.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +mkdir -p ~/.conda +chmod 0000 ~/.conda diff --git a/.travis/run.inc.sh b/.travis/run.inc.sh new file mode 100644 index 00000000..588b517e --- /dev/null +++ b/.travis/run.inc.sh @@ -0,0 +1,58 @@ +if [ -z "$PLATFORMS" ]; then + if [ -z "$SKIP_PLATFORMS" ]; then + SKIP_PLATFORMS="sim" + fi + if [ -z "$PLATFORM" ]; then + PLATFORMS=$(ls targets/ | grep -v ".py" | grep -v "common" | grep -v "$SKIP_PLATFORMS" | sed -e"s+targets/++") + else + PLATFORMS="$PLATFORM" + fi +fi +echo "Running with PLATFORMS='$PLATFORMS'" + +if [ -z "$CPUS" ]; then + if [ -z "$CPU" ]; then + #CPUS="lm32 or1k riscv32" + CPUS="lm32 or1k" + else + CPUS="$CPU" + unset CPU + fi +fi + +declare -a SUCCESSES +declare -a FAILURES + +START_TARGET="$TARGET" +START_TARGETS="$TARGETS" +for FULL_PLATFORM in $PLATFORMS; do + if [ -z "$START_TARGETS" ]; then + if [ -z "$SKIP_TARGETS" ]; then + SKIP_TARGETS="__" + fi + if [ ! -z "$START_TARGETS" ]; then + TARGETS="$START_TARGETS" + elif [ ! -z "$START_TARGET" ]; then + TARGETS="$START_TARGET" + else + TARGETS=$(ls targets/${FULL_PLATFORM}/*.py | grep -v "__" | grep -v "$SKIP_TARGETS" | sed -e"s+targets/${FULL_PLATFORM}/++" -e"s/.py//") + fi + fi + + echo "" + echo "" + echo "" + echo "Running with TARGETS='$TARGETS'" + for TARGET in $TARGETS; do + echo "Running with CPUS='$CPUS'" + for FULL_CPU in $CPUS; do + $FUNC $FULL_PLATFORM $TARGET $FULL_CPU $FIRMWARE && : + RETURN=$? + if [ "$RETURN" -eq 0 ]; then + SUCCESSES+=("$FULL_PLATFORM+$TARGET+$FULL_CPU+$FIRMWARE") + else + FAILURES+=("$FULL_PLATFORM+$TARGET+$FULL_CPU+$FIRMWARE") + fi + done + done +done diff --git a/.travis/setup.sh b/.travis/setup.sh index e5dcf8b0..9913f56f 100755 --- a/.travis/setup.sh +++ b/.travis/setup.sh @@ -2,144 +2,98 @@ set -e -echo "" -echo "" -echo "" -echo "- Disk space free (initial)" -echo "---------------------------------------------" -df -h -echo "" -DF_INITIAL="$(($(stat -f --format="%a*%S" .)))" -DF_LAST=$DF_INITIAL +./.travis/prevent-condarc.sh -echo "" -echo "" -echo "" -echo "- Fetching non shallow to get git version" -echo "---------------------------------------------" -git fetch origin --unshallow && git fetch origin --tags - -if [ z"$TRAVIS_PULL_REQUEST_SLUG" != z ]; then - echo "" - echo "" - echo "" - echo "- Fetching from pull request source" - echo "---------------------------------------------" - git remote add source https://github.com/$TRAVIS_PULL_REQUEST_SLUG.git - git fetch source && git fetch --tags - - echo "" - echo "" - echo "" - echo "- Fetching the actual pull request" - echo "---------------------------------------------" - git fetch origin pull/$TRAVIS_PULL_REQUEST/head:pull-$TRAVIS_PULL_REQUEST-head - git fetch origin pull/$TRAVIS_PULL_REQUEST/merge:pull-$TRAVIS_PULL_REQUEST-merge - echo "---------------------------------------------" - git log -n 5 --graph pull-$TRAVIS_PULL_REQUEST-merge - echo "---------------------------------------------" - - echo "" - echo "" - echo "" - echo "- Using pull request version of submodules (if they exist)" - echo "---------------------------------------------" - git submodule status | while read SHA1 MODULE_PATH - do - "$PWD/.travis/add-local-submodule.sh" "$TRAVIS_PULL_REQUEST_SLUG" "$MODULE_PATH" - done - echo "---------------------------------------------" - git submodule foreach --recursive 'git remote -v; echo' - echo "---------------------------------------------" -fi +./.travis/fixup-git.sh -if [ z"$TRAVIS_REPO_SLUG" != z ]; then - echo "" - echo "" - echo "" - echo "- Using local version of submodules (if they exist)" - echo "---------------------------------------------" - git submodule status | while read SHA1 MODULE_PATH DESC - do - "$PWD/.travis/add-local-submodule.sh" "$TRAVIS_REPO_SLUG" "$MODULE_PATH" - done - echo "---------------------------------------------" - git submodule foreach --recursive 'git remote -v; echo' - echo "---------------------------------------------" -fi +function setup() { + export FULL_PLATFORM=$1 + export TARGET=$2 + export FULL_CPU=$3 -if [ z"$TRAVIS_BRANCH" != z ]; then - TRAVIS_COMMIT_ACTUAL=$(git log --pretty=format:'%H' -n 1) - echo "" - echo "" - echo "" - echo "Fixing detached head (current $TRAVIS_COMMIT_ACTUAL -> $TRAVIS_COMMIT)" - echo "---------------------------------------------" - git log -n 5 --graph - echo "---------------------------------------------" - git fetch origin $TRAVIS_COMMIT - git branch -v - echo "---------------------------------------------" - git log -n 5 --graph - echo "---------------------------------------------" - git branch -D $TRAVIS_BRANCH || true - git checkout $TRAVIS_COMMIT -b $TRAVIS_BRANCH - git branch -v -fi -echo "" -echo "" -echo "" -echo "Git Revision" -echo "---------------------------------------------" -git status -echo "---------------------------------------------" -git describe -echo "=============================================" -GIT_REVISION=$(git describe) + if [ x$4 != x ]; then + FIRMWARE=$4 + else + unset $FIRMWARE + fi -echo "" -echo "" -echo "" -echo "- Disk space free (after fixing git)" -echo "---------------------------------------------" -df -h -echo "" -DF_AFTER_GIT="$(($(stat -f --format="%a*%S" .)))" -awk "BEGIN {printf \"Git is using %.2f megabytes\n\",($DF_LAST-$DF_AFTER_GIT)/1024/1024}" -DF_LAST="$DF_AFTER_GIT" + if [ -z "$FULL_PLATFORM" -o -z "$TARGET" -o -z "$FULL_CPU" ]; then + echo "usage: setup FULL_PLATFORM TARGET FULL_CPU FIRMWARE" + echo " got: setup '$FULL_PLATFORM' '$TARGET' '$FULL_CPU' '$FIRMWARE'" + return 1 + fi + + DF_BEFORE_DOWNLOAD="$(($(stat -f --format="%a*%S" .)))" + ( + echo "" + echo "=============================================" + echo "" + echo "" + # Run the script once to check it works + time scripts/download-env.sh || exit 1 + echo "" + echo "" + echo "=============================================" + echo "" + echo "" + # Run the script again to check it doesn't break things + time scripts/download-env.sh || exit 1 + echo "" + echo "" + echo "=============================================" + + echo "" + echo "" + echo "" + echo "- Disk space free (after downloading environment)" + echo "---------------------------------------------" + df -h + echo "" + DF_AFTER_DOWNLOAD="$(($(stat -f --format="%a*%S" .)))" + awk "BEGIN {printf \"Environment is using %.2f megabytes\n\",($DF_BEFORE_DOWNLOAD-$DF_AFTER_DOWNLOAD)/1024/1024}" + + echo "=============================================" + echo "=============================================" + echo "" + echo "" + set +x + set +e + source scripts/enter-env.sh || exit 1 + ); return $? +} + +export FUNC=setup +source .travis/run.inc.sh echo "" -echo "=============================================" -echo "" -echo "" -# Run the script once to check it works -time scripts/download-env.sh echo "" echo "" +echo "The following setups succeeded" echo "=============================================" + +for S in ${SUCCESSES[@]}; do + echo $S | sed -e's/+/ /g' +done echo "" echo "" -# Run the script again to check it doesn't break things -time scripts/download-env.sh -echo "" echo "" +echo "The following setups failed!" echo "=============================================" +for F in ${FAILURES[@]}; do + echo $F | sed -e's/+/ /g' +done + echo "" echo "" echo "" -echo "- Disk space free (after downloading environment)" -echo "---------------------------------------------" -df -h -echo "" -DF_AFTER_DOWNLOAD="$(($(stat -f --format="%a*%S" .)))" -awk "BEGIN {printf \"Environment is using %.2f megabytes\n\",($DF_LAST-$DF_AFTER_DOWNLOAD)/1024/1024}" -DF_LAST="$DF_AFTER_DOWNLOAD" - echo "=============================================" -echo "=============================================" -echo "" -echo "" -set +x -set +e -source scripts/enter-env.sh + +if [ ${#FAILURES[@]} -ne 0 ]; then + echo "One or more setups failed :(" + exit 1 +else + echo "All setups succeeded! \\o/" +fi + +./.travis/download-prebuilt.sh diff --git a/.travis/update-prebuilt-list.sh b/.travis/update-prebuilt-list.sh new file mode 100755 index 00000000..3fa491ab --- /dev/null +++ b/.travis/update-prebuilt-list.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +function prebuilt() { + export FULL_PLATFORM=$1 + export TARGET=$2 + export FULL_CPU=$3 + + if [ x"$4" != x"" ]; then + FIRMWARE=$4 + else + unset $FIRMWARE + fi + export FIRMWARE + .travis/generate-prebuilt-list.py || return 1 + return 0 +} + +if [ x"$TRAVIS_BRANCH" = x"master" ]; then + echo "" + echo "" + echo "" + echo "Updating prebuilt binaries" + echo "=============================================" + for i in 1 2 3 4 5 6 7 8 9 10; do # Try 10 times. + export FUNC=prebuilt + + . .travis/run.inc.sh && : + FAILED=$? + + if [ $FAILED -eq 0 ]; then + echo "Update succeed!" + break + else + echo "Update failed!" + fi + done + echo + echo "Push finished!" +fi diff --git a/Makefile b/Makefile index 50d4bc1f..e7afc4d1 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,11 @@ ifneq ($(OS),Windows_NT) ifeq ($(HDMI2USB_ENV),) $(error "Please enter environment. 'source scripts/enter-env.sh'") endif + +# Force colors despite running through tee. +COLORAMA=force +export COLORAMA + endif PYTHON ?= python @@ -10,41 +15,114 @@ export PYTHON MESON ?= meson export MESON -PLATFORM ?= opsis -export PLATFORM -# Default board -ifeq ($(PLATFORM),) - $(error "PLATFORM not set, please set it.") +SPLIT_REGEX := ^\([^.]*\)\.\?\(.*\)$$ + +# The platform to run on. It is made up of FPGA_MAIN_BOARD.EXPANSION_BOARD +DEFAULT_PLATFORM = opsis +DEFAULT_PLATFORM_EXPANSION = + +ifneq ($(FULL_PLATFORM),) + PLATFORM_PART := $(shell echo $(FULL_PLATFORM) | sed -e's/$(SPLIT_REGEX)/\1/') + PLATFORM_EXPANSION_PART := $(shell echo $(FULL_PLATFORM) | sed -e's/$(SPLIT_REGEX)/\2/') + + # Check PLATFORM value matches FULL_PLATFORM bits + ifneq ($(PLATFORM),) + ifneq ($(PLATFORM),$(PLATFORM_PART)) + $(error "FULL_PLATFORM was set to '$(FULL_PLATFORM)' ($(PLATFORM_PART)), but PLATFORM was set to '$(PLATFORM)'.") + endif + else + PLATFORM=$(PLATFORM_PART) + endif + + # Check PLATFORM_EXPANSION value matches FULL_PLATFORM bits + ifneq ($(PLATFORM_EXPANSION),) + ifneq ($(PLATFORM_EXPANSION),$(PLATFORM_EXPANSION_PART)) + $(error "FULL_PLATFORM was set to '$(FULL_PLATFORM)', but PLATFORM_EXPANSION was set to '$(PLATFORM_EXPANSION)'.") + endif + else + PLATFORM_EXPANSION=$(PLATFORM_EXPANSION_PART) + endif endif +PLATFORM ?= $(DEFAULT_PLATFORM) +PLATFORM_EXPANSION ?= $(DEFAULT_PLATFORM_EXPANSION) -# Include platform specific targets -include targets/$(PLATFORM)/Makefile.mk -TARGET ?= $(DEFAULT_TARGET) -ifeq ($(TARGET),) - $(error "Internal error: TARGET not set.") +ifeq ($(PLATFORM),) + $(error "Internal error: PLATFORM not set.") +endif +export PLATFORM +ifeq ($(PLATFORM_EXPANSION),) +FULL_PLATFORM = $(PLATFORM) +else +FULL_PLATFORM = $(PLATFORM).$(PLATFORM_EXPANSION) +MAKE_LITEX_EXTRA_CMDLINE += -Ot expansion $(PLATFORM_EXPANSION) endif -export TARGET +# The soft CPU core to use inside the FPGA it is made up of CPU.VARIANT. DEFAULT_CPU = lm32 +DEFAULT_CPU_VARIANT = +ifneq ($(FULL_CPU),) + CPU_PART := $(shell echo $(FULL_CPU) | sed -e's/$(SPLIT_REGEX)/\1/') + CPU_VARIANT_PART := $(shell echo $(FULL_CPU) | sed -e's/$(SPLIT_REGEX)/\2/') + + # Check CPU value matches FULL_CPU bits + ifneq ($(CPU),) + ifneq ($(CPU),$(CPU_PART)) + $(error "FULL_CPU was set to '$(FULL_CPU)' ($(CPU_PART)), but CPU was set to '$(CPU)'.") + endif + else + CPU=$(CPU_PART) + endif + + # Check CPU_VARIANT value matches FULL_CPU bits + ifneq ($(CPU_VARIANT),) + ifneq ($(CPU_VARIANT),$(CPU_VARIANT_PART)) + $(error "FULL_CPU was set to '$(FULL_CPU)', but CPU_VARIANT was set to '$(CPU_VARIANT)'.") + endif + else + CPU_VARIANT=$(CPU_VARIANT_PART) + endif +endif + CPU ?= $(DEFAULT_CPU) +CPU_VARIANT ?= $(DEFAULT_CPU_VARIANT) + ifeq ($(CPU),) $(error "Internal error: CPU not set.") endif export CPU +ifeq ($(CPU_VARIANT),) +FULL_CPU = $(CPU) +else +FULL_CPU = $(CPU).$(CPU_VARIANT) +MAKE_LITEX_EXTRA_CMDLINE += -Ot cpu_variant $(CPU_VARIANT) +endif + +# Include platform specific targets +include targets/$(PLATFORM)/Makefile.mk +TARGET ?= $(DEFAULT_TARGET) +ifeq ($(TARGET),) + $(error "Internal error: TARGET not set.") +endif +export TARGET FIRMWARE ?= firmware +ifeq ($(FIRMWARE),) + FIRMWARE = firmware +endif +export FIRMWARE # We don't use CLANG CLANG = 0 export CLANG -ifeq ($(PLATFORM_EXPANSION),) -FULL_PLATFORM = $(PLATFORM) -else -FULL_PLATFORM = $(PLATFORM).$(PLATFORM_EXPANSION) -LITEX_EXTRA_CMDLINE += -Ot expansion $(PLATFORM_EXPANSION) +JOBS ?= $(shell nproc) +JOBS ?= 2 + +ifeq ($(shell [ $(JOBS) -gt 1 ] && echo true),true) + export MAKEFLAGS="-j $(JOBS) -l $(JOBS)" endif -TARGET_BUILD_DIR = build/$(FULL_PLATFORM)_$(TARGET)_$(CPU)/ + +TARGET_BUILD_DIR = build/$(FULL_PLATFORM)_$(TARGET)_$(FULL_CPU)/ GATEWARE_FILEBASE = $(TARGET_BUILD_DIR)/gateware/top BIOS_FILE = $(TARGET_BUILD_DIR)/software/bios/bios.bin @@ -55,6 +133,13 @@ TFTP_IPRANGE ?= 192.168.100 export TFTP_IPRANGE TFTPD_DIR ?= build/tftpd/ +# Well known TFTP Server Port is UDP/69 +# Default to high numbered port so we can run TFTP server as non-root +# (export into shell environment to use during building firmware BIOS) +# +TFTP_SERVER_PORT ?= 6069 +export TFTP_SERVER_PORT + # Couple of Python settings. # --------------------------------- # Turn off Python's hash randomization @@ -70,6 +155,7 @@ MAKE_CMD=\ --iprange=$(TFTP_IPRANGE) \ $(MISOC_EXTRA_CMDLINE) \ $(LITEX_EXTRA_CMDLINE) \ + $(MAKE_LITEX_EXTRA_CMDLINE) \ # We use the special PIPESTATUS which is bash only below. SHELL := /bin/bash @@ -85,7 +171,6 @@ build/cache.mk: targets/*/*.py scripts/makefile-cache.sh TARGETS=$(TARGETS_$(PLATFORM)) - # Initialize submodules automatically third_party/%/.git: .gitmodules git submodule sync --recursive -- $$(dirname $@) @@ -96,13 +181,15 @@ third_party/%/.git: .gitmodules # -------------------------------------- ifeq ($(FIRMWARE),none) OVERRIDE_FIRMWARE=--override-firmware=none +FIRMWARE_FBI= else OVERRIDE_FIRMWARE=--override-firmware=$(FIRMWARE_FILEBASE).fbi +FIRMWARE_FBI=$(FIRMWARE_FILEBASE).fbi endif -$(IMAGE_FILE): $(GATEWARE_FILEBASE).bin $(BIOS_FILE) $(FIRMWARE_FILEBASE).fbi +$(IMAGE_FILE): $(GATEWARE_FILEBASE).bin $(BIOS_FILE) $(FIRMWARE_FBI) $(PYTHON) mkimage.py \ - $(MISOC_EXTRA_CMDLINE) $(LITEX_EXTRA_CMDLINE) \ + $(MISOC_EXTRA_CMDLINE) $(LITEX_EXTRA_CMDLINE) $(MAKE_LITEX_EXTRA_CMDLINE) \ --override-gateware=$(GATEWARE_FILEBASE).bin \ --override-bios=$(BIOS_FILE) \ $(OVERRIDE_FIRMWARE) \ @@ -124,14 +211,38 @@ image-flash-py: image $(PYTHON) flash.py --mode=image .PHONY: image image-load image-flash image-flash-py image-flash-$(PLATFORM) image-load-$(PLATFORM) +.NOTPARALLEL: image-load image-flash image-flash-py image-flash-$(PLATFORM) image-load-$(PLATFORM) + +# Submodule checks +# +# Generate third_party/*/.git dependencies to force checkouts of submodules +# +# Also check for non-matching submodules, and warn that update might be +# needed (but do not force to match, as that makes development difficult) +# This is indicated by a "git submodule status" that does not start with +# a space (" "). +# +LITEX_SUBMODULES=migen litex litedram liteeth litepcie litesata litescope liteusb litevideo +litex-submodules: $(addsuffix /.git,$(addprefix third_party/,$(LITEX_SUBMODULES))) + @if git submodule status --recursive | grep "^[^ ]" >/dev/null; then \ + echo ""; \ + echo "***************************************************************************"; \ + echo "WARNING: the following submodules do not match expected commit:"; \ + echo ""; \ + git submodule status --recursive | grep "^[^ ]"; \ + echo ""; \ + echo "If you are not developing in submodules you may need to run:"; \ + echo ""; \ + echo "git submodule update --init --recursive"; \ + echo ""; \ + echo "manually to bring everything back in sync with upstream"; \ + echo "***************************************************************************"; \ + echo ""; \ + fi # Gateware - the stuff which configures the FPGA. # -------------------------------------- -GATEWARE_MODULES=litex litedram liteeth litepcie litesata litescope liteusb litevideo litex -gateware-submodules: $(addsuffix /.git,$(addprefix third_party/,$(GATEWARE_MODULES))) - @true - -gateware: gateware-submodules +gateware: litex-submodules mkdir -p $(TARGET_BUILD_DIR) ifneq ($(OS),Windows_NT) $(MAKE_CMD) \ @@ -163,6 +274,7 @@ gateware-clean: rm -rf $(TARGET_BUILD_DIR)/gateware .PHONY: gateware gateware-load gateware-flash gateware-flash-py gateware-clean gateware-load-$(PLATFORM) gateware-flash-$(PLATFORM) +.NOTPARALLEL: gateware-load gateware-flash gateware-flash-py gateware-flash-$(PLATFORM) gateware-load-$(PLATFORM) # Firmware - the stuff which runs in the soft CPU inside the FPGA. # -------------------------------------- @@ -170,7 +282,7 @@ FIRMWARE_MODULES=libmodem firmware-submodules: $(addsuffix /.git,$(addprefix third_party/,$(FIRMWARE_MODULES))) @true -firmware-cmd: firmware-submodules +firmware-cmd: litex-submodules firmware-submodules mkdir -p $(TARGET_BUILD_DIR) ifneq ($(OS),Windows_NT) $(MAKE_CMD) --no-compile-gateware \ @@ -203,12 +315,16 @@ firmware-connect: firmware-connect-$(PLATFORM) firmware-clear: firmware-clear-$(PLATFORM) @true -.PHONY: firmware-load-$(PLATFORM) firmware-flash-$(PLATFORM) firmware-connect-$(PLATFORM) firmware-clear-$(PLATFORM) - firmware-clean: rm -rf $(TARGET_BUILD_DIR)/software -.PHONY: firmware-cmd $(FIRMWARE_FILEBASE).bin firmware firmware-load firmware-flash firmware-connect firmware-clean +firmware-test: + scripts/check-firmware-newlines.sh + +.PHONY: firmware-load-$(PLATFORM) firmware-flash-$(PLATFORM) firmware-flash-py firmware-connect-$(PLATFORM) firmware-clear-$(PLATFORM) +.NOTPARALLEL: firmware-load-$(PLATFORM) firmware-flash-$(PLATFORM) firmware-flash-py firmware-connect-$(PLATFORM) firmware-clear-$(PLATFORM) +.PHONY: firmware-cmd $(FIRMWARE_FILEBASE).bin firmware firmware-load firmware-flash firmware-connect firmware-clean firmware-test +.NOTPARALLEL: firmware-cmd firmware-load firmware-flash firmware-connect $(BIOS_FILE): firmware-cmd @true @@ -220,34 +336,77 @@ bios-flash: $(BIOS_FILE) bios-flash-$(PLATFORM) @true .PHONY: $(FIRMWARE_FILE) bios bios-flash bios-flash-$(PLATFORM) +.NOTPARALLEL: bios-flash bios-flash-$(PLATFORM) # TFTP booting stuff # -------------------------------------- # TFTP server for minisoc to load firmware from +# +# We can run the TFTP server as the user if port >= 1024 +# otherwise we need to run as root using sudo + +ATFTPD:=$(shell which atftpd 2>/dev/null) +ifeq ($(ATFTPD),) +ATFTPD:=/usr/sbin/atftpd +endif + +# Requires HPA in.tftpd not traditional BSD in.tftpd +# Unfortunately in.tftpd seems to require root always +# even if run as current user, otherwise it reports +# "cannot set groups for user $USER" +# +IN_TFTPD:=$(shell which in.tftpd 2>/dev/null) +ifeq ($(IN_TFTPD),) +IN_TFTPD:=/usr/sbin/in.tftpd +endif + tftp: $(FIRMWARE_FILEBASE).bin mkdir -p $(TFTPD_DIR) cp $(FIRMWARE_FILEBASE).bin $(TFTPD_DIR)/boot.bin tftpd_stop: - sudo true - sudo killall atftpd || sudo killall in.tftpd || true # FIXME: This is dangerous... + # FIXME: This is dangerous... + @if [ $(TFTP_SERVER_PORT) -lt 1024 ]; then \ + sudo true; \ + sudo killall atftpd || sudo killall in.tftpd || true; \ + else \ + killall atftpd || \ + if ps axuwww | grep -v grep | \ + grep "[i]n.tftpd" >/dev/null 2>&1; then \ + sudo killall in.tftpd; \ + fi || true; \ + fi tftpd_start: mkdir -p $(TFTPD_DIR) - sudo true - @if command -v atftpd >/dev/null ; then \ - echo "Starting aftpd"; \ - sudo atftpd --verbose --bind-address $(TFTP_IPRANGE).100 --daemon --logfile /dev/stdout --no-fork --user $(shell whoami) $(TFTPD_DIR) & \ - elif command -v in.tftpd >/dev/null; then \ + @if [ $(TFTP_SERVER_PORT) -lt 1024 ]; then \ + echo "Root required to run TFTP Server, will use sudo"; \ + sudo true; \ + fi + @if [ -x "$(ATFTPD)" ]; then \ + echo "Starting atftpd"; \ + if [ $(TFTP_SERVER_PORT) -lt 1024 ]; then \ + sudo "$(ATFTPD)" --verbose --bind-address $(TFTP_IPRANGE).100 --port $(TFTP_SERVER_PORT) --daemon --logfile /dev/stdout --no-fork --user $(shell whoami) --group $(shell id -gn) $(TFTPD_DIR) & \ + else \ + "$(ATFTPD)" --verbose --bind-address $(TFTP_IPRANGE).100 --port $(TFTP_SERVER_PORT) --daemon --logfile /dev/stdout --no-fork --user $(shell whoami) --group $(shell id -gn) $(TFTPD_DIR) & \ + fi \ + elif [ -x "$(IN_TFTPD)" ]; then \ echo "Starting in.tftpd"; \ - sudo in.tftpd --verbose --listen --address $(TFTP_IPRANGE).100 --user $(shell whoami) -s $(TFTPD_DIR) & \ + if [ $(TFTP_SERVER_PORT) -lt 1024 ]; then \ + sudo "$(IN_TFTPD)" --verbose --listen --address $(TFTP_IPRANGE).100:$(TFTP_SERVER_PORT) --user $(shell whoami) -s $(TFTPD_DIR) & \ + else \ + echo "Root required to run in.tftpd, will use sudo"; \ + sudo true; \ + sudo "$(IN_TFTPD)" --verbose --listen --address $(TFTP_IPRANGE).100:$(TFTP_SERVER_PORT) --user $(shell whoami) -s $(TFTPD_DIR) & \ + fi \ else \ echo "Cannot find an appropriate tftpd binary to launch the server."; \ false; \ fi .PHONY: tftp tftpd_stop tftpd_start +.NOTPARALLEL: tftp tftpd_stop tftpd_start # Extra targets # -------------------------------------- @@ -257,10 +416,10 @@ flash: image-flash env: @echo "export PLATFORM='$(PLATFORM)'" @echo "export PLATFORM_EXPANSION='$(PLATFORM_EXPANSION)'" - @echo "export FULL_PLATFORM='$(FULL_PLATFORM)'" @echo "export TARGET='$(TARGET)'" @echo "export DEFAULT_TARGET='$(DEFAULT_TARGET)'" @echo "export CPU='$(CPU)'" + @echo "export CPU_VARIANT='$(CPU_VARIANT)'" @echo "export FIRMWARE='$(FIRMWARE)'" @echo "export OVERRIDE_FIRMWARE='$(OVERRIDE_FIRMWARE)'" @echo "export PROG='$(PROG)'" @@ -268,27 +427,34 @@ env: @echo "export TFTP_DIR='$(TFTPD_DIR)'" @echo "export MISOC_EXTRA_CMDLINE='$(MISOC_EXTRA_CMDLINE)'" @echo "export LITEX_EXTRA_CMDLINE='$(LITEX_EXTRA_CMDLINE)'" + @echo "export MAKE_LITEX_EXTRA_CMDLINE='$(MAKE_LITEX_EXTRA_CMDLINE)'" @# Hardcoded values @echo "export CLANG=$(CLANG)" @echo "export PYTHONHASHSEED=$(PYTHONHASHSEED)" + @echo "export JOBS=$(JOBS)" @# Files @echo "export IMAGE_FILE='$(IMAGE_FILE)'" @echo "export GATEWARE_FILEBASE='$(GATEWARE_FILEBASE)'" @echo "export FIRMWARE_FILEBASE='$(FIRMWARE_FILEBASE)'" @echo "export BIOS_FILE='$(BIOS_FILE)'" + @# Network settings + @echo "export TFTP_IPRANGE='$(TFTP_IPRANGE)'" + @echo "export TFTP_SERVER_PORT='$(TFTP_SERVER_PORT)'" + @echo "export TFTPD_DIR='$(TFTPD_DIR)'" info: @echo " Platform: $(FULL_PLATFORM)" @echo " Target: $(TARGET) (default: $(DEFAULT_TARGET))" - @echo " CPU: $(CPU)" + @echo " CPU: $(FULL_CPU) (default: $(DEFAULT_CPU))" @if [ x"$(FIRMWARE)" != x"firmware" ]; then \ echo " Firmare: $(FIRMWARE) (default: firmware)"; \ fi prompt: - @echo -n "P=$(PLATFORM)" + @echo -n "P=$(FULL_PLATFORM)" @if [ x"$(TARGET)" != x"$(DEFAULT_TARGET)" ]; then echo -n " T=$(TARGET)"; fi @if [ x"$(CPU)" != x"$(DEFAULT_CPU)" ]; then echo -n " C=$(CPU)"; fi + @if [ x"$(CPU_VARIANT)" != x"$(DEFAULT_CPU_VARIANT)" ]; then echo -n ".$(CPU_VARIANT)"; fi @if [ x"$(FIRMWARE)" != x"firmware" ]; then \ echo -n " F=$(FIRMWARE)"; \ fi @@ -325,6 +491,10 @@ help: @echo " CPU=lm32 OR or1k" @echo " (current: $(CPU), default: $(DEFAULT_CPU))" @echo "" + @echo " CPU_VARIANT describes which soft-CPU variant to use on the FPGA." + @echo " CPU_VARIANT=" + @echo " (current: $(CPU_VARIANT), default: $(DEFAULT_CPU_VARIANT))" + @echo "" @echo " FIRMWARE describes the code running on the soft-CPU inside the FPGA." @echo " FIRMWARE=firmware OR micropython" @echo " (current: $(FIRMWARE))" @@ -340,6 +510,7 @@ help: @echo "" @echo "Firmware make commands avaliable:" @echo " make firmware - Build the firmware" + @echo " make firmware-test - Run firmware tests" @echo " make firmware-load - *Temporarily* load the firmware onto a device" @echo " make firmware-flash - *Permanently* flash the firmware onto a device" @echo " make firmware-connect - *Connect* to the firmware running on a device" @@ -353,20 +524,22 @@ help: @echo "" @echo "Other Make commands avaliable:" @make -s help-$(PLATFORM) + @echo " make test - Run all tests" @echo " make clean - Clean all build artifacts." reset: reset-$(PLATFORM) @true clean: - rm build/cache.mk + rm -f build/cache.mk rm -rf $(TARGET_BUILD_DIR) - py3clean . || rm -rf $$(find -name __pycache__) + py3clean . 2>/dev/null || rm -rf $$(find -name __pycache__) dist-clean: rm -rf build -.PHONY: flash help clean dist-clean help-$(PLATFORM) reset reset-$(PLATFORM) +.PHONY: flash env info prompt help clean dist-clean help-$(PLATFORM) reset reset-$(PLATFORM) +.NOTPARALLEL: flash env prompt info help help-$(PLATFORM) reset reset-$(PLATFORM) # Tests # -------------------------------------- @@ -377,7 +550,8 @@ test-submodules: $(addsuffix /.git,$(addprefix third_party/,$(TEST_MODULES))) test-edid: test-submodules $(MAKE) -C test/edid check -test: - true +test: firmware-test + @echo "Tests passed" .PHONY: test test-edid +.NOTPARALLEL: test test-edid diff --git a/README.md b/README.md index 37b4ad6b..dac52c01 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ conferences; ![Digilent Atlys Picture](https://hdmi2usb.tv/img/digilent-atlys-small.jpg) - * [Numato Opsis](https://hdmi2usb.tv/numato-opsis/) - `PLATFORM=opsis` - https://crowdsupply.com/numato-lab/opsis + * [Numato Opsis](https://hdmi2usb.tv/numato-opsis/) - `PLATFORM=opsis` - https://numato.com/product/numato-opsis-fpga-based-open-video-platform The first production board made in conjunction with TimVideos.us project. diff --git a/doc/notes.md b/doc/notes.md index a880c2aa..c7269f0f 100644 --- a/doc/notes.md +++ b/doc/notes.md @@ -41,7 +41,7 @@ Bunch of packages are needed; * Libraries for talking to USB - libftdi, libusb, fxload - + * udev rules. * Kernel modules for some boards. Mostly not needed.... @@ -77,7 +77,9 @@ directory will totally remove the installed environment. ### Step 4 - Enter self contained environment & set environment variables. - + * If you installed Xilinx to anywhere other than `/opt/Xilinx/`, run + `export XILINX_DIR=`. This must be set before entering the + environment, as it is not updated from within it. * `source scripts/enter-env.sh` - enter-env checks that your environment is setup correctly and contains all the dependencies you need. diff --git a/firmware/ci.c b/firmware/ci.c index 319b2ac3..2d0d4957 100644 --- a/firmware/ci.c +++ b/firmware/ci.c @@ -101,13 +101,13 @@ static void help_heartbeat(void) static void heartbeat_enable(void) { hb_status(true); - wprintf("Heartbeat enabled\r\n"); + wprintf("Heartbeat enabled\n"); } static void heartbeat_disable(void) { hb_status(false); - wprintf("Heartbeat disabled\r\n"); + wprintf("Heartbeat disabled\n"); } #ifdef CSR_HDMI_OUT0_BASE @@ -174,7 +174,7 @@ static void help_debug(void) wputs(" debug ddr - show DDR bandwidth"); #endif wputs(" debug dna - show Board's DNA"); - wputs(" debug edid - dump monitor EDID"); + wputs(" debug edid - dump monitor EDID"); #if defined(CSR_SPIFLASH_BASE) && defined(FLASH_BOOT_ADDRESS) wputs(" debug spiflash - test bitbang write"); #endif @@ -204,6 +204,7 @@ static void ci_help(void) wputs("mdio_status - show mdio status"); #endif wputs("pattern (p) - select next pattern"); + wputs("version - show firmware version"); wputs(""); help_status(); wputs(""); @@ -286,10 +287,11 @@ static char *readstr(void) break; case 0x07: break; - case '\r': case '\n': + break; + case '\r': s[ptr] = 0x00; - wputsnonl("\n"); + wputs(""); ptr = 0; return s; default: @@ -336,25 +338,25 @@ static char *get_token(char **str) static void status_enable(void) { - wprintf("Enabling status\r\n"); + wprintf("Enabling status\n"); status_enabled = 1; } static void status_disable(void) { - wprintf("Disabling status\r\n"); + wprintf("Disabling status\n"); status_enabled = 0; } static void status_short_enable(void) { - wprintf("Enabling short status\r\n"); + wprintf("Enabling short status\n"); status_short_enabled = 1; } static void status_short_disable(void) { - wprintf("Disabling status\r\n"); + wprintf("Disabling status\n"); status_short_enabled = 0; } @@ -425,7 +427,7 @@ static void status_short_print(void) wprintf("off "); #endif - wprintf("\r\nstatus2: "); + wprintf("\nstatus2: "); wprintf("EDID: "); wprintf("%dx%d@" REFRESH_RATE_PRINTF "Hz/", processor_h_active, @@ -458,7 +460,7 @@ static void status_short_print(void) wprintf("ddr: "); debug_ddr(); #endif - wprintf("\r\n"); + wputchar('\n'); } static void status_print(void) @@ -478,7 +480,7 @@ static void status_print(void) wprintf(" (disabled)"); } #endif - wprintf("\r\n"); + wputchar('\n'); #endif #ifdef CSR_HDMI_IN1_BASE @@ -495,7 +497,7 @@ static void status_print(void) } else { wprintf(" (disabled)"); } - wprintf("\r\n"); + wputchar('\n'); #endif #ifdef CSR_HDMI_OUT0_BASE @@ -515,7 +517,7 @@ static void status_print(void) hdmi_out0_core_underflow_enable_write(1); } else wprintf("off"); - wprintf("\r\n"); + wputchar('\n'); #endif #ifdef CSR_HDMI_OUT1_BASE @@ -535,7 +537,7 @@ static void status_print(void) hdmi_out1_core_underflow_enable_write(1); } else wprintf("off"); - wprintf("\r\n"); + wputchar('\n'); #endif wprintf("EDID primary mode: "); @@ -543,7 +545,7 @@ static void status_print(void) processor_h_active, processor_v_active, REFRESH_RATE_PRINTF_ARGS(processor_refresh)); - wprintf("\r\n"); + wputchar('\n'); wprintf("EDID secondary mode: "); if (processor_secondary_mode == EDID_SECONDARY_MODE_OFF) { @@ -554,7 +556,7 @@ static void status_print(void) processor_describe_mode(mode_descriptor, processor_secondary_mode); wprintf("%s", mode_descriptor); } - wprintf("\r\n"); + wputchar('\n'); #ifdef ENCODER_BASE wprintf("encoder: "); @@ -568,12 +570,12 @@ static void status_print(void) encoder_quality); } else wprintf("off"); - wprintf("\r\n"); + wputchar('\n'); #endif #ifdef CSR_SDRAM_CONTROLLER_BANDWIDTH_UPDATE_ADDR wprintf("ddr: "); debug_ddr(); - wprintf("\r\n"); + wputchar('\n'); #endif } @@ -584,7 +586,7 @@ static void status_service(void) if(elapsed(&last_event, SYSTEM_CLOCK_FREQUENCY)) { if(status_enabled) { status_print(); - wprintf("\r\n"); + wputchar('\n'); } if(status_short_enabled) { status_short_print(); @@ -592,44 +594,76 @@ static void status_service(void) } } -// FIXME +#ifdef CSR_HDMI_IN0_BASE +#ifndef HDMI_IN0_MNEMONIC +#warning "Missing HDMI IN0 mnemonic!" #define HDMI_IN0_MNEMONIC "" -#define HDMI_IN1_MNEMONIC "" -#define HDMI_OUT0_MNEMONIC "" -#define HDMI_OUT1_MNEMONIC "" - +#endif +#ifndef HDMI_IN0_DESCRIPTION +#warning "Missing HDMI IN0 description!" #define HDMI_IN0_DESCRIPTION "" +#endif +#endif + +#ifdef CSR_HDMI_IN1_BASE +#ifndef HDMI_IN1_MNEMONIC +#warning "Missing HDMI IN1 mnemonic!" +#define HDMI_IN1_MNEMONIC "" +#endif +#ifndef HDMI_IN1_DESCRIPTION +#warning "Missing HDMI IN1 description!" #define HDMI_IN1_DESCRIPTION "" +#endif +#endif + +#ifdef CSR_HDMI_OUT0_BASE +#ifndef HDMI_OUT0_MNEMONIC +#warning "Missing HDMI OUT0 mnemonic!" +#define HDMI_OUT0_MNEMONIC "" +#endif +#ifndef HDMI_OUT0_DESCRIPTION +#warning "Missing HDMI OUT0 description!" #define HDMI_OUT0_DESCRIPTION "" +#endif +#endif + +#ifdef CSR_HDMI_OUT1_BASE +#ifndef HDMI_OUT1_MNEMONIC +#warning "Missing HDMI OUT1 mnemonic!" +#define HDMI_OUT1_MNEMONIC "" +#endif +#ifndef HDMI_OUT1_DESCRIPTION +#warning "Missing HDMI OUT1 description!" #define HDMI_OUT1_DESCRIPTION "" -// FIXME +#endif +#endif static void video_matrix_list(void) { - wprintf("Video sources:\r\n"); + wprintf("Video sources:\n"); #ifdef CSR_HDMI_IN0_BASE - wprintf("input0 (0): %s\r\n", HDMI_IN0_MNEMONIC); + wprintf("input0 (0): %s\n", HDMI_IN0_MNEMONIC); wputs(HDMI_IN0_DESCRIPTION); #endif #ifdef CSR_HDMI_IN1_BASE - wprintf("input1 (1): %s\r\n", HDMI_IN1_MNEMONIC); + wprintf("input1 (1): %s\n", HDMI_IN1_MNEMONIC); wputs(HDMI_IN1_DESCRIPTION); #endif - wprintf("pattern (p):\r\n"); - wprintf(" Video pattern\r\n"); + wprintf("pattern (p):\n"); + wprintf(" Video pattern\n"); wputs(" "); - wprintf("Video sinks:\r\n"); + wprintf("Video sinks:\n"); #ifdef CSR_HDMI_OUT0_BASE - wprintf("output0 (0): %s\r\n", HDMI_OUT0_MNEMONIC); + wprintf("output0 (0): %s\n", HDMI_OUT0_MNEMONIC); wputs(HDMI_OUT0_DESCRIPTION); #endif #ifdef CSR_HDMI_OUT1_BASE - wprintf("output1 (1): %s\r\n", HDMI_OUT1_MNEMONIC); + wprintf("output1 (1): %s\n", HDMI_OUT1_MNEMONIC); wputs(HDMI_OUT1_DESCRIPTION); #endif #ifdef ENCODER_BASE - wprintf("encoder (e):\r\n"); - wprintf(" JPEG encoder (USB output)\r\n"); + wprintf("encoder (e):\n"); + wprintf(" JPEG encoder (USB output)\n"); #endif wputs(" "); } @@ -639,24 +673,24 @@ static void video_matrix_connect(int source, int sink) if(source >= 0 && source <= VIDEO_IN_PATTERN) { if(sink >= 0 && sink <= VIDEO_OUT_HDMI_OUT1) { - wprintf("Connecting %s to output%d\r\n", processor_get_source_name(source), sink); + wprintf("Connecting %s to output%d\n", processor_get_source_name(source), sink); if(sink == VIDEO_OUT_HDMI_OUT0) #ifdef CSR_HDMI_OUT0_BASE processor_set_hdmi_out0_source(source); #else - wprintf("hdmi_out0 is missing.\r\n"); + wprintf("hdmi_out0 is missing.\n"); #endif else if(sink == VIDEO_OUT_HDMI_OUT1) #ifdef CSR_HDMI_OUT1_BASE processor_set_hdmi_out1_source(source); #else - wprintf("hdmi_out1 is missing.\r\n"); + wprintf("hdmi_out1 is missing.\n"); #endif processor_update(); } #ifdef ENCODER_BASE else if(sink == VIDEO_OUT_ENCODER) { - wprintf("Connecting %s to encoder\r\n", processor_get_source_name(source)); + wprintf("Connecting %s to encoder\n", processor_get_source_name(source)); processor_set_encoder_source(source); processor_update(); } @@ -670,10 +704,10 @@ static void video_mode_list(void) int i; processor_list_modes(mode_descriptors); - wprintf("Available video modes:\r\n"); + wprintf("Available video modes:\n"); for(i=0;iflags = modeFlags; processor_set_custom_mode(); - wprintf("Custom video mode set.\r\n"); + wprintf("Custom video mode set.\n"); } static void hdp_toggle(int source) @@ -846,7 +880,7 @@ static void hdp_toggle(int source) #if defined(CSR_HDMI_IN0_BASE) || defined(CSR_HDMI_IN1_BASE) int i; #endif - wprintf("Toggling HDP on output%d\r\n", source); + wprintf("Toggling HDP on output%d\n", source); #ifdef CSR_HDMI_IN0_BASE if(source == VIDEO_IN_HDMI_IN0) { hdmi_in0_edid_hpd_en_write(0); @@ -854,7 +888,7 @@ static void hdp_toggle(int source) hdmi_in0_edid_hpd_en_write(1); } #else - wprintf("hdmi_in0 is missing.\r\n"); + wprintf("hdmi_in0 is missing.\n"); #endif #ifdef CSR_HDMI_IN1_BASE if(source == VIDEO_IN_HDMI_IN1) { @@ -863,20 +897,20 @@ static void hdp_toggle(int source) hdmi_in1_edid_hpd_en_write(1); } #else - wprintf("hdmi_in1 is missing.\r\n"); + wprintf("hdmi_in1 is missing.\n"); #endif } #ifdef CSR_HDMI_IN0_BASE void input0_on(void) { - wprintf("Enabling input0\r\n"); + wprintf("Enabling input0\n"); hdmi_in0_enable(); } void input0_off(void) { - wprintf("Disabling input0\r\n"); + wprintf("Disabling input0\n"); hdmi_in0_disable(); } #endif @@ -884,13 +918,13 @@ void input0_off(void) #ifdef CSR_HDMI_IN1_BASE void input1_on(void) { - wprintf("Enabling input1\r\n"); + wprintf("Enabling input1\n"); hdmi_in1_enable(); } void input1_off(void) { - wprintf("Disabling input1\r\n"); + wprintf("Disabling input1\n"); hdmi_in1_disable(); } #endif @@ -898,13 +932,13 @@ void input1_off(void) #ifdef CSR_HDMI_OUT0_BASE void output0_on(void) { - wprintf("Enabling output0\r\n"); + wprintf("Enabling output0\n"); hdmi_out0_core_initiator_enable_write(1); } void output0_off(void) { - wprintf("Disabling output0\r\n"); + wprintf("Disabling output0\n"); hdmi_out0_core_initiator_enable_write(0); } #endif @@ -912,13 +946,13 @@ void output0_off(void) #ifdef CSR_HDMI_OUT1_BASE void output1_on(void) { - wprintf("Enabling output1\r\n"); + wprintf("Enabling output1\n"); hdmi_out1_core_initiator_enable_write(1); } void output1_off(void) { - wprintf("Disabling output1\r\n"); + wprintf("Disabling output1\n"); hdmi_out1_core_initiator_enable_write(0); } #endif @@ -926,25 +960,25 @@ void output1_off(void) #ifdef ENCODER_BASE void encoder_on(void) { - wprintf("Enabling encoder\r\n"); + wprintf("Enabling encoder\n"); encoder_enable(1); } void encoder_configure_quality(int quality) { - wprintf("Setting encoder quality to %d\r\n", quality); + wprintf("Setting encoder quality to %d\n", quality); encoder_set_quality(quality); } void encoder_configure_fps(int fps) { - wprintf("Setting encoder fps to %d\r\n", fps); + wprintf("Setting encoder fps to %d\n", fps); encoder_set_fps(fps); } void encoder_off(void) { - wprintf("Disabling encoder\r\n"); + wprintf("Disabling encoder\n"); encoder_enable(0); } #endif @@ -953,7 +987,7 @@ static void debug_clocks(void) { // Only the active clock system will output anything pll_dump(); - mmcm_dump(); + mmcm_dump_all(); } static unsigned int log2(unsigned int v) @@ -979,7 +1013,7 @@ static void debug_ddr(void) burstbits = (2*DFII_NPHASES) << DFII_PIX_DATA_SIZE; rdb = (nr*f >> (24 - log2(burstbits)))/1000000ULL; wrb = (nw*f >> (24 - log2(burstbits)))/1000000ULL; - wprintf("read:%5dMbps write:%5dMbps all:%5dMbps\r\n", rdb, wrb, rdb + wrb); + wprintf("read:%5dMbps write:%5dMbps all:%5dMbps\n", rdb, wrb, rdb + wrb); */ } #endif @@ -1143,7 +1177,7 @@ void ci_service(void) source = VIDEO_IN_PATTERN; } else { - wprintf("Unknown video source: '%s'\r\n", token); + wprintf("Unknown video source: '%s'\n", token); } /* get video sink */ @@ -1159,7 +1193,7 @@ void ci_service(void) sink = VIDEO_OUT_ENCODER; } else - wprintf("Unknown video sink: '%s'\r\n", token); + wprintf("Unknown video sink: '%s'\n", token); if (source >= 0 && sink >= 0) video_matrix_connect(source, sink); @@ -1254,7 +1288,7 @@ void ci_service(void) #endif else if((strcmp(token, "p") == 0) || (strcmp(token, "p") == 0)) { pattern_next(); - wprintf("Pattern now %d\r\n", pattern); + wprintf("Pattern now %d\n", pattern); } else if((strcmp(token, "status") == 0) || (strcmp(token, "s") == 0)) { token = get_token(&str); @@ -1290,7 +1324,7 @@ void ci_service(void) hdmi_in0_debug = 1; else hdmi_in0_debug = !hdmi_in0_debug; - wprintf("HDMI Input 0 debug %s\r\n", hdmi_in0_debug ? "on" : "off"); + wprintf("HDMI Input 0 debug %s\n", hdmi_in0_debug ? "on" : "off"); } #endif #ifdef CSR_HDMI_IN1_BASE @@ -1302,18 +1336,20 @@ void ci_service(void) hdmi_in1_debug = 1; else hdmi_in1_debug = !hdmi_in1_debug; - wprintf("HDMI Input 1 debug %s\r\n", hdmi_in1_debug ? "on" : "off"); + wprintf("HDMI Input 1 debug %s\n", hdmi_in1_debug ? "on" : "off"); } #endif #ifdef CSR_SDRAM_CONTROLLER_BANDWIDTH_UPDATE_ADDR else if(strcmp(token, "ddr") == 0) { debug_ddr(); - wprintf("\r\n"); + wputchar('\n'); } #endif #ifdef CSR_INFO_DNA_ID_ADDR - else if(strcmp(token, "dna") == 0) + else if(strcmp(token, "dna") == 0) { print_board_dna(); + wputchar('\n'); + } #endif #ifdef CSR_OPSIS_I2C_MASTER_W_ADDR else if(strcmp(token, "opsis_eeprom") == 0) { @@ -1357,7 +1393,7 @@ void ci_service(void) } #endif if(found == 0) - wprintf("%s port has no EDID capabilities\r\n", token); + wprintf("no such port\n"); #if defined(CSR_SPIFLASH_BASE) && defined(FLASH_BOOT_ADDRESS) } else if(strcmp(token, "spiflash") == 0) { bitbang_test(); @@ -1374,14 +1410,14 @@ void ci_service(void) #endif #ifdef CSR_CAS_SWITCHES_IN_ADDR else if(strcmp(token, "switches") == 0) { - wprintf("%X\r\n", (int)cas_switches_in_read()); + wprintf("%X\n", (int)cas_switches_in_read()); } #endif #ifdef CSR_CAS_BUTTONS_EV_STATUS_ADDR else if(strcmp(token, "buttons") == 0) { int status = cas_buttons_ev_status_read(); int pending = cas_buttons_ev_pending_read(); - wprintf("%X %X\r\n", status, pending); + wprintf("%X %X\n", status, pending); token = get_token(&str); if(strcmp(token, "clear") == 0) { cas_buttons_ev_pending_write(pending); diff --git a/firmware/encoder.c b/firmware/encoder.c index cd5dc42c..1460f85c 100644 --- a/firmware/encoder.c +++ b/firmware/encoder.c @@ -153,7 +153,7 @@ int encoder_set_quality(int quality) { encoder_quality = quality; break; default: - wprintf("Unsupported encoder quality (50, 75, 85 or 100)\r\n"); + wprintf("Unsupported encoder quality (50, 75, 85 or 100)\n"); return 0; } return 1; diff --git a/firmware/framebuffer.h b/firmware/framebuffer.h index e0d7c177..9fae2018 100644 --- a/firmware/framebuffer.h +++ b/firmware/framebuffer.h @@ -14,18 +14,62 @@ #ifndef __FRAMEBUFFER_H #define __FRAMEBUFFER_H +#include #include #include "generated/mem.h" +/** + * Frame buffers must be aligned to XXX boundary. + * + * 0x01000000 - Pattern Buffer - Frame Buffer n + * + * Each input then has 3 frame buffers spaced like this; + * // HDMI Input 0 + * 0x02000000 - HDMI Input 0 - Frame Buffer n + * 0x02040000 - HDMI Input 0 - Frame Buffer n+1 + * 0x02080000 - HDMI Input 0 - Frame Buffer n+2 + * // HDMI Input 1 + * 0x03000000 - HDMI Input 1 - Frame Buffer n + * 0x03040000 - HDMI Input 1 - Frame Buffer n+1 + * 0x03080000 - HDMI Input 1 - Frame Buffer n+2 + * ... + * // HDMI Input x + * 0x0.000000 - HDMI Input x - Frame Buffer n + * 0x0.040000 - HDMI Input x - Frame Buffer n+1 + * 0x0.080000 - HDMI Input x - Frame Buffer n+2 + * + */ +#define FRAMEBUFFER_OFFSET 0x01000000 +#define FRAMEBUFFER_PATTERNS 1 + +#define FRAMEBUFFER_PIXELS_X 1920 // pixels +#define FRAMEBUFFER_PIXELS_Y 1080 // pixels +#define FRAMEBUFFER_PIXELS_BYTES 2 // bytes + +#define FRAMEBUFFER_BASE(x) ((x+1)*FRAMEBUFFER_OFFSET) +#define FRAMEBUFFER_BASE_PATTERN FRAMEBUFFER_BASE(0) +#define FRAMEBUFFER_BASE_HDMI_INPUT(x) FRAMEBUFFER_BASE(x+FRAMEBUFFER_PATTERNS) + // Largest frame size at 16bpp (ish) -#define FRAMEBUFFER_SIZE (1920*1080*2) -#define FRAMEBUFFER_COUNT 4 -#define FRAMEBUFFER_MASK (FRAMEBUFFER_COUNT - 1) +#define FRAMEBUFFER_SIZE 0x400000 // bytes +#if (FRAMEBUFFER_PIXELS_X*FRAMEBUFFER_PIXELS_Y*FRAMEBUFFER_PIXELS_BYTES) > FRAMEBUFFER_SIZE +#error "Number of pixels don't fit in frame buffer" +#endif + +#define FRAMEBUFFER_COUNT 4 // Must be a multiple of 2 +#define FRAMEBUFFER_MASK (FRAMEBUFFER_COUNT - 1) + typedef unsigned int fb_ptrdiff_t; // FIXME: typedef uint16_t framebuffer_t[FRAMEBUFFER_SIZE]; inline unsigned int *fb_ptrdiff_to_main_ram(fb_ptrdiff_t p) { +#ifdef MAIN_RAM_BASE return (unsigned int *)(MAIN_RAM_BASE + p); +#else +/* FIXME! Should be unreachable if we have no main ram! */ + assert(0); + return (unsigned int *)(0); +#endif } #endif /* __FRAMEBUFFER_H */ diff --git a/firmware/fx2.c b/firmware/fx2.c index 1ffd0410..a57ae222 100644 --- a/firmware/fx2.c +++ b/firmware/fx2.c @@ -35,7 +35,7 @@ static inline uint8_t fx2_fw_get_value(unsigned addr) { #endif } } else { - wprintf("fx2: Read from invalid address %02X (end: %02X)\r\n", addr, end_addr); + wprintf("fx2: Read from invalid address %02X (end: %02X)\n", addr, end_addr); } return r; } @@ -68,7 +68,7 @@ static void fx2_load_init(void) static void fx2_load(void) { fx2_load_init(); - wprintf("fx2: Waiting for FX2 to load firmware.\r\n"); + wprintf("fx2: Waiting for FX2 to load firmware.\n"); uint64_t i = 0; while((i < FX2_WAIT_PERIOD)) { @@ -79,13 +79,13 @@ static void fx2_load(void) break; } } else if ((i % FX2_REPORT_PERIOD) == 0) { - wprintf("fx2: Waiting at %02X (end: %02X)\r\n", next_read_addr, end_addr); + wprintf("fx2: Waiting at %02X (end: %02X)\n", next_read_addr, end_addr); } } if (i > 0) { - wprintf("fx2: Timeout loading!\r\n"); + wprintf("fx2: Timeout loading!\n"); } else { - wprintf("fx2: Booted.\r\n"); + wprintf("fx2: Booted.\n"); } } @@ -94,7 +94,7 @@ bool fx2_service(bool verbose) unsigned char status = opsis_i2c_fx2_hack_status_read(); if(status == FX2_HACK_SHIFT_REG_EMPTY) { // there's been a master READ if (verbose) { - wprintf("fx2: read %02X (end: %02X)\r\n", next_read_addr, end_addr); + wprintf("fx2: read %02X (end: %02X)\n", next_read_addr, end_addr); } if (next_read_addr < end_addr) { // Load next value into the system @@ -102,12 +102,12 @@ bool fx2_service(bool verbose) opsis_i2c_fx2_hack_status_write(FX2_HACK_STATUS_READY); next_read_addr++; } else { - wprintf("fx2: Finished loading firmware.\r\n"); + wprintf("fx2: Finished loading firmware.\n"); fx2_load_init(); } return true; } else if (status != 0) { - wprintf("fx2: Bad status %02X\r\n", status); + wprintf("fx2: Bad status %02X\n", status); } return false; } @@ -117,19 +117,19 @@ void fx2_reboot(enum fx2_fw_version fw) OPSIS_I2C_ACTIVE(OPSIS_I2C_FX2HACK); unsigned int i; fx2_fw_active = fw; - wprintf("fx2: Turning off.\r\n"); + wprintf("fx2: Turning off.\n"); opsis_i2c_fx2_reset_out_write(1); for(i=0;i/dev/null || mktemp --suffix=.h) +TMPFILE_C=$(tempfile -s .c 2>/dev/null || mktemp --suffix=.c) cat $FIRMWARE_DIR/hdmi_in0.h | sed \ + -e"s/IN0_INDEX\([^0-9]\+\)0/IN${X}_INDEX\1$X/g" \ -e"s/IN0/IN$X/g" \ -e"s/in0/in$X/g" \ + -e"s/dvisampler0/dvisampler$X/g" \ > $TMPFILE_H cat $FIRMWARE_DIR/hdmi_in0.c | sed \ -e"s/IN0/IN$X/g" \ -e"s/in0/in$X/g" \ + -e"s/dvisampler0/dvisampler$X/g" \ > $TMPFILE_C if ! cmp -s $TMPFILE_H hdmi_in$X.h; then diff --git a/firmware/hdmi_in0.c b/firmware/hdmi_in0.c index 9e62abc2..0c78879d 100644 --- a/firmware/hdmi_in0.c +++ b/firmware/hdmi_in0.c @@ -19,8 +19,6 @@ int hdmi_in0_debug; int hdmi_in0_fb_index; -#define HDMI_IN0_FRAMEBUFFERS_BASE (0x00000000 + 0x100000) - //#define CLEAN_COMMUTATION //#define DEBUG @@ -45,10 +43,10 @@ void hdmi_in0_isr(void) address_max = address_min + FRAMEBUFFER_SIZE*FRAMEBUFFER_COUNT; if((hdmi_in0_dma_slot0_status_read() == DVISAMPLER_SLOT_PENDING) && ((hdmi_in0_dma_slot0_address_read() < address_min) || (hdmi_in0_dma_slot0_address_read() > address_max))) - wprintf("dvisampler0: slot0: stray DMA\r\n"); + wprintf("dvisampler0: slot0: stray DMA\n"); if((hdmi_in0_dma_slot1_status_read() == DVISAMPLER_SLOT_PENDING) && ((hdmi_in0_dma_slot1_address_read() < address_min) || (hdmi_in0_dma_slot1_address_read() > address_max))) - wprintf("dvisampler0: slot1: stray DMA\r\n"); + wprintf("dvisampler0: slot1: stray DMA\n"); #ifdef CLEAN_COMMUTATION if((hdmi_in0_resdetection_hres_read() != hdmi_in0_hres) @@ -75,7 +73,7 @@ void hdmi_in0_isr(void) hdmi_in0_next_fb_index = (hdmi_in0_next_fb_index + 1) & FRAMEBUFFER_MASK; } else { #ifdef DEBUG - wprintf("dvisampler0: slot0: unexpected frame length: %d\r\n", length); + wprintf("dvisampler0: slot0: unexpected frame length: %d\n", length); #endif } hdmi_in0_dma_slot0_address_write(hdmi_in0_framebuffer_base(hdmi_in0_fb_slot_indexes[0])); @@ -89,7 +87,7 @@ void hdmi_in0_isr(void) hdmi_in0_next_fb_index = (hdmi_in0_next_fb_index + 1) & FRAMEBUFFER_MASK; } else { #ifdef DEBUG - wprintf("dvisampler0: slot1: unexpected frame length: %d\r\n", length); + wprintf("dvisampler0: slot1: unexpected frame length: %d\n", length); #endif } hdmi_in0_dma_slot1_address_write(hdmi_in0_framebuffer_base(hdmi_in0_fb_slot_indexes[1])); @@ -180,7 +178,7 @@ void hdmi_in0_print_status(void) hdmi_in0_data0_wer_update_write(1); hdmi_in0_data1_wer_update_write(1); hdmi_in0_data2_wer_update_write(1); - wprintf("dvisampler0: ph:%4d %4d %4d // charsync:%d%d%d [%d %d %d] // WER:%3d %3d %3d // chansync:%d // res:%dx%d\r\n", + wprintf("dvisampler0: ph:%4d %4d %4d // charsync:%d%d%d [%d %d %d] // WER:%3d %3d %3d // chansync:%d // res:%dx%d\n", hdmi_in0_d0, hdmi_in0_d1, hdmi_in0_d2, hdmi_in0_data0_charsync_char_synced_read(), hdmi_in0_data1_charsync_char_synced_read(), @@ -207,7 +205,7 @@ static int wait_idelays(void) || hdmi_in0_data1_cap_dly_busy_read() || hdmi_in0_data2_cap_dly_busy_read()) { if(elapsed(&ev, SYSTEM_CLOCK_FREQUENCY >> 6) == 0) { - wprintf("dvisampler0: IDELAY busy timeout (%hhx %hhx %hhx)\r\n", + wprintf("dvisampler0: IDELAY busy timeout (%hhx %hhx %hhx)\n", hdmi_in0_data0_cap_dly_busy_read(), hdmi_in0_data1_cap_dly_busy_read(), hdmi_in0_data2_cap_dly_busy_read()); @@ -367,16 +365,16 @@ int hdmi_in0_phase_startup(int freq) attempts++; hdmi_in0_calibrate_delays(freq); if(hdmi_in0_debug) - wprintf("dvisampler0: delays calibrated\r\n"); + wprintf("dvisampler0: delays calibrated\n"); ret = hdmi_in0_init_phase(); if(ret) { if(hdmi_in0_debug) - wprintf("dvisampler0: phase init OK\r\n"); + wprintf("dvisampler0: phase init OK\n"); return 1; } else { - wprintf("dvisampler0: phase init failed\r\n"); + wprintf("dvisampler0: phase init failed\n"); if(attempts > 3) { - wprintf("dvisampler0: giving up\r\n"); + wprintf("dvisampler0: giving up\n"); hdmi_in0_calibrate_delays(freq); return 0; } @@ -387,7 +385,7 @@ int hdmi_in0_phase_startup(int freq) static void hdmi_in0_check_overflow(void) { if(hdmi_in0_frame_overflow_read()) { - wprintf("dvisampler0: FIFO overflow\r\n"); + wprintf("dvisampler0: FIFO overflow\n"); hdmi_in0_frame_overflow_write(1); } } @@ -422,7 +420,7 @@ void hdmi_in0_service(int freq) if(hdmi_in0_connected) { if(!hdmi_in0_edid_hpd_notif_read()) { if(hdmi_in0_debug) - wprintf("dvisampler0: disconnected\r\n"); + wprintf("dvisampler0: disconnected\n"); hdmi_in0_connected = 0; hdmi_in0_locked = 0; #ifdef CSR_HDMI_IN0_CLOCKING_PLL_RESET_ADDR @@ -441,14 +439,14 @@ void hdmi_in0_service(int freq) } } else { if(hdmi_in0_debug) - wprintf("dvisampler0: lost PLL lock\r\n"); + wprintf("dvisampler0: lost PLL lock\n"); hdmi_in0_locked = 0; hdmi_in0_clear_framebuffers(); } } else { if(hdmi_in0_clocking_locked_filtered()) { if(hdmi_in0_debug) - wprintf("dvisampler0: PLL locked\r\n"); + wprintf("dvisampler0: PLL locked\n"); hdmi_in0_phase_startup(freq); if(hdmi_in0_debug) hdmi_in0_print_status(); @@ -459,7 +457,7 @@ void hdmi_in0_service(int freq) } else { if(hdmi_in0_edid_hpd_notif_read()) { if(hdmi_in0_debug) - wprintf("dvisampler0: connected\r\n"); + wprintf("dvisampler0: connected\n"); hdmi_in0_connected = 1; #ifdef CSR_HDMI_IN0_CLOCKING_PLL_RESET_ADDR hdmi_in0_clocking_pll_reset_write(0); diff --git a/firmware/hdmi_in0.h b/firmware/hdmi_in0.h index bc618067..9dbe4848 100644 --- a/firmware/hdmi_in0.h +++ b/firmware/hdmi_in0.h @@ -4,6 +4,13 @@ #ifndef __HDMI_IN0_H #define __HDMI_IN0_H +#ifdef HDMI_IN0_INDEX +#error "HDMI_IN0_INDEX already defined!" +#endif + +#define HDMI_IN0_INDEX 0 +#define HDMI_IN0_FRAMEBUFFERS_BASE FRAMEBUFFER_BASE_HDMI_INPUT(HDMI_IN0_INDEX) + extern int hdmi_in0_debug; extern int hdmi_in0_fb_index; diff --git a/firmware/hdmi_out0.c b/firmware/hdmi_out0.c index 5bdc1356..2845c3b0 100644 --- a/firmware/hdmi_out0.c +++ b/firmware/hdmi_out0.c @@ -16,7 +16,7 @@ void hdmi_out0_i2c_init(void) { hdmi_out0_i2c.w_write = hdmi_out0_i2c_w_write; hdmi_out0_i2c.r_read = hdmi_out0_i2c_r_read; i2c_init(&hdmi_out0_i2c); - wprintf("finished.\r\n"); + wprintf("finished.\n"); } void hdmi_out0_print_edid(void) { @@ -27,42 +27,42 @@ void hdmi_out0_print_edid(void) { i2c_start_cond(&hdmi_out0_i2c); b = i2c_write(&hdmi_out0_i2c, 0xa0); if (!b && hdmi_out0_debug_enabled) - wprintf("hdmi_out0: NACK while writing slave address!\r\n"); + wprintf("hdmi_out0: NACK while writing slave address!\n"); b = i2c_write(&hdmi_out0_i2c, 0x00); if (!b && hdmi_out0_debug_enabled) - wprintf("hdmi_out0: NACK while writing eeprom address!\r\n"); + wprintf("hdmi_out0: NACK while writing eeprom address!\n"); i2c_start_cond(&hdmi_out0_i2c); b = i2c_write(&hdmi_out0_i2c, 0xa1); if (!b && hdmi_out0_debug_enabled) - wprintf("hdmi_out0: NACK while writing slave address (2)!\r\n"); + wprintf("hdmi_out0: NACK while writing slave address (2)!\n"); for (eeprom_addr = 0 ; eeprom_addr < 128 ; eeprom_addr++) { b = i2c_read(&hdmi_out0_i2c, eeprom_addr == 127 && extension_number == 0 ? 0 : 1); sum +=b; wprintf("%02X ", b); if(!((eeprom_addr+1) % 16)) - wprintf("\r\n"); + wprintf("\n"); if(eeprom_addr == 126) extension_number = b; if(eeprom_addr == 127 && sum != 0) { - wprintf("Checksum ERROR in EDID block 0\r\n"); + wprintf("Checksum ERROR in EDID block 0\n"); i2c_stop_cond(&hdmi_out0_i2c); return; } } for(e = 0; e < extension_number; e++) { - wprintf("\r\n"); + wprintf("\n"); sum = 0; for (eeprom_addr = 0 ; eeprom_addr < 128 ; eeprom_addr++) { b = i2c_read(&hdmi_out0_i2c, eeprom_addr == 127 && e == extension_number - 1 ? 0 : 1); sum += b; wprintf("%02X ", b); if(!((eeprom_addr+1) % 16)) - wprintf("\r\n"); + wprintf("\n"); if(eeprom_addr == 127 && sum != 0) { - wprintf("Checksum ERROR in EDID extension block %d\r\n", e); + wprintf("Checksum ERROR in EDID extension block %d\n", e); i2c_stop_cond(&hdmi_out0_i2c); return; } diff --git a/firmware/hdmi_out1.c b/firmware/hdmi_out1.c index 8fc16531..1733617f 100644 --- a/firmware/hdmi_out1.c +++ b/firmware/hdmi_out1.c @@ -16,7 +16,7 @@ void hdmi_out1_i2c_init(void) { hdmi_out1_i2c.w_write = hdmi_out1_i2c_w_write; hdmi_out1_i2c.r_read = hdmi_out1_i2c_r_read; i2c_init(&hdmi_out1_i2c); - wprintf("finished.\r\n"); + wprintf("finished.\n"); } void hdmi_out1_print_edid(void) { @@ -27,42 +27,42 @@ void hdmi_out1_print_edid(void) { i2c_start_cond(&hdmi_out1_i2c); b = i2c_write(&hdmi_out1_i2c, 0xa0); if (!b && hdmi_out1_debug_enabled) - wprintf("hdmi_out1: NACK while writing slave address!\r\n"); + wprintf("hdmi_out1: NACK while writing slave address!\n"); b = i2c_write(&hdmi_out1_i2c, 0x00); if (!b && hdmi_out1_debug_enabled) - wprintf("hdmi_out1: NACK while writing eeprom address!\r\n"); + wprintf("hdmi_out1: NACK while writing eeprom address!\n"); i2c_start_cond(&hdmi_out1_i2c); b = i2c_write(&hdmi_out1_i2c, 0xa1); if (!b && hdmi_out1_debug_enabled) - wprintf("hdmi_out1: NACK while writing slave address (2)!\r\n"); + wprintf("hdmi_out1: NACK while writing slave address (2)!\n"); for (eeprom_addr = 0 ; eeprom_addr < 128 ; eeprom_addr++) { b = i2c_read(&hdmi_out1_i2c, eeprom_addr == 127 && extension_number == 0 ? 0 : 1); sum +=b; wprintf("%02X ", b); if(!((eeprom_addr+1) % 16)) - wprintf("\r\n"); + wputchar('\n'); if(eeprom_addr == 126) extension_number = b; if(eeprom_addr == 127 && sum != 0) { - wprintf("Checksum ERROR in EDID block 0\r\n"); + wprintf("Checksum ERROR in EDID block 0\n"); i2c_stop_cond(&hdmi_out1_i2c); return; } } for(e = 0; e < extension_number; e++) { - wprintf("\r\n"); + wputchar('\n'); sum = 0; for (eeprom_addr = 0 ; eeprom_addr < 128 ; eeprom_addr++) { b = i2c_read(&hdmi_out1_i2c, eeprom_addr == 127 && e == extension_number - 1 ? 0 : 1); sum += b; wprintf("%02X ", b); if(!((eeprom_addr+1) % 16)) - wprintf("\r\n"); + wputchar('\n'); if(eeprom_addr == 127 && sum != 0) { - wprintf("Checksum ERROR in EDID extension block %d\r\n", e); + wprintf("Checksum ERROR in EDID extension block %d\n", e); i2c_stop_cond(&hdmi_out1_i2c); return; } diff --git a/firmware/main.c b/firmware/main.c index efa18148..6d0dcb62 100644 --- a/firmware/main.c +++ b/firmware/main.c @@ -58,7 +58,7 @@ int main(void) irq_setie(1); uart_init(); - wputs("HDMI2USB firmware booting...\r\n"); + wputs("HDMI2USB firmware booting...\n"); #ifdef CSR_OPSIS_I2C_MASTER_W_ADDR opsis_eeprom_i2c_init(); diff --git a/firmware/mdio.c b/firmware/mdio.c index 2344bab6..f417fc8a 100644 --- a/firmware/mdio.c +++ b/firmware/mdio.c @@ -93,7 +93,6 @@ void mdio_dump(void) { int mdio_status(void) { int status; - mdio_dump(); status = mdio_read(0, 17); diff --git a/firmware/mmcm.c b/firmware/mmcm.c index 7e73d31b..241401f7 100644 --- a/firmware/mmcm.c +++ b/firmware/mmcm.c @@ -2,97 +2,120 @@ #include #include "mmcm.h" +#include "stdio_wrap.h" /* * Despite varying pixel clocks, we must keep the PLL VCO operating * in the specified range of 600MHz - 1200MHz. */ -#ifdef CSR_HDMI_OUT0_CLOCKING_MMCM_RESET_ADDR -void hdmi_out0_mmcm_write(int adr, int data) { +#ifdef CSR_HDMI_OUT0_DRIVER_CLOCKING_MMCM_RESET_ADDR +void hdmi_out0_driver_clocking_mmcm_write(int adr, int data) +{ hdmi_out0_driver_clocking_mmcm_adr_write(adr); hdmi_out0_driver_clocking_mmcm_dat_w_write(data); hdmi_out0_driver_clocking_mmcm_write_write(1); while(!hdmi_out0_driver_clocking_mmcm_drdy_read()); } -int hdmi_out0_mmcm_read(int adr) { +int hdmi_out0_driver_clocking_mmcm_read(int adr) +{ hdmi_out0_driver_clocking_mmcm_adr_write(adr); hdmi_out0_driver_clocking_mmcm_read_write(1); while(!hdmi_out0_driver_clocking_mmcm_drdy_read()); return hdmi_out0_driver_clocking_mmcm_dat_r_read(); } + +MMCM hdmi_out0_driver_clocking_mmcm = { + .write = &hdmi_out0_driver_clocking_mmcm_write, + .read = &hdmi_out0_driver_clocking_mmcm_read, +}; #endif #ifdef CSR_HDMI_IN0_CLOCKING_MMCM_RESET_ADDR -void hdmi_in0_clocking_mmcm_write(int adr, int data) { +void hdmi_in0_clocking_mmcm_write(int adr, int data) +{ hdmi_in0_clocking_mmcm_adr_write(adr); hdmi_in0_clocking_mmcm_dat_w_write(data); hdmi_in0_clocking_mmcm_write_write(1); while(!hdmi_in0_clocking_mmcm_drdy_read()); } -int hdmi_in0_clocking_mmcm_read(int adr) { +int hdmi_in0_clocking_mmcm_read(int adr) +{ hdmi_in0_clocking_mmcm_adr_write(adr); hdmi_in0_clocking_mmcm_read_write(1); while(!hdmi_in0_clocking_mmcm_drdy_read()); return hdmi_in0_clocking_mmcm_dat_r_read(); } -static void hdmi_in_0_config_30_60mhz(void) { - hdmi_in0_clocking_mmcm_write(0x14, 0x1000 | (10<<6) | 10); /* clkfbout_mult = 20 */ - hdmi_in0_clocking_mmcm_write(0x08, 0x1000 | (10<<6) | 10); /* clkout0_divide = 20 */ - hdmi_in0_clocking_mmcm_write(0x0a, 0x1000 | (8<<6) | 8); /* clkout1_divide = 16 */ - hdmi_in0_clocking_mmcm_write(0x0c, 0x1000 | (2<<6) | 2); /* clkout2_divide = 4 */ - hdmi_in0_clocking_mmcm_write(0x0d, 0); /* clkout2_divide = 4 */ +MMCM hdmi_in0_clocking_mmcm = { + .write = &hdmi_in0_clocking_mmcm_write, + .read = &hdmi_in0_clocking_mmcm_read, +}; +#endif + +static void mmcm_config_30to60mhz(MMCM *mmcm) +{ + mmcm->write(0x14, 0x1000 | (10<<6) | 10); /* clkfbout_mult = 20 */ + mmcm->write(0x08, 0x1000 | (10<<6) | 10); /* clkout0_divide = 20 */ + mmcm->write(0x0a, 0x1000 | (8<<6) | 8); /* clkout1_divide = 16 */ + mmcm->write(0x0c, 0x1000 | (2<<6) | 2); /* clkout2_divide = 4 */ + mmcm->write(0x0d, 0); /* clkout2_divide = 4 */ } -static void hdmi_in_0_config_60_120mhz(void) { - hdmi_in0_clocking_mmcm_write(0x14, 0x1000 | (5<<6) | 5); /* clkfbout_mult = 10 */ - hdmi_in0_clocking_mmcm_write(0x08, 0x1000 | (5<<6) | 5); /* clkout0_divide = 10 */ - hdmi_in0_clocking_mmcm_write(0x0a, 0x1000 | (4<<6) | 4); /* clkout1_divide = 8 */ - hdmi_in0_clocking_mmcm_write(0x0c, 0x1000 | (1<<6) | 1); /* clkout2_divide = 2 */ - hdmi_in0_clocking_mmcm_write(0x0d, 0); /* clkout2_divide = 2 */ +static void mmcm_config_60to120mhz(MMCM *mmcm) +{ + mmcm->write(0x14, 0x1000 | (5<<6) | 5); /* clkfbout_mult = 10 */ + mmcm->write(0x08, 0x1000 | (5<<6) | 5); /* clkout0_divide = 10 */ + mmcm->write(0x0a, 0x1000 | (4<<6) | 4); /* clkout1_divide = 8 */ + mmcm->write(0x0c, 0x1000 | (1<<6) | 1); /* clkout2_divide = 2 */ + mmcm->write(0x0d, 0); /* clkout2_divide = 2 */ } -static void hdmi_in_0_config_120_240mhz(void) { - hdmi_in0_clocking_mmcm_write(0x14, 0x1000 | (2<<6) | 3); /* clkfbout_mult = 5 */ - hdmi_in0_clocking_mmcm_write(0x08, 0x1000 | (2<<6) | 3); /* clkout0_divide = 5 */ - hdmi_in0_clocking_mmcm_write(0x0a, 0x1000 | (2<<6) | 2); /* clkout1_divide = 4 */ - hdmi_in0_clocking_mmcm_write(0x0c, 0x1000 | (0<<6) | 0); /* clkout2_divide = 1 */ - hdmi_in0_clocking_mmcm_write(0x0d, (1<<6)); /* clkout2_divide = 1 */ +static void mmcm_config_120to240mhz(MMCM *mmcm) +{ + mmcm->write(0x14, 0x1000 | (2<<6) | 3); /* clkfbout_mult = 5 */ + mmcm->write(0x08, 0x1000 | (2<<6) | 3); /* clkout0_divide = 5 */ + mmcm->write(0x0a, 0x1000 | (2<<6) | 2); /* clkout1_divide = 4 */ + mmcm->write(0x0c, 0x1000 | (0<<6) | 0); /* clkout2_divide = 1 */ + mmcm->write(0x0d, (1<<6)); /* clkout2_divide = 1 */ } -void mmcm_config_for_clock(int freq) +void mmcm_config_for_clock(MMCM *mmcm, int freq) { /* * FIXME: we also need to configure phase detector */ if(freq < 3000) - printf("Frequency too low for input MMCMs\r\n"); + wprintf("Frequency too low for input MMCMs\n"); else if(freq < 6000) - hdmi_in_0_config_30_60mhz(); + mmcm_config_30to60mhz(mmcm); else if(freq < 12000) - hdmi_in_0_config_60_120mhz(); + mmcm_config_60to120mhz(mmcm); else if(freq < 24000) - hdmi_in_0_config_120_240mhz(); + mmcm_config_120to240mhz(mmcm); else - printf("Frequency too high for input MMCMs\r\n"); + wprintf("Frequency too high for input MMCMs\n"); } -#endif -void mmcm_dump(void) +void mmcm_dump(MMCM* mmcm) { int i; -#ifdef CSR_HDMI_OUT0_CLOCKING_MMCM_RESET_ADDR - printf("framebuffer MMCM:\r\n"); for(i=0;i<128;i++) - printf("%04x ", hdmi_out0_mmcm_read(i)); - printf("\r\n"); + printf("%04x ", mmcm->read(i)); + +} +void mmcm_dump_all(void) +{ + int i; +#ifdef CSR_HDMI_OUT0_DRIVER_CLOCKING_MMCM_RESET_ADDR + printf("framebuffer MMCM:\n"); + mmcm_dump(&hdmi_out0_driver_clocking_mmcm); + printf("\n"); #endif #ifdef CSR_HDMI_IN0_CLOCKING_MMCM_RESET_ADDR - printf("dvisampler MMCM:\r\n"); - for(i=0;i<128;i++) - printf("%04x ", hdmi_in0_clocking_mmcm_read(i)); - printf("\r\n"); + printf("dvisampler MMCM:\n"); + mmcm_dump(&hdmi_in0_clocking_mmcm); + printf("\n"); #endif } diff --git a/firmware/mmcm.h b/firmware/mmcm.h index 4912b6fc..3dd3b406 100644 --- a/firmware/mmcm.h +++ b/firmware/mmcm.h @@ -3,16 +3,28 @@ #include -#ifdef CSR_HDMI_IN0_CLOCKING_MMCM_RESET_ADDR +typedef void (*mmcm_write_t)(int,int); +typedef int (*mmcm_read_t)(int); -void hdmi_out0_mmcm_write(int adr, int data); -int hdmi_out0_mmcm_read(int adr); -void hdmi_in0_clocking_mmcm_write(int adr, int data); -int hdmi_in0_clocking_mmcm_read(int adr); +typedef struct { + mmcm_write_t write; + mmcm_read_t read; +} MMCM; + +void mmcm_config_for_clock(MMCM *mmcm, int freq); +void mmcm_dump(MMCM *mmcm); +void mmcm_dump_all(void); -void mmcm_config_for_clock(int freq); +#ifdef CSR_HDMI_OUT0_DRIVER_CLOCKING_MMCM_RESET_ADDR +void hdmi_out0_driver_clocking_mmcm_write(int adr, int data); +int hdmi_out0_driver_clocking_mmcm_read(int adr); +extern MMCM hdmi_out0_driver_clocking_mmcm; #endif -void mmcm_dump(void); +#ifdef CSR_HDMI_IN0_CLOCKING_MMCM_RESET_ADDR +void hdmi_in0_clocking_mmcm_write(int adr, int data); +int hdmi_in0_clocking_mmcm_read(int adr); +extern MMCM hdmi_in0_clocking_mmcm; +#endif #endif diff --git a/firmware/opsis_eeprom.c b/firmware/opsis_eeprom.c index 1cb10313..b096d381 100644 --- a/firmware/opsis_eeprom.c +++ b/firmware/opsis_eeprom.c @@ -16,7 +16,7 @@ void opsis_eeprom_i2c_init(void) { opsis_eeprom_i2c.r_read = opsis_i2c_master_r_read; OPSIS_I2C_ACTIVE(OPSIS_I2C_GPIO); i2c_init(&opsis_eeprom_i2c); - wprintf("finished.\r\n"); + wprintf("finished.\n"); } static void opsis_eeprom_read(uint8_t addr) { @@ -29,16 +29,16 @@ static void opsis_eeprom_read(uint8_t addr) { i2c_start_cond(&opsis_eeprom_i2c); b = i2c_write(&opsis_eeprom_i2c, OPSIS_EEPROM_SLAVE_ADDRESS | I2C_WRITE); if (!b && opsis_eeprom_debug_enabled) - wprintf("opsis_eeprom: NACK while writing slave address!\r\n"); + wprintf("opsis_eeprom: NACK while writing slave address!\n"); b = i2c_write(&opsis_eeprom_i2c, addr); if (!b && opsis_eeprom_debug_enabled) - wprintf("opsis_eeprom: NACK while writing opsis_eeprom address!\r\n"); + wprintf("opsis_eeprom: NACK while writing opsis_eeprom address!\n"); // Read data from I2C EEPROM i2c_start_cond(&opsis_eeprom_i2c); b = i2c_write(&opsis_eeprom_i2c, OPSIS_EEPROM_SLAVE_ADDRESS | I2C_READ); if (!b && opsis_eeprom_debug_enabled) - wprintf("opsis_eeprom: NACK while writing slave address (2)!\r\n"); + wprintf("opsis_eeprom: NACK while writing slave address (2)!\n"); } void opsis_eeprom_dump(void) { @@ -47,7 +47,7 @@ void opsis_eeprom_dump(void) { unsigned char b = i2c_read(&opsis_eeprom_i2c, 1); wprintf("%02X ", b); if(!((i+1) % 16)) - wprintf("\r\n"); + wputchar('\n'); } i2c_stop_cond(&opsis_eeprom_i2c); } diff --git a/firmware/pattern.c b/firmware/pattern.c index 7354d13d..1e7a8a4b 100644 --- a/firmware/pattern.c +++ b/firmware/pattern.c @@ -12,10 +12,8 @@ #include "uptime.h" #include "version_data.h" -#define PATTERN_FRAMEBUFFER_BASE 0x02000000 + 0x100000 - unsigned int pattern_framebuffer_base(void) { - return PATTERN_FRAMEBUFFER_BASE; + return FRAMEBUFFER_BASE_PATTERN; } static const unsigned int color_bar[8] = { @@ -134,9 +132,10 @@ static int inc_color(int color) { } static void pattern_draw_text_color(int x, int y, char *ptr, long background_color, long text_color) { +#ifdef MAIN_RAM_BASE int i, j, k; int adr; - volatile unsigned int *framebuffer = (unsigned int *)(MAIN_RAM_BASE + PATTERN_FRAMEBUFFER_BASE); + volatile unsigned int *framebuffer = (unsigned int *)(MAIN_RAM_BASE + pattern_framebuffer_base()); for(i=0; ptr[i] != '\0'; i++) { for(j=-1; j<8; j++) { for(k=-1; k<6; k++) { @@ -151,6 +150,8 @@ static void pattern_draw_text_color(int x, int y, char *ptr, long background_col } } } +/* FIXME: Framebuffer Should not even be compiled if no MAIN RAM */ +#endif } static void pattern_draw_text(int x, int y, char *ptr) { @@ -159,19 +160,20 @@ static void pattern_draw_text(int x, int y, char *ptr) { void pattern_next(void) { pattern++; - pattern = pattern % MAX_PATTERN; + pattern = pattern % PATTERN_MAX; pattern_fill_framebuffer(processor_h_active, processor_v_active); } void pattern_fill_framebuffer(int h_active, int w_active) { +#ifdef MAIN_RAM_BASE int i, j; int color; flush_l2_cache(); color = -1; - volatile unsigned int *framebuffer = (unsigned int *)(MAIN_RAM_BASE + PATTERN_FRAMEBUFFER_BASE); - if(pattern == COLOR_BAR_PATTERN) { + volatile unsigned int *framebuffer = (unsigned int *)(MAIN_RAM_BASE + pattern_framebuffer_base()); + if(pattern == PATTERN_COLOR_BARS) { /* color bar pattern */ for(i=0; i hdmi_out0_driver_clocking_clkfx_md_max_1000_read()) { wprintf( - "WARNING: md1000 (%d) > (%d)\r\n", + "WARNING: md1000 (%d) > (%d)\n", md1000, hdmi_out0_driver_clocking_clkfx_md_max_1000_read()); } @@ -510,7 +504,7 @@ static void fb_set_clock(unsigned int pixel_clock) hdmi_out0_driver_clocking_send_go_write(1); while(!(hdmi_out0_driver_clocking_status_read() & CLKGEN_STATUS_PROGDONE)); while(!(hdmi_out0_driver_clocking_status_read() & CLKGEN_STATUS_LOCKED)); -#elif CSR_HDMI_OUT0_CLOCKING_MMCM_RESET_ADDR +#elif CSR_HDMI_OUT0_DRIVER_CLOCKING_MMCM_RESET_ADDR fb_clkgen_write(clock_m, clock_d); #endif } @@ -521,8 +515,6 @@ static void fb_set_mode(const struct video_timing *mode) unsigned int hdmi_out0_enabled; unsigned int hdmi_out1_enabled; - fb_set_clock(mode->pixel_clock); - #ifdef CSR_HDMI_OUT0_BASE if (hdmi_out0_core_initiator_enable_read()) { hdmi_out0_enabled = 1; @@ -560,6 +552,8 @@ static void fb_set_mode(const struct video_timing *mode) hdmi_out1_core_initiator_enable_write(hdmi_out1_enabled); #endif + + fb_set_clock(mode->pixel_clock); } static void edid_set_mode(const struct video_timing *mode, const struct video_timing *sec_mode) @@ -592,7 +586,7 @@ void processor_init(int sec_mode) encoder_enable(0); encoder_target_fps = 30; #endif - pattern = COLOR_BAR_PATTERN; + pattern = PATTERN_COLOR_BARS; processor_secondary_mode = sec_mode; } @@ -622,7 +616,7 @@ void processor_start(int mode) #ifdef CSR_HDMI_OUT1_BASE hdmi_out1_core_initiator_enable_write(0); #endif -#ifdef CSR_HDMI_IN0_CLOCKING_MMCM_RESET_ADDR +#ifdef CSR_HDMI_OUT0_DRIVER_CLOCKING_MMCM_RESET_ADDR hdmi_out0_driver_clocking_mmcm_reset_write(1); #endif #ifdef CSR_HDMI_OUT0_DRIVER_CLOCKING_PLL_RESET_ADDR @@ -649,8 +643,8 @@ void processor_start(int mode) #ifdef CSR_HDMI_OUT0_DRIVER_CLOCKING_PLL_RESET_ADDR pll_config_for_clock(m->pixel_clock); -#elif CSR_HDMI_OUT0_DRIVER_CLOCKING_DRP_DWE_ADDR - mmcm_config_for_clock(m->pixel_clock); +#elif CSR_HDMI_OUT0_DRIVER_CLOCKING_MMCM_RESET_ADDR + mmcm_config_for_clock(&hdmi_out0_driver_clocking_mmcm, m->pixel_clock); #endif fb_set_mode(m); @@ -665,7 +659,7 @@ void processor_start(int mode) #ifdef CSR_HDMI_OUT0_DRIVER_CLOCKING_PLL_RESET_ADDR hdmi_out0_driver_clocking_pll_reset_write(0); -#elif CSR_HDMI_OUT0_DRIVER_CLOCKING_DRP_DWE_ADDR +#elif CSR_HDMI_OUT0_DRIVER_CLOCKING_MMCM_RESET_ADDR hdmi_out0_driver_clocking_mmcm_reset_write(0); #endif #ifdef CSR_HDMI_OUT0_BASE diff --git a/firmware/stdio_wrap.c b/firmware/stdio_wrap.c index 800e18a9..333d8ef6 100644 --- a/firmware/stdio_wrap.c +++ b/firmware/stdio_wrap.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -9,14 +10,56 @@ #include "stdio_wrap.h" +/* Transform LF -> CRLF in s, putting the result in stdio_write_buffer + */ +char *translate_crlf(const char *s, int trailing_lf) { + assert(tailing_lf == 0 || trailing_lf == 1); + char *out = stdio_write_buffer; + char *end = stdio_write_buffer + STDIO_BUFFER_SIZE - 2 - trailing_lf; + while (*s != '\0' && out < end) { + if (*s == '\n') { + assert(out < end); + *out++ = '\r'; + } + assert(out < end); + *out++ = *s++; + } + if (trailing_lf) { + *out++ = '\r'; + } + *out++ = '\0'; + return stdio_write_buffer; +} + int wputs(const char *s) { + char *s_crlf = translate_crlf(s, 1); #ifdef ETHMAC_BASE if(telnet_active) - telnet_puts(s); + telnet_puts(s_crlf); else #endif - puts(s); + puts(s_crlf); + return 0; +} + +int wputchar(int c) +{ +#ifdef ETHMAC_BASE + if(telnet_active) { + if(c == '\n') { + telnet_putchar('\r'); + } + telnet_putchar(c); + } else { +#endif + if(c == '\n') { + putchar('\r'); + } + putchar(c); +#ifdef ETHMAC_BASE + } +#endif return 0; } @@ -26,12 +69,15 @@ int wprintf(const char *fmt, ...) int len; va_list args; va_start(args, fmt); + + char *fmt_crlf = translate_crlf(fmt, 0); + #ifdef ETHMAC_BASE if(telnet_active) - len = telnet_vprintf(fmt, args); + len = telnet_vprintf(fmt_crlf, args); else #endif - len = vprintf(fmt, args); + len = vprintf(fmt_crlf, args); va_end(args); return len; } diff --git a/firmware/stdio_wrap.h b/firmware/stdio_wrap.h index b83f425c..5f1d51b4 100644 --- a/firmware/stdio_wrap.h +++ b/firmware/stdio_wrap.h @@ -1,6 +1,12 @@ #include +#define STDIO_BUFFER_SIZE 256 +char stdio_write_buffer[STDIO_BUFFER_SIZE]; + +char *translate_crlf(const char *s, int trailing_lf); + int wputs(const char *s); +int wputchar(int c); int wprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); void wputsnonl(const char *s); diff --git a/firmware/telnet.c b/firmware/telnet.c index 278ff456..21db6859 100644 --- a/firmware/telnet.c +++ b/firmware/telnet.c @@ -23,7 +23,7 @@ void telnet_init(void) (tcp_socket_data_callback_t) telnet_data_callback, (tcp_socket_event_callback_t) telnet_event_callback); tcp_socket_listen(&telnet_socket, TELNET_PORT); - printf("Telnet listening on port %d\n", TELNET_PORT); + printf("Telnet listening on port %d\r\n", TELNET_PORT); } int telnet_event_callback(struct tcp_socket *s, void *ptr, tcp_socket_event_t event) @@ -31,13 +31,13 @@ int telnet_event_callback(struct tcp_socket *s, void *ptr, tcp_socket_event_t ev switch(event) { case TCP_SOCKET_CONNECTED: - printf("\nTelnet connected.\n"); + printf("\r\nTelnet connected.\r\n"); telnet_active = 1; break; case TCP_SOCKET_CLOSED: case TCP_SOCKET_TIMEDOUT: case TCP_SOCKET_ABORTED: - printf("\nTelnet disconnected.\n"); + printf("\r\nTelnet disconnected.\r\n"); telnet_active = 0; default: break; diff --git a/firmware/telnet.h b/firmware/telnet.h index 6aa03229..549bb08d 100644 --- a/firmware/telnet.h +++ b/firmware/telnet.h @@ -18,8 +18,8 @@ #endif #define TELNET_PORT 23 -#define TELNET_BUFFER_SIZE_RX 1512 -#define TELNET_BUFFER_SIZE_TX 1512 +#define TELNET_BUFFER_SIZE_RX 4096 +#define TELNET_BUFFER_SIZE_TX 4096 int telnet_active; diff --git a/firmware/tofe_eeprom.c b/firmware/tofe_eeprom.c index 6007f305..27408097 100644 --- a/firmware/tofe_eeprom.c +++ b/firmware/tofe_eeprom.c @@ -13,7 +13,7 @@ void tofe_eeprom_i2c_init(void) { tofe_eeprom_i2c.w_write = tofe_i2c_w_write; tofe_eeprom_i2c.r_read = tofe_i2c_r_read; i2c_init(&tofe_eeprom_i2c); - wprintf("finished.\r\n"); + wprintf("finished.\n"); } void tofe_eeprom_dump(void) { @@ -23,21 +23,21 @@ void tofe_eeprom_dump(void) { i2c_start_cond(&tofe_eeprom_i2c); b = i2c_write(&tofe_eeprom_i2c, 0xa0); if (!b && tofe_eeprom_debug_enabled) - wprintf("tofe_eeprom: NACK while writing slave address!\r\n"); + wprintf("tofe_eeprom: NACK while writing slave address!\n"); b = i2c_write(&tofe_eeprom_i2c, 0x00); if (!b && tofe_eeprom_debug_enabled) - wprintf("tofe_eeprom: NACK while writing tofe_eeprom address!\r\n"); + wprintf("tofe_eeprom: NACK while writing tofe_eeprom address!\n"); i2c_start_cond(&tofe_eeprom_i2c); b = i2c_write(&tofe_eeprom_i2c, 0xa1); if (!b && tofe_eeprom_debug_enabled) - wprintf("tofe_eeprom: NACK while writing slave address (2)!\r\n"); + wprintf("tofe_eeprom: NACK while writing slave address (2)!\n"); for (tofe_eeprom_addr = 0 ; tofe_eeprom_addr < 256 ; tofe_eeprom_addr++) { b = i2c_read(&tofe_eeprom_i2c, 1); wprintf("%02X ", b); if(!((tofe_eeprom_addr+1) % 16)) - wprintf("\r\n"); + wputchar('\n'); } i2c_stop_cond(&tofe_eeprom_i2c); } diff --git a/firmware/uptime.c b/firmware/uptime.c index 4073c31b..e12378d6 100644 --- a/firmware/uptime.c +++ b/firmware/uptime.c @@ -25,7 +25,7 @@ int uptime(void) void uptime_print(void) { - wprintf("uptime: %s\r\n", uptime_str()); + wprintf("uptime: %s\n", uptime_str()); } const char* uptime_str(void) diff --git a/firmware/version.c b/firmware/version.c index 49a7967b..a568768e 100644 --- a/firmware/version.c +++ b/firmware/version.c @@ -23,8 +23,7 @@ static void print_csr_string(unsigned int addr, size_t size) { unsigned char c = MMPTR(ptr+i); if (c == '\0') return; - // FIXME: Wrap putchar - putchar(c); + wputchar(c); } } @@ -61,44 +60,44 @@ void print_board_mac(void) { } void print_version(void) { - wprintf("\r\n"); - wprintf("hardware version info\r\n"); - wprintf("===============================================\r\n"); + wputchar('\n'); + wprintf("hardware version info\n"); + wprintf("===============================================\n"); wprintf(" DNA: "); print_board_dna(); - wprintf("\r\n"); + wputchar('\n'); wprintf(" MAC: "); print_board_mac(); - wprintf("\r\n"); - wprintf("\r\n"); - wprintf("gateware version info\r\n"); - wprintf("===============================================\r\n"); + wputchar('\n'); + wputchar('\n'); + wprintf("gateware version info\n"); + wprintf("===============================================\n"); #ifdef CSR_INFO_PLATFORM_PLATFORM_ADDR wprintf(" platform: "); print_csr_string(CSR_INFO_PLATFORM_PLATFORM_ADDR, CSR_INFO_PLATFORM_PLATFORM_SIZE); - wprintf("\r\n"); + wputchar('\n'); #endif #ifdef CSR_INFO_PLATFORM_TARGET_ADDR wprintf(" target: "); print_csr_string(CSR_INFO_PLATFORM_TARGET_ADDR, CSR_INFO_PLATFORM_TARGET_SIZE); - wprintf("\r\n"); + wputchar('\n'); #endif #ifdef CSR_INFO_GIT_COMMIT_ADDR wprintf(" revision: "); print_csr_hex(CSR_INFO_GIT_COMMIT_ADDR, CSR_INFO_GIT_COMMIT_SIZE); - wprintf("\r\n"); + wputchar('\n'); #endif -// wprintf("misoc revision: %08x\r\n", identifier_revision_read()); - wprintf("\r\n"); - wprintf("firmware version info\r\n"); - wprintf("===============================================\r\n"); - wprintf(" platform: %s\r\n", board); - wprintf(" target: %s\r\n", target); - wprintf(" git commit: %s\r\n", git_commit); - wprintf(" git branch: %s\r\n", git_branch); - wprintf(" git describe: %s\r\n", git_describe); - wprintf(" git status:\r\n%s\r\n", git_status); - wprintf(" built: "__DATE__" "__TIME__"\r\n"); - wprintf(" uptime: %s\r\n", uptime_str()); - wprintf("-----------------------------------------------\r\n"); +// wprintf("misoc revision: %08x\n", identifier_revision_read()); + wputchar('\n'); + wprintf("firmware version info\n"); + wprintf("===============================================\n"); + wprintf(" platform: %s\n", board); + wprintf(" target: %s\n", target); + wprintf(" git commit: %s\n", git_commit); + wprintf(" git branch: %s\n", git_branch); + wprintf(" git describe: %s\n", git_describe); + wprintf(" git status:\n%s\n", git_status); + wprintf(" built: "__DATE__" "__TIME__"\n"); + wprintf(" uptime: %s\n", uptime_str()); + wprintf("-----------------------------------------------\n"); } diff --git a/firmware/version_data.py b/firmware/version_data.py new file mode 100644 index 00000000..bc67853c --- /dev/null +++ b/firmware/version_data.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python +""" +This file embeds in the firmware information like the git commit +number, git branch information and git status of the build tree. +""" + +import subprocess +import os +import sys +import io + +commit = subprocess.check_output( + ['git', 'log', '--format="%H"', '-n', '1']).decode('utf-8') +branch = subprocess.check_output( + ['git', 'symbolic-ref', '--short', 'HEAD']).decode('utf-8') +describe = subprocess.check_output( + ['git', 'describe', '--dirty']).decode('utf-8') +status = subprocess.check_output(['git', 'status', '--short']).decode('utf-8') +length = status.count('\n') + +if "PLATFORM" in os.environ: + platform = os.environ['PLATFORM'] +else: + sys.stderr.write("""\ + PLATFORM environment variable is not set. + + This script should only be run as part of LiteX Build Environment. + + Try 'source ./scripts/enter-env.sh' +""") + sys.exit(1) + +if "TARGET" in os.environ: + target = os.environ['TARGET'] +else: + sys.stderr.write("""\ + TARGET environment variable is not set. + + This script should only be run as part of LiteX Build Environment + + Try 'source ./scripts/enter-env.sh' +""") + sys.exit(1) + +temp_h = io.StringIO() +temp_h.write("""\ +#ifndef __VERSION_DATA_H +#define __VERSION_DATA_H + +extern const char* board; +extern const char* target; + +extern const char* git_commit; +extern const char* git_branch; +extern const char* git_describe; +extern const char* git_status; + +#endif // __VERSION_DATA_H""") +temp_h.seek(0) + +temp_c = io.StringIO() +temp_c.write("""\ +#ifndef PLATFORM_{UPLATFORM} +#error "Version mismatch - PLATFORM_{UPLATFORM} not defined!" +#endif +const char* board = "{PLATFORM}"; + +#ifndef TARGET_{UTARGET} +#error "Version mismatch - TARGET_{UTARGET} not defined!" +#endif +const char* target = "{TARGET}"; + +const char* git_commit = "{COMMIT}"; +const char* git_branch = "{BRANCH}"; +const char* git_describe = "{DESCRIBE}"; +const char* git_status = + " --\\r\\n" +""".format(UPLATFORM=platform.upper(), PLATFORM=platform, + UTARGET=target.upper(), TARGET=target, + COMMIT=commit[1:-2], BRANCH=branch[:-1], DESCRIBE=describe[:-1])) + +for line in range(0, length): + temp = status.splitlines()[line] + temp = ' " ' + temp + '\\r\\n"' + temp_c.write(temp) + temp_c.write('\n') +temp_c.write(' " --\\r\\n";') +temp_c.seek(0) + +try: + myfile = open("version_data.c", "r+") +except IOError: + myfile = open("version_data.c", "w+") +data = myfile.read() +data_c = temp_c.getvalue() +if not (dat a == data_c): + print("Updating version_data.c") + myfile.seek(0) + myfile.truncate(0) + myfile.write(data_c) +myfile.close() + +try: + myfile = open("version_data.h", "r+") +except IOError: + myfile = open("version_data.h", "w+") +data = myfile.read() +data_h = temp_h.getvalue() +if not (data == data_h): + print("Updating version_data.h") + myfile.seek(0) + myfile.truncate(0) + myfile.write(data_h) +myfile.close() + +temp_c.close() +temp_h.close() diff --git a/firmware/version_data.sh b/firmware/version_data.sh index da8af13e..17e06f26 100755 --- a/firmware/version_data.sh +++ b/firmware/version_data.sh @@ -7,8 +7,8 @@ COMMIT="$(git log --format="%H" -n 1)" BRANCH="$(git symbolic-ref --short HEAD)" DESCRIBE="$(git describe --dirty)" -TMPFILE_H=$(tempfile -s .h | mktemp --suffix=.h) -TMPFILE_C=$(tempfile -s .c | mktemp --suffix=.c) +TMPFILE_H=$(tempfile -s .h 2>/dev/null || mktemp --suffix=.h) +TMPFILE_C=$(tempfile -s .c 2>/dev/null || mktemp --suffix=.c) UPLATFORM="$(echo $PLATFORM | tr '[:lower:]' '[:upper:]')" UTARGET="$(echo $TARGET | tr '[:lower:]' '[:upper:]')" diff --git a/flash.py b/flash.py index 376bd61f..3ec2ed14 100755 --- a/flash.py +++ b/flash.py @@ -41,12 +41,12 @@ def main(): filename = make.get_firmware(builddir, "flash") address_start = platform.gateware_size + make.BIOS_SIZE - address_end = platform.gateware_size + address_end = platform.spiflash_total_size elif args.mode == 'other': - filename = args.other + filename = args.other_file address_start = args.address - address_end = platform.gateware_size + address_end = platform.spiflash_total_size else: assert False, "Unknown flashing mode." @@ -60,8 +60,8 @@ def main(): file_size = len(open(filepath, 'rb').read()) file_end = address_start+file_size - assert file_end < address_end, "File is too big!\n%s file doesn't fit in %s space." % ( - address_end - address_start, file_size) + assert file_end < address_end, "File is too big!\n%s file doesn't fit in %s space (%s extra bytes)." % ( + filename, file_size, address_end - address_start) prog = make.get_prog(args, platform) prog.flash(address_start, filepath) diff --git a/gateware/cas.py b/gateware/cas.py index 677d1725..70603b65 100644 --- a/gateware/cas.py +++ b/gateware/cas.py @@ -7,7 +7,7 @@ from litex.soc.interconnect.csr import AutoCSR from litex.soc.interconnect.csr_eventmanager import * -from litex.gen.genlib.misc import WaitTimer +from migen.genlib.misc import WaitTimer from litex.soc.cores.gpio import GPIOIn, GPIOOut diff --git a/gateware/encoder/core.py b/gateware/encoder/core.py index 31eb0e2e..bfff2a36 100644 --- a/gateware/encoder/core.py +++ b/gateware/encoder/core.py @@ -1,8 +1,8 @@ import os -from litex.gen import * -from litex.gen.genlib.cdc import MultiReg -from litex.gen.genlib.misc import chooser +from migen import * +from migen.genlib.cdc import MultiReg +from migen.genlib.misc import chooser from litex.soc.interconnect import wishbone from litex.soc.interconnect import stream @@ -29,7 +29,7 @@ def __init__(self, dram_port): burst_pixels = dram_port.dw//pixel_bits alignment_bits = bits_for(dram_port.dw//8) - 1 - self.comb += dma.source.connect(source) # XXX add Converter + self.comb += dma.source.connect(source) base = Signal(32) h_width = self.h_width.storage diff --git a/gateware/firmware.py b/gateware/firmware.py index f2a7b11c..7c50a3d4 100644 --- a/gateware/firmware.py +++ b/gateware/firmware.py @@ -1,7 +1,7 @@ import os import struct -from litex.gen import * +from migen import * from litex.soc.interconnect import wishbone diff --git a/gateware/freq_measurement.py b/gateware/freq_measurement.py index 4545b8de..c421cd18 100644 --- a/gateware/freq_measurement.py +++ b/gateware/freq_measurement.py @@ -1,6 +1,6 @@ -from litex.gen import * -from litex.gen.genlib.cdc import MultiReg, GrayCounter -from litex.gen.genlib.cdc import GrayDecoder +from migen import * +from migen.genlib.cdc import MultiReg, GrayCounter +from migen.genlib.cdc import GrayDecoder from litex.soc.interconnect.csr import * diff --git a/gateware/i2c.py b/gateware/i2c.py index 409da42a..24114271 100644 --- a/gateware/i2c.py +++ b/gateware/i2c.py @@ -1,6 +1,6 @@ -from litex.gen import * -from litex.gen.fhdl import * -from litex.gen.fhdl.specials import TSTriple +from migen import * +from migen.fhdl import * +from migen.fhdl.specials import TSTriple from litex.soc.interconnect.csr import * diff --git a/gateware/info/__init__.py b/gateware/info/__init__.py index bb4c92f5..2cc96869 100644 --- a/gateware/info/__init__.py +++ b/gateware/info/__init__.py @@ -3,7 +3,7 @@ """ from litex.build.generic_platform import ConstraintError -from litex.gen import * +from migen import * from litex.soc.interconnect.csr import * from gateware.info import git diff --git a/gateware/info/dna.py b/gateware/info/dna.py index 324659d7..879f938e 100644 --- a/gateware/info/dna.py +++ b/gateware/info/dna.py @@ -1,6 +1,6 @@ # Copyright 2014-2015 Robert Jordens -from litex.gen import * +from migen import * from litex.soc.interconnect.csr import * diff --git a/gateware/info/git.py b/gateware/info/git.py index fd4c750a..f7104c32 100644 --- a/gateware/info/git.py +++ b/gateware/info/git.py @@ -3,7 +3,7 @@ import subprocess import sys -from litex.gen.fhdl import * +from migen.fhdl import * from litex.soc.interconnect.csr import * def git_root(): diff --git a/gateware/info/platform.py b/gateware/info/platform.py index 8e42a56d..a15c2e89 100644 --- a/gateware/info/platform.py +++ b/gateware/info/platform.py @@ -1,4 +1,4 @@ -from litex.gen.fhdl import * +from migen.fhdl import * from litex.soc.interconnect.csr import * diff --git a/gateware/info/xadc.py b/gateware/info/xadc.py index b4c2896d..1aae84bd 100644 --- a/gateware/info/xadc.py +++ b/gateware/info/xadc.py @@ -1,4 +1,4 @@ -from litex.gen import * +from migen import * from litex.soc.interconnect.csr import * diff --git a/gateware/led.py b/gateware/led.py index cf9e1960..a245f9e1 100644 --- a/gateware/led.py +++ b/gateware/led.py @@ -1,4 +1,4 @@ -from litex.gen import * +from migen import * from litex.soc.interconnect.csr import * from litex.soc.cores import gpio diff --git a/gateware/memtest.py b/gateware/memtest.py index 8cc9331f..329c0ed1 100644 --- a/gateware/memtest.py +++ b/gateware/memtest.py @@ -1,6 +1,6 @@ """Built In Self Test (BIST) modules for testing liteDRAM functionality.""" -from litex.gen import * +from migen import * class LiteDRAMBISTCheckerScope(Module): diff --git a/gateware/oled.py b/gateware/oled.py index 97ed8c9c..0170f5cb 100644 --- a/gateware/oled.py +++ b/gateware/oled.py @@ -1,8 +1,8 @@ -from litex.gen import * +from migen import * from litex.soc.interconnect.csr import * from litex.soc.cores.gpio import GPIOOut -from litex.gen import * +from migen import * from litex.soc.interconnect.csr import * diff --git a/gateware/opsis_i2c.py b/gateware/opsis_i2c.py index 8136ec8a..6376c73b 100644 --- a/gateware/opsis_i2c.py +++ b/gateware/opsis_i2c.py @@ -3,13 +3,13 @@ FIXME: Refactor this properly... """ -from litex.gen.fhdl import * -from litex.gen.fhdl.specials import TSTriple +from migen.fhdl import * +from migen.fhdl.specials import TSTriple -from litex.gen.genlib.cdc import MultiReg -from litex.gen.genlib.fsm import FSM, NextState -from litex.gen.genlib.misc import chooser -from litex.gen.genlib.misc import split, displacer, chooser +from migen.genlib.cdc import MultiReg +from migen.genlib.fsm import FSM, NextState +from migen.genlib.misc import chooser +from migen.genlib.misc import split, displacer, chooser from litex.soc.cores.gpio import GPIOIn, GPIOOut from litex.soc.interconnect.csr import * diff --git a/gateware/pwm.py b/gateware/pwm.py index 31d8cbe9..3725346f 100644 --- a/gateware/pwm.py +++ b/gateware/pwm.py @@ -1,4 +1,4 @@ -from litex.gen import * +from migen import * from litex.soc.interconnect.csr import * diff --git a/gateware/s6rgmii.py b/gateware/s6rgmii.py index ac8a6ffb..0a1d96f7 100644 --- a/gateware/s6rgmii.py +++ b/gateware/s6rgmii.py @@ -1,11 +1,11 @@ # RGMII PHY for Spartan-6 from liteeth.common import * -from litex.gen.genlib.io import DDROutput -from litex.gen.genlib.misc import WaitTimer -from litex.gen.genlib.fsm import FSM, NextState +from migen.genlib.io import DDROutput +from migen.genlib.misc import WaitTimer +from migen.genlib.fsm import FSM, NextState -from litex.gen.genlib.resetsync import AsyncResetSynchronizer +from migen.genlib.resetsync import AsyncResetSynchronizer from liteeth.phy.common import * diff --git a/gateware/shared_uart.py b/gateware/shared_uart.py index fe2ab237..130188f1 100644 --- a/gateware/shared_uart.py +++ b/gateware/shared_uart.py @@ -5,7 +5,7 @@ import operator -from litex.gen import * +from migen import * from litex.soc.cores import uart diff --git a/gateware/spi_flash.py b/gateware/spi_flash.py index d85e5bdc..02311082 100644 --- a/gateware/spi_flash.py +++ b/gateware/spi_flash.py @@ -1,5 +1,5 @@ -from litex.gen import * -from litex.gen.genlib.misc import timeline +from migen import * +from migen.genlib.misc import timeline from litex.soc.interconnect import wishbone from litex.soc.interconnect.csr import AutoCSR, CSRStorage, CSRStatus diff --git a/gateware/streamer/core.py b/gateware/streamer/core.py index d61a1477..914f404c 100644 --- a/gateware/streamer/core.py +++ b/gateware/streamer/core.py @@ -1,7 +1,7 @@ import os -from litex.gen import * -from litex.gen.genlib.resetsync import AsyncResetSynchronizer +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer from litex.soc.interconnect import stream class USBStreamer(Module): diff --git a/gateware/tofe.py b/gateware/tofe.py index 476b53d1..aef02a03 100644 --- a/gateware/tofe.py +++ b/gateware/tofe.py @@ -1,6 +1,6 @@ """Module for talking to TOFE boards.""" -from litex.gen.fhdl import * +from migen.fhdl import * from litex.soc.cores.gpio import GPIOIn, GPIOOut from litex.soc.interconnect.csr import * diff --git a/getting-started.md b/getting-started.md index b19f42b2..b6a34d35 100644 --- a/getting-started.md +++ b/getting-started.md @@ -240,7 +240,7 @@ this step. Load the gateware and firmware - see [1] if using a VM: ``` -make load-gateware +make gateware-load ``` On the Opsis, while loading the Blue LED (D1 / Done) and Green LED (D2) will @@ -312,6 +312,56 @@ to switch to serial mode and then back to the jtag mode like this; ``` hdmi2usb-mode-switch --mode=serial hdmi2usb-mode-switch --mode=jtag +``` +Load the firmware +``` +make firmware-load + +``` +If you see no output, press ‘Enter’ a few times. You can then kick off the firmware loading process again: +``` +BIOS> serialboot +Booting from serial... +Press Q or ESC to abort boot completely. +sL5DdSMmkekro +[FLTERM] Received firmware download request from the device. +[FLTERM] Uploading kernel (86484 bytes)... +[FLTERM] Upload complete (10.6KB/s). +[FLTERM] Booting the device. +[FLTERM] Done. +Executing booted program at 0x40000000 +HDMI2USB firmware booting... + +opsis_eeprom: Init...finished. + +hardware version info +=============================================== + DNA: 0137be87d98719f0 + MAC: d8:80:39:57:04:94 + +gateware version info +=============================================== + platform: opsis + target: video + revision: 5f07955beabcf9cebe0e896c4e51242075566cb6 + +firmware version info +=============================================== + platform: opsis + target: video + git commit: 5f07955beabcf9cebe0e896c4e51242075566cb6 + git branch: master + git describe: v0.0.4-203-g5f07955 + git status: + -- + ?? ../../../../HDMI2USB-mode-switch/ + -- + + built: May 31 2018 10:43:25 + uptime: 00:00:00 +----------------------------------------------- +MDIO mode: 1000Mbps / link: down + ``` ## 5) Testing @@ -319,7 +369,7 @@ hdmi2usb-mode-switch --mode=jtag Connect to lm32 softcore to send direct commands to the HDMI2USB such as changing resolution: ``` -make connect-lm32 +make firmware-connect ``` Set a mode/capture - type 'help' and read instructions. @@ -336,6 +386,21 @@ video_matrix connect input1 output1 video_matrix connect input1 encoder ``` +The following commands are an example to view the video output on monitor +``` +H2U 00:01:28>i0 on +Enabling input0 +H2U 00:02:24>i1 on +Enabling input1 +H2U 00:02:26>o0 on +Enabling output0 +H2U 00:02:30>o1 on +Enabling output +H2U 00:04:20>x c pattern output0 # You should see the pattern on the monitor +Connecting pattern to output0 +H2U 00:04:48>x c input0 output0 # You should see your desktop on the monior +Connecting input0 to output0 +``` View the video output on your computer with your preferred tool. The scripts/view-hdmi2usb.sh script will try and find a suitable tool to display. diff --git a/make.py b/make.py index ec4fda58..14532df8 100755 --- a/make.py +++ b/make.py @@ -14,6 +14,7 @@ def get_args(parser, platform='opsis', target='hdmi2usb'): parser.add_argument("--platform", action="store", default=os.environ.get('PLATFORM', platform)) parser.add_argument("--target", action="store", default=os.environ.get('TARGET', target)) parser.add_argument("--cpu-type", default=os.environ.get('CPU', 'lm32')) + parser.add_argument("--cpu-variant", default=os.environ.get('CPU_VARIANT', '')) parser.add_argument("--iprange", default="192.168.100") @@ -33,7 +34,10 @@ def get_builddir(args): for name, value in args.target_option: if name == 'tofe_board': full_platform = "{}.{}".format(full_platform, value) - return "build/{}_{}_{}/".format(full_platform.lower(), args.target.lower(), args.cpu_type) + full_cpu = args.cpu_type + if args.cpu_variant: + full_cpu = "{}.{}".format(full_cpu, args.cpu_variant) + return "build/{}_{}_{}/".format(full_platform.lower(), args.target.lower(), full_cpu.lower()) def get_testdir(args): @@ -101,7 +105,7 @@ def main(): platform = get_platform(args) exec("from targets.{}.{} import SoC".format(args.platform, args.target.lower(), args.target), globals()) - soc = SoC(platform, **soc_sdram_argdict(args), **dict(args.target_option)) + soc = SoC(platform, ident=SoC.__name__, **soc_sdram_argdict(args), **dict(args.target_option)) if hasattr(soc, 'configure_iprange'): soc.configure_iprange(args.iprange) @@ -111,15 +115,19 @@ def main(): buildargs = builder_argdict(args) if not buildargs.get('output_dir', None): buildargs['output_dir'] = builddir - if not buildargs.get('csr_csv', None): - buildargs['csr_csv'] = os.path.join(testdir, "csr.csv") - - builder = Builder(soc, **buildargs) - if not args.no_compile_firmware or args.override_firmware: - builder.add_software_package("uip", "{}/firmware/uip".format(os.getcwd())) - builder.add_software_package("modem", "{}/firmware/modem".format(os.getcwd())) - builder.add_software_package("firmware", "{}/firmware".format(os.getcwd())) - vns = builder.build(**dict(args.build_option)) + + if hasattr(soc, 'cpu_type'): + if not buildargs.get('csr_csv', None): + buildargs['csr_csv'] = os.path.join(testdir, "csr.csv") + + builder = Builder(soc, **buildargs) + if not args.no_compile_firmware or args.override_firmware: + builder.add_software_package("uip", "{}/firmware/uip".format(os.getcwd())) + builder.add_software_package("modem", "{}/firmware/modem".format(os.getcwd())) + builder.add_software_package("firmware", "{}/firmware".format(os.getcwd())) + vns = builder.build(**dict(args.build_option)) + else: + vns = platform.build(soc, build_dir=os.path.join(builddir, "gateware")) if hasattr(soc, 'pcie_phy'): from targets.common import cpu_interface diff --git a/platforms/basys3.py b/platforms/basys3.py new file mode 100644 index 00000000..10c0067a --- /dev/null +++ b/platforms/basys3.py @@ -0,0 +1,113 @@ +# This file is Copyright (c) 2015 Yann Sionneau +# This file is Copyright (c) 2015 Florent Kermarrec +# License: BSD + +from litex.build.generic_platform import * +from litex.build.openocd import OpenOCD +from litex.build.xilinx import XilinxPlatform, XC3SProg, VivadoProgrammer + +_io = [ + ("user_led", 0, Pins("U16"), IOStandard("LVCMOS33")), + ("user_led", 1, Pins("E19"), IOStandard("LVCMOS33")), + ("user_led", 2, Pins("U19"), IOStandard("LVCMOS33")), + ("user_led", 3, Pins("V19"), IOStandard("LVCMOS33")), + ("user_led", 4, Pins("W18"), IOStandard("LVCMOS33")), + ("user_led", 5, Pins("U15"), IOStandard("LVCMOS33")), + ("user_led", 6, Pins("U14"), IOStandard("LVCMOS33")), + ("user_led", 7, Pins("V14"), IOStandard("LVCMOS33")), + ("user_led", 8, Pins("V13"), IOStandard("LVCMOS33")), + ("user_led", 9, Pins("V3"), IOStandard("LVCMOS33")), + ("user_led", 10, Pins("W3"), IOStandard("LVCMOS33")), + ("user_led", 11, Pins("U3"), IOStandard("LVCMOS33")), + ("user_led", 12, Pins("P3"), IOStandard("LVCMOS33")), + ("user_led", 13, Pins("N3"), IOStandard("LVCMOS33")), + ("user_led", 14, Pins("P1"), IOStandard("LVCMOS33")), + ("user_led", 15, Pins("L1"), IOStandard("LVCMOS33")), + + ("user_sw", 0, Pins("V17"), IOStandard("LVCMOS33")), + ("user_sw", 1, Pins("V16"), IOStandard("LVCMOS33")), + ("user_sw", 2, Pins("W16"), IOStandard("LVCMOS33")), + ("user_sw", 3, Pins("W17"), IOStandard("LVCMOS33")), + ("user_sw", 4, Pins("W15"), IOStandard("LVCMOS33")), + ("user_sw", 5, Pins("V15"), IOStandard("LVCMOS33")), + ("user_sw", 6, Pins("W14"), IOStandard("LVCMOS33")), + ("user_sw", 7, Pins("W13"), IOStandard("LVCMOS33")), + ("user_sw", 8, Pins("V2"), IOStandard("LVCMOS33")), + ("user_sw", 9, Pins("T3"), IOStandard("LVCMOS33")), + ("user_sw", 10, Pins("T2"), IOStandard("LVCMOS33")), + ("user_sw", 11, Pins("R3"), IOStandard("LVCMOS33")), + ("user_sw", 12, Pins("W2"), IOStandard("LVCMOS33")), + ("user_sw", 13, Pins("U1"), IOStandard("LVCMOS33")), + ("user_sw", 14, Pins("T1"), IOStandard("LVCMOS33")), + ("user_sw", 15, Pins("R2"), IOStandard("LVCMOS33")), + + ("user_btn", 0, Pins("W19"), IOStandard("LVCMOS33")), + ("user_btn", 1, Pins("T17"), IOStandard("LVCMOS33")), + ("user_btn", 2, Pins("T18"), IOStandard("LVCMOS33")), + ("user_btn", 3, Pins("U17"), IOStandard("LVCMOS33")), + ("user_btn", 4, Pins("U18"), IOStandard("LVCMOS33")), + + ("clk100", 0, Pins("W5"), IOStandard("LVCMOS33")), + + ("serial", 0, + Subsignal("tx", Pins("A18")), + Subsignal("rx", Pins("B18")), + IOStandard("LVCMOS33")), + + ("spiflash_4x", 0, # clock needs to be accessed through STARTUPE2 + Subsignal("cs_n", Pins("K19")), + Subsignal("dq", Pins("D18", "D19", "G18", "F18")), + IOStandard("LVCMOS33") + ), + ("spiflash_1x", 0, # clock needs to be accessed through STARTUPE2 + Subsignal("cs_n", Pins("K19")), + Subsignal("mosi", Pins("D18")), + Subsignal("miso", Pins("D19")), + Subsignal("wp", Pins("G18")), + Subsignal("hold", Pins("F18")), + IOStandard("LVCMOS33") + ), +] + + +class Platform(XilinxPlatform): + name = "basys3" + default_clk_name = "clk100" + default_clk_period = 10.0 + + # From https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf + # 17536096 bits == 2192012 == 0x21728c -- Therefore 0x220000 + gateware_size = 0x220000 + + # Micron N25Q128A13ESF40 (ID 0x0018ba20) + # FIXME: Create a "spi flash module" object in the same way we have SDRAM + # module objects. + spiflash_model = "n25q128a13" + spiflash_read_dummy_bits = 10 + spiflash_clock_div = 4 + spiflash_total_size = int((128/8)*1024*1024) # 128Mbit + spiflash_page_size = 256 + spiflash_sector_size = 0x10000 + + def __init__(self, toolchain="vivado", programmer="openocd"): + XilinxPlatform.__init__(self, "xc7a35t-cpg236-1", _io, + toolchain=toolchain) + self.toolchain.bitstream_commands = \ + ["set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]"] + self.toolchain.additional_commands = \ + ["write_cfgmem -force -format bin -interface spix4 -size 16 " + "-loadbit \"up 0x0 {build_name}.bit\" -file {build_name}.bin"] + self.programmer = programmer + self.add_platform_command("set_property INTERNAL_VREF 0.750 [get_iobanks 34]") + + def create_programmer(self): + if self.programmer == "openocd": + proxy="bscan_spi_{}.bit".format(self.device.split('-')[0]) + return OpenOCD(config="board/digilent_arty.cfg", flash_proxy_basename=proxy) + elif self.programmer == "xc3sprog": + return XC3SProg("nexys4") + elif self.programmer == "vivado": + return VivadoProgrammer(flash_part="n25q128-3.3v-spi-x1_x2_x4") + else: + raise ValueError("{} programmer is not supported" + .format(self.programmer)) diff --git a/platforms/cmod_a7.py b/platforms/cmod_a7.py new file mode 100644 index 00000000..e0451e37 --- /dev/null +++ b/platforms/cmod_a7.py @@ -0,0 +1,177 @@ +# This file is Copyright (c) 2017 Tim 'mithro' Ansell +# License: BSD + +from litex.build.generic_platform import * +from litex.build.openocd import OpenOCD +from litex.build.xilinx import XilinxPlatform, VivadoProgrammer + +_io = [ + + ## LEDs + #set_property -dict { PACKAGE_PIN A17 IOSTANDARD LVCMOS33 } [get_ports { led[0] }]; #IO_L12N_T1_MRCC_16 Sch=led[1] + #set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports { led[1] }]; #IO_L13P_T2_MRCC_16 Sch=led[2] + ("user_led", 0, Pins("A17"), IOStandard("LVCMOS33")), + ("user_led", 1, Pins("C16"), IOStandard("LVCMOS33")), + + #set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVCMOS33 } [get_ports { led0_b }]; #IO_L14N_T2_SRCC_16 Sch=led0_b + #set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVCMOS33 } [get_ports { led0_g }]; #IO_L13N_T2_MRCC_16 Sch=led0_g + #set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { led0_r }]; #IO_L14P_T2_SRCC_16 Sch=led0_r + ("rgb_leds", 0, + Subsignal("r", Pins("C17")), + Subsignal("g", Pins("B16")), + Subsignal("b", Pins("B17")), + IOStandard("LVCMOS33") + ), + + ## Buttons + #set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVCMOS33 } [get_ports { btn[0] }]; #IO_L19N_T3_VREF_16 Sch=btn[0] + #set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports { btn[1] }]; #IO_L19P_T3_16 Sch=btn[1] + ("user_btn", 0, Pins("A18"), IOStandard("LVCMOS33")), + ("user_btn", 1, Pins("B18"), IOStandard("LVCMOS33")), + + ## Clock signal 12 MHz + #set_property -dict { PACKAGE_PIN L17 IOSTANDARD LVCMOS33 } [get_ports { sysclk }]; #IO_L12P_T1_MRCC_14 Sch=gclk + #create_clock -add -name sys_clk_pin -period 83.33 -waveform {0 41.66} [get_ports {sysclk}]; + ("clk12", 0, Pins("L17"), IOStandard("LVCMOS33")), + + ## UART + #set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { uart_rxd_out }]; #IO_L7N_T1_D10_14 Sch=uart_rxd_out + #set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { uart_txd_in }]; #IO_L7P_T1_D09_14 Sch=uart_txd_in + ("serial", 0, + Subsignal("tx", Pins("J18")), + Subsignal("rx", Pins("J17")), + IOStandard("LVCMOS33")), + + ## QSPI - N25Q032A13EF440F + #set_property -dict { PACKAGE_PIN K19 IOSTANDARD LVCMOS33 } [get_ports { qspi_cs }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_cs + #set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[0] }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0] + #set_property -dict { PACKAGE_PIN D19 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[1] }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1] + #set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[2] }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2] + #set_property -dict { PACKAGE_PIN F18 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[3] }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3] + ("spiflash_4x", 0, # clock needs to be accessed through STARTUPE2 + Subsignal("cs_n", Pins("K19")), + Subsignal("dq", Pins("D18", "D19", "G18", "F18")), + IOStandard("LVCMOS33") + ), + ("spiflash_1x", 0, # clock needs to be accessed through STARTUPE2 + Subsignal("cs_n", Pins("K19")), + Subsignal("mosi", Pins("D18")), # DQ0 + Subsignal("miso", Pins("D19")), # DQ1 + Subsignal("wp", Pins("G18")), # DQ2 + Subsignal("hold", Pins("F18")), # DQ3 + IOStandard("LVCMOS33") + ), + + ## SRAM + ## 512KB SRAM with an 8-bit bus and 8ns access times + #set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[0] }]; #IO_L11P_T1_SRCC_14 Sch=sram- a[0] + #set_property -dict { PACKAGE_PIN M19 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[1] }]; #IO_L11N_T1_SRCC_14 Sch=sram- a[1] + #set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[2] }]; #IO_L12N_T1_MRCC_14 Sch=sram- a[2] + #set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[3] }]; #IO_L13P_T2_MRCC_14 Sch=sram- a[3] + #set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[4] }]; #IO_L13N_T2_MRCC_14 Sch=sram- a[4] + #set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[5] }]; #IO_L14P_T2_SRCC_14 Sch=sram- a[5] + #set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[6] }]; #IO_L14N_T2_SRCC_14 Sch=sram- a[6] + #set_property -dict { PACKAGE_PIN W19 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[7] }]; #IO_L16N_T2_A15_D31_14 Sch=sram- a[7] + #set_property -dict { PACKAGE_PIN U19 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[8] }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=sram- a[8] + #set_property -dict { PACKAGE_PIN V19 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[9] }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=sram- a[9] + #set_property -dict { PACKAGE_PIN W18 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[10] }]; #IO_L16P_T2_CSI_B_14 Sch=sram- a[10] + #set_property -dict { PACKAGE_PIN T17 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[11] }]; #IO_L17P_T2_A14_D30_14 Sch=sram- a[11] + #set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[12] }]; #IO_L17N_T2_A13_D29_14 Sch=sram- a[12] + #set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[13] }]; #IO_L18P_T2_A12_D28_14 Sch=sram- a[13] + #set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[14] }]; #IO_L18N_T2_A11_D27_14 Sch=sram- a[14] + #set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[15] }]; #IO_L19P_T3_A10_D26_14 Sch=sram- a[15] + #set_property -dict { PACKAGE_PIN W16 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[16] }]; #IO_L20P_T3_A08_D24_14 Sch=sram- a[16] + #set_property -dict { PACKAGE_PIN W17 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[17] }]; #IO_L20N_T3_A07_D23_14 Sch=sram- a[17] + #set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[18] }]; #IO_L21P_T3_DQS_14 Sch=sram- a[18] + #set_property -dict { PACKAGE_PIN W15 IOSTANDARD LVCMOS33 } [get_ports { MemDB[0] }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=sram-dq[0] + #set_property -dict { PACKAGE_PIN W13 IOSTANDARD LVCMOS33 } [get_ports { MemDB[1] }]; #IO_L22P_T3_A05_D21_14 Sch=sram-dq[1] + #set_property -dict { PACKAGE_PIN W14 IOSTANDARD LVCMOS33 } [get_ports { MemDB[2] }]; #IO_L22N_T3_A04_D20_14 Sch=sram-dq[2] + #set_property -dict { PACKAGE_PIN U15 IOSTANDARD LVCMOS33 } [get_ports { MemDB[3] }]; #IO_L23P_T3_A03_D19_14 Sch=sram-dq[3] + #set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { MemDB[4] }]; #IO_L23N_T3_A02_D18_14 Sch=sram-dq[4] + #set_property -dict { PACKAGE_PIN V13 IOSTANDARD LVCMOS33 } [get_ports { MemDB[5] }]; #IO_L24P_T3_A01_D17_14 Sch=sram-dq[5] + #set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { MemDB[6] }]; #IO_L24N_T3_A00_D16_14 Sch=sram-dq[6] + #set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { MemDB[7] }]; #IO_25_14 Sch=sram-dq[7] + #set_property -dict { PACKAGE_PIN P19 IOSTANDARD LVCMOS33 } [get_ports { RamOEn }]; #IO_L10P_T1_D14_14 Sch=sram-oe + #set_property -dict { PACKAGE_PIN R19 IOSTANDARD LVCMOS33 } [get_ports { RamWEn }]; #IO_L10N_T1_D15_14 Sch=sram-we + #set_property -dict { PACKAGE_PIN N19 IOSTANDARD LVCMOS33 } [get_ports { RamCEn }]; #IO_L9N_T1_DQS_D13_14 Sch=sram-ce + ("sram", 0, + Subsignal( + "a", + Pins("M18 M19 K17 N17 P17 P18 R18 W19", + "U19 V19 W18 T17 T18 U17 U18 V16", + "W16 W17 V15"), + IOStandard("LVCMOS33")), + Subsignal( + "dq", + Pins("W15 W13 W14 U15 U16 V13 V14 U14"), + IOStandard("LVCMOS33")), + Subsignal("oe_n", Pins("R19"), IOStandard("LVCMOS33")), + Subsignal("we_n", Pins("R19"), IOStandard("LVCMOS33")), + Subsignal("ce_n", Pins("N19"), IOStandard("LVCMOS33")), + Misc("SLEW=FAST"), + ), + + ## Analog XADC Pins + ## Only declare these if you want to use pins 15 and 16 as single ended analog inputs. pin 15 -> vaux4, pin16 -> vaux12 + #set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { xa_n[0] }]; #IO_L1N_T0_AD4N_35 Sch=ain_n[15] + #set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { xa_p[0] }]; #IO_L1P_T0_AD4P_35 Sch=ain_p[15] + #set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { xa_n[1] }]; #IO_L2N_T0_AD12N_35 Sch=ain_n[16] + #set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { xa_p[1] }]; #IO_L2P_T0_AD12P_35 Sch=ain_p[16] + + ## Crypto 1 Wire Interface - ATSHA204A-MAHCZ-T + #set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { crypto_sda }]; #IO_0_14 Sch=crypto_sda + + ## Pmod Header JA + #set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { ja[0] }]; #IO_L5N_T0_D07_14 Sch=ja[1] + #set_property -dict { PACKAGE_PIN G19 IOSTANDARD LVCMOS33 } [get_ports { ja[1] }]; #IO_L4N_T0_D05_14 Sch=ja[2] + #set_property -dict { PACKAGE_PIN N18 IOSTANDARD LVCMOS33 } [get_ports { ja[2] }]; #IO_L9P_T1_DQS_14 Sch=ja[3] + #set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { ja[3] }]; #IO_L8P_T1_D11_14 Sch=ja[4] + #set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L5P_T0_D06_14 Sch=ja[7] + #set_property -dict { PACKAGE_PIN H19 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L4P_T0_D04_14 Sch=ja[8] + #set_property -dict { PACKAGE_PIN J19 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L6N_T0_D08_VREF_14 Sch=ja[9] + #set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_L8N_T1_D12_14 Sch=ja[10] +] + + +class Platform(XilinxPlatform): + name = "cmod_a7" + default_clk_name = "clk12" + default_clk_period = 1e9/12e6 + + # From https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf + # 17536096 bits == 2192012 == 0x21728c -- Therefore 0x220000 + gateware_size = 0x220000 + + # Micron N25Q032A13EF440F (ID 0x0016ba20) + # 3V, Multiple I/O, 4KB Sector Erase + # 108 MHz (MAX) clock frequency + # FIXME: Create a "spi flash module" object in the same way we have SDRAM + # module objects. + spiflash_model = "n25q32" + spiflash_read_dummy_bits = 10 + spiflash_clock_div = 4 + spiflash_total_size = int((32/8)*1024*1024) # 32MMbit + spiflash_page_size = 256 + spiflash_sector_size = 0x10000 + + def __init__(self, toolchain="vivado", programmer="openocd"): + XilinxPlatform.__init__(self, "xc7a35t-cpg236-1", _io, + toolchain=toolchain) + self.toolchain.bitstream_commands = \ + ["set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]"] + self.toolchain.additional_commands = \ + ["write_cfgmem -force -format bin -interface spix4 -size 16 " + "-loadbit \"up 0x0 {build_name}.bit\" -file {build_name}.bin"] + self.programmer = programmer + self.add_platform_command("set_property INTERNAL_VREF 0.750 [get_iobanks 34]") + + def create_programmer(self): + if self.programmer == "openocd": + proxy="bscan_spi_{}.bit".format(self.device.split('-')[0]) + return OpenOCD(config="board/digilent_cmod_a7.cfg", flash_proxy_basename=proxy) + elif self.programmer == "vivado": + # n25q32-3.3v-spi-x1_x2_x4 + return VivadoProgrammer(flash_part="n25q32-3.3v-spi-x1_x2_x4") + else: + raise ValueError( + "{} programmer is not supported".format(self.programmer)) diff --git a/platforms/galatea.py b/platforms/galatea.py new file mode 100644 index 00000000..7b6b6f42 --- /dev/null +++ b/platforms/galatea.py @@ -0,0 +1,180 @@ +# Support for the Numato Galatea - PCI Express Spartan 6 Development Board +# https://numato.com/product/galatea-pci-express-spartan-6-fpga-development-board + +from collections import OrderedDict + +from litex.build.generic_platform import * +from litex.build.xilinx import XilinxPlatform, iMPACT + +from third_party.litex.litex.build.xilinx.programmer import XC3SProg + +_io = [ + # ---------------------- Clocks --------------------------- + # Clock U18 - 100MHz - CMOS Crystal Oscillator + # NET "CLK1" LOC = "AB13" | IOSTANDARD = "LVCMOS33" | Period = 100 MHz; # Bank = 0 + ("clk100", 0, Pins("G9"), IOStandard("LVCMOS33")), + # Clock U19 - 100MHz - CMOS Crystal Oscillator + # NET "CLK2" LOC = "Y13" | IOSTANDARD = "LVCMOS33" | Period = 100 MHz; # Bank = 2 + ("clk2", 0, Pins("Y13"), IOStandard("LVCMOS33")), + # Clock U17 - 100MHz - CMOS Crystal Oscillator + # NET "CLK3" LOC = "AB13" | IOSTANDARD = "LVCMOS33" | Period = 100 MHz; # Bank = 2 + ("clk3", 0, Pins("AB13"), IOStandard("LVCMOS33")), + + # Clock U21 SMA Clock + # NET "EXT_CLK1" LOC = "U12" | IOSTANDARD = "LVCMOS33"; # Bank = 2 + + # Clock U6 SMA Clock + # NET "EXT_CLK2" LOC = "T12" | IOSTANDARD = "LVCMOS33"; # Bank = 2 + + # SW1 + #NET "RST_N" LOC = "AB19" | IOSTANDARD = "LVCMOS33" | PULLUP ; # Bank = 2 + ("cpu_reset", 0, Pins("AB19"), IOStandard("LVCMOS33"), Misc("PULLUP")), + + # ---------------------- UART ----------------------------- + #NET "UART_RX" LOC = "V17" | IOSTANDARD = "LVCMOS33"; # Bank = 2 + #NET "UART_TX" LOC = "W18" | IOSTANDARD = "LVCMOS33"; # Bank = 2 + ("serial", 0, + Subsignal("rx", Pins("V17"), IOStandard("LVCMOS33")), + Subsignal("tx", Pins("W18"), IOStandard("LVCMOS33")), + ), + # SPI Flash # + #NET "SPI_Flash_SCK" LOC = "Y20" | IOSTANDARD = "LVCMOS33"; # Bank = 2 + #NET "SPI_Flash_MISO" LOC = "T14" | IOSTANDARD = "LVCMOS33"; # Bank = 2 + #NET "SPI_Flash_MOSI" LOC = "AB20" | IOSTANDARD = "LVCMOS33"; # Bank = 2 + #NET "SPI_Flash_SS" LOC = "AA3" | IOSTANDARD = "LVCMOS33"; # Bank = 2 + + ## onBoard Quad-SPI Flash + ## N25Q128A13ESE40E - 128 Mb QSPI flash memory + + #QSPI_FLASH_SCLK Y20 LVCMOS33 16 FAST + #QSPI_FLASH_IO0 AB20 LVCMOS33 16 FAST + #QSPI_FLASH_IO1 AA20 LVCMOS33 16 FAST + #QSPI_FLASH_IO2 R13 LVCMOS33 16 FAST + #QSPI_FLASH_IO3 T14 LVCMOS33 16 FAST + #QSPI_FLASH_SS AA3 LVCMOS33 16 FAST + + ("spiflash1x", 0, + #NET "SPI_Flash_SCK" LOC = "Y20" | IOSTANDARD = "LVCMOS33"; # Bank = 2 + Subsignal("clk", Pins("Y20")), + #NET "SPI_Flash_SS" LOC = "AA3" | IOSTANDARD = "LVCMOS33"; # Bank = 2 + Subsignal("cs_n", Pins("AA3")), + #NET "SPI_Flash_MISO" LOC = "T14" | IOSTANDARD = "LVCMOS33"; # Bank = 2 + #NET "SPI_Flash_MOSI" LOC = "AB20" | IOSTANDARD = "LVCMOS33"; # Bank = 2 + #Subsignal("dq", Pins("AB20", "AA20", "R13", "T14")), + IOStandard("LVCMOS33"), Misc("SLEW=FAST") + ), + + ## DDR3 Chip:0 + # MT41J128M16JT-125:K - 16 Meg x 16 x 8 Banks - DDR3-1600 11-11-11 + # FBGA Code: D9PSL, Part Number: MT41J128M16 - http://www.micron.com/support/fbga + ("ddram_clock", 0, + Subsignal("p", Pins("K4")), + Subsignal("n", Pins("K3")), + IOStandard("DIFF_SSTL15_II"), Misc("IN_TERM=NONE") + ), + ("ddram", 0, + Subsignal("cke", Pins("F2"), IOStandard("SSTL15_II")), + Subsignal("ras_n", Pins("M5"), IOStandard("SSTL15_II")), + Subsignal("cas_n", Pins("M4"), IOStandard("SSTL15_II")), + Subsignal("we_n", Pins("H2"), IOStandard("SSTL15_II")), + Subsignal("ba", Pins("J3 J1 H1"), IOStandard("SSTL15_II")), + Subsignal("a", Pins("K2 K1 K5 M6 H3 L4 M3 K6 G3 G1 J4 E1 F1 J6 H5"), IOStandard("SSTL15_II")), + Subsignal("dq", Pins( + "R3 R1 P2 P1 L3 L1 M2 M1", + "T2 T1 U3 U1 W3 W1 Y2 Y1"), IOStandard("SSTL15_II")), + Subsignal("dqs", Pins("N3 V2"), IOStandard("DIFF_SSTL15_II")), + Subsignal("dqs_n", Pins("N1 V1"), IOStandard("DIFF_SSTL15_II")), + Subsignal("dm", Pins("N4 P3"), IOStandard("SSTL15_II")), + Subsignal("odt", Pins("L6"), IOStandard("SSTL15_II")), + Subsignal("reset_n", Pins("E3"), IOStandard("LVCMOS15")), + Misc("SLEW=FAST"), + Misc("VCCAUX_IO=HIGH") + ), + + ## DDR3 Chip:1 + # MT41J128M16JT-125:K - 16 Meg x 16 x 8 Banks - DDR3-1600 11-11-11 + # FBGA Code: D9PSL, Part Number: MT41J128M16 - http://www.micron.com/support/fbga + ("ddram_clock", 1, + Subsignal("p", Pins("K20")), + Subsignal("n", Pins("L19")), + IOStandard("DIFF_SSTL15_II"), Misc("IN_TERM=NONE") + ), + ("ddram", 1, + Subsignal("cke", Pins("F21"), IOStandard("SSTL15_II")), + Subsignal("ras_n", Pins("K21"), IOStandard("SSTL15_II")), + Subsignal("cas_n", Pins("K22"), IOStandard("SSTL15_II")), + Subsignal("we_n", Pins("K19"), IOStandard("SSTL15_II")), + Subsignal("ba", Pins("K17 L17 K18"), IOStandard("SSTL15_II")), + Subsignal("a", Pins("H21 H22 G22 J20 H20 M20 M19 G20 E20 E22 J19 H19 F22 G19 F20"), IOStandard("SSTL15_II")), + Subsignal("dq", Pins( + "R20 R22 P21 P22 L20 L22 M21 M22", + "T21 T22 U20 U22 W20 W22 Y21 Y22"), IOStandard("SSTL15_II")), + Subsignal("dqs", Pins("N20 V21"), IOStandard("DIFF_SSTL15_II")), + Subsignal("dqs_n", Pins("N22 V22"), IOStandard("DIFF_SSTL15_II")), + Subsignal("dm", Pins("N19 P20"), IOStandard("SSTL15_II")), + Subsignal("odt", Pins("J22"), IOStandard("SSTL15_II")), + Subsignal("reset_n", Pins("H18"), IOStandard("LVCMOS15")), + Misc("SLEW=FAST"), + Misc("VCCAUX_IO=HIGH") + ), +] + +_connectors = [] + +class Platform(XilinxPlatform): + name = "galatea" + default_clk_name = "clk100" + default_clk_period = 10.0 + + # W25Q128FVEIG - component U3 + # 128M (16M x 8) - 104MHz + # Pretends to be a Micron N25Q128 (ID 0x0018ba20) + # FIXME: Create a "spi flash module" object in the same way we have SDRAM + # module objects. + spiflash_model = "n25q128" + spiflash_read_dummy_bits = 10 + spiflash_clock_div = 4 + spiflash_total_size = int((128/8)*1024*1024) # 128Mbit + spiflash_page_size = 256 + spiflash_sector_size = 0x10000 + + # The Galatea has a XC6SLX45 which bitstream takes up ~12Mbit (1484472 bytes) + # 0x200000 offset (16Mbit) gives plenty of space + gateware_size = 0x200000 + + def __init__(self, programmer="openocd"): + # XC6SLX45T-3FGG484C + XilinxPlatform.__init__(self, "xc6slx45t-fgg484-3", _io, _connectors) + self.programmer = programmer + + pins = { + 'ProgPin': 'PullUp', + 'DonePin': 'PullUp', + 'TckPin': 'PullNone', + 'TdiPin': 'PullNone', + 'TdoPin': 'PullNone', + 'TmsPin': 'PullNone', + 'UnusedPin': 'PullNone', + } + for pin, config in pins.items(): + self.toolchain.bitgen_opt += " -g %s:%s " % (pin, config) + + # FPGA AUX is connected to the 3.3V supply + self.add_platform_command("""CONFIG VCCAUX="3.3";""") + + def create_programmer(self): + if self.programmer == "xc3sprog": + return XC3SProg(cable='xpc') + elif self.programmer == "impact": + return iMPACT() + else: + raise ValueError("{} programmer is not supported".format(self.programmer)) + + def do_finalize(self, fragment): + XilinxPlatform.do_finalize(self, fragment) + + # The oscillator clock sources. + try: + self.add_period_constraint(self.lookup_request("clk100"), 10.0) + except ConstraintError: + pass diff --git a/platforms/neso.py b/platforms/neso.py new file mode 100644 index 00000000..31d14cd7 --- /dev/null +++ b/platforms/neso.py @@ -0,0 +1,99 @@ +# This file is Copyright (c) 2018 TimVideos +# License: BSD + +from litex.build.generic_platform import * +from litex.build.openocd import OpenOCD +from litex.build.xilinx import XilinxPlatform, XC3SProg, VivadoProgrammer + +_io = [ + + ("clk100", 0, Pins("F4"), IOStandard("LVCMOS33")), + + ("serial", 0, + Subsignal("tx", Pins("B18")), + Subsignal("rx", Pins("A18")), + IOStandard("LVCMOS33")), + + ("spiflash_4x", 0, # clock needs to be accessed through STARTUPE2 + Subsignal("cs_n", Pins("L13")), + Subsignal("dq", Pins("K17", "K18", "L14", "M14")), + IOStandard("LVCMOS33") + ), + ("spiflash_1x", 0, # clock needs to be accessed through STARTUPE2 + Subsignal("cs_n", Pins("L13")), + Subsignal("mosi", Pins("K17")), + Subsignal("miso", Pins("K18")), + Subsignal("wp", Pins("L14")), + Subsignal("hold", Pins("M14")), + IOStandard("LVCMOS33") + ), + + ("ddram", 0, + Subsignal("a", Pins( + "M4 P4 M6 T1 L3 P5 M2 N1", + "L4 N5 R2 K5 N6 K3"), + IOStandard("SSTL15")), + Subsignal("ba", Pins("P2 P3 R1"), IOStandard("SSTL15")), + Subsignal("ras_n", Pins("N4"), IOStandard("SSTL15")), + Subsignal("cas_n", Pins("L1"), IOStandard("SSTL15")), + Subsignal("we_n", Pins("N2"), IOStandard("SSTL15")), + Subsignal("cs_n", Pins("K6"), IOStandard("SSTL15")), + Subsignal("dm", Pins("T6 U1"), IOStandard("SSTL15")), + Subsignal("dq", Pins( + "R7 V6 R8 U7 V7 R6 U6 R5", + "T5 U3 V5 U4 V4 T4 V1 T3"), + IOStandard("SSTL15"), + Misc("IN_TERM=UNTUNED_SPLIT_40")), + Subsignal("dqs_p", Pins("U9 U2"), IOStandard("DIFF_SSTL15")), + Subsignal("dqs_n", Pins("V9 V2"), IOStandard("DIFF_SSTL15")), + Subsignal("clk_p", Pins("L6"), IOStandard("DIFF_SSTL15")), + Subsignal("clk_n", Pins("L5"), IOStandard("DIFF_SSTL15")), + Subsignal("cke", Pins("M1"), IOStandard("SSTL15")), + Subsignal("odt", Pins("M3"), IOStandard("SSTL15")), + Subsignal("reset_n", Pins("U8"), IOStandard("SSTL15")), + Misc("SLEW=FAST"), + ), +] + + +class Platform(XilinxPlatform): + name = "neso" + default_clk_name = "clk100" + default_clk_period = 10.0 + + # From https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf + # 17536096 bits == 2192012 == 0x21728c -- Therefore 0x220000 + gateware_size = 0x220000 + + # Micron N25Q128A13ESF40 (ID 0x0018ba20) + # FIXME: Create a "spi flash module" object in the same way we have SDRAM + # module objects. + spiflash_model = "n25q128a13" + spiflash_read_dummy_bits = 10 + spiflash_clock_div = 4 + spiflash_total_size = int((128/8)*1024*1024) # 128Mbit + spiflash_page_size = 256 + spiflash_sector_size = 0x10000 + + def __init__(self, toolchain="vivado", programmer="openocd"): + XilinxPlatform.__init__(self, "xc7a100t-csg324-1", _io, + toolchain=toolchain) + self.toolchain.bitstream_commands = \ + ["set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]"] + self.toolchain.additional_commands = \ + ["write_cfgmem -force -format bin -interface spix4 -size 16 " + "-loadbit \"up 0x0 {build_name}.bit\" -file {build_name}.bin"] + self.programmer = programmer + self.add_platform_command("set_property INTERNAL_VREF 0.750 [get_iobanks 34]") + + def create_programmer(self): + if self.programmer == "openocd": + proxy="bscan_spi_{}.bit".format(self.device.split('-')[0]) + return OpenOCD(config="board/numato_neso.cfg", flash_proxy_basename=proxy) + elif self.programmer == "xc3sprog": + return XC3SProg("saturn") + elif self.programmer == "vivado": + return VivadoProgrammer(flash_part="n25q128-3.3v-spi-x1_x2_x4") + else: + raise ValueError("{} programmer is not supported" + .format(self.programmer)) diff --git a/platforms/netv2.py b/platforms/netv2.py index 5e88c8f0..309a1a24 100644 --- a/platforms/netv2.py +++ b/platforms/netv2.py @@ -83,11 +83,23 @@ ] +_hdmi_infos = { + "HDMI_OUT0_MNEMONIC": "TX1", + "HDMI_OUT0_DESCRIPTION" : ( + " FIXME in platforms/netv2.py\\r\\n" + ), + + "HDMI_IN0_MNEMONIC": "RX1", + "HDMI_IN0_DESCRIPTION" : ( + " FIXME in platforms/netv2.py\\r\\n" + ), +} class Platform(XilinxPlatform): name = "netv2" default_clk_name = "clk50" default_clk_period = 20.0 + hdmi_infos = _hdmi_infos # From https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf # 17536096 bits == 2192012 == 0x21728c -- Therefore 0x220000 diff --git a/platforms/nexys_video.py b/platforms/nexys_video.py index 28e3c9b7..2a6cf00c 100644 --- a/platforms/nexys_video.py +++ b/platforms/nexys_video.py @@ -228,10 +228,23 @@ ) ] +_hdmi_infos = { + "HDMI_OUT0_MNEMONIC": "TX1", + "HDMI_OUT0_DESCRIPTION" : ( + " FIXME in platforms/nexys_video.py\\r\\n" + ), + + "HDMI_IN0_MNEMONIC": "RX1", + "HDMI_IN0_DESCRIPTION" : ( + " FIXME in platforms/nexys_video.py\\r\\n" + ), +} + class Platform(XilinxPlatform): name = "nexys_video" default_clk_name = "clk100" default_clk_period = 10.0 + hdmi_infos = _hdmi_infos # From https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf # 77,845,216 bits == 9730652 == 0x947a5c -- Therefore 0x1000000 diff --git a/platforms/opsis.py b/platforms/opsis.py index f190813b..7b97cc28 100644 --- a/platforms/opsis.py +++ b/platforms/opsis.py @@ -240,8 +240,9 @@ def tofe_pin(tofe_netname): Subsignal("hpd_en", Pins("V19"), IOStandard("LVCMOS33")) ), - # Debug header? - #("debug", 0, Pins("AA2"), IOStandard("LVCMOS15")), # (/FPGA_Bank_0_3/DEBUG_IO0) + # Debug header + ("debug_io0", 0, Pins("AA2"), IOStandard("LVCMOS15")), # (/FPGA_Bank_0_3/DEBUG_IO0) + ("debug_io1", 0, Pins("AA1"), IOStandard("LVCMOS15")), # (/FPGA_Bank_0_3/DEBUG_IO1) ## onboard HDMI OUT1 ## HDMI - connector J3 - Direction TX diff --git a/platforms/picoevb.py b/platforms/picoevb.py new file mode 100644 index 00000000..e1d97aa1 --- /dev/null +++ b/platforms/picoevb.py @@ -0,0 +1,135 @@ +from litex.build.generic_platform import * +from litex.build.xilinx import XilinxPlatform, VivadoProgrammer + +_io = [ + # SYS clock 100 MHz (input) signal. The sys_clk_p and sys_clk_n + # signals are the PCI Express reference clock. + #set_property PACKAGE_PIN B6 [get_ports sys_clk_p] + ("clk100", 0, Pins("B6"), IOStandard("LVCMOS33")), + + #set_property PACKAGE_PIN V14 [get_ports {status_leds[3]}] + #set_property PACKAGE_PIN V13 [get_ports {status_leds[2]}] + #set_property PACKAGE_PIN V11 [get_ports {status_leds[1]}] + #set_property PACKAGE_PIN V12 [get_ports {status_leds[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {status_leds[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {status_leds[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {status_leds[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {status_leds[0]}] + #set_property PULLUP true [get_ports {status_leds[3]}] + #set_property PULLUP true [get_ports {status_leds[2]}] + #set_property PULLUP true [get_ports {status_leds[1]}] + #set_property PULLUP true [get_ports {status_leds[0]}] + #set_property DRIVE 8 [get_ports {status_leds[3]}] + #set_property DRIVE 8 [get_ports {status_leds[2]}] + #set_property DRIVE 8 [get_ports {status_leds[1]}] + #set_property DRIVE 8 [get_ports {status_leds[0]}] + ("user_led", 0, Pins("V12"), IOStandard("LVCMOS33"), Drive(8), Misc("PULLUP")), + ("user_led", 1, Pins("V11"), IOStandard("LVCMOS33"), Drive(8), Misc("PULLUP")), + ("user_led", 2, Pins("V13"), IOStandard("LVCMOS33"), Drive(8), Misc("PULLUP")), + ("user_led", 3, Pins("V14"), IOStandard("LVCMOS33"), Drive(8), Misc("PULLUP")), + + ## Serial input/output + ## Available on NanoEVB only! + #set_property IOSTANDARD LVCMOS33 [get_ports RxD] + #set_property IOSTANDARD LVCMOS33 [get_ports TxD] + #set_property PACKAGE_PIN V17 [get_ports RxD] + #set_property PACKAGE_PIN V16 [get_ports TxD] + #set_property PULLUP true [get_ports RxD] + #set_property OFFCHIP_TERM NONE [get_ports TxD] + ("serial", 0, + Subsignal("tx", Pins("V16")), # MCU_RX + Subsignal("rx", Pins("V17")), # MCU_TX + IOStandard("LVCMOS33"), + ), + + ## SYS reset (input) signal. The sys_reset_n signal is generated + ## by the PCI Express interface (PERST#). + #set_property PACKAGE_PIN A10 [get_ports sys_rst_n] + #set_property IOSTANDARD LVCMOS33 [get_ports sys_rst_n] + #set_property PULLDOWN true [get_ports sys_rst_n] + + ## PCIe x1 link + #set_property PACKAGE_PIN G4 [get_ports pcie_mgt_rxp] + #set_property PACKAGE_PIN G3 [get_ports pcie_mgt_rxn] + #set_property PACKAGE_PIN B2 [get_ports pcie_mgt_txp] + #set_property PACKAGE_PIN B1 [get_ports pcie_mgt_txn] + ("pcie_x1", 0, + Subsignal("rst_n", Pins("A10"), IOStandard("LVCMOS33"), Misc("PULLDOWN")), + Subsignal("clk_p", Pins("D6")), + Subsignal("clk_n", Pins("D5")), + Subsignal("rx_p", Pins("G4")), + Subsignal("rx_n", Pins("G3")), + Subsignal("tx_p", Pins("B2")), + Subsignal("tx_n", Pins("B1")) + ), + + ## clkreq_l is active low clock request for M.2 card to + ## request PCI Express reference clock + #set_property PACKAGE_PIN A9 [get_ports clkreq_l] + #set_property IOSTANDARD LVCMOS33 [get_ports clkreq_l] + #set_property PULLDOWN true [get_ports clkreq_l] + + ## High-speed configuration so FPGA is up in time to negotiate with PCIe root complex + #set_property BITSTREAM.CONFIG.CONFIGRATE 33 [current_design] + #set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design] + #set_property CONFIG_MODE SPIx4 [current_design] + #set_property BITSTREAM.CONFIG.SPI_FALL_EDGE YES [current_design] + #set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design] +] + + +class Platform(XilinxPlatform): + name = "picoevb" + default_clk_name = "clk100" + default_clk_period = 10.0 + + # From https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf + # 17536096 bits == 2192012 == 0x21728c -- Therefore 0x220000 + gateware_size = 0x220000 + + # ??? + # FIXME: Create a "spi flash module" object in the same way we have SDRAM + # module objects. + spiflash_read_dummy_bits = 10 + spiflash_clock_div = 4 + spiflash_total_size = int((256/8)*1024*1024) # 256Mbit + spiflash_page_size = 256 + spiflash_sector_size = 0x10000 + spiflash_model = "n25q128" + + def __init__(self, toolchain="vivado", programmer="vivado"): + XilinxPlatform.__init__(self, "xc7a50t-csg325-2", _io, + toolchain=toolchain) + + self.add_platform_command( + "set_property CONFIG_VOLTAGE 1.5 [current_design]") + self.add_platform_command( + "set_property CFGBVS GND [current_design]") + self.add_platform_command( + "set_property BITSTREAM.CONFIG.CONFIGRATE 22 [current_design]") + self.add_platform_command( + "set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 1 [current_design]") + self.toolchain.bitstream_commands = [ + "set_property CONFIG_VOLTAGE 1.5 [current_design]", + "set_property CFGBVS GND [current_design]", + "set_property BITSTREAM.CONFIG.CONFIGRATE 22 [current_design]", + "set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 1 [current_design]", + ] + self.toolchain.additional_commands = \ + ["write_cfgmem -verbose -force -format bin -interface spix1 -size 64 " + "-loadbit \"up 0x0 {build_name}.bit\" -file {build_name}.bin"] + self.programmer = programmer + + self.add_platform_command(""" +create_clock -name pcie_phy_clk -period 10.0 [get_pins {{pcie_phy/pcie_support_i/pcie_i/inst/inst/gt_top_i/pipe_wrapper_i/pipe_lane[0].gt_wrapper_i/gtp_channel.gtpe2_channel_i/TXOUTCLK}}] +""") + + def create_programmer(self): + if self.programmer == "vivado": + return VivadoProgrammer(flash_part="n25q128-3.3v-spi-x1_x2_x4") + else: + raise ValueError("{} programmer is not supported" + .format(self.programmer)) + + def do_finalize(self, fragment): + XilinxPlatform.do_finalize(self, fragment) diff --git a/platforms/saturn.py b/platforms/saturn.py new file mode 100644 index 00000000..fd21513e --- /dev/null +++ b/platforms/saturn.py @@ -0,0 +1,151 @@ +# Support for the Numato Saturn (http://numato.com/product/saturn-spartan-6-fpga-development-board-with-ddr-sdram) +from litex.build.generic_platform import * +from litex.build.xilinx import XilinxPlatform + +#FIXME: +#this is for the LX45 version +#check on "no connect pins" for LX9 and LX25 + +_io = [ + ("clk100", 0, Pins("V10"), IOStandard("LVTTL")), + + ("serial", 0, + Subsignal("tx", Pins("L18")), + Subsignal("rx", Pins("L17"), Misc("PULLUP")), + Subsignal("cts", Pins("M16"), Misc("PULLUP")), + Subsignal("rts", Pins("M18"), Misc("PULLUP")), + IOStandard("LVTTL") + ), + + #the board has a FTDI FT2232H + ("usb_fifo", 0, + Subsignal("data", Pins("L17 L18 M16 M18 N17 N18 P17 P18")), + Subsignal("rxf_n", Pins("K18")), + Subsignal("txe_n", Pins("K17")), + Subsignal("rd_n", Pins("J18")), + Subsignal("wr_n", Pins("J16")), + Subsignal("siwua", Pins("H18")), + IOStandard("LVTTL"), + ), + + ("spiflash", 0, + Subsignal("cs_n", Pins("V3")), + Subsignal("clk", Pins("R15")), + Subsignal("mosi", Pins("R13")), + Subsignal("miso", Pins("T13"), Misc("PULLUP")), + IOStandard("LVCMOS33"), Misc("SLEW=FAST") + ), + + ("ddram_clock", 0, + Subsignal("p", Pins("G3")), + Subsignal("n", Pins("G1")), + IOStandard("MOBILE_DDR") + ), + + ("ddram", 0, + Subsignal("a", Pins("J7 J6 H5 L7 F3 H4 H3 H6 D2 D1 F4 D3 G6")), + Subsignal("ba", Pins("F2 F1")), + Subsignal("cke", Pins("H7")), + Subsignal("ras_n", Pins("L5")), + Subsignal("cas_n", Pins("K5")), + Subsignal("we_n", Pins("E3")), + Subsignal("dq", Pins("L2 L1 K2 K1 H2 H1 J3 J1 M3 M1 N2 N1 T2 T1 U2 U1")), + Subsignal("dqs", Pins("L4 P2")), + Subsignal("dm", Pins("K3 K4")), + IOStandard("MOBILE_DDR") + ) +] + +_connectors = [ + ("P3", "G13 H12 K14 J13 H16 H15 H14 H13 G14 F14 G18 G16 F16 F15 F18" #15 pins + "F17 E18 E16 D18 D17 C18 C17 A16 B16 A15 C15 C14 D14 A14 B14" #15 pins + "E13 F13 A13 C13 A12 B12 C11 D11 A11 B11 A10 C10 F9 G9 C9 D9" #16 pins + "A9 B9 C8 D8 A8 B8 A7 C7 A6 B6 C6 D6 A5 C5 A4 B4 A3 B3 A2 B2" #20 pins + ), + + ("P2", "K12 K13 L14 M13 M14 N14 L12 L13 L15 L16 K15 K16 N15 N16 T17" #15 pins + "T18 P15 P16 U16 V16 U17 U18 T14 V14 U15 V15 T12 V12 U13 V13" #15 pins + "R11 T11 M11 N11 N10 P11 U11 V11 R10 T10 M10 N9 T9 V9 R8 T8" #16 pins + "N7 P8 M8 N8 U7 V7 U8 V8 R7 T7 N6 P7 N5 P6 T6 V6 R5 T5 U5" #19 pins + "V5 R3 T3 T4 V4" # 5 pins + ) +] + +# FPGA P3 _connector "P3" FPGA P2 _connector P2 +# 5 0 G13 7 0 K12 +# 6 1 H12 8 1 K13 +# 7 2 K14 11 2 L14 +# 8 3 J13 12 3 M13 +# 9 4 H16 15 4 M14 +# 10 5 H15 16 5 N14 +# 11 6 H14 17 6 L12 +# 12 7 H13 18 7 L13 +# 13 8 G14 19 8 L15 +# 14 9 F14 20 9 L16 +# 15 10 G18 21 10 K15 +# 16 11 G16 22 11 K16 +# 17 12 F16 23 12 N15 +# 18 13 F15 24 13 N16 +# 19 14 F18 25 14 T17 +# 20 15 F17 26 15 T18 +# 21 16 E18 27 16 P15 +# 22 17 E16 28 17 P16 +# 23 18 D18 29 18 U16 +# 24 19 D17 30 19 V16 +# 25 20 C18 31 20 U17 +# 26 21 C17 32 21 U18 +# 27 22 A16 33 22 T14 +# 28 23 B16 34 23 V14 +# 29 24 A15 35 24 U15 +# 30 25 C15 36 25 V15 +# 31 26 C14 37 26 T12 +# 32 27 D14 38 27 V12 +# 33 28 A14 39 28 U13 +# 34 29 B14 40 29 V13 +# 35 30 E13 41 30 R11 +# 36 31 F13 42 31 T11 +# 37 32 A13 43 32 M11 +# 38 33 C13 44 33 N11 +# 43 34 A12 53 34 N10 +# 44 35 B12 54 35 P11 +# 47 36 C11 55 36 U11 +# 48 37 D11 56 37 V11 +# 55 38 A11 57 38 R10 +# 56 39 B11 58 39 T10 +# 57 40 A10 59 40 M10 +# 58 41 C10 60 41 N9 +# 59 42 F9 61 42 T9 +# 60 43 G9 62 43 V9 +# 61 44 C9 63 44 R8 +# 62 45 D9 64 45 T8 +# 63 46 A9 65 46 N7 +# 64 47 B9 66 47 P8 +# 69 48 C8 67 48 M8 +# 70 49 D8 68 49 N8 +# 71 50 A8 69 50 U7 +# 72 51 B8 70 51 V7 +# 75 52 A7 71 52 U8 +# 76 53 C7 72 53 V8 +# 77 54 A6 73 54 R7 +# 78 55 B6 74 55 T7 +# 79 56 C6 75 56 N6 +# 80 57 D6 76 57 P7 +# 81 58 A5 77 58 N5 +# 82 59 C5 78 59 P6 +# 83 60 A4 79 60 T6 +# 84 61 B4 80 61 V6 +# 85 62 A3 81 62 R5 +# 86 63 B3 82 63 T5 +# 87 64 A2 83 64 U5 +# 88 65 B2 84 65 V5 +# 85 66 R3 +# 86 67 T3 +# 87 68 T4 +# 88 69 V4 + +class Platform(XilinxPlatform): + default_clk_name = "clk100" + default_clk_period = 10.00 + + def __init__(self): + XilinxPlatform.__init__(self, "xc6slx45-2csg324", _io, _connectors) diff --git a/platforms/waxwing.py b/platforms/waxwing.py new file mode 100644 index 00000000..3035669c --- /dev/null +++ b/platforms/waxwing.py @@ -0,0 +1,161 @@ +# Support for the Numato Waxwing Spartan 6 Development Module +# https://numato.com/product/waxwing-spartan-6-fpga-development-board + +from litex.build.generic_platform import * +from litex.build.xilinx import XilinxPlatform + + +_io = [ + ("clk100", 0, Pins("V10"), IOStandard("LVTTL")), + + ("serial", 0, + Subsignal("tx", Pins("L18")), + Subsignal("rx", Pins("L17"), Misc("PULLUP")), + Subsignal("cts", Pins("M16"), Misc("PULLUP")), + Subsignal("rts", Pins("M18"), Misc("PULLUP")), + IOStandard("LVTTL") + ), + + #the board has a FTDI FT2232H + ("usb_fifo", 0, + Subsignal("data", Pins("L17 L18 M16 M18 N17 N18 P17 P18")), + Subsignal("rxf_n", Pins("K18")), + Subsignal("txe_n", Pins("K17")), + Subsignal("rd_n", Pins("J18")), + Subsignal("wr_n", Pins("J16")), + Subsignal("siwua", Pins("H18")), + IOStandard("LVTTL"), + ), + + ("spiflash", 0, + Subsignal("cs_n", Pins("V3")), + Subsignal("clk", Pins("R15")), + Subsignal("mosi", Pins("R13")), + Subsignal("miso", Pins("T13"), Misc("PULLUP")), + IOStandard("LVCMOS33"), Misc("SLEW=FAST") + ), + + ("ddram_clock", 0, + Subsignal("p", Pins("G3")), + Subsignal("n", Pins("G1")), + IOStandard("MOBILE_DDR") + ), + + ("ddram", 0, + Subsignal("a", Pins("J7 J6 H5 L7 F3 H4 H3 H6 D2 D1 F4 D3 G6")), + Subsignal("ba", Pins("F2 F1")), + Subsignal("cke", Pins("H7")), + Subsignal("ras_n", Pins("L5")), + Subsignal("cas_n", Pins("K5")), + Subsignal("we_n", Pins("E3")), + Subsignal("dq", Pins("L2 L1 K2 K1 H2 H1 J3 J1 M3 M1 N2 N1 T2 T1 U2 U1")), + Subsignal("dqs", Pins("L4 P2")), + Subsignal("dm", Pins("K3 K4")), + IOStandard("MOBILE_DDR") + ), + + # Small DIP switches + # DP1 (user_sw:0) -> DP8 (user_sw:7) + ("user_sw", 0, Pins("L17"), IOStandard("LVCMOS33"), Misc("PULLUP")), + ("user_sw", 1, Pins("C18"), IOStandard("LVCMOS33"), Misc("PULLUP")), + ("user_sw", 2, Pins("C17"), IOStandard("LVCMOS33"), Misc("PULLUP")), + ("user_sw", 3, Pins("G14"), IOStandard("LVCMOS33"), Misc("PULLUP")), + + ("user_btn", 0, Pins("F14"), IOStandard("LVCMOS33"), Misc("PULLUP")), + ("user_btn", 1, Pins("A14"), IOStandard("LVCMOS33"), Misc("PULLUP")), + ("user_btn", 2, Pins("T6"), IOStandard("LVCMOS33"), Misc("PULLUP")), + ("user_btn", 3, Pins("R5"), IOStandard("LVCMOS33"), Misc("PULLUP")), + ("user_btn", 4, Pins("B14"), IOStandard("LVCMOS33"), Misc("PULLUP")), + ("user_btn", 5, Pins("V6"), IOStandard("LVCMOS33"), Misc("PULLUP")), + ("user_btn", 6, Pins("T5"), IOStandard("LVCMOS33"), Misc("PULLUP")), + + ("vga_out", 0, + Subsignal("hsync_n", Pins("U8"), IOStandard("LVCMOS33"), + Misc("SLEW=FAST")), + Subsignal("vsync_n", Pins("V8"), IOStandard("LVCMOS33"), + Misc("SLEW=FAST")), + Subsignal("r", Pins("M8 R11 T11"), IOStandard("LVCMOS33"), + Misc("SLEW=FAST")), + Subsignal("g", Pins("N7 P8 N8"), IOStandard("LVCMOS33"), + Misc("SLEW=FAST")), + Subsignal("b", Pins("P7 N6"), IOStandard("LVCMOS33"), + Misc("SLEW=FAST"))), + + ("sevenseg", 0, + Subsignal("segment7", Pins("L18"), IOStandard("LVCMOS33")), # A + Subsignal("segment6", Pins("F18"), IOStandard("LVCMOS33")), # B + Subsignal("segment5", Pins("G18"), IOStandard("LVCMOS33")), # C + Subsignal("segment4", Pins("K12"), IOStandard("LVCMOS33")), # D + Subsignal("segment3", Pins("K13"), IOStandard("LVCMOS33")), # E + Subsignal("segment2", Pins("L16"), IOStandard("LVCMOS33")), # F + Subsignal("segment1", Pins("L15"), IOStandard("LVCMOS33")), # G + Subsignal("segment0", Pins("G16"), IOStandard("LVCMOS33")), # Dot + Subsignal("enable0", Pins("F17"), IOStandard("LVCMOS33")), # EN0 + Subsignal("enable1", Pins("L14"), IOStandard("LVCMOS33")), # EN1 + Subsignal("enable2", Pins("M13"), IOStandard("LVCMOS33"))), # EN2 + + ("mmc", 0, + Subsignal("dat", Pins("N10 P11 R8 T8"), IOStandard("LVCMOS33"), + Misc("SLEW=FAST")), + + Subsignal("cmd", Pins("T9"), IOStandard("LVCMOS33"), + Misc("SLEW=FAST")), + + Subsignal("clk", Pins("V9"), IOStandard("LVCMOS33"), + Misc("SLEW=FAST"))), + + ("eth_clocks", 0, + Subsignal("tx", Pins("R10")), + Subsignal("rx", Pins("T10")), + IOStandard("LVCMOS33") + ), + ("eth", 0, + Subsignal("rst_n", Pins("P18")), + Subsignal("mdio", Pins("V16")), + Subsignal("mdc", Pins("T18")), + Subsignal("dv", Pins("N14")), + Subsignal("rx_er", Pins("P16")), + Subsignal("rx_data", Pins("U17 U18 M18 M16")), + Subsignal("tx_en", Pins("M14")), + Subsignal("tx_data", Pins("N16 N15 V12 T12")), + Subsignal("col", Pins("U16")), + Subsignal("crs", Pins("P17")), + IOStandard("LVCMOS33") + ), + + ("hdmi_out", 0, + Subsignal("clk_p", Pins("C10"), IOStandard("TMDS_33")), + Subsignal("clk_n", Pins("A10"), IOStandard("TMDS_33")), + Subsignal("data0_p", Pins("C7"), IOStandard("TMDS_33")), + Subsignal("data0_n", Pins("A7"), IOStandard("TMDS_33")), + Subsignal("data1_p", Pins("B8"), IOStandard("TMDS_33")), + Subsignal("data1_n", Pins("A8"), IOStandard("TMDS_33")), + Subsignal("data2_p", Pins("D8"), IOStandard("TMDS_33")), + Subsignal("data2_n", Pins("C8"), IOStandard("TMDS_33")), + Subsignal("scl", Pins("C6"), IOStandard("I2C")), + Subsignal("sda", Pins("D6"), IOStandard("I2C")), + Subsignal("hpd_notif", Pins("D14"), IOStandard("LVCMOS33")) + ), + + ("ac97", 0, + Subsignal("sdo", Pins("B9"), IOStandard("LVCMOS33")), + Subsignal("bit_clk", Pins("C9"), IOStandard("LVCMOS33")), + Subsignal("sdi", Pins("A9"), IOStandard("LVCMOS33")), + Subsignal("sync", Pins("D9"), IOStandard("LVCMOS33")), + Subsignal("reset", Pins("C13"), IOStandard("LVCMOS33")), + ), +] + +_connectors = [ + ("P3", "F15 F16 E16 E18 B12 A12 B11 A11"), + ("P4", "B6 A6 D11 C11 H15 H16 F13 E13"), + ("P5", "B4 A4 C5 A5 B3 A3 B2 A2"), +] + + +class Platform(XilinxPlatform): + default_clk_name = "clk100" + default_clk_period = 10.00 + + def __init__(self): + XilinxPlatform.__init__(self, "xc6slx45-2csg324", _io, _connectors) diff --git a/scripts/build-linux.sh b/scripts/build-linux.sh new file mode 100755 index 00000000..e6477cbd --- /dev/null +++ b/scripts/build-linux.sh @@ -0,0 +1,150 @@ +#!/bin/bash + +if [ "$(whoami)" = "root" ] +then + echo "Running the script as root is not permitted" + exit 1 +fi + +CALLED=$_ +[[ "${BASH_SOURCE[0]}" != "${0}" ]] && SOURCED=1 || SOURCED=0 + +SCRIPT_SRC=$(realpath ${BASH_SOURCE[0]}) +SCRIPT_DIR=$(dirname $SCRIPT_SRC) +TOP_DIR=$(realpath $SCRIPT_DIR/..) + +if [ $SOURCED = 1 ]; then + echo "You must run this script, rather then try to source it." + echo "$SCRIPT_SRC" + return +fi + +if [ -z "$HDMI2USB_ENV" ]; then + echo "You appear to not be inside the HDMI2USB environment." + echo "Please enter environment with:" + echo " source scripts/enter-env.sh" + exit 1 +fi + +# Imports TARGET, PLATFORM, CPU and TARGET_BUILD_DIR from Makefile +eval $(make env) +make info + +set -x +set -e + +if [ "$CPU" != or1k ]; then + echo "Linux is only supported on or1k at the moment." + exit 1 +fi +if [ "$CPU_VARIANT" != "linux" ]; then + echo "Linux needs a CPU_VARIANT set to 'linux' to enable features" + echo "needed by Linux like the MMU." + exit 1 +fi +if [ "$FIRMWARE" != "linux" ]; then + echo "When building Linux you should set FIRMWARE to 'linux'." + exit 1 +fi + +# Install a toolchain with the newlib standard library +if ! $CPU-elf-newlib-gcc --version > /dev/null 2>&1; then + conda install gcc-$CPU-elf-newlib +fi + +# Get linux-litex is needed +LINUX_SRC="$TOP_DIR/third_party/linux" +LINUX_LOCAL="$LINUX_GITLOCAL" # Local place to clone from +LINUX_REMOTE="${LINUX_REMOTE:-https://github.com/mithro/linux-litex.git}" +LINUX_REMOTE_NAME=mithro-linux-litex +LINUX_REMOTE_BIT=$(echo $LINUX_REMOTE | sed -e's-^.*://--' -e's/.git$//') +LINUX_CLONE_FROM="${LINUX_LOCAL:-$LINUX_REMOTE}" +LINUX_BRANCH=${LINUX_BRANCH:-litex-minimal} +( + # Download the Linux source for the first time + if [ ! -d "$LINUX_SRC" ]; then + ( + cd $(dirname $LINUX_SRC) + echo "Downloading Linux source tree." + echo "If you already have a local git checkout you can set 'LINUX_GITLOCAL' to speed up this step." + git clone $LINUX_CLONE_FROM $LINUX_SRC + ) + fi + + # Change into the dir + cd $LINUX_SRC + + # Add the remote if it doesn't exist + CURRENT_LINUX_REMOTE_NAME=$(git remote -v | grep fetch | grep "$LINUX_REMOTE_BIT" | sed -e's/\t.*$//') + if [ x"$CURRENT_LINUX_REMOTE_NAME" = x ]; then + git remote add $LINUX_REMOTE_NAME $LINUX_REMOTE + CURRENT_LINUX_REMOTE_NAME=$LINUX_REMOTE_NAME + fi + + # Get any new data + git fetch $CURRENT_LINUX_REMOTE_NAME + + # Checkout or1k-linux branch it not already on it + if [ "$(git rev-parse --abbrev-ref HEAD)" != "$LINUX_BRANCH" ]; then + git checkout $LINUX_BRANCH || \ + git checkout "$CURRENT_LINUX_REMOTE_NAME/$LINUX_BRANCH" -b $LINUX_BRANCH + fi +) + +# Get litex-devicetree +LITEX_DT_SRC="$TOP_DIR/third_party/litex-devicetree" +LITEX_DT_REMOTE="${LITEX_DT_REMOTE:-https://github.com/mithro/litex-devicetree.git}" +LITEX_DT_REMOTE_BIT=$(echo $LITEX_DT_REMOTE | sed -e's-^.*://--' -e's/.git$//') +LITEX_DT_REMOTE_NAME=mithro-litex-devicetree +LITEX_DT_BRANCH=master +( + # Download the Linux source for the first time + if [ ! -d "$LITEX_DT_SRC" ]; then + ( + cd $(dirname $LITEX_DT_SRC) + echo "Downloading LiteX devicetree code." + git clone $LITEX_DT_REMOTE $LITEX_DT_SRC + ) + fi + + # Change into the dir + cd $LITEX_DT_SRC + + # Add the remote if it doesn't exist + CURRENT_LITEX_DT_REMOTE_NAME=$(git remote -v | grep fetch | grep "$LITEX_DT_REMOTE_BIT" | sed -e's/\t.*$//') + if [ x"$CURRENT_LITEX_DT_REMOTE_NAME" = x ]; then + git remote add $LITEX_DT_REMOTE_NAME $LITEX_DT_REMOTE + CURRENT_LITEX_DT_REMOTE_NAME=$LITEX_DT_REMOTE_NAME + fi + + # Get any new data + git fetch $CURRENT_LITEX_DT_REMOTE_NAME + + # Checkout or1k-linux branch it not already on it + if [ "$(git rev-parse --abbrev-ref HEAD)" != "$LITEX_DT_BRANCH" ]; then + git checkout $LITEX_DT_BRANCH || \ + git checkout "$CURRENT_LITEX_DT_REMOTE_NAME/$LITEX_DT_BRANCH" -b $LITEX_DT_BRANCH + fi +) + +# Build linux-litex +export ARCH=openrisc +export CROSS_COMPILE=$CPU-elf-newlib- +TARGET_LINUX_BUILD_DIR=$(dirname $TOP_DIR/$FIRMWARE_FILEBASE) +( + cd $LINUX_SRC + echo "Building Linux in $TARGET_LINUX_BUILD_DIR" + mkdir -p $TARGET_LINUX_BUILD_DIR + ( + cd $TARGET_LINUX_BUILD_DIR + # To rebuild, use https://ozlabs.org/~joel/litex_or1k_defconfig + ROOTFS=openrisc-rootfs.cpio.gz + if [ ! -e $ROOTFS ]; then + wget "https://ozlabs.org/~joel/openrisc-rootfs.cpio.gz" -O $ROOTFS + fi + ) + make O="$TARGET_LINUX_BUILD_DIR" litex_defconfig + time make O="$TARGET_LINUX_BUILD_DIR" -j$JOBS + ls -l $TARGET_LINUX_BUILD_DIR/arch/openrisc/boot/vmlinux.bin + ln -sf $TARGET_LINUX_BUILD_DIR/arch/openrisc/boot/vmlinux.bin $TOP_DIR/$FIRMWARE_FILEBASE.bin +) diff --git a/scripts/build-micropython.sh b/scripts/build-micropython.sh index cf5612c8..5147defc 100755 --- a/scripts/build-micropython.sh +++ b/scripts/build-micropython.sh @@ -33,6 +33,11 @@ make info set -x set -e +if [ "$FIRMWARE" != "micropython" ]; then + echo "When building MicroPython you should set FIRMWARE to 'micropython'." + exit 1 +fi + # Install a toolchain with the newlib standard library if ! $CPU-elf-newlib-gcc --version > /dev/null 2>&1; then conda install gcc-$CPU-elf-newlib @@ -43,7 +48,7 @@ MPY_SRC_DIR=$TOP_DIR/third_party/micropython if [ ! -d "$MPY_SRC_DIR" ]; then ( cd $(dirname $MPY_SRC_DIR) - git clone https://github.com/upy-fpga/micropython.git + git clone https://github.com/fupy/micropython.git cd $MPY_SRC_DIR git submodule update --init ) @@ -71,9 +76,8 @@ export BUILDINC_DIRECTORY="$(realpath $TARGET_BUILD_DIR/software/include)" export BUILD="$(realpath $TARGET_MPY_BUILD_DIR)" OLD_DIR=$PWD cd $TARGET_MPY_BUILD_DIR -make V=1 -C $(realpath ../../../../third_party/micropython/litex/) +make V=1 -C $(realpath ../../../../third_party/micropython/litex/) -j$JOBS cd $OLD_DIR # Generate a firmware image suitable for flashing. -python -m litex.soc.tools.mkmscimg -f $TARGET_MPY_BUILD_DIR/firmware.bin -o $TARGET_MPY_BUILD_DIR/firmware.fbi -/usr/bin/env python mkimage.py $MISOC_EXTRA_CMDLINE $LITEX_EXTRA_CMDLINE --output-file=$TARGET_BUILD_DIR/micropython.bin --override-firmware=$TARGET_MPY_BUILD_DIR/firmware.fbi +make image diff --git a/scripts/build-qemu.sh b/scripts/build-qemu.sh index 93f6294f..e4308bfc 100755 --- a/scripts/build-qemu.sh +++ b/scripts/build-qemu.sh @@ -33,6 +33,10 @@ make info set -x set -e +QEMU_REMOTE="${QEMU_REMOTE:-https://github.com/timvideos/qemu-litex.git}" +QEMU_REMOTE_NAME=timvideos-qemu-litex +QEMU_REMOTE_BIT=$(echo $QEMU_REMOTE | sed -e's-^.*://--' -e's/.git$//') +QEMU_BRANCH=${QEMU_BRANCH:-master} QEMU_SRC_DIR=$TOP_DIR/third_party/qemu-litex if [ ! -d "$QEMU_SRC_DIR" ]; then ( @@ -41,6 +45,26 @@ if [ ! -d "$QEMU_SRC_DIR" ]; then cd $QEMU_SRC_DIR git submodule update --init dtc ) +else + ( + cd $QEMU_SRC_DIR + + # Add the remote if it doesn't exist + CURRENT_QEMU_REMOTE_NAME=$(git remote -v | grep fetch | grep "$QEMU_REMOTE_BIT" | sed -e's/\t.*$//') + if [ x"$CURRENT_QEMU_REMOTE_NAME" = x ]; then + git remote add $QEMU_REMOTE_NAME $QEMU_REMOTE + CURRENT_QEMU_REMOTE_NAME=$QEMU_REMOTE_NAME + fi + + # Get any new data + git fetch $CURRENT_QEMU_REMOTE_NAME + + # Checkout master branch it not already on it + if [ "$(git rev-parse --abbrev-ref HEAD)" != "$QEMU_BRANCH" ]; then + git checkout $QEMU_BRANCH || \ + git checkout "$CURRENT_QEMU_REMOTE_NAME/$QEMU_BRANCH" -b $QEMU_BRANCH + fi + ) fi TARGET_QEMU_BUILD_DIR=$TARGET_BUILD_DIR/qemu @@ -83,7 +107,7 @@ fi OLD_DIR=$PWD cd $TARGET_QEMU_BUILD_DIR -make -j8 +make -j$JOBS cd $OLD_DIR # Need the .fbi for mkimage below... @@ -92,7 +116,7 @@ if [ ! -d $FIRMWARE_FILEBASE.fbi ]; then fi QEMU_IMAGE_FILE=$IMAGE_FILE.4qemu -/usr/bin/env python mkimage.py $MISOC_EXTRA_CMDLINE $LITEX_EXTRA_CMDLINE --output-file=$QEMU_IMAGE_FILE --override-gateware=none --force-image-size=true $OVERRIDE_FIRMWARE +/usr/bin/env python mkimage.py $MISOC_EXTRA_CMDLINE $LITEX_EXTRA_CMDLINE $MAKE_LITEX_EXTRA_CMDLINE --output-file=$QEMU_IMAGE_FILE --override-gateware=none --force-image-size=true $OVERRIDE_FIRMWARE $TARGET_QEMU_BUILD_DIR/qemu-img convert -f raw $QEMU_IMAGE_FILE -O qcow2 -S 16M $TARGET_BUILD_DIR/qemu.qcow2 # BIOS @@ -113,18 +137,81 @@ fi # Ethernet if grep -q ETHMAC_BASE $TARGET_BUILD_DIR/software/include/generated/csr.h; then - if [ ! -e /dev/net/tap0 ]; then - sudo true - echo "Need to bring up a tun device." - IPRANGE=192.168.100 - sudo openvpn --mktun --dev tap0 - sudo ifconfig tap0 $IPRANGE.100 up - sudo mknod /dev/net/tap0 c 10 200 - sudo chown $(whoami) /dev/net/tap0 + QEMU_NETWORK=${QEMU_NETWORK:-tap} + case $QEMU_NETWORK in + tap) + echo "Using tun device for QEmu networking, (may need sudo)..." + # Make the tap0 dev node exists + if [ ! -e /dev/net/tap0 ]; then + sudo true + sudo mknod /dev/net/tap0 c 10 200 + sudo chown $(whoami) /dev/net/tap0 + fi + + # Check that the tap0 network interface exists + if [ ! -e /sys/class/net/tap0 ]; then + sudo true + if sudo which openvpn > /dev/null; then + sudo openvpn --mktun --dev tap0 --user $(whoami) + elif sudo which tunctl > /dev/null; then + sudo tunctl -t tap0 -u $(whoami) + else + echo "Unable to find tool to create tap0 device!" + exit 1 + fi + fi + + # Check the tap0 device if configure and up + if sudo which ifconfig > /dev/null; then + if ! ifconfig tap0 | grep -q "UP" || ! ifconfig tap0 | grep -q "$TFTP_IPRANGE.100"; then + sudo true + sudo ifconfig tap0 $TFTP_IPRANGE.100 netmask 255.255.255.0 up + fi + elif sudo which ip > /dev/null; then + if ! ip addr show tap0 | grep -q "UP" || ! ip addr show tap0 | grep -q "$TFTP_IPRANGE.100"; then + sudo true + sudo ip addr add $TFTP_IPRANGE.100/24 dev tap0 + sudo ip link set dev tap0 up + fi + else + echo "Unable to find tool to configure tap0 address" + exit 1 + fi + + # Restart tftpd + make tftpd_stop make tftpd_start - fi + + EXTRA_ARGS+=("-net nic -net tap,ifname=tap0,script=no,downscript=no") + ;; + + user) + # Make qemu emulate a network device + EXTRA_ARGS+=("-net nic") + # Use the userspace network support. QEMU will pretend to be a + # machine a $TFTP_IPRANGE.100. Any connections to that IP will + # automatically be forwarded to the real localhost. + # + # Connections to real localhost on port 2223, will be + # forwarded to the expected guest ip ($TFTP_IPRANGE.50) on port + # 23 (telnet). + EXTRA_ARGS+=("-net user,net=$TFTP_IPRANGE.0/24,host=$TFTP_IPRANGE.100,dhcpstart=$TFTP_IPRANGE.50,tftp=$TFTPD_DIR,hostfwd=tcp::2223-:23") + + # Make debugging the userspace networking easier, dump all + # packets to a file. + # FIXME: Make this optional. + EXTRA_ARGS+=("-net dump,file=/tmp/data.pcap") + ;; + none) + echo "QEmu networking disabled..." + ;; + *) + echo "Unknown QEMU_NETWORK mode '$QEMU_NETWORK'" + ;; + esac + + # Build/copy the image into the TFTP directory. make tftp - EXTRA_ARGS+=("-net nic -net tap,ifname=tap0,script=no,downscript=no") fi # Allow gdb connections @@ -136,6 +223,6 @@ echo $SPIFLASH_MODEL $TARGET_QEMU_BUILD_DIR/$QEMU_ARCH/qemu-system-$QEMU_CPU \ -M litex \ -nographic -nodefaults \ - -monitor pty \ + -monitor telnet::10000,server,nowait \ -serial stdio \ ${EXTRA_ARGS[@]} diff --git a/scripts/check-firmware-newlines.sh b/scripts/check-firmware-newlines.sh new file mode 100755 index 00000000..cebbbe1d --- /dev/null +++ b/scripts/check-firmware-newlines.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +if [ "`whoami`" = "root" ] +then + echo "Running the script as root is not permitted" + exit 1 +fi + +CALLED=$_ +[[ "${BASH_SOURCE[0]}" != "${0}" ]] && SOURCED=1 || SOURCED=0 + +SETUP_SRC="$(realpath ${BASH_SOURCE[0]})" +SETUP_DIR="$(dirname "${SETUP_SRC}")" +TOP_DIR="$(realpath "${SETUP_DIR}/..")" + +if [ $SOURCED = 1 ]; then + echo "You must run this script, rather then try to source it." + echo "$SETUP_SRC" + return +fi + +set -euf +cd $TOP_DIR/firmware + +find . '(' -name '*.c' -o -name '*.h' ')' \ +| while read fn; do + case $fn in + ./telnet.c) + continue + ;; + esac + if grep -qF '\r\n' $fn; then + echo "$fn" 'contains a \\r\\n.' + echo 'You should just write \\n, stdio_wrap will transform this to a \\r\\n, as appropriate' + exit 1 + fi +done diff --git a/scripts/download-env.sh b/scripts/download-env.sh index 0f79ca44..e083ec99 100755 --- a/scripts/download-env.sh +++ b/scripts/download-env.sh @@ -19,12 +19,6 @@ if [ $SOURCED = 1 ]; then return fi -if [ ! -z "$HDMI2USB_ENV" ]; then - echo "You appear to have sourced the HDMI2USB settings, these are incompatible with setting up." - echo "Please exit this terminal and run again from a clean shell." - exit 1 -fi - if [ ! -z "$SETTINGS_FILE" -o ! -z "$XILINX" ]; then echo "You appear to have sourced the Xilinx ISE settings, these are incompatible with setting up." echo "Please exit this terminal and run again from a clean shell." @@ -69,7 +63,8 @@ if [ ! -z "$XILINX_PASSPHRASE" ]; then echo $XILINX_PASSPHRASE >> $XILINX_PASSPHRASE_FILE # Need gpg to do the unencryption - XILINX_DIR=$BUILD_DIR/Xilinx + export XILINX_DIR=$BUILD_DIR/Xilinx + export LIKELY_XILINX_LICENSE_DIR=$XILINX_DIR if [ ! -d "$XILINX_DIR" -o ! -d "$XILINX_DIR/opt" ]; then ( cd $BUILD_DIR @@ -93,6 +88,10 @@ if [ ! -z "$XILINX_PASSPHRASE" ]; then mkdir -p $XILINX_DIR/opt/Xilinx/Vivado/2017.3/scripts/rt/data/svlog/sdbs mkdir -p $XILINX_DIR/opt/Xilinx/Vivado/2017.3/tps/lnx64/jre + # Make ISE stop complaining about missing wbtc binary + mkdir -p $XILINX_DIR/opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64 + ln -s /bin/true $XILINX_DIR/opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64/wbtc + # Relocate ISE from /opt to $XILINX_DIR for i in $(grep -l -Rsn "/opt/Xilinx" $XILINX_DIR/opt) do @@ -106,20 +105,76 @@ if [ ! -z "$XILINX_PASSPHRASE" ]; then #make ) fi - export MISOC_EXTRA_CMDLINE="-Ob toolchain_path $XILINX_DIR/opt/Xilinx/" - # Reserved MAC address from documentation block, see - # http://www.iana.org/assignments/ethernet-numbers/ethernet-numbers.xhtml - export XILINXD_LICENSE_FILE=$XILINX_DIR - export MACADDR=90:10:00:00:00:01 - #export LD_PRELOAD=$XILINX_DIR/impersonate_macaddress/impersonate_macaddress.so - #ls -l $LD_PRELOAD - rm $XILINX_PASSPHRASE_FILE trap - EXIT -elif [ -z "$XILINX_DIR" ]; then - XILINX_DIR=/ fi +if [ -z "$LIKELY_XILINX_LICENSE_DIR" ]; then + LIKELY_XILINX_LICENSE_DIR="$HOME/.Xilinx" +fi + +XILINX_SETTINGS_ISE='/opt/Xilinx/*/ISE_DS/settings64.sh' +XILINX_SETTINGS_VIVADO='/opt/Xilinx/Vivado/*/settings64.sh' + +if [ -z "$XILINX_DIR" ]; then + LOCAL_XILINX_DIR=$BUILD_DIR/Xilinx + if [ -d "$LOCAL_XILINX_DIR/opt/Xilinx/" ]; then + # Reserved MAC address from documentation block, see + # http://www.iana.org/assignments/ethernet-numbers/ethernet-numbers.xhtml + export LIKELY_XILINX_LICENSE_DIR=$LOCAL_XILINX_DIR + export MACADDR=90:10:00:00:00:01 + #export LD_PRELOAD=$XILINX_DIR/impersonate_macaddress/impersonate_macaddress.so + #ls -l $LD_PRELOAD + export XILINX_DIR=$LOCAL_XILINX_DIR + export XILINX_LOCAL_USER_DATA=no + fi +fi +if [ -z "$LIKELY_XILINX_LICENSE_DIR" ]; then + LIKELY_XILINX_LICENSE_DIR="$HOME/.Xilinx" +fi +shopt -s nullglob +XILINX_SETTINGS_ISE=($XILINX_DIR/$XILINX_SETTINGS_ISE) +XILINX_SETTINGS_VIVADO=($XILINX_DIR/$XILINX_SETTINGS_VIVADO) +shopt -u nullglob + echo " Xilinx directory is: $XILINX_DIR/opt/Xilinx/" +if [ ${#XILINX_SETTINGS_ISE[@]} -gt 0 ]; then + echo -n " - Xilinx ISE toolchain found!" + if [ ${#XILINX_SETTINGS_ISE[@]} -gt 1 ]; then + echo -n " (${#XILINX_SETTINGS_ISE[@]} versions)" + fi + echo "" + export HAVE_XILINX_ISE=1 +else + export HAVE_XILINX_ISE=0 +fi +if [ ${#XILINX_SETTINGS_VIVADO[@]} -gt 0 ]; then + echo -n " - Xilinx Vivado toolchain found!" + if [ ${#XILINX_SETTINGS_VIVADO[@]} -gt 1 ]; then + echo -n " (${#XILINX_SETTINGS_VIVADO[@]} versions)" + fi + echo "" + export HAVE_XILINX_VIVADO=1 +else + export HAVE_XILINX_VIVADO=0 +fi +if [ $HAVE_XILINX_ISE -eq 1 -o $HAVE_XILINX_VIVADO -eq 1 ]; then + export HAVE_XILINX_TOOLCHAIN=1 +else + export HAVE_XILINX_TOOLCHAIN=0 +fi +if [ $HAVE_XILINX_TOOLCHAIN -eq 1 ]; then + export MISOC_EXTRA_CMDLINE="-Ob toolchain_path $XILINX_DIR/opt/Xilinx/" +fi + +# Detect a likely lack of license early, but just warn if it's missing +# just in case they've set it up elsewhere. +if [ ! -e $LIKELY_XILINX_LICENSE_DIR/Xilinx.lic ]; then + echo "(WARNING) Please ensure you have installed Xilinx and have a license." + echo "(WARNING) Copy your Xilinx license to Xilinx.lic in $LIKELY_XILINX_LICENSE_DIR to suppress this warning." +else + echo " Xilinx license in: $LIKELY_XILINX_LICENSE_DIR" + export XILINXD_LICENSE_FILE=$LIKELY_XILINX_LICENSE_DIR +fi function check_exists { TOOL=$1 @@ -173,6 +228,17 @@ function check_import_version { fi } +function fix_conda { + for py in $(find $CONDA_DIR -name envs_manager.py); do + START_SUM=$(sha256sum $py | sed -e's/ .*//') + sed -i -e"s^expand(join('~', '.conda', 'environments.txt'))^join('$CONDA_DIR', 'environments.txt')^" $py + END_SUM=$(sha256sum $py | sed -e's/ .*//') + if [ $START_SUM != $END_SUM ]; then + sed -i -e"s/$START_SUM/$END_SUM/" $(find $CONDA_DIR -name paths.json) + fi + done +} + echo "" echo "Initializing environment" echo "---------------------------------" @@ -190,68 +256,88 @@ export PATH=$CONDA_DIR/bin:$PATH:/sbin # -b to enable batch mode (no prompts) # -f to not return an error if the location specified by -p already exists ./Miniconda3-latest-Linux-x86_64.sh -p $CONDA_DIR -b -f - conda config --set always_yes yes --set changeps1 no + fix_conda + conda config --system --set always_yes yes + conda config --system --set changeps1 no + conda config --system --add envs_dirs $CONDA_DIR/envs + conda config --system --add pkgs_dirs $CONDA_DIR/pkgs conda update -q conda fi - conda config --add channels timvideos + fix_conda + conda config --system --add channels timvideos + conda info ) +eval $(cd $TOP_DIR; export HDMI2USB_ENV=1; make env || return 1) || exit 1 +( + cd $TOP_DIR + export HDMI2USB_ENV=1 + make info || return 1 + echo +) || exit 1 + +echo "python ==3.6" > $CONDA_DIR/conda-meta/pinned # Make sure it stays at version 3.6 + # Check the Python version echo -echo "Installing python3.5" -conda install python=3.5 -check_version python 3.5 -echo "python ==3.5.4" > $CONDA_DIR/conda-meta/pinned # Make sure it stays at version 3.5 +echo "Installing python3.6" +conda install -y $CONDA_FLAGS python=3.6 +fix_conda +check_version python 3.6 echo "" echo "Installing binaries into environment" echo "---------------------------------" # fxload -echo -echo "Installing fxload (tool for Cypress FX2)" -# conda install fxload -check_exists fxload +if [ "$PLATFORM" == "opsis" -o "$PLATFORM" == "atlys" ]; then + echo + echo "Installing fxload (tool for Cypress FX2)" + # conda install fxload + check_exists fxload +fi # FIXME: Remove this once @jimmo has finished his new firmware # MimasV2Config.py -MIMASV2CONFIG=$BUILD_DIR/conda/bin/MimasV2Config.py -echo -echo "Installing MimasV2Config.py (mimasv2 flashing tool)" -if [ ! -e $MIMASV2CONFIG ]; then - wget https://raw.githubusercontent.com/numato/samplecode/master/FPGA/MimasV2/tools/configuration/python/MimasV2Config.py -O $MIMASV2CONFIG - chmod a+x $MIMASV2CONFIG +if [ "$PLATFORM" == "mimasv2" ]; then + MIMASV2CONFIG=$BUILD_DIR/conda/bin/MimasV2Config.py + echo + echo "Installing MimasV2Config.py (mimasv2 flashing tool)" + if [ ! -e $MIMASV2CONFIG ]; then + wget https://raw.githubusercontent.com/numato/samplecode/master/FPGA/MimasV2/tools/configuration/python/MimasV2Config.py -O $MIMASV2CONFIG + chmod a+x $MIMASV2CONFIG + fi + check_exists MimasV2Config.py fi -check_exists MimasV2Config.py # flterm echo echo "Installing flterm (serial terminal tool)" -conda install flterm +conda install -y $CONDA_FLAGS flterm check_exists flterm # binutils for the target echo echo "Installing binutils for ${CPU} (assembler, linker, and other tools)" -conda install binutils-${CPU}-elf=$BINUTILS_VERSION +conda install -y $CONDA_FLAGS binutils-${CPU}-elf=$BINUTILS_VERSION check_version ${CPU}-elf-ld $BINUTILS_VERSION # gcc for the target echo echo "Installing gcc for ${CPU} ('bare metal' C cross compiler)" -conda install gcc-${CPU}-elf-nostdc=$GCC_VERSION +conda install -y $CONDA_FLAGS gcc-${CPU}-elf-nostdc=$GCC_VERSION check_version ${CPU}-elf-gcc $GCC_VERSION # gdb for the target #echo #echo "Installing gdb for ${CPU} (debugger)" -#conda install gdb-${CPU}-elf=$GDB_VERSION +#conda install -y $CONDA_FLAGS gdb-${CPU}-elf=$GDB_VERSION #check_version ${CPU}-elf-gdb $GDB_VERSION # openocd for programming via Cypress FX2 echo echo "Installing openocd (jtag tool for programming and debug)" -conda install openocd=$OPENOCD_VERSION +conda install -y $CONDA_FLAGS openocd=$OPENOCD_VERSION check_version openocd $OPENOCD_VERSION echo "" @@ -260,13 +346,13 @@ echo "---------------------------------------" # pyserial for communicating via uarts echo echo "Installing pyserial (python module)" -conda install pyserial +conda install -y $CONDA_FLAGS pyserial check_import serial # ipython for interactive debugging echo echo "Installing ipython (python module)" -conda install ipython +conda install -y $CONDA_FLAGS ipython check_import IPython # progressbar2 for progress bars @@ -293,7 +379,18 @@ echo "Installing HDMI2USB-mode-switch (flashing and config tool)" pip install --upgrade git+https://github.com/timvideos/HDMI2USB-mode-switch.git check_import_version hdmi2usb.modeswitch $HDMI2USB_MODESWITCH_VERSION -# git submodules +# git commands +echo "" +echo "Updating git config" +echo "-----------------------" +( + git config status.submodulesummary 1 + git config push.recurseSubmodules check + git config diff.submodule log + git config checkout.recurseSubmodules 1 + git config alias.sdiff '!'"git diff && git submodule foreach 'git diff'" + git config alias.spush 'push --recurse-submodules=on-demand' +) echo "" echo "Updating git submodules" echo "-----------------------" @@ -302,7 +399,7 @@ echo "-----------------------" git submodule update --recursive --init git submodule foreach \ git submodule update --recursive --init - git status + git submodule status --recursive ) # lite diff --git a/scripts/enter-env.sh b/scripts/enter-env.sh index bf4ab38c..706440cb 100755 --- a/scripts/enter-env.sh +++ b/scripts/enter-env.sh @@ -12,7 +12,6 @@ CALLED=$_ SETUP_SRC="$(realpath ${BASH_SOURCE[0]})" SETUP_DIR="$(dirname "${SETUP_SRC}")" TOP_DIR="$(realpath "${SETUP_DIR}/..")" -LIKELY_XILINX_LICENSE_LOCATION="$HOME/.Xilinx/Xilinx.lic" if [ $SOURCED = 0 ]; then echo "You must source this script, rather than try and run it." @@ -45,10 +44,10 @@ if echo "${SETUP_DIR}" | grep -q ':'; then exit 1 fi -# Check ixo-usb-jtag *isn't* install -if [ -d /lib/firmware/ixo-usb-jtag/ ]; then - echo "Please uninstall ixo-usb-jtag package, the required firmware is" - echo "included in the HDMI2USB modeswitch tool." +# Check ixo-usb-jtag *isn't* installed +if [ -e /lib/udev/rules.d/85-ixo-usb-jtag.rules ]; then + echo "Please uninstall ixo-usb-jtag package from the timvideos PPA, the" + echo "required firmware is included in the HDMI2USB modeswitch tool." echo echo "On Debian/Ubuntu run:" echo " sudo apt-get remove ixo-usb-jtag" @@ -65,25 +64,12 @@ else return 1 fi -# Detect a likely lack of license early, but just warn if it's missing -# just in case they've set it up elsewhere. -license_found=0 -if [ ! -e $LIKELY_XILINX_LICENSE_LOCATION ]; then - echo "(WARNING) Please ensure you have installed Xilinx and have a license." - echo "(WARNING) Copy your Xilinx license to $LIKELY_XILINX_LICENSE_LOCATION to suppress this warning." -else - license_found=1 -fi - . $SETUP_DIR/settings.sh echo " This script is: $SETUP_SRC" echo " Firmware directory: $TOP_DIR" echo " Build directory is: $BUILD_DIR" echo " 3rd party directory is: $THIRD_DIR" -if [ $license_found == 1 ]; then - echo " Xilinx license in: $LIKELY_XILINX_LICENSE_LOCATION" -fi # Check the build dir if [ ! -d $BUILD_DIR ]; then @@ -91,25 +77,72 @@ if [ ! -d $BUILD_DIR ]; then return 1 fi -# Xilinx ISE +XILINX_SETTINGS_ISE='/opt/Xilinx/*/ISE_DS/settings64.sh' +XILINX_SETTINGS_VIVADO='/opt/Xilinx/Vivado/*/settings64.sh' + if [ -z "$XILINX_DIR" ]; then LOCAL_XILINX_DIR=$BUILD_DIR/Xilinx - if [ -f "$LOCAL_XILINX_DIR/opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64/xreport" ]; then + if [ -d "$LOCAL_XILINX_DIR/opt/Xilinx/" ]; then # Reserved MAC address from documentation block, see # http://www.iana.org/assignments/ethernet-numbers/ethernet-numbers.xhtml - export XILINXD_LICENSE_FILE=$LOCAL_XILINX_DIR + export LIKELY_XILINX_LICENSE_DIR=$LOCAL_XILINX_DIR export MACADDR=90:10:00:00:00:01 #export LD_PRELOAD=$XILINX_DIR/impersonate_macaddress/impersonate_macaddress.so #ls -l $LD_PRELOAD export XILINX_DIR=$LOCAL_XILINX_DIR - else - XILINX_DIR=/ + export XILINX_LOCAL_USER_DATA=no fi fi -if [ ! -z "$XILINX_DIR" ]; then - export MISOC_EXTRA_CMDLINE="-Ob toolchain_path $XILINX_DIR/opt/Xilinx/" +if [ -z "$LIKELY_XILINX_LICENSE_DIR" ]; then + LIKELY_XILINX_LICENSE_DIR="$HOME/.Xilinx" fi + +# Find Xilinx toolchain versions... +shopt -s nullglob +XILINX_SETTINGS_ISE=($XILINX_DIR/$XILINX_SETTINGS_ISE) +XILINX_SETTINGS_VIVADO=($XILINX_DIR/$XILINX_SETTINGS_VIVADO) +shopt -u nullglob + +# Tell user what we found... echo " Xilinx directory is: $XILINX_DIR/opt/Xilinx/" +if [ ${#XILINX_SETTINGS_ISE[@]} -gt 0 ]; then + echo -n " - Xilinx ISE toolchain found!" + if [ ${#XILINX_SETTINGS_ISE[@]} -gt 1 ]; then + echo -n " (${#XILINX_SETTINGS_ISE[@]} versions)" + fi + echo "" + export HAVE_XILINX_ISE=1 +else + export HAVE_XILINX_ISE=0 +fi +if [ ${#XILINX_SETTINGS_VIVADO[@]} -gt 0 ]; then + echo -n " - Xilinx Vivado toolchain found!" + if [ ${#XILINX_SETTINGS_VIVADO[@]} -gt 1 ]; then + echo -n " (${#XILINX_SETTINGS_VIVADO[@]} versions)" + fi + echo "" + export HAVE_XILINX_VIVADO=1 +else + export HAVE_XILINX_VIVADO=0 +fi +if [ $HAVE_XILINX_ISE -eq 1 -o $HAVE_XILINX_VIVADO -eq 1 ]; then + export HAVE_XILINX_TOOLCHAIN=1 +else + export HAVE_XILINX_TOOLCHAIN=0 +fi +if [ $HAVE_XILINX_TOOLCHAIN -eq 1 ]; then + export MISOC_EXTRA_CMDLINE="-Ob toolchain_path $XILINX_DIR/opt/Xilinx/" +fi + +# Detect a likely lack of license early, but just warn if it's missing +# just in case they've set it up elsewhere. +if [ ! -e $LIKELY_XILINX_LICENSE_DIR/Xilinx.lic ]; then + echo "(WARNING) Please ensure you have installed Xilinx and have a license." + echo "(WARNING) Copy your Xilinx license to Xilinx.lic in $LIKELY_XILINX_LICENSE_DIR to suppress this warning." +else + echo " Xilinx license in: $LIKELY_XILINX_LICENSE_DIR" + export XILINXD_LICENSE_FILE=$LIKELY_XILINX_LICENSE_DIR +fi function check_exists { TOOL=$1 @@ -167,35 +200,49 @@ echo "" echo "Checking environment" echo "---------------------------------" # Install and setup conda for downloading packages -export PATH=$CONDA_DIR/bin:$PATH +export PATH=$CONDA_DIR/bin:$PATH:/sbin + +eval $(cd $TOP_DIR; export HDMI2USB_ENV=1; make env || return 1) || return 1 +( + cd $TOP_DIR + export HDMI2USB_ENV=1 + make info || return 1 + echo +) || return 1 + + # Check the Python version -check_version python 3.5 || return 1 + +check_version python 3.6 || return 1 echo "" echo "Checking binaries in environment" echo "---------------------------------" # fxload +if [ "$PLATFORM" == "opsis" -o "$PLATFORM" == "atlys" ]; then + -# check sbin for fxload as well -export PATH=$PATH:/sbin -check_exists fxload || return 1 + check_exists fxload || return 1 +fi # FIXME: Remove this once @jimmo has finished his new firmware # MimasV2Config.py -MIMASV2CONFIG=$BUILD_DIR/conda/bin/MimasV2Config.py +if [ "$PLATFORM" == "mimasv2" ]; then + MIMASV2CONFIG=$BUILD_DIR/conda/bin/MimasV2Config.py -check_exists MimasV2Config.py || return 1 + check_exists MimasV2Config.py || return 1 +fi # flterm @@ -266,7 +313,7 @@ check_import_version hexfile $HEXFILE_VERSION || return 1 check_import_version hdmi2usb.modeswitch $HDMI2USB_MODESWITCH_VERSION || return 1 -# git submodules +# git commands echo "" echo "Checking git submodules" echo "-----------------------" @@ -275,7 +322,7 @@ echo "-----------------------" - git status + git submodule status --recursive ) # lite @@ -299,9 +346,9 @@ export HDMI2USB_ENV=1 # Set prompt ORIG_PS1="$PS1" -hdmi2usb_prompt() { +litex_buildenv_prompt() { P="$(cd $TOP_DIR; make prompt)" - PS1="(H2U $P) $ORIG_PS1" + PS1="(LX $P) $ORIG_PS1" case "$TERM" in xterm*|rxvt*) PS1="$PS1\[\033]0;($P) \w\007\]" @@ -310,4 +357,4 @@ hdmi2usb_prompt() { ;; esac } -PROMPT_COMMAND=hdmi2usb_prompt +PROMPT_COMMAND="litex_buildenv_prompt; ${PROMPT_COMMAND}" diff --git a/scripts/settings.sh b/scripts/settings.sh index 5eba63e0..29f51761 100644 --- a/scripts/settings.sh +++ b/scripts/settings.sh @@ -1,16 +1,12 @@ #!/bin/bash # Settings for the download-env.sh and setup-env.sh scripts - -export PLATFORM=${PLATFORM:-opsis} -export CPU=${CPU:-lm32} - BUILD_DIR=$TOP_DIR/build THIRD_DIR=$TOP_DIR/third_party CONDA_DIR=$BUILD_DIR/conda # Python module versions -HDMI2USB_MODESWITCH_VERSION=0.0.0 +HDMI2USB_MODESWITCH_VERSION=0.0.1 HEXFILE_VERSION=0.1 # Conda package versions @@ -21,6 +17,7 @@ OPENOCD_VERSION=0.10.0 # lite modules LITE_REPOS=" + migen litex litedram liteeth diff --git a/targets/arty/Makefile.mk b/targets/arty/Makefile.mk index d2af89c4..51f04b77 100644 --- a/targets/arty/Makefile.mk +++ b/targets/arty/Makefile.mk @@ -25,7 +25,8 @@ gateware-flash-$(PLATFORM): gateware-flash-py # Firmware firmware-load-$(PLATFORM): - flterm --port=$(COMM_PORT) --kernel=$(TARGET_BUILD_DIR)/software/firmware/firmware.bin --speed=$(BAUD) + flterm --port=$(COMM_PORT) --kernel=$(FIRMWARE_FILEBASE).bin --speed=$(BAUD) + firmware-flash-$(PLATFORM): firmwage-flash-py @true diff --git a/targets/arty/base.py b/targets/arty/base.py index 0e5e40aa..f0346352 100755 --- a/targets/arty/base.py +++ b/targets/arty/base.py @@ -1,6 +1,6 @@ # Support for the Digilent Arty Board -from litex.gen import * -from litex.gen.genlib.resetsync import AsyncResetSynchronizer +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer from litex.soc.integration.soc_core import mem_decoder from litex.soc.integration.soc_sdram import * @@ -23,10 +23,11 @@ def __init__(self, platform): self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) self.clock_domains.cd_sys4x_dqs = ClockDomain(reset_less=True) self.clock_domains.cd_clk200 = ClockDomain() + self.clock_domains.cd_clk100 = ClockDomain() self.clock_domains.cd_clk50 = ClockDomain() clk100 = platform.request("clk100") - rst = platform.request("cpu_reset") + rst = ~platform.request("cpu_reset") pll_locked = Signal() pll_fb = Signal() @@ -34,6 +35,7 @@ def __init__(self, platform): pll_sys4x = Signal() pll_sys4x_dqs = Signal() pll_clk200 = Signal() + pll_clk100 = Signal() pll_clk50 = Signal() self.specials += [ Instance("PLLE2_BASE", @@ -62,16 +64,22 @@ def __init__(self, platform): # 50MHz p_CLKOUT4_DIVIDE=32, p_CLKOUT4_PHASE=0.0, - o_CLKOUT4=pll_clk50 + o_CLKOUT4=pll_clk50, + + # 100MHz + p_CLKOUT5_DIVIDE=16, p_CLKOUT5_PHASE=0.0, + o_CLKOUT5=pll_clk100 ), Instance("BUFG", i_I=self.pll_sys, o_O=self.cd_sys.clk), Instance("BUFG", i_I=pll_sys4x, o_O=self.cd_sys4x.clk), Instance("BUFG", i_I=pll_sys4x_dqs, o_O=self.cd_sys4x_dqs.clk), Instance("BUFG", i_I=pll_clk200, o_O=self.cd_clk200.clk), + Instance("BUFG", i_I=pll_clk100, o_O=self.cd_clk100.clk), Instance("BUFG", i_I=pll_clk50, o_O=self.cd_clk50.clk), - AsyncResetSynchronizer(self.cd_sys, ~pll_locked | ~rst), + AsyncResetSynchronizer(self.cd_sys, ~pll_locked | rst), AsyncResetSynchronizer(self.cd_clk200, ~pll_locked | rst), - AsyncResetSynchronizer(self.cd_clk50, ~pll_locked | ~rst), + AsyncResetSynchronizer(self.cd_clk100, ~pll_locked | rst), + AsyncResetSynchronizer(self.cd_clk50, ~pll_locked | rst), ] reset_counter = Signal(4, reset=15) @@ -97,8 +105,8 @@ class BaseSoC(SoCSDRAM): "spiflash", "ddrphy", "info", - "leds", - "rgb_leds", +# "leds", +# "rgb_leds", ) csr_map_update(SoCSDRAM.csr_map, csr_peripherals) @@ -120,8 +128,8 @@ def __init__(self, platform, spiflash="spiflash_1x", **kwargs): # Basic peripherals self.submodules.info = info.Info(platform, self.__class__.__name__) - self.submodules.leds = led.ClassicLed(Cat(platform.request("user_led", i) for i in range(4))) - self.submodules.rgb_leds = led.RGBLed(platform.request("rgb_leds")) +# self.submodules.leds = led.ClassicLed(Cat(platform.request("user_led", i) for i in range(4))) +# self.submodules.rgb_leds = led.RGBLed(platform.request("rgb_leds")) # spi flash spiflash_pads = platform.request(spiflash) @@ -148,8 +156,8 @@ def __init__(self, platform, spiflash="spiflash_1x", **kwargs): sdram_module = MT41K128M16(self.clk_freq, "1:4") self.submodules.ddrphy = a7ddrphy.A7DDRPHY( platform.request("ddram")) - self.add_constant("A7DDRPHY_BITSLIP", 2) - self.add_constant("A7DDRPHY_DELAY", 6) + self.add_constant("READ_LEVELING_BITSLIP", 3) + self.add_constant("READ_LEVELING_DELAY", 14) controller_settings = ControllerSettings( with_bandwidth=True, cmd_buffer_depth=8, @@ -159,4 +167,5 @@ def __init__(self, platform, spiflash="spiflash_1x", **kwargs): sdram_module.timing_settings, controller_settings=controller_settings) + SoC = BaseSoC diff --git a/targets/arty/ddr3.py b/targets/arty/ddr3.py index 83411197..9b63dc0a 100755 --- a/targets/arty/ddr3.py +++ b/targets/arty/ddr3.py @@ -1,5 +1,5 @@ -from litex.gen import * -from litex.gen.genlib.resetsync import AsyncResetSynchronizer +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer from litex.soc.integration.soc_core import mem_decoder from litex.soc.integration.soc_sdram import * diff --git a/targets/atlys/base.py b/targets/atlys/base.py index 3c09475a..9dca3784 100644 --- a/targets/atlys/base.py +++ b/targets/atlys/base.py @@ -1,9 +1,9 @@ # Support for the Digilent Atlys board - digilentinc.com/atlys/ from fractions import Fraction -from litex.gen import * -from litex.gen.genlib.resetsync import AsyncResetSynchronizer -from litex.gen.genlib.misc import WaitTimer +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer +from migen.genlib.misc import WaitTimer from litex.soc.integration.soc_sdram import * from litex.soc.integration.builder import * diff --git a/targets/atlys/hdmi2usb.py b/targets/atlys/hdmi2usb.py index f9a0ea0b..b8db83b6 100644 --- a/targets/atlys/hdmi2usb.py +++ b/targets/atlys/hdmi2usb.py @@ -1,4 +1,4 @@ -from litex.gen.fhdl.decorators import ClockDomainsRenamer +from migen.fhdl.decorators import ClockDomainsRenamer from litex.soc.integration.soc_core import mem_decoder from litex.soc.interconnect import stream @@ -23,7 +23,7 @@ class HDMI2USBSoC(BaseSoC): def __init__(self, platform, *args, **kwargs): BaseSoC.__init__(self, platform, *args, **kwargs) - encoder_port = self.sdram.crossbar.get_port() + encoder_port = self.sdram.crossbar.get_port(mode="read", dw=128, reverse=True) self.submodules.encoder_reader = EncoderDMAReader(encoder_port) encoder_cdc = stream.AsyncFIFO([("data", 128)], 4) encoder_cdc = ClockDomainsRenamer({"write": "sys", diff --git a/targets/atlys/video.py b/targets/atlys/video.py index e2ee4674..e65c13ac 100644 --- a/targets/atlys/video.py +++ b/targets/atlys/video.py @@ -2,7 +2,7 @@ from litevideo.output import VideoOut from targets.utils import csr_map_update -from targets.atlys.net import NetSoC as BaseSoC +from targets.atlys.base import BaseSoC class VideoSoC(BaseSoC): @@ -71,5 +71,8 @@ def __init__(self, platform, *args, **kwargs): self.hdmi_out0.driver.clocking.cd_pix.clk, self.hdmi_out1.driver.clocking.cd_pix.clk) + for name, value in sorted(self.platform.hdmi_infos.items()): + self.add_constant(name, value) + SoC = VideoSoC diff --git a/targets/basys3/Makefile.mk b/targets/basys3/Makefile.mk new file mode 100644 index 00000000..bc6e7af0 --- /dev/null +++ b/targets/basys3/Makefile.mk @@ -0,0 +1,48 @@ +# basys3 targets + +ifneq ($(PLATFORM),basys3) + $(error "Platform should be basys3 when using this file!?") +endif + +# Settings +DEFAULT_TARGET = base +TARGET ?= $(DEFAULT_TARGET) + +PROG_PORT ?= /dev/ttyUSB0 +COMM_PORT ?= /dev/ttyUSB1 +BAUD ?= 115200 + +# Image +image-flash-$(PLATFORM): image-flash-py + @true + +# Gateware +gateware-load-$(PLATFORM): + openocd -f board/digilent_$(PLATFORM).cfg -c "init; pld load 0 $(TARGET_BUILD_DIR)/gateware/top.bit; exit" + +gateware-flash-$(PLATFORM): gateware-flash-py + @true + +# Firmware +firmware-load-$(PLATFORM): + flterm --port=$(COMM_PORT) --kernel=$(FIRMWARE_FILEBASE).bin --speed=$(BAUD) + + +firmware-flash-$(PLATFORM): firmwage-flash-py + @true + +firmware-connect-$(PLATFORM): + flterm --port=$(COMM_PORT) --speed=$(BAUD) + +# Bios +bios-flash-$(PLATFORM): + @echo "Unsupported." + @false + +# Extra commands +help-$(PLATFORM): + @true + +reset-$(PLATFORM): + @echo "Unsupported." + @false diff --git a/targets/basys3/base.py b/targets/basys3/base.py new file mode 100755 index 00000000..460277fc --- /dev/null +++ b/targets/basys3/base.py @@ -0,0 +1,99 @@ +# Support for the Digilent Arty Board +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex.soc.integration.soc_core import * +from litex.soc.integration.soc_sdram import * +from litex.soc.integration.builder import * + +from litedram.modules import MT41K128M16 +from litedram.phy import a7ddrphy +from litedram.core import ControllerSettings + +from gateware import info +from gateware import led +from gateware import spi_flash + +from targets.utils import csr_map_update, period_ns + + +class _CRG(Module): + def __init__(self, platform): + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) + self.clock_domains.cd_sys4x_dqs = ClockDomain(reset_less=True) + self.clock_domains.cd_clk200 = ClockDomain() + self.clock_domains.cd_clk50 = ClockDomain() + + clk100 = platform.request("clk100") + rst = platform.request("user_btn") + + pll_locked = Signal() + pll_fb = Signal() + self.pll_sys = Signal() + self.specials += [ + Instance("PLLE2_BASE", + p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, + + # VCO @ 1600 MHz + p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=10.0, + p_CLKFBOUT_MULT=16, p_DIVCLK_DIVIDE=1, + i_CLKIN1=clk100, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, + + # 100 MHz + p_CLKOUT0_DIVIDE=16, p_CLKOUT0_PHASE=0.0, + o_CLKOUT0=self.pll_sys, + ), + Instance("BUFG", i_I=self.pll_sys, o_O=self.cd_sys.clk), + AsyncResetSynchronizer(self.cd_sys, ~pll_locked | rst), + ] + + +class BaseSoC(SoCCore): + csr_peripherals = ( + "spiflash", + "info", + ) + csr_map_update(SoCCore.csr_map, csr_peripherals) + + mem_map = { + "spiflash": 0x20000000, # (default shadow @0xa0000000) + } + mem_map.update(SoCCore.mem_map) + + def __init__(self, platform, spiflash="spiflash_1x", **kwargs): + clk_freq = int(100e6) + SoCCore.__init__(self, platform, clk_freq, + integrated_rom_size=0x8000, + integrated_sram_size=0x8000, + **kwargs) + + self.submodules.crg = _CRG(platform) + self.crg.cd_sys.clk.attr.add("keep") + self.platform.add_period_constraint(self.crg.cd_sys.clk, period_ns(clk_freq)) + + # Basic peripherals + self.submodules.info = info.Info(platform, self.__class__.__name__) + + # spi flash + spiflash_pads = platform.request(spiflash) + spiflash_pads.clk = Signal() + self.specials += Instance("STARTUPE2", + i_CLK=0, i_GSR=0, i_GTS=0, i_KEYCLEARB=0, i_PACK=0, + i_USRCCLKO=spiflash_pads.clk, i_USRCCLKTS=0, i_USRDONEO=1, i_USRDONETS=1) + spiflash_dummy = { + "spiflash_1x": 9, + "spiflash_4x": 11, + } + self.submodules.spiflash = spi_flash.SpiFlash( + spiflash_pads, + dummy=spiflash_dummy[spiflash], + div=2) + self.add_constant("SPIFLASH_PAGE_SIZE", 256) + self.add_constant("SPIFLASH_SECTOR_SIZE", 0x10000) + self.add_wb_slave(mem_decoder(self.mem_map["spiflash"]), self.spiflash.bus) + self.add_memory_region( + "spiflash", self.mem_map["spiflash"] | self.shadow_base, 16*1024*1024) + + +SoC = BaseSoC diff --git a/targets/cmod_a7/Makefile.mk b/targets/cmod_a7/Makefile.mk new file mode 100644 index 00000000..806d2ae6 --- /dev/null +++ b/targets/cmod_a7/Makefile.mk @@ -0,0 +1,57 @@ +# cmod_a7 targets + +ifneq ($(PLATFORM),cmod_a7) + $(error "Platform should be cmod_a7 when using this file!?") +endif + +# Settings +DEFAULT_TARGET = base +TARGET ?= $(DEFAULT_TARGET) + +PROG_PORT ?= /dev/ttyUSB0 +COMM_PORT ?= /dev/ttyUSB1 +BAUD ?= 115200 + +# Image +image-flash-$(PLATFORM): image-flash-py + @true + +.PHONY: image-flash-$(PLATFORM) + +# Gateware +gateware-load-$(PLATFORM): + openocd -f board/digilent_$(PLATFORM).cfg -c "init; pld load 0 $(TARGET_BUILD_DIR)/gateware/top.bit; exit" + +gateware-flash-$(PLATFORM): gateware-flash-py + @true + +.PHONY: gateware-load-$(PLATFORM) gateware-flash-$(PLATFORM) + +# Firmware +firmware-load-$(PLATFORM): + flterm --port=$(COMM_PORT) --kernel=$(TARGET_BUILD_DIR)/software/firmware/firmware.bin --speed=$(BAUD) + +firmware-flash-$(PLATFORM): firmwage-flash-py + @true + +firmware-connect-$(PLATFORM): + flterm --port=$(COMM_PORT) --speed=$(BAUD) + +.PHONY: firmware-load-$(PLATFORM) firmware-flash-$(PLATFORM) firmware-connect-$(PLATFORM) + +# Bios +bios-flash-$(PLATFORM): + @echo "Unsupported." + @false + +.PHONY: bios-flash-$(PLATFORM) + +# Extra commands +help-$(PLATFORM): + @true + +reset-$(PLATFORM): + @echo "Unsupported." + @false + +.PHONY: help-$(PLATFORM) reset-$(PLATFORM) diff --git a/targets/cmod_a7/base.py b/targets/cmod_a7/base.py new file mode 100755 index 00000000..3de458f7 --- /dev/null +++ b/targets/cmod_a7/base.py @@ -0,0 +1,74 @@ +# Support for the Digilent Cmod A7 Board +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex.soc.integration.soc_core import * +from litex.soc.integration.builder import * + +from gateware import info +from gateware import led +from gateware import spi_flash + +from targets.utils import csr_map_update, period_ns + + +class _CRG(Module): + def __init__(self, platform): + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_clk200 = ClockDomain() + clk12 = platform.request("clk12") + rst = platform.request("user_btn", 0) + self.specials += [ + Instance("BUFG", i_I=clk12, o_O=self.cd_sys.clk), + AsyncResetSynchronizer(self.cd_sys, rst), + ] + + +class BaseSoC(SoCCore): + csr_peripherals = ( + "spiflash", + "info", + ) + csr_map_update(SoCCore.csr_map, csr_peripherals) + + mem_map = { + "spiflash": 0x20000000, # (default shadow @0xa0000000) + } + mem_map.update(SoCCore.mem_map) + + def __init__(self, platform, spiflash="spiflash_1x", **kwargs): + clk_freq = int(100e6) + SoCCore.__init__(self, platform, clk_freq, + integrated_rom_size=0x8000, + integrated_sram_size=0x8000, + **kwargs) + + self.submodules.crg = _CRG(platform) + self.crg.cd_sys.clk.attr.add("keep") + self.platform.add_period_constraint(self.crg.cd_sys.clk, period_ns(clk_freq)) + + # Basic peripherals + self.submodules.info = info.Info(platform, self.__class__.__name__) + + # spi flash + spiflash_pads = platform.request(spiflash) + spiflash_pads.clk = Signal() + self.specials += Instance("STARTUPE2", + i_CLK=0, i_GSR=0, i_GTS=0, i_KEYCLEARB=0, i_PACK=0, + i_USRCCLKO=spiflash_pads.clk, i_USRCCLKTS=0, i_USRDONEO=1, i_USRDONETS=1) + spiflash_dummy = { + "spiflash_1x": 9, + "spiflash_4x": 11, + } + self.submodules.spiflash = spi_flash.SpiFlash( + spiflash_pads, + dummy=spiflash_dummy[spiflash], + div=2) + self.add_constant("SPIFLASH_PAGE_SIZE", 256) + self.add_constant("SPIFLASH_SECTOR_SIZE", 0x10000) + self.add_wb_slave(mem_decoder(self.mem_map["spiflash"]), self.spiflash.bus) + self.add_memory_region( + "spiflash", self.mem_map["spiflash"] | self.shadow_base, 16*1024*1024) + + +SoC = BaseSoC diff --git a/targets/common/cpu_interface.py b/targets/common/cpu_interface.py index 2a18b291..d013567b 100644 --- a/targets/common/cpu_interface.py +++ b/targets/common/cpu_interface.py @@ -1,4 +1,4 @@ -from litex.gen import * +from migen import * from litex.soc.interconnect.csr import CSRStatus diff --git a/targets/galatea/Makefile.mk b/targets/galatea/Makefile.mk new file mode 100644 index 00000000..776a6acd --- /dev/null +++ b/targets/galatea/Makefile.mk @@ -0,0 +1,49 @@ +# galatea targets + +ifneq ($(PLATFORM),galatea) + $(error "Platform should be galatea when using this file!?") +endif + +# Settings +DEFAULT_TARGET = base +TARGET ?= $(DEFAULT_TARGET) + +# Image +image-flash-$(PLATFORM): image-flash-py + @true + +# Gateware +gateware-load-$(PLATFORM): + @echo "Unsupported." + @false + +gateware-flash-$(PLATFORM): gateware-flash-py + @true + +# Firmware +firmware-load-$(PLATFORM): + @echo "Unsupported." + @false + +firmware-flash-$(PLATFORM): firmwage-flash-py + @true + +firmware-connect-$(PLATFORM): + flterm --port=$(COMM_PORT) --speed=$(BAUD) + +firmware-clear-$(PLATFORM): + @echo "FIXME: Unsupported?." + @false + +# Bios +bios-flash-$(PLATFORM): + @echo "Unsupported." + @false + +# Extra commands +help-$(PLATFORM): + @true + +reset-$(PLATFORM): + @echo "Unsupported." + @false diff --git a/targets/galatea/base.py b/targets/galatea/base.py new file mode 100644 index 00000000..d555a481 --- /dev/null +++ b/targets/galatea/base.py @@ -0,0 +1,213 @@ +# Support for Numato Galatea - https://numato.com/product/galatea-pci-express-spartan-6-fpga-development-board +from fractions import Fraction + +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex.soc.integration.soc_sdram import * +from litex.soc.integration.builder import * + +from litedram.modules import MT41J128M16 +from litedram.phy import s6ddrphy +from litedram.core import ControllerSettings + +from targets.utils import csr_map_update + + +class _CRG(Module): + def __init__(self, platform, clk_freq): + # Clock domains for the system (soft CPU and related components run at). + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sys2x = ClockDomain() + # Clock domains for the DDR interface. + self.clock_domains.cd_sdram_half = ClockDomain() + self.clock_domains.cd_sdram_full_wr = ClockDomain() + self.clock_domains.cd_sdram_full_rd = ClockDomain() + # Clock domain for peripherals (such as HDMI output). + self.clock_domains.cd_base50 = ClockDomain() + + self.reset = Signal() + + # Input 100MHz clock + f0 = 100*1000000 + clk100 = platform.request("clk100") + clk100a = Signal() + # Input 100MHz clock (buffered) + self.specials += Instance("IBUFG", i_I=clk100, o_O=clk100a) + clk100b = Signal() + self.specials += Instance( + "BUFIO2", p_DIVIDE=1, + p_DIVIDE_BYPASS="TRUE", p_I_INVERT="FALSE", + i_I=clk100a, o_DIVCLK=clk100b) + + f = Fraction(int(clk_freq), int(f0)) + n, m = f.denominator, f.numerator + assert f0/n*m == clk_freq + p = 8 + + # Unbuffered output signals from the PLL. They need to be buffered + # before feeding into the fabric. + unbuf_sdram_full = Signal() + unbuf_sdram_half_a = Signal() + unbuf_sdram_half_b = Signal() + unbuf_encoder = Signal() + unbuf_sys = Signal() + unbuf_sys2x = Signal() + + # PLL signals + pll_lckd = Signal() + pll_fb = Signal() + self.specials.pll = Instance( + "PLL_ADV", + name="crg_pll_adv", + p_SIM_DEVICE="SPARTAN6", p_BANDWIDTH="OPTIMIZED", p_COMPENSATION="INTERNAL", + p_REF_JITTER=.01, + i_DADDR=0, i_DCLK=0, i_DEN=0, i_DI=0, i_DWE=0, i_RST=0, i_REL=0, + p_DIVCLK_DIVIDE=1, + # Input Clocks (100MHz) + i_CLKIN1=clk100b, + p_CLKIN1_PERIOD=1e9/f0, + i_CLKIN2=0, + p_CLKIN2_PERIOD=0., + i_CLKINSEL=1, + # Feedback + i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, o_LOCKED=pll_lckd, + p_CLK_FEEDBACK="CLKFBOUT", + p_CLKFBOUT_MULT=m*p//n, p_CLKFBOUT_PHASE=0., + # (400MHz) ddr3 wr/rd full clock + o_CLKOUT0=unbuf_sdram_full, p_CLKOUT0_DUTY_CYCLE=.5, + p_CLKOUT0_PHASE=0., p_CLKOUT0_DIVIDE=p//8, + # ( 66MHz) encoder + o_CLKOUT1=unbuf_encoder, p_CLKOUT1_DUTY_CYCLE=.5, + p_CLKOUT1_PHASE=0., p_CLKOUT1_DIVIDE=6, + # (200MHz) sdram_half - ddr3 dqs adr ctrl off-chip + o_CLKOUT2=unbuf_sdram_half_a, p_CLKOUT2_DUTY_CYCLE=.5, + p_CLKOUT2_PHASE=230., p_CLKOUT2_DIVIDE=p//4, + # (200MHz) off-chip ddr - ddr3 half clock + o_CLKOUT3=unbuf_sdram_half_b, p_CLKOUT3_DUTY_CYCLE=.5, + p_CLKOUT3_PHASE=210., p_CLKOUT3_DIVIDE=p//4, + # (100MHz) sys2x - 2x system clock + o_CLKOUT4=unbuf_sys2x, p_CLKOUT4_DUTY_CYCLE=.5, + p_CLKOUT4_PHASE=0., p_CLKOUT4_DIVIDE=p//2, + # ( 50MHz) periph / sys - system clock + o_CLKOUT5=unbuf_sys, p_CLKOUT5_DUTY_CYCLE=.5, + p_CLKOUT5_PHASE=0., p_CLKOUT5_DIVIDE=p//1, + ) + + + # power on reset? + reset = ~platform.request("cpu_reset") | self.reset + self.clock_domains.cd_por = ClockDomain() + por = Signal(max=1 << 11, reset=(1 << 11) - 1) + self.sync.por += If(por != 0, por.eq(por - 1)) + self.specials += AsyncResetSynchronizer(self.cd_por, reset) + + # System clock - 50MHz + self.specials += Instance("BUFG", name="sys_bufg", i_I=unbuf_sys, o_O=self.cd_sys.clk) + self.comb += self.cd_por.clk.eq(self.cd_sys.clk) + self.specials += AsyncResetSynchronizer(self.cd_sys, ~pll_lckd | (por > 0)) + + # sys2x + self.specials += Instance("BUFG", name="sys2x_bufg", i_I=unbuf_sys2x, o_O=self.cd_sys2x.clk) + self.specials += AsyncResetSynchronizer(self.cd_sys2x, ~pll_lckd | (por > 0)) + + # SDRAM clocks + # ------------------------------------------------------------------------------ + self.clk8x_wr_strb = Signal() + self.clk8x_rd_strb = Signal() + + # sdram_full + self.specials += Instance("BUFPLL", name="sdram_full_bufpll", + p_DIVIDE=4, + i_PLLIN=unbuf_sdram_full, i_GCLK=self.cd_sys2x.clk, + i_LOCKED=pll_lckd, + o_IOCLK=self.cd_sdram_full_wr.clk, + o_SERDESSTROBE=self.clk8x_wr_strb) + self.comb += [ + self.cd_sdram_full_rd.clk.eq(self.cd_sdram_full_wr.clk), + self.clk8x_rd_strb.eq(self.clk8x_wr_strb), + ] + # sdram_half + self.specials += Instance("BUFG", name="sdram_half_a_bufpll", i_I=unbuf_sdram_half_a, o_O=self.cd_sdram_half.clk) + clk_sdram_half_shifted = Signal() + self.specials += Instance("BUFG", name="sdram_half_b_bufpll", i_I=unbuf_sdram_half_b, o_O=clk_sdram_half_shifted) + + output_clk = Signal() + clk = platform.request("ddram_clock") + self.specials += Instance("ODDR2", p_DDR_ALIGNMENT="NONE", + p_INIT=0, p_SRTYPE="SYNC", + i_D0=1, i_D1=0, i_S=0, i_R=0, i_CE=1, + i_C0=clk_sdram_half_shifted, + i_C1=~clk_sdram_half_shifted, + o_Q=output_clk) + self.specials += Instance("OBUFDS", i_I=output_clk, o_O=clk.p, o_OB=clk.n) + + # Peripheral clock - 50MHz + # ------------------------------------------------------------------------------ + # The peripheral clock is kept separate from the system clock to allow + # the system clock to be increased in the future. + dcm_base50_locked = Signal() + self.specials += [ + Instance("DCM_CLKGEN", name="crg_periph_dcm_clkgen", + p_CLKIN_PERIOD=10.0, + p_CLKFX_MULTIPLY=2, + p_CLKFX_DIVIDE=4, + p_CLKFX_MD_MAX=0.5, # CLKFX_MULTIPLY/CLKFX_DIVIDE + p_CLKFXDV_DIVIDE=2, + p_SPREAD_SPECTRUM="NONE", + p_STARTUP_WAIT="FALSE", + + i_CLKIN=clk100a, + o_CLKFX=self.cd_base50.clk, + o_LOCKED=dcm_base50_locked, + i_FREEZEDCM=0, + i_RST=ResetSignal(), + ), + AsyncResetSynchronizer(self.cd_base50, + self.cd_sys.rst | ~dcm_base50_locked) + ] + platform.add_period_constraint(self.cd_base50.clk, 20) + + +class BaseSoC(SoCSDRAM): + csr_peripherals = ( + "spiflash", + "ddrphy", + ) + csr_map_update(SoCSDRAM.csr_map, csr_peripherals) + + def __init__(self, platform, **kwargs): + clk_freq = 50*1000000 + + if 'expansion' in kwargs: + tofe_board_name = kwargs.get('expansion') + del kwargs['expansion'] + else: + tofe_board_name = None + + SoCSDRAM.__init__(self, platform, clk_freq, + integrated_rom_size=0x8000, + integrated_sram_size=0x4000, + with_uart=True, + **kwargs) + self.submodules.crg = _CRG(platform, clk_freq) + self.platform.add_period_constraint(self.crg.cd_sys.clk, 1e9/clk_freq) + + # sdram + sdram_module = MT41J128M16(self.clk_freq, "1:4") + self.submodules.ddrphy = s6ddrphy.S6QuarterRateDDRPHY( + platform.request("ddram"), + rd_bitslip=0, + wr_bitslip=4, + dqs_ddr_alignment="C0") + controller_settings = ControllerSettings(with_bandwidth=True) + self.register_sdram(self.ddrphy, + sdram_module.geom_settings, + sdram_module.timing_settings, + controller_settings=controller_settings) + self.comb += [ + self.ddrphy.clk8x_wr_strb.eq(self.crg.clk8x_wr_strb), + self.ddrphy.clk8x_rd_strb.eq(self.crg.clk8x_rd_strb), + ] + +SoC = BaseSoC diff --git a/targets/mimasv2/Makefile.mk b/targets/mimasv2/Makefile.mk index c56f5cdf..902f1a76 100644 --- a/targets/mimasv2/Makefile.mk +++ b/targets/mimasv2/Makefile.mk @@ -30,8 +30,26 @@ gateware-load-$(PLATFORM): @echo "make gateware-flash" @false -gateware-flash-$(PLATFORM): - $(PYTHON) $$(which MimasV2Config.py) $(PROG_PORT) $(GATEWARE_FILEBASE).bin +# On Mimas v2 both the gateware and the BIOS need to be in the same flash, +# which means that they can only really usefully be updated together. As +# a result we should flash "Gateware + BIOS + no application" if the user +# asks us to flash the gatware. This mirrors the behaviour of embedding +# the BIOS in the Gateware loaded via gateware-load, on other platforms, +# eg, on the Arty. +# +GATEWARE_BIOS_FILE = $(TARGET_BUILD_DIR)/image-gateware+bios+none.bin + +gateware-flash-$(PLATFORM): $(GATEWARE_BIOS_FILE) + $(PYTHON) $$(which MimasV2Config.py) $(PROG_PORT) $(GATEWARE_BIOS_FILE) + +# To avoid duplicating the mkimage.py call here, if the user has not +# already built a image-gateware+bios+none.bin, we call make recursively +# to build one here, with the FIRMWARE=none override. +# +ifneq ($(GATEWARE_BIOS_FILE),$(IMAGE_FILE)) +$(GATEWARE_BIOS_FILE): $(GATEWARE_FILEBASE).bin $(BIOS_FILE) mkimage.py + FIRMWARE=none make image +endif # Firmware firmware-load-$(PLATFORM): diff --git a/targets/mimasv2/base.py b/targets/mimasv2/base.py index 18dcc454..9cafccb5 100644 --- a/targets/mimasv2/base.py +++ b/targets/mimasv2/base.py @@ -4,8 +4,8 @@ from fractions import Fraction -from litex.gen import * -from litex.gen.genlib.resetsync import AsyncResetSynchronizer +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer from litex.soc.integration.soc_sdram import * from litex.soc.integration.builder import * diff --git a/targets/minispartan6/base.py b/targets/minispartan6/base.py index 3137d485..60b6b43a 100755 --- a/targets/minispartan6/base.py +++ b/targets/minispartan6/base.py @@ -1,9 +1,9 @@ # Support for the MiniSpartan6+ - https://www.scarabhardware.com/minispartan6/ from fractions import Fraction -from litex.gen import * -from litex.gen.genlib.io import CRG -from litex.gen.genlib.resetsync import AsyncResetSynchronizer +from migen import * +from migen.genlib.io import CRG +from migen.genlib.resetsync import AsyncResetSynchronizer from litex.soc.integration.soc_sdram import * from litex.soc.integration.builder import * diff --git a/targets/neso/Makefile.mk b/targets/neso/Makefile.mk new file mode 100644 index 00000000..bbbc34f5 --- /dev/null +++ b/targets/neso/Makefile.mk @@ -0,0 +1,51 @@ +# neso targets + +ifneq ($(PLATFORM),neso) + $(error "Platform should be neso when using this file!?") +endif + +# Settings +DEFAULT_TARGET = base +TARGET ?= $(DEFAULT_TARGET) + +PROG_PORT ?= /dev/ttyUSB0 +COMM_PORT ?= /dev/ttyUSB1 +BAUD ?= 115200 + +# Image +image-flash-$(PLATFORM): image-flash-py + @true + +# Gateware +gateware-load-$(PLATFORM): + openocd -f board/numato_$(PLATFORM).cfg -c "init; pld load 0 $(TARGET_BUILD_DIR)/gateware/top.bit; exit" + +gateware-flash-$(PLATFORM): gateware-flash-py + @true + +# Firmware +firmware-load-$(PLATFORM): + flterm --port=$(COMM_PORT) --kernel=$(FIRMWARE_FILEBASE).bin --speed=$(BAUD) + +firmware-flash-$(PLATFORM): firmwage-flash-py + @true + +firmware-connect-$(PLATFORM): + flterm --port=$(COMM_PORT) --speed=$(BAUD) + +firmware-clear-$(PLATFORM): + @echo "FIXME: Unsupported?." + @false + +# Bios +bios-flash-$(PLATFORM): + @echo "Unsupported." + @false + +# Extra commands +help-$(PLATFORM): + @true + +reset-$(PLATFORM): + @echo "Unsupported." + @false diff --git a/targets/neso/base.py b/targets/neso/base.py new file mode 100755 index 00000000..206ca8e5 --- /dev/null +++ b/targets/neso/base.py @@ -0,0 +1,150 @@ +# Support for the Numato Neso Artix 7 100T Board +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex.soc.integration.soc_core import mem_decoder +from litex.soc.integration.soc_sdram import * +from litex.soc.integration.builder import * + +from litedram.modules import MT41K128M16 +from litedram.phy import a7ddrphy +from litedram.core import ControllerSettings + +from gateware import info +from gateware import spi_flash + +from targets.utils import csr_map_update, period_ns + + +class _CRG(Module): + def __init__(self, platform): + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) + self.clock_domains.cd_sys4x_dqs = ClockDomain(reset_less=True) + self.clock_domains.cd_clk200 = ClockDomain() + self.clock_domains.cd_clk50 = ClockDomain() + + clk100 = platform.request("clk100") + + pll_locked = Signal() + pll_fb = Signal() + self.pll_sys = Signal() + pll_sys4x = Signal() + pll_sys4x_dqs = Signal() + pll_clk200 = Signal() + pll_clk50 = Signal() + self.specials += [ + Instance("PLLE2_BASE", + p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, + + # VCO @ 1600 MHz + p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=10.0, + p_CLKFBOUT_MULT=16, p_DIVCLK_DIVIDE=1, + i_CLKIN1=clk100, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, + + # 100 MHz + p_CLKOUT0_DIVIDE=16, p_CLKOUT0_PHASE=0.0, + o_CLKOUT0=self.pll_sys, + + # 400 MHz + p_CLKOUT1_DIVIDE=4, p_CLKOUT1_PHASE=0.0, + o_CLKOUT1=pll_sys4x, + + # 400 MHz dqs + p_CLKOUT2_DIVIDE=4, p_CLKOUT2_PHASE=90.0, + o_CLKOUT2=pll_sys4x_dqs, + + # 200 MHz + p_CLKOUT3_DIVIDE=8, p_CLKOUT3_PHASE=0.0, + o_CLKOUT3=pll_clk200, + + # 50MHz + p_CLKOUT4_DIVIDE=32, p_CLKOUT4_PHASE=0.0, + o_CLKOUT4=pll_clk50 + ), + Instance("BUFG", i_I=self.pll_sys, o_O=self.cd_sys.clk), + Instance("BUFG", i_I=pll_sys4x, o_O=self.cd_sys4x.clk), + Instance("BUFG", i_I=pll_sys4x_dqs, o_O=self.cd_sys4x_dqs.clk), + Instance("BUFG", i_I=pll_clk200, o_O=self.cd_clk200.clk), + Instance("BUFG", i_I=pll_clk50, o_O=self.cd_clk50.clk), + AsyncResetSynchronizer(self.cd_sys, ~pll_locked), + AsyncResetSynchronizer(self.cd_clk200, ~pll_locked), + AsyncResetSynchronizer(self.cd_clk50, ~pll_locked), + ] + + reset_counter = Signal(4, reset=15) + ic_reset = Signal(reset=1) + self.sync.clk200 += \ + If(reset_counter != 0, + reset_counter.eq(reset_counter - 1) + ).Else( + ic_reset.eq(0) + ) + self.specials += Instance("IDELAYCTRL", i_REFCLK=ClockSignal("clk200"), i_RST=ic_reset) + + +class BaseSoC(SoCSDRAM): + csr_peripherals = ( + "spiflash", + "ddrphy", + "info", + ) + csr_map_update(SoCSDRAM.csr_map, csr_peripherals) + + mem_map = { + "spiflash": 0x20000000, # (default shadow @0xa0000000) + } + mem_map.update(SoCSDRAM.mem_map) + + def __init__(self, platform, spiflash="spiflash_1x", **kwargs): + clk_freq = int(100e6) + SoCSDRAM.__init__(self, platform, clk_freq, + integrated_rom_size=0x8000, + integrated_sram_size=0x8000, + **kwargs) + + self.submodules.crg = _CRG(platform) + self.crg.cd_sys.clk.attr.add("keep") + self.platform.add_period_constraint(self.crg.cd_sys.clk, period_ns(clk_freq)) + + # Basic peripherals + self.submodules.info = info.Info(platform, self.__class__.__name__) + + # spi flash + spiflash_pads = platform.request(spiflash) + spiflash_pads.clk = Signal() + self.specials += Instance("STARTUPE2", + i_CLK=0, i_GSR=0, i_GTS=0, i_KEYCLEARB=0, i_PACK=0, + i_USRCCLKO=spiflash_pads.clk, i_USRCCLKTS=0, i_USRDONEO=1, i_USRDONETS=1) + spiflash_dummy = { + "spiflash_1x": 9, + "spiflash_4x": 11, + } + self.submodules.spiflash = spi_flash.SpiFlash( + spiflash_pads, + dummy=spiflash_dummy[spiflash], + div=2) + self.add_constant("SPIFLASH_PAGE_SIZE", 256) + self.add_constant("SPIFLASH_SECTOR_SIZE", 0x10000) + self.add_wb_slave(mem_decoder(self.mem_map["spiflash"]), self.spiflash.bus) + self.add_memory_region( + "spiflash", self.mem_map["spiflash"] | self.shadow_base, 16*1024*1024) + + + # sdram + sdram_module = MT41K128M16(self.clk_freq, "1:4") + self.submodules.ddrphy = a7ddrphy.A7DDRPHY( + platform.request("ddram")) + self.add_constant("READ_LEVELING_BITSLIP", 3) + self.add_constant("READ_LEVELING_DELAY", 14) + controller_settings = ControllerSettings( + with_bandwidth=True, + cmd_buffer_depth=8, + with_refresh=True) + self.register_sdram(self.ddrphy, + sdram_module.geom_settings, + sdram_module.timing_settings, + controller_settings=controller_settings) + + +SoC = BaseSoC diff --git a/targets/netv2/base.py b/targets/netv2/base.py index 68c0e6af..417671dc 100755 --- a/targets/netv2/base.py +++ b/targets/netv2/base.py @@ -1,6 +1,6 @@ # Support for netv2 -from litex.gen import * -from litex.gen.genlib.resetsync import AsyncResetSynchronizer +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer from litex.soc.integration.soc_core import mem_decoder from litex.soc.integration.soc_sdram import * @@ -94,7 +94,6 @@ def __init__(self, platform, **kwargs): SoCSDRAM.__init__(self, platform, clk_freq, integrated_rom_size=0x8000, integrated_sram_size=0x8000, - ident="NeTV2 LiteX Base SoC", **kwargs) self.submodules.crg = _CRG(platform) @@ -108,8 +107,8 @@ def __init__(self, platform, **kwargs): sdram_module = MT41J128M16(self.clk_freq, "1:4") self.submodules.ddrphy = a7ddrphy.A7DDRPHY( platform.request("ddram")) - self.add_constant("A7DDRPHY_BITSLIP", 2) - self.add_constant("A7DDRPHY_DELAY", 8) + self.add_constant("READ_LEVELING_BITSLIP", 2) + self.add_constant("READ_LEVELING_DELAY", 8) controller_settings = ControllerSettings( with_bandwidth=True, cmd_buffer_depth=8, diff --git a/targets/netv2/bridge_pcie.py b/targets/netv2/bridge_pcie.py index 656d6224..50a8220e 100644 --- a/targets/netv2/bridge_pcie.py +++ b/targets/netv2/bridge_pcie.py @@ -1,7 +1,7 @@ -from litex.gen import * -from litex.gen.genlib.io import CRG -from litex.gen.genlib.resetsync import AsyncResetSynchronizer -from litex.gen.genlib.misc import timeline +from migen import * +from migen.genlib.io import CRG +from migen.genlib.resetsync import AsyncResetSynchronizer +from migen.genlib.misc import timeline from litex.soc.interconnect.csr import * from litex.soc.interconnect import wishbone @@ -64,7 +64,6 @@ def __init__(self, platform, with_uart_bridge=True, **kwargs): shadow_base=0x00000000, csr_data_width=32, with_uart=False, - ident="NeTV2 LiteX PCIe SoC", with_timer=False, **kwargs) self.submodules.crg = _CRG(platform) diff --git a/targets/netv2/bridge_uart.py b/targets/netv2/bridge_uart.py index 97611664..43895822 100644 --- a/targets/netv2/bridge_uart.py +++ b/targets/netv2/bridge_uart.py @@ -1,6 +1,6 @@ -from litex.gen import * -from litex.gen.genlib.resetsync import AsyncResetSynchronizer -from litex.gen.fhdl.specials import Keep +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer +from migen.fhdl.specials import Keep from litex.soc.integration.soc_core import mem_decoder from litex.soc.integration.soc_sdram import * @@ -113,7 +113,6 @@ def __init__(self, platform, **kwargs): SoCSDRAM.__init__(self, platform, clk_freq, integrated_rom_size=0x8000, integrated_sram_size=0x8000, - ident="NeTV2 LiteX Base SoC", with_uart=False, **kwargs) @@ -126,8 +125,8 @@ def __init__(self, platform, **kwargs): # sdram self.submodules.ddrphy = a7ddrphy.A7DDRPHY(platform.request("ddram")) - self.add_constant("A7DDRPHY_BITSLIP", 2) - self.add_constant("A7DDRPHY_DELAY", 8) + self.add_constant("READ_LEVELING_BITSLIP", 2) + self.add_constant("READ_LEVELING_DELAY", 8) sdram_module = MT41J128M16(self.clk_freq, "1:4") self.register_sdram(self.ddrphy, sdram_module.geom_settings, diff --git a/targets/netv2/pcie.py b/targets/netv2/pcie.py index 7469c29c..fac7416e 100644 --- a/targets/netv2/pcie.py +++ b/targets/netv2/pcie.py @@ -1,4 +1,4 @@ -from litex.gen import * +from migen import * from litepcie.phy.s7pciephy import S7PCIEPHY from litepcie.core import LitePCIeEndpoint, LitePCIeMSI diff --git a/targets/netv2/video.py b/targets/netv2/video.py index b88c30eb..2be9baec 100644 --- a/targets/netv2/video.py +++ b/targets/netv2/video.py @@ -37,5 +37,8 @@ def __init__(self, platform, *args, **kwargs): self.crg.cd_sys.clk, self.hdmi_out0.driver.clocking.cd_pix.clk) + for name, value in sorted(self.platform.hdmi_infos.items()): + self.add_constant(name, value) + SoC = VideoOutSoC diff --git a/targets/nexys_video/base.py b/targets/nexys_video/base.py index 00513258..f17e4dde 100755 --- a/targets/nexys_video/base.py +++ b/targets/nexys_video/base.py @@ -1,6 +1,6 @@ # Support for Digilent Nexys Video board -from litex.gen import * -from litex.gen.genlib.resetsync import AsyncResetSynchronizer +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer from litex.soc.integration.soc_core import mem_decoder from litex.soc.integration.soc_sdram import * @@ -127,8 +127,8 @@ def __init__(self, platform, spiflash="spiflash_1x", **kwargs): # sdram self.submodules.ddrphy = a7ddrphy.A7DDRPHY(platform.request("ddram")) - self.add_constant("A7DDRPHY_BITSLIP", 3) - self.add_constant("A7DDRPHY_DELAY", 14) + self.add_constant("READ_LEVELING_BITSLIP", 3) + self.add_constant("READ_LEVELING_DELAY", 14) sdram_module = MT41K256M16(self.clk_freq, "1:4") self.register_sdram(self.ddrphy, sdram_module.geom_settings, diff --git a/targets/nexys_video/bridge_net.py b/targets/nexys_video/bridge_net.py index 5c8855fd..a54032c1 100755 --- a/targets/nexys_video/bridge_net.py +++ b/targets/nexys_video/bridge_net.py @@ -3,7 +3,7 @@ from liteeth.core import LiteEthUDPIPCore from liteeth.frontend.etherbone import LiteEthEtherbone -from litex.gen.fhdl.specials import Keep +from migen.fhdl.specials import Keep from targets.nexys_video.base import BaseSoC diff --git a/targets/nexys_video/ddr3.py b/targets/nexys_video/ddr3.py index fd884bac..915846e1 100755 --- a/targets/nexys_video/ddr3.py +++ b/targets/nexys_video/ddr3.py @@ -1,5 +1,5 @@ -from litex.gen import * -from litex.gen.genlib.resetsync import AsyncResetSynchronizer +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer from litex.soc.integration.soc_core import mem_decoder from litex.soc.integration.soc_sdram import * diff --git a/targets/nexys_video/video.py b/targets/nexys_video/video.py index e499de6e..c99e2971 100755 --- a/targets/nexys_video/video.py +++ b/targets/nexys_video/video.py @@ -89,6 +89,9 @@ def __init__(self, platform, *args, **kwargs): self.hdmi_out0.driver.clocking.cd_pix.clk, self.hdmi_out0.driver.clocking.cd_pix5x.clk) + for name, value in sorted(self.platform.hdmi_infos.items()): + self.add_constant(name, value) + class VideoSoCDebug(VideoSoC): csr_peripherals = ( diff --git a/targets/opsis/axiom.py b/targets/opsis/axiom.py index 4794511a..db3ab512 100644 --- a/targets/opsis/axiom.py +++ b/targets/opsis/axiom.py @@ -1,4 +1,4 @@ -from litex.gen import * +from migen import * from litex.soc.cores.gpio import GPIOIn, GPIOOut from targets.utils import csr_map_update diff --git a/targets/opsis/base.py b/targets/opsis/base.py index bdece491..1ddf6913 100644 --- a/targets/opsis/base.py +++ b/targets/opsis/base.py @@ -1,9 +1,9 @@ # Support for Numato Opsis - https://opsis.hdmi2usb.tv from fractions import Fraction -from litex.gen import * -from litex.gen.genlib.resetsync import AsyncResetSynchronizer -from litex.gen.genlib.misc import WaitTimer +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer +from migen.genlib.misc import WaitTimer from litex.soc.integration.soc_sdram import * from litex.soc.integration.builder import * diff --git a/targets/opsis/encoder.py b/targets/opsis/encoder.py index f86bd0eb..9ad69c9b 100644 --- a/targets/opsis/encoder.py +++ b/targets/opsis/encoder.py @@ -1,4 +1,4 @@ -from litex.gen.fhdl.decorators import ClockDomainsRenamer +from migen.fhdl.decorators import ClockDomainsRenamer from litex.soc.integration.soc_core import mem_decoder from litex.soc.interconnect import stream diff --git a/targets/opsis/hdmi2usb.py b/targets/opsis/hdmi2usb.py index 427666c9..00f94f2d 100644 --- a/targets/opsis/hdmi2usb.py +++ b/targets/opsis/hdmi2usb.py @@ -1,4 +1,4 @@ -from litex.gen.fhdl.decorators import ClockDomainsRenamer +from migen.fhdl.decorators import ClockDomainsRenamer from litex.soc.integration.soc_core import mem_decoder from litex.soc.interconnect import stream diff --git a/targets/opsis/video.py b/targets/opsis/video.py index a7ec6b94..4fb104ce 100644 --- a/targets/opsis/video.py +++ b/targets/opsis/video.py @@ -122,5 +122,8 @@ def __init__(self, platform, *args, **kwargs): self.hdmi_out0.driver.clocking.cd_pix.clk, self.hdmi_out1.driver.clocking.cd_pix.clk) + for name, value in sorted(self.platform.hdmi_infos.items()): + self.add_constant(name, value) + SoC = VideoSoC diff --git a/targets/pipistrello/base.py b/targets/pipistrello/base.py index dc005726..146100c7 100644 --- a/targets/pipistrello/base.py +++ b/targets/pipistrello/base.py @@ -1,8 +1,8 @@ # Support for the Pipistrello - http://pipistrello.saanlima.com/ from fractions import Fraction -from litex.gen import * -from litex.gen.genlib.resetsync import AsyncResetSynchronizer +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer from litex.soc.integration.soc_sdram import * from litex.soc.integration.builder import * diff --git a/targets/saturn/Makefile.mk b/targets/saturn/Makefile.mk new file mode 100644 index 00000000..ac1e3cd8 --- /dev/null +++ b/targets/saturn/Makefile.mk @@ -0,0 +1,53 @@ +# saturn targets + +ifneq ($(PLATFORM),saturn) + $(error "Platform should be saturn when using this file!?") +endif + +# Settings +DEFAULT_TARGET = base +TARGET ?= $(DEFAULT_TARGET) + +PROG_PORT ?= /dev/ttyUSB0 +COMM_PORT ?= /dev/ttyUSB1 +BAUD ?= 115200 + +# Image +image-flash-$(PLATFORM): image-flash-py + @true + +# Gateware +gateware-load-$(PLATFORM): + @echo "Unsupported." + @false + +gateware-flash-$(PLATFORM): gateware-flash-py + @true + +# Firmware +firmware-load-$(PLATFORM): + @echo "Unsupported." + @false + +firmware-flash-$(PLATFORM): firmwage-flash-py + @true + +firmware-connect-$(PLATFORM): + flterm --port=$(COMM_PORT) --speed=$(BAUD) + +firmware-clear-$(PLATFORM): + @echo "FIXME: Unsupported?." + @false + +# Bios +bios-flash-$(PLATFORM): + @echo "Unsupported." + @false + +# Extra commands +help-$(PLATFORM): + @true + +reset-$(PLATFORM): + @echo "Unsupported." + @false diff --git a/targets/saturn/base.py b/targets/saturn/base.py new file mode 100644 index 00000000..5a4a079c --- /dev/null +++ b/targets/saturn/base.py @@ -0,0 +1,220 @@ +# Support for the Numato Saturn (http://numato.com/product/saturn-spartan-6-fpga-development-board-with-ddr-sdram) + +from fractions import Fraction + +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex.build.generic_platform import * + +from litex.soc.integration.soc_sdram import * +from litex.soc.integration.builder import * + +from litedram.modules import MT46H32M16 +from litedram.phy import s6ddrphy +from litedram.core import ControllerSettings + +from targets.utils import csr_map_update + + +class _CRG(Module): + def __init__(self, platform, clk_freq): + # Clock domains for the system (soft CPU and related components run at). + self.clock_domains.cd_sys = ClockDomain() + # Clock domains for the DDR interface. + self.clock_domains.cd_sdram_half = ClockDomain() + self.clock_domains.cd_sdram_full_wr = ClockDomain() + self.clock_domains.cd_sdram_full_rd = ClockDomain() + + # Input 100MHz clock + f0 = Fraction(100, 1)*1000000 + clk100 = platform.request("clk100") + clk100a = Signal() + # Input 100MHz clock (buffered) + self.specials += Instance( + "IBUFG", + i_I=clk100, + o_O=clk100a + ) + + clk100b = Signal() + + self.specials += Instance( + "BUFIO2", + p_DIVIDE=1, + p_DIVIDE_BYPASS="TRUE", p_I_INVERT="FALSE", + i_I=clk100a, + o_DIVCLK=clk100b + ) + + #PLL parameters + f = Fraction(10, 1) + n, d = f.numerator, f.denominator + p = 8 + + assert f0*n/d/p/4 == clk_freq + assert 19e6 <= f0/d <= 500e6 # pfd + assert 400e6 <= f0*n/d <= 1000e6 # vco + + # Unbuffered output signals from the PLL. They need to be buffered + # before feeding into the fabric. + unbuf_sdram_full = Signal() + unbuf_sdram_half_a = Signal() + unbuf_sdram_half_b = Signal() + unbuf_unused_a = Signal() + unbuf_unused_b = Signal() + unbuf_sys = Signal() + + # PLL signals + pll_lckd = Signal() + pll_fb = Signal() + self.specials.pll = Instance( + "PLL_ADV", + name="crg_pll_adv", + p_SIM_DEVICE="SPARTAN6", p_BANDWIDTH="OPTIMIZED", p_COMPENSATION="INTERNAL", + p_REF_JITTER=.01, + i_DADDR=0, i_DCLK=0, i_DEN=0, i_DI=0, i_DWE=0, i_RST=0, i_REL=0, + p_DIVCLK_DIVIDE=d, + # Input Clocks (100MHz) + i_CLKIN1=clk100b, + p_CLKIN1_PERIOD=1e9/f0, + i_CLKIN2=0, + p_CLKIN2_PERIOD=0., + i_CLKINSEL=1, + # Feedback + i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, o_LOCKED=pll_lckd, + p_CLK_FEEDBACK="CLKFBOUT", + p_CLKFBOUT_MULT=n, p_CLKFBOUT_PHASE=0., + # Outputs + # (125 MHz) sdram wr rd + o_CLKOUT0=unbuf_sdram_full, p_CLKOUT0_DUTY_CYCLE=.5, + p_CLKOUT0_PHASE=0., p_CLKOUT0_DIVIDE=p, + # (125 MHz) unused + o_CLKOUT1=unbuf_unused_a, p_CLKOUT1_DUTY_CYCLE=.5, + p_CLKOUT1_PHASE=0., p_CLKOUT1_DIVIDE=p, + # (62.5 MHz) sdram_half - sdram dqs adr ctrl + o_CLKOUT2=unbuf_sdram_half_a, p_CLKOUT2_DUTY_CYCLE=.5, + p_CLKOUT2_PHASE=270., p_CLKOUT2_DIVIDE=(p*2), + # (62.5 MHz) off-chip ddr + o_CLKOUT3=unbuf_sdram_half_b, p_CLKOUT3_DUTY_CYCLE=.5, + p_CLKOUT3_PHASE=270., p_CLKOUT3_DIVIDE=(p*2), + # (31.25 MHz) unused + o_CLKOUT4=unbuf_unused_b, p_CLKOUT4_DUTY_CYCLE=.5, + p_CLKOUT4_PHASE=0., p_CLKOUT4_DIVIDE=(p*4), + # (31.25 MHz) sysclk + o_CLKOUT5=unbuf_sys, p_CLKOUT5_DUTY_CYCLE=.5, + p_CLKOUT5_PHASE=0., p_CLKOUT5_DIVIDE=(p*4), + ) + + #power on reset? + reset_pin = [("reset", 0, Pins("P2:0")), ] + platform.add_extension(reset_pin) + reset = platform.request("reset") + self.clock_domains.cd_por = ClockDomain() + por = Signal(max=1 << 11, reset=(1 << 11) - 1) + self.sync.por += If(por != 0, por.eq(por - 1)) + self.specials += AsyncResetSynchronizer(self.cd_por, reset) + + #System clock + self.specials += Instance("BUFG", i_I=unbuf_sys, o_O=self.cd_sys.clk) + self.comb += self.cd_por.clk.eq(self.cd_sys.clk) + self.specials += AsyncResetSynchronizer(self.cd_sys, ~pll_lckd | (por > 0)) + + # SDRAM clocks + # ------------------------------------------------------------------------------ + self.clk4x_wr_strb = Signal() + self.clk4x_rd_strb = Signal() + + # sdram_full + self.specials += Instance( + "BUFPLL", + p_DIVIDE=4, + i_PLLIN=unbuf_sdram_full, + i_GCLK=self.cd_sys.clk, + i_LOCKED=pll_lckd, + o_IOCLK=self.cd_sdram_full_wr.clk, + o_SERDESSTROBE=self.clk4x_wr_strb + ) + + self.comb += [ + self.cd_sdram_full_rd.clk.eq(self.cd_sdram_full_wr.clk), + self.clk4x_rd_strb.eq(self.clk4x_wr_strb), + ] + + # sdram_half + self.specials += Instance( + "BUFG", + i_I=unbuf_sdram_half_a, + o_O=self.cd_sdram_half.clk + ) + + clk_sdram_half_shifted = Signal() + self.specials += Instance( + "BUFG", + i_I=unbuf_sdram_half_b, + o_O=clk_sdram_half_shifted + ) + + clk = platform.request("ddram_clock") + self.specials += Instance( + "ODDR2", + p_DDR_ALIGNMENT="NONE", + p_INIT=0, p_SRTYPE="SYNC", + i_D0=1, i_D1=0, i_S=0, i_R=0, i_CE=1, + i_C0=clk_sdram_half_shifted, + i_C1=~clk_sdram_half_shifted, + o_Q=clk.p + ) + + self.specials += Instance( + "ODDR2", + p_DDR_ALIGNMENT="NONE", + p_INIT=0, p_SRTYPE="SYNC", + i_D0=0, i_D1=1, i_S=0, i_R=0, i_CE=1, + i_C0=clk_sdram_half_shifted, + i_C1=~clk_sdram_half_shifted, + o_Q=clk.n + ) + +class BaseSoC(SoCSDRAM): + csr_peripherals = ( + "ddrphy", + ) + csr_map_update(SoCSDRAM.csr_map, csr_peripherals) + + def __init__(self, platform, **kwargs): + clk_freq=(31 + Fraction(1, 4))*1000*1000 + + SoCSDRAM.__init__(self, platform, clk_freq, + integrated_rom_size = 0x8000, + integrated_sram_size = 0x4000, + **kwargs + ) + self.submodules.crg = _CRG(platform, clk_freq) + + # sdram + sdram_module = MT46H32M16(self.clk_freq, "1:2") + self.submodules.ddrphy = s6ddrphy.S6HalfRateDDRPHY( + platform.request("ddram"), + sdram_module.memtype, + rd_bitslip=2, + wr_bitslip=3, + dqs_ddr_alignment="C1" + ) + + controller_settings = ControllerSettings( + with_bandwidth=True + ) + + self.register_sdram(self.ddrphy, + sdram_module.geom_settings, + sdram_module.timing_settings, + controller_settings=controller_settings + ) + + self.comb += [ + self.ddrphy.clk4x_wr_strb.eq(self.crg.clk4x_wr_strb), + self.ddrphy.clk4x_rd_strb.eq(self.crg.clk4x_rd_strb), + ] + +SoC = BaseSoC diff --git a/targets/sim/base.py b/targets/sim/base.py index 2ba1b742..1ee20703 100644 --- a/targets/sim/base.py +++ b/targets/sim/base.py @@ -1,6 +1,6 @@ # Support for simulation via verilator -from litex.gen import * -from litex.gen.genlib.io import CRG +from migen import * +from migen.genlib.io import CRG from litex.soc.integration.soc_sdram import * from litex.soc.integration.builder import * diff --git a/targets/sim/video.py b/targets/sim/video.py index f2e06d2f..fa92849f 100644 --- a/targets/sim/video.py +++ b/targets/sim/video.py @@ -1,4 +1,4 @@ -from litex.gen import * +from migen import * from litevideo.output.common import * from litevideo.output.core import VideoOutCore diff --git a/targets/waxwing/Makefile.mk b/targets/waxwing/Makefile.mk new file mode 100644 index 00000000..4ab9b6df --- /dev/null +++ b/targets/waxwing/Makefile.mk @@ -0,0 +1,51 @@ +# waxwing targets + +ifneq ($(PLATFORM),waxwing) + $(error "Platform should be saturn when using this file!?") +endif + +# Settings +DEFAULT_TARGET = base +TARGET ?= $(DEFAULT_TARGET) + +PROG_PORT ?= /dev/ttyUSB0 +COMM_PORT ?= /dev/ttyUSB1 +BAUD ?= 115200 + +# Image +image-flash-$(PLATFORM): image-flash-py + @true + +# Gateware +gateware-load-$(PLATFORM): + openocd -f board/numato_$(PLATFORM).cfg -c "init; pld load 0 $(TARGET_BUILD_DIR)/gateware/top.bit; exit" + +gateware-flash-$(PLATFORM): gateware-flash-py + @true + +# Firmware +firmware-load-$(PLATFORM): + flterm --port=$(COMM_PORT) --kernel=$(FIRMWARE_FILEBASE).bin --speed=$(BAUD) + +firmware-flash-$(PLATFORM): firmwage-flash-py + @true + +firmware-connect-$(PLATFORM): + flterm --port=$(COMM_PORT) --speed=$(BAUD) + +firmware-clear-$(PLATFORM): + @echo "FIXME: Unsupported?." + @false + +# Bios +bios-flash-$(PLATFORM): + @echo "Unsupported." + @false + +# Extra commands +help-$(PLATFORM): + @true + +reset-$(PLATFORM): + @echo "Unsupported." + @false diff --git a/targets/waxwing/base.py b/targets/waxwing/base.py new file mode 100644 index 00000000..4d979388 --- /dev/null +++ b/targets/waxwing/base.py @@ -0,0 +1,218 @@ +# Support for the Numato Saturn (http://numato.com/product/saturn-spartan-6-fpga-development-board-with-ddr-sdram) + +from fractions import Fraction + +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex.build.generic_platform import * + +from litex.soc.integration.soc_sdram import * +from litex.soc.integration.builder import * + +from litedram.modules import MT46H32M16 +from litedram.phy import s6ddrphy +from litedram.core import ControllerSettings + +from targets.utils import csr_map_update + + +class _CRG(Module): + def __init__(self, platform, clk_freq): + # Clock domains for the system (soft CPU and related components run at). + self.clock_domains.cd_sys = ClockDomain() + # Clock domains for the DDR interface. + self.clock_domains.cd_sdram_half = ClockDomain() + self.clock_domains.cd_sdram_full_wr = ClockDomain() + self.clock_domains.cd_sdram_full_rd = ClockDomain() + + # Input 100MHz clock + f0 = Fraction(100, 1)*1000000 + clk100 = platform.request("clk100") + clk100a = Signal() + # Input 100MHz clock (buffered) + self.specials += Instance( + "IBUFG", + i_I=clk100, + o_O=clk100a + ) + + clk100b = Signal() + + self.specials += Instance( + "BUFIO2", + p_DIVIDE=1, + p_DIVIDE_BYPASS="TRUE", p_I_INVERT="FALSE", + i_I=clk100a, + o_DIVCLK=clk100b + ) + + #PLL parameters + f = Fraction(10, 1) + n, d = f.numerator, f.denominator + p = 8 + + assert f0*n/d/p/4 == clk_freq + assert 19e6 <= f0/d <= 500e6 # pfd + assert 400e6 <= f0*n/d <= 1000e6 # vco + + # Unbuffered output signals from the PLL. They need to be buffered + # before feeding into the fabric. + unbuf_sdram_full = Signal() + unbuf_sdram_half_a = Signal() + unbuf_sdram_half_b = Signal() + unbuf_unused_a = Signal() + unbuf_unused_b = Signal() + unbuf_sys = Signal() + + # PLL signals + pll_lckd = Signal() + pll_fb = Signal() + self.specials.pll = Instance( + "PLL_ADV", + name="crg_pll_adv", + p_SIM_DEVICE="SPARTAN6", p_BANDWIDTH="OPTIMIZED", p_COMPENSATION="INTERNAL", + p_REF_JITTER=.01, + i_DADDR=0, i_DCLK=0, i_DEN=0, i_DI=0, i_DWE=0, i_RST=0, i_REL=0, + p_DIVCLK_DIVIDE=d, + # Input Clocks (100MHz) + i_CLKIN1=clk100b, + p_CLKIN1_PERIOD=1e9/f0, + i_CLKIN2=0, + p_CLKIN2_PERIOD=0., + i_CLKINSEL=1, + # Feedback + i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, o_LOCKED=pll_lckd, + p_CLK_FEEDBACK="CLKFBOUT", + p_CLKFBOUT_MULT=n, p_CLKFBOUT_PHASE=0., + # Outputs + # (125 MHz) sdram wr rd + o_CLKOUT0=unbuf_sdram_full, p_CLKOUT0_DUTY_CYCLE=.5, + p_CLKOUT0_PHASE=0., p_CLKOUT0_DIVIDE=p, + # (125 MHz) unused + o_CLKOUT1=unbuf_unused_a, p_CLKOUT1_DUTY_CYCLE=.5, + p_CLKOUT1_PHASE=0., p_CLKOUT1_DIVIDE=p, + # (62.5 MHz) sdram_half - sdram dqs adr ctrl + o_CLKOUT2=unbuf_sdram_half_a, p_CLKOUT2_DUTY_CYCLE=.5, + p_CLKOUT2_PHASE=270., p_CLKOUT2_DIVIDE=(p*2), + # (62.5 MHz) off-chip ddr + o_CLKOUT3=unbuf_sdram_half_b, p_CLKOUT3_DUTY_CYCLE=.5, + p_CLKOUT3_PHASE=270., p_CLKOUT3_DIVIDE=(p*2), + # (31.25 MHz) unused + o_CLKOUT4=unbuf_unused_b, p_CLKOUT4_DUTY_CYCLE=.5, + p_CLKOUT4_PHASE=0., p_CLKOUT4_DIVIDE=(p*4), + # (31.25 MHz) sysclk + o_CLKOUT5=unbuf_sys, p_CLKOUT5_DUTY_CYCLE=.5, + p_CLKOUT5_PHASE=0., p_CLKOUT5_DIVIDE=(p*4), + ) + + #power on reset? + reset = ~platform.request("user_btn", 0) + self.clock_domains.cd_por = ClockDomain() + por = Signal(max=1 << 11, reset=(1 << 11) - 1) + self.sync.por += If(por != 0, por.eq(por - 1)) + self.specials += AsyncResetSynchronizer(self.cd_por, reset) + + #System clock + self.specials += Instance("BUFG", i_I=unbuf_sys, o_O=self.cd_sys.clk) + self.comb += self.cd_por.clk.eq(self.cd_sys.clk) + self.specials += AsyncResetSynchronizer(self.cd_sys, ~pll_lckd | (por > 0)) + + # SDRAM clocks + # ------------------------------------------------------------------------------ + self.clk4x_wr_strb = Signal() + self.clk4x_rd_strb = Signal() + + # sdram_full + self.specials += Instance( + "BUFPLL", + p_DIVIDE=4, + i_PLLIN=unbuf_sdram_full, + i_GCLK=self.cd_sys.clk, + i_LOCKED=pll_lckd, + o_IOCLK=self.cd_sdram_full_wr.clk, + o_SERDESSTROBE=self.clk4x_wr_strb + ) + + self.comb += [ + self.cd_sdram_full_rd.clk.eq(self.cd_sdram_full_wr.clk), + self.clk4x_rd_strb.eq(self.clk4x_wr_strb), + ] + + # sdram_half + self.specials += Instance( + "BUFG", + i_I=unbuf_sdram_half_a, + o_O=self.cd_sdram_half.clk + ) + + clk_sdram_half_shifted = Signal() + self.specials += Instance( + "BUFG", + i_I=unbuf_sdram_half_b, + o_O=clk_sdram_half_shifted + ) + + clk = platform.request("ddram_clock") + self.specials += Instance( + "ODDR2", + p_DDR_ALIGNMENT="NONE", + p_INIT=0, p_SRTYPE="SYNC", + i_D0=1, i_D1=0, i_S=0, i_R=0, i_CE=1, + i_C0=clk_sdram_half_shifted, + i_C1=~clk_sdram_half_shifted, + o_Q=clk.p + ) + + self.specials += Instance( + "ODDR2", + p_DDR_ALIGNMENT="NONE", + p_INIT=0, p_SRTYPE="SYNC", + i_D0=0, i_D1=1, i_S=0, i_R=0, i_CE=1, + i_C0=clk_sdram_half_shifted, + i_C1=~clk_sdram_half_shifted, + o_Q=clk.n + ) + +class BaseSoC(SoCSDRAM): + csr_peripherals = ( + "ddrphy", + ) + csr_map_update(SoCSDRAM.csr_map, csr_peripherals) + + def __init__(self, platform, **kwargs): + clk_freq=(31 + Fraction(1, 4))*1000*1000 + + SoCSDRAM.__init__(self, platform, clk_freq, + integrated_rom_size = 0x8000, + integrated_sram_size = 0x4000, + **kwargs + ) + self.submodules.crg = _CRG(platform, clk_freq) + + # sdram + sdram_module = MT46H32M16(self.clk_freq, "1:2") + self.submodules.ddrphy = s6ddrphy.S6HalfRateDDRPHY( + platform.request("ddram"), + sdram_module.memtype, + rd_bitslip=2, + wr_bitslip=3, + dqs_ddr_alignment="C1" + ) + + controller_settings = ControllerSettings( + with_bandwidth=True + ) + + self.register_sdram(self.ddrphy, + sdram_module.geom_settings, + sdram_module.timing_settings, + controller_settings=controller_settings + ) + + self.comb += [ + self.ddrphy.clk4x_wr_strb.eq(self.crg.clk4x_wr_strb), + self.ddrphy.clk4x_rd_strb.eq(self.crg.clk4x_rd_strb), + ] + +SoC = BaseSoC diff --git a/test/common.py b/test/common.py index 810b4c08..11fa49c7 100644 --- a/test/common.py +++ b/test/common.py @@ -8,8 +8,10 @@ from litex.soc.tools.remote import RemoteClient from litex.soc.tools.remote import CommUART -sys.path.append(os.path.join(os.path.dirname(__file__), "..")) -from make import make_args, make_testdir +TOP_DIR=os.path.join(os.path.dirname(__file__), "..") + +sys.path.append(TOP_DIR) +from make import get_args, get_testdir class ServerProxy(threading.Thread): @@ -31,7 +33,7 @@ def run(self): def connect(desc, *args, add_args=None, **kw): parser = argparse.ArgumentParser(description=desc) - make_args(parser, *args, **kw) + get_args(parser, *args, **kw) parser.add_argument("--ipaddress") parser.add_argument("--port") #, desc="Serial port") if add_args is not None: @@ -50,7 +52,8 @@ def connect(desc, *args, add_args=None, **kw): args.ipaddress = "{}.50".format(args.iprange) print("Connecting to {}".format(args.ipaddress)) - wb = RemoteClient(args.ipaddress, 1234, csr_csv="{}/csr.csv".format(make_testdir(args)), csr_data_width=32) + test_dir = os.path.join(TOP_DIR, get_testdir(args)) + wb = RemoteClient(args.ipaddress, 1234, csr_csv="{}/csr.csv".format(test_dir)) wb.open() print() print("Device DNA: {}".format(get_dna(wb))) diff --git a/third_party/edid-decode b/third_party/edid-decode index f56f329e..dcc8b834 160000 --- a/third_party/edid-decode +++ b/third_party/edid-decode @@ -1 +1 @@ -Subproject commit f56f329ed23a25d002352dedba1e8f092a47286f +Subproject commit dcc8b8346ee4bb541c0637f3cb38349296231616 diff --git a/third_party/flash_proxies b/third_party/flash_proxies index 070d8b29..a628956d 160000 --- a/third_party/flash_proxies +++ b/third_party/flash_proxies @@ -1 +1 @@ -Subproject commit 070d8b29acf1445c08ebf3073d04206461819bbe +Subproject commit a628956da7dc794e6e3c95b31ff9ce3af58bc763 diff --git a/third_party/merge-upstream.sh b/third_party/merge-upstream.sh index 59573f4a..61305cf8 100755 --- a/third_party/merge-upstream.sh +++ b/third_party/merge-upstream.sh @@ -2,23 +2,36 @@ set -e -TARGETS=${@-$(find * -maxdepth 0 -type d | grep -v micropython | grep -v qemu | grep -v libuip)} +TARGETS=${@-$(find * -maxdepth 0 -type d)} COMMIT_MSG=$(tempfile) || exit trap "rm -f -- '$COMMIT_MSG'" EXIT +MODULES=() for TARGET in $TARGETS; do + if [ ! -e $TARGET/.git ] || ! grep -q "gitdir:" $TARGET/.git 2> /dev/null; then + echo "Skipping $TARGET as not submodule" + continue + else + echo "Submodule $TARGET" + MODULES+=("$TARGET") + fi git submodule sync --recursive -- $TARGET git submodule update --recursive --init $TARGET done +echo +echo "Found submodules:" +declare -p MODULES +echo + cat > $COMMIT_MSG < /dev/null VERSION=$(git describe --always --dirty) echo -n "$TARGET version ($VERSION) " | grep --color -E "dirty|$" @@ -28,14 +41,14 @@ for TARGET in $TARGETS; do popd > /dev/null done -if [ $DIRTY -eq 0 ]; then +if [ $DIRTY = 0 ]; then echo "All targets clean, good to update." else echo "Some target are dirty, can't update." exit 1 fi -for TARGET in $TARGETS; do +for TARGET in ${MODULES[@]}; do ( case $TARGET in *) @@ -49,13 +62,20 @@ for TARGET in $TARGETS; do BEFORE_VER=$(git describe --always --dirty) git fetch origin | sed -e's/^/ /' git checkout origin/$BRANCH | sed -e's/^/ /' + git submodule update --recursive --init AFTER_VER=$(git describe --always --dirty) + if echo $AFTER_VER | grep -q "dirty"; then + echo "Updated version is dirty!?" + exit 1 + fi if [ x"$BEFORE_VER" = x"$AFTER_VER" ]; then echo "$TARGET is unchanged" else echo "Move $TARGET from $BEFORE_VER to $AFTER_VER" cat >> $COMMIT_MSG <' --no-color --abbrev-commit $BEFORE_VER..$AFTER_VER | sed -e's/^/ /') + EOF fi echo diff --git a/third_party/migen b/third_party/migen new file mode 160000 index 00000000..881741be --- /dev/null +++ b/third_party/migen @@ -0,0 +1 @@ +Subproject commit 881741be6c1920e21821168298ed2bf13c3e651b