Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] LiteX Arty #15

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion hwci/boards/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@
# Copyright Tock Contributors 2024.

from .tockloader_board import TockloaderBoard
from .nrf52dk import Nrf52dk
from .mock_board import MockBoard
118 changes: 118 additions & 0 deletions hwci/boards/imix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Licensed under the Apache License, Version 2.0 or the MIT License.
# SPDX-License-Identifier: Apache-2.0 OR MIT
# Copyright Tock Contributors 2024.

import time
import os
import subprocess
import logging
from contextlib import contextmanager
import serial.tools.list_ports
from boards.tockloader_board import TockloaderBoard
from utils.serial_port import SerialPort
from gpio.gpio import GPIO
import yaml
import os
import traceback

class Imix(TockloaderBoard):
def __init__(self):
super().__init__()
self.arch = "cortex-m4"
self.kernel_path = os.path.join(
self.base_dir, "repos/tock")
self.kernel_board_path = os.path.join(
self.kernel_path, "boards/imix")
self.uart_port = self.get_uart_port()
self.uart_baudrate = self.get_uart_baudrate()
self.board = "imix"
self.program_method = "serial_bootloader"
self.serial = self.get_serial_port()
self.gpio = self.get_gpio_interface()
self.open_serial_during_flash = False
self.app_sha256_credential = True

def get_uart_port(self):
logging.info("Getting list of serial ports")
ports = list(serial.tools.list_ports.comports())
for port in ports:
if "imix IoT Module" in port.description:
logging.info(f"Found imix IoT programming port: {port.device}")
return port.device
if ports:
logging.info(f"Automatically selected port: {ports[0].device}")
return ports[0].device
else:
logging.error("No serial ports found")
raise Exception("No serial ports found")

def get_uart_baudrate(self):
return 115200 # Default baudrate for the board

def get_serial_port(self):
logging.info(
f"Using serial port: {self.uart_port} at baudrate {self.uart_baudrate}"
)
return SerialPort(self.uart_port, self.uart_baudrate, open_rts=False, open_dtr=True)

def get_gpio_interface(self):
return None

def cleanup(self):
if self.gpio:
for interface in self.gpio.gpio_interfaces.values():
interface.cleanup()
if self.serial:
self.serial.close()

def flash_kernel(self):
logging.info("Flashing the Tock OS kernel")
if not os.path.exists(self.kernel_path):
logging.error(f"Tock directory {self.kernel_path} not found")
raise FileNotFoundError(f"Tock directory {self.kernel_path} not found")

# Run make program from the board directory (this uses the Tock bootloader)
subprocess.run(
["make", "program"], cwd=self.kernel_board_path, check=True
)

def erase_board(self):
logging.info("Erasing the board")
# We erase all apps, but don't erase the kernel. Is there a simple way
# that we can prevent the installed kernel from starting (by
# overwriting its reset vector?)
subprocess.run(["tockloader", "erase-apps"], check=True)

def reset(self):
if self.serial.is_open():
logging.info("Performing a target reset by toggling RTS")
self.serial.set_rts(True)
time.sleep(0.1)
self.serial.set_rts(False)
else:
logging.info("Performing a target reset by reading address 0")
subprocess.run(["tockloader", "read", "0x0", "1"], check=True)

# The flash_app method is inherited from TockloaderBoard

@contextmanager
def change_directory(self, new_dir):
previous_dir = os.getcwd()
os.chdir(new_dir)
logging.info(f"Changed directory to: {os.getcwd()}")
try:
yield
finally:
os.chdir(previous_dir)
logging.info(f"Reverted to directory: {os.getcwd()}")


def load_target_spec():
# Assume the target spec file is in a fixed location
target_spec_path = os.path.join(os.getcwd(), "target_spec_imix.yaml")
with open(target_spec_path, "r") as f:
target_spec = yaml.safe_load(f)
return target_spec


board = Imix()
143 changes: 143 additions & 0 deletions hwci/boards/litex_arty.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# Licensed under the Apache License, Version 2.0 or the MIT License.
# SPDX-License-Identifier: Apache-2.0 OR MIT
# Copyright Tock Contributors 2024.

