image: debian:10
+cache:
+ when: always
+ paths:
+ - ccache
+
build:
stage: build
before_script:
- apt-get update
- - apt-get install -y xc3sprog
+ - >-
+ apt-get install -y
+ autoconf
+ bison
+ build-essential
+ ccache
+ clang
+ cmake
+ cython3
+ flex
+ gawk
+ git
+ gperf
+ libboost-all-dev
+ libeigen3-dev
+ libffi-dev
+ libftdi-dev
+ libreadline-dev
+ pkg-config
+ python3
+ python3-dev
+ python3-jinja2
+ python3-numpy
+ python3-pip
+ python3-setuptools
+ python3-wheel
+ tcl-dev
+ wget
+ zlib1g-dev
+ - export PATH="$HOME/.local/bin:/usr/lib/ccache:$PATH"
+ - export CCACHE_BASEDIR="$PWD"
+ - if [[ -z "$CCACHE_DIR" ]]; then export CCACHE_DIR="$PWD/ccache"; fi
+ - export CCACHE_COMPILERCHECK=content
+ - ccache --zero-stats || true
+ - ccache --show-stats || true
+ - pip3 install textx fasm
+ - export XC3SPROG="$PWD/program-fpga.py"
script:
- - ls -l /dev/tty*
- - xc3sprog -c nexys4 -T -j
+ - git clone --depth 1 https://github.com/YosysHQ/yosys.git yosys
+ - pushd yosys
+ - git rev-parse HEAD
+ - make config-gcc
+ - make -j$(nproc)
+ - make install
+ - popd
+ - yosys -V
+
+ - git clone https://gitlab.com/nmigen/nmigen.git nmigen
+ - pushd nmigen
+ - git rev-parse HEAD
+ - if [[ -z "`git tag --list v0.2`" ]]; then git tag v0.2 1025b98c279a5889e58bc27e7f183928dbbd1735; fi
+ - python3 setup.py develop
+ - popd
+
+ - git clone --depth 1 https://gitlab.com/nmigen/nmigen-boards.git nmigen-boards
+ - pushd nmigen-boards
+ - git rev-parse HEAD
+ - python3 setup.py develop
+ - popd
+
+ - git clone https://github.com/f4pga/prjxray.git prjxray
+ - pushd prjxray
+ - git checkout 18b92012afe2b03f3f975a78c4372c74b60dca0c
+ - git submodule update --init --recursive
+ - mkdir build; cd build
+ - cmake -DCMAKE_INSTALL_PREFIX=/usr/local/nextpnr-xilinx ..
+ - make -j$(nproc)
+ - make install
+ - install -d -m 0755 /usr/local/nextpnr-xilinx/build/tools
+ - install -m 0755 tools/{bitread,bittool,frame_address_decoder,gen_part_base_yaml,segmatch,xc7frames2bit,xc7patch} /usr/local/nextpnr-xilinx/build/tools
+ - cd ..
+ - cp -dpr utils /usr/local/nextpnr-xilinx
+ - sed -i -e '/^# Vivado /,$d' /usr/local/nextpnr-xilinx/utils/environment.sh
+ - python3 setup.py develop
+ - popd
+
+ - git clone https://github.com/f4pga/prjxray-db.git prjxray-db
+ - pushd prjxray-db
+ - git archive --format=tar --prefix=database/ 0a0addedd73e7e4139d52a6d8db4258763e0f1f3 | tar -C /usr/local/nextpnr-xilinx -xf -
+ - popd
+
+ - git clone https://github.com/gatecat/nextpnr-xilinx.git nextpnr-xilinx
+ - pushd nextpnr-xilinx
+ - git checkout 565588a69ea95a52f7c7592f4ed81d9bef6cfb60
+ - git submodule update --init --recursive
+ - cmake -DARCH=xilinx -DBUILD_GUI=OFF -DCMAKE_INSTALL_PREFIX=/usr/local/nextpnr-xilinx .
+ - make -j$(nproc)
+ - make install
+ - ln -s xc7a100tcsg324-1 xilinx/external/prjxray-db/artix7/xc7a100t
+ - python3 xilinx/python/bbaexport.py --device xc7a100tcsg324-1 --bba xilinx/xc7a100t.bba
+ - ./bbasm --l xilinx/xc7a100t.bba xilinx/xc7a100t.bin
+ - install -d -m 0755 /usr/local/nextpnr-xilinx/share/xilinx
+ - install -m 0755 xilinx/xc7a100t.bin /usr/local/nextpnr-xilinx/share/xilinx
+ - popd
+ - export PATH=/usr/local/nextpnr-xilinx/bin:$PATH
+ - export XRAY_DIR=/usr/local/nextpnr-xilinx
+
+ - python3 blinky.py
--- /dev/null
+#!/usr/bin/env python3
+import io
+import pty
+import socket
+import socketserver
+import os
+import sys
+
+SOCKET_PATH = os.environ.get('ARTY_PROG_SOCKET', '/arty-prog-socket')
+LAST_BIT_FILE = "last.bit"
+CHUNK_SIZE_FIELD_SIZE = 4
+MAX_CHUNK_SIZE = 0x10 ** CHUNK_SIZE_FIELD_SIZE
+
+
+class InvalidSize(IOError):
+ pass
+
+
+def recv_chunk(sock: socket.socket):
+ size = sock.recv(CHUNK_SIZE_FIELD_SIZE)
+ # print("recv size:", size, flush=True)
+ if size == b'' or size == b'Z' * CHUNK_SIZE_FIELD_SIZE:
+ return b''
+ if len(size) != CHUNK_SIZE_FIELD_SIZE or not size.isalnum():
+ raise InvalidSize("invalid size", size)
+ try:
+ size = int(b'0x' + size, 16)
+ except ValueError:
+ raise InvalidSize("invalid size", size)
+ assert size >= 0
+ if size == 0:
+ size = MAX_CHUNK_SIZE
+ if size > MAX_CHUNK_SIZE:
+ raise InvalidSize("invalid size", size)
+ retval = b''
+ while len(retval) < size:
+ buf = sock.recv(size - len(retval))
+ # print("recv buf:", len(buf), flush=True)
+ if buf == b'':
+ raise EOFError()
+ retval += buf
+ return retval
+
+
+def send_chunk(sock: socket.socket, chunk: bytes):
+ size = len(chunk)
+ assert size <= MAX_CHUNK_SIZE
+ if size > 0:
+ if size == MAX_CHUNK_SIZE:
+ size = 0
+ size = hex(size)[2:].encode().zfill(CHUNK_SIZE_FIELD_SIZE)
+ else:
+ size = b'Z' * CHUNK_SIZE_FIELD_SIZE
+ # print("send size:", size, flush=True)
+ sock.sendall(size)
+ # print("send buf:", len(chunk), flush=True)
+ sock.sendall(chunk)
+
+
+class RequestHandler(socketserver.BaseRequestHandler):
+ request: socket.socket
+
+ def handle(self):
+ with open(LAST_BIT_FILE, 'wb') as file:
+ while True:
+ buf = recv_chunk(self.request)
+ if len(buf) == 0:
+ break
+ file.write(buf)
+
+ def read_output(fd):
+ buf = os.read(fd, 8192)
+ send_chunk(self.request, buf)
+ return buf
+ cmd_line = ['xc3sprog', '-c', 'nexys4', LAST_BIT_FILE]
+ send_chunk(self.request, f"{' '.join(cmd_line)}\n".encode())
+ status = pty.spawn(cmd_line, read_output)
+ send_chunk(self.request, b'')
+ send_chunk(self.request, str(status).encode())
+
+
+if sys.argv[1:] == ["--daemon"]:
+ try:
+ os.unlink(SOCKET_PATH)
+ except FileNotFoundError:
+ pass
+ fd = os.open("/dev/null", os.O_RDONLY)
+ os.dup2(fd, sys.stdin.fileno())
+ os.close(fd)
+ with socketserver.UnixStreamServer(SOCKET_PATH, RequestHandler) as server:
+ server.allow_reuse_address = True
+ server.serve_forever()
+else:
+ assert len(sys.argv) == 4, "invalid command line"
+ assert sys.argv[1] == '-c', "invalid command line"
+ assert sys.argv[2] == 'nexys4', "invalid command line"
+ file_name = sys.argv[3]
+ assert not file_name.startswith('-'), "invalid command line"
+ assert ':' not in file_name, "programming options not supported"
+ assert file_name != '', "invalid command line"
+ with open(file_name, 'rb') as file:
+ with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as client:
+ client.connect(SOCKET_PATH)
+ while True:
+ buf = file.read(MAX_CHUNK_SIZE)
+ if len(buf) == 0:
+ break
+ send_chunk(client, buf)
+ send_chunk(client, b'')
+ with os.fdopen(sys.stdout.fileno(), "wb", closefd=False,
+ buffering=0) as stdout:
+ while True:
+ buf = recv_chunk(client)
+ if len(buf) == 0:
+ break
+ stdout.write(buf)
+ status = recv_chunk(client)
+ if status != b'0':
+ print(f"Failed: status: {status}", file=sys.stderr)
+ exit(1)