import time
import os
import subprocess
import logging
from contextlib import contextmanager
import serial.tools.list_ports
from boards.tockloader_board import TockloaderBoard
from utils.serial_port import SerialPort
from gpio.gpio import GPIO
import yaml
import os
import traceback

class LiteXArty(TockloaderBoard):
def __init__(self):
super().__init__()
self.arch = "rv32imc"
self.tock_targets = None
self.kernel_path = os.path.join(
self.base_dir, "repos/tock")
self.kernel_board_path = os.path.join(
self.kernel_path, "boards/litex/arty")
self.uart_port = self.get_uart_port()
self.uart_baudrate = self.get_uart_baudrate()
self.board = "litex_arty"
self.program_method = "none"
self.program_args = ["--flash-file=/srv/tftp/boot.bin"]
self.serial = self.get_serial_port()
self.gpio = self.get_gpio_interface()
self.open_serial_during_flash = True
self.app_sha256_credential = False

def get_uart_port(self):
logging.info("Getting list of serial ports")
ports = list(serial.tools.list_ports.comports())
for port in ports:
if "Digilent USB Device" in port.description:
logging.info(f"Found LiteX Arty UART: {port.device}")
return port.device
if ports:
logging.info(f"Automatically selected port: {ports[0].device}")
return ports[0].device
else:
logging.error("No serial ports found")
raise Exception("No serial ports found")

def get_uart_baudrate(self):
return 1000000 # Default baudrate for the board

def get_serial_port(self):
logging.info(
f"Using serial port: {self.uart_port} at baudrate {self.uart_baudrate}"
)
return SerialPort(self.uart_port, self.uart_baudrate, open_rts=False, open_dtr=True)

def get_gpio_interface(self):
return None

def cleanup(self):
if self.gpio:
for interface in self.gpio.gpio_interfaces.values():
interface.cleanup()
if self.serial:
self.serial.close()

def flash_kernel(self):
logging.info("Flashing the Tock OS kernel")
if not os.path.exists(self.kernel_path):
logging.error(f"Tock directory {self.kernel_path} not found")
raise FileNotFoundError(f"Tock directory {self.kernel_path} not found")

# Run make program from the board directory
subprocess.run(
["make"], cwd=self.kernel_board_path, check=True
)
# Then, flash this kernel into the board's flash file:
subprocess.run(
[
"tockloader",
"flash",
"--board=litex_arty",
"--flash-file=/srv/tftp/boot.bin",
"--address=0x40000000",
os.path.join(self.kernel_path, "target/riscv32imc-unknown-none-elf/release/litex_arty.bin"),
],
cwd=self.kernel_board_path,
check=True,
)
# Finally, reset the board:


def erase_board(self):
logging.info("Erasing the board")
subprocess.run(
[
"truncate",
"-s0",
"/srv/tftp/boot.bin",
],
check=True,
)
self.reset()

def reset(self):
if self.serial.is_open():
self.serial.close()
time.sleep(0.1)
self.serial.open()
else:
self.serial.open()
self.serial.close()

def wait_boot(self):
logging.info("Waiting 10sec for target to boot")
time.sleep(15)

# The flash_app method is inherited from TockloaderBoard

@contextmanager
def change_directory(self, new_dir):
previous_dir = os.getcwd()
os.chdir(new_dir)
logging.info(f"Changed directory to: {os.getcwd()}")
try:
yield
finally:
os.chdir(previous_dir)
logging.info(f"Reverted to directory: {os.getcwd()}")


def load_target_spec():
# Assume the target spec file is in a fixed location
target_spec_path = os.path.join(os.getcwd(), "target_spec_imix.yaml")
with open(target_spec_path, "r") as f:
target_spec = yaml.safe_load(f)
return target_spec


board = LiteXArty()
3 changes: 2 additions & 1 deletion hwci/boards/nrf52dk.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@ def __init__(self):
self.kernel_path, "boards/nordic/nrf52840dk")
self.uart_port = self.get_uart_port()
self.uart_baudrate = self.get_uart_baudrate()
self.program_method = "openocd"
self.openocd_board = "nrf52dk"
self.board = "nrf52dk"
self.serial = self.get_serial_port()
self.gpio = self.get_gpio_interface()

def get_uart_port(self):
logging.info("Getting list of serial ports")
logging.info("Getting list of serial ports!")
ports = list(serial.tools.list_ports.comports())
for port in ports:
if "J-Link" in port.description:
Expand Down
46 changes: 37 additions & 9 deletions hwci/boards/tockloader_board.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ def __init__(self):
super().__init__()
self.board = None # Should be set in subclass
self.arch = None # Should be set in subclass
self.tock_targets = None # Optional
self.base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
self.program_method = "serial_bootloader"
self.program_args = []
self.app_sha256_credential = False

def flash_app(self, app):
if type(app) == str:
Expand All @@ -38,36 +42,57 @@ def flash_app(self, app):
logging.error(f"App directory {app_dir} not found")
raise FileNotFoundError(f"App directory {app_dir} not found")


make_args = [
"make",
"-j",
] + (
[f"TOCK_TARGETS={self.tock_targets}"]
if self.tock_targets is not None else []
)
# if self.app_sha256_credential:
# make_args.append("ELF2TAB_ARGS=\"--sha256\"")

# Build the app using absolute paths
logging.info(f"Building app: {app_name}")
if app_name != "lua-hello":
subprocess.run(
["make", f"TOCK_TARGETS={self.arch}"], cwd=app_dir, check=True
)
subprocess.run(make_args, cwd=app_dir, check=True)
else:
# if the app is lua-hello, we need to build the libtock-c submodule first so we need to change directory
# into the libtock-c directory so it knows we are in a git repostiory
self.change_directory(libtock_c_dir)
subprocess.run(
["make", f"TOCK_TARGETS={self.arch}"], cwd=app_dir, check=True
)
subprocess.run(make_args, cwd=app_dir, check=True)

tab_path = os.path.join(app_dir, tab_file)
if not os.path.exists(tab_path):
logging.error(f"Tab file {tab_path} not found")
raise FileNotFoundError(f"Tab file {tab_path} not found")

if self.program_method == "serial_bootloader":
program_method_arg = "--serial"
elif self.program_method == "jlink":
program_method_arg = "--jlink"
elif self.program_method == "openocd":
program_method_arg = "--openocd"
elif self.program_method == "none":
program_method_arg = None
else:
raise NotImplemented(f"Unknown program method: {self.program_method}")

logging.info(f"Installing app: {app_name}")
subprocess.run(
[
"tockloader",
"install",
"--board",
self.board,
"--openocd",
tab_path,
],
]
+ ([program_method_arg] if program_method_arg is not None else [])
+ self.program_args
+ [tab_path],
check=True,
)
self.reset()

def get_uart_port(self):
raise NotImplementedError
Expand All @@ -78,6 +103,9 @@ def get_uart_baudrate(self):
def erase_board(self):
raise NotImplementedError

def wait_boot(self):
pass

def reset(self):
raise NotImplementedError

Expand Down
3 changes: 2 additions & 1 deletion hwci/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ sudo DEBIAN_FRONTEND=noninteractive apt install -y \
git cargo openocd python3 python3-pip python3-serial \
python3-pexpect gcc-arm-none-eabi libnewlib-arm-none-eabi \
pkg-config libudev-dev cmake libusb-1.0-0-dev udev make \
gdb-multiarch gcc-arm-none-eabi build-essential jq || true
gdb-multiarch gcc-arm-none-eabi build-essential jq \
gcc-riscv64-unknown-elf || true

# If we don't have any of the tock or libtock-c repos checked out, clone them
# here. We never want to do this for CI, as that'll want to check out specific
Expand Down
3 changes: 3 additions & 0 deletions hwci/target_spec_imix.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
model: imix
serial_number: 0xfoobar
pin_mappings:
Loading