Skip to content
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
14 changes: 9 additions & 5 deletions psh/test.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
test:
targets:
#TODO: remove when sparcv8leon3-gr716-mimas target will stop being experimental
include: [sparcv8leon3-gr716-mimas]

tests:
- name: gibber
harness: test-gibber.py
Expand All @@ -13,7 +17,7 @@ test:
- name: pshlogin
harness: test-pshlogin.py
targets:
exclude: [armv7m7-imxrt106x-evk, armv7m7-imxrt117x-evk, armv7m4-stm32l4x6-nucleo]
exclude: [armv7m7-imxrt106x-evk, armv7m7-imxrt117x-evk, armv7m4-stm32l4x6-nucleo, sparcv8leon3-gr716-mimas]

- name: echo
harness: test-echo.py
Expand All @@ -36,7 +40,7 @@ test:
- name: cat-shells
harness: test-cat-shells.py
targets:
exclude: [armv7m7-imxrt106x-evk, armv7m7-imxrt117x-evk, armv7m4-stm32l4x6-nucleo]
exclude: [armv7m7-imxrt106x-evk, armv7m7-imxrt117x-evk, armv7m4-stm32l4x6-nucleo, sparcv8leon3-gr716-mimas]

- name: kill
harness: test-kill.py
Expand All @@ -50,21 +54,21 @@ test:
- name: touch-rootfs
harness: test-touch-rootfs.py
targets:
exclude: [armv7m7-imxrt106x-evk, armv7m7-imxrt117x-evk, armv7m4-stm32l4x6-nucleo]
exclude: [armv7m7-imxrt106x-evk, armv7m7-imxrt117x-evk, armv7m4-stm32l4x6-nucleo, sparcv8leon3-gr716-mimas]

- name: ls
harness: test-ls.py

- name: ls-rootfs
harness: test-ls-rootfs.py
targets:
exclude: [armv7m7-imxrt106x-evk, armv7m7-imxrt117x-evk, armv7m4-stm32l4x6-nucleo]
exclude: [armv7m7-imxrt106x-evk, armv7m7-imxrt117x-evk, armv7m4-stm32l4x6-nucleo, sparcv8leon3-gr716-mimas]

- name: runfile
harness: test-runfile.py
targets:
# runfile applet is not intended for non-rootfs targets
exclude: [armv7m7-imxrt106x-evk, armv7m7-imxrt117x-evk, armv7m4-stm32l4x6-nucleo]
exclude: [armv7m7-imxrt106x-evk, armv7m7-imxrt117x-evk, armv7m4-stm32l4x6-nucleo, sparcv8leon3-gr716-mimas]

- name: history
harness: test-history.py
Expand Down
14 changes: 10 additions & 4 deletions runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
STM32L4x6Target,
Zynq7000ZedboardTarget,
IMX6ULLEvkTarget,
MimasSparcV8EvkTarget,
)
from trunner.ctx import TestContext
from trunner.target.base import TargetBase
Expand Down Expand Up @@ -109,9 +110,11 @@ def parse_args(targets: Dict[str, Type[TargetBase]], hosts: Dict[str, Type[Host]
"--output",
action="store",
const="report.xml",
nargs='?',
help=("Write machine-readable test results as csv and xml file. "
"When no value is provided uses %(const)s"),
nargs="?",
help=(
"Write machine-readable test results as csv and xml file. "
"When no value is provided uses %(const)s"
),
)

parser.add_argument(
Expand Down Expand Up @@ -218,7 +221,9 @@ def __call__(self, parser, namespace, values, option_string=None):
return args


def resolve_targets_and_hosts() -> Tuple[Dict[str, Type[TargetBase]], Dict[str, Type[Host]]]:
def resolve_targets_and_hosts() -> (
Tuple[Dict[str, Type[TargetBase]], Dict[str, Type[Host]]]
):
"""
Returns a tuple of dictionaries that map host and target names to an equivalent class.

Expand All @@ -236,6 +241,7 @@ def resolve_targets_and_hosts() -> Tuple[Dict[str, Type[TargetBase]], Dict[str,
IMXRT117xEvkTarget,
Zynq7000ZedboardTarget,
IMX6ULLEvkTarget,
MimasSparcV8EvkTarget,
]

hosts: List[Type[Host]] = [EmulatorHost, RpiHost]
Expand Down
2 changes: 2 additions & 0 deletions trunner/target/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from .armv7m4 import STM32L4x6Target
from .armv7a7 import IMX6ULLEvkTarget
from .armv7a9 import Zynq7000ZedboardTarget
from .sparcv8 import MimasSparcV8EvkTarget
from .emulated import (
IA32GenericQemuTarget,
RISCV64GenericQemuTarget,
Expand All @@ -23,4 +24,5 @@
"TargetBase",
"find_port",
"IMX6ULLEvkTarget",
"MimasSparcV8EvkTarget",
]
139 changes: 139 additions & 0 deletions trunner/target/sparcv8.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import subprocess
import time
from typing import Callable, Optional

import pexpect
import pexpect.fdpexpect
import usb.core

from trunner.dut import SerialDut
from trunner.harness import (
HarnessBuilder,
PloPhoenixdAppLoader,
PloHarness,
Rebooter,
ShellHarness,
FlashError,
TestStartRunningHarness,
)
from trunner.host import Host
from trunner.tools import Phoenixd
from trunner.types import TestResult, TestOptions
from .base import TargetBase, find_port


class GR716Rebooter(Rebooter):
def _reboot_soft(self):
self._reboot_hard()
# TODO implement soft restarts after implementing flash memory
# self.host.set_reset(1)
# time.sleep(0.5)
# self.dut.clear_buffer()
# self.host.set_reset(0)
# time.sleep(0.25)

def _reboot_hard(self):
# Make sure that that reset pin is in low state
self.host.set_reset(0)
self.host.set_power(False)
time.sleep(0.75)
self.host.set_power(True)
time.sleep(0.5)


class GR716Target(TargetBase):
def __init__(self, host: Host, port: str, baudrate: int = 115200):
self.dut = SerialDut(port, baudrate, encoding="utf-8", codec_errors="ignore")
self.rebooter = GR716Rebooter(host, self.dut)
super().__init__()

@classmethod
def from_context(cls, ctx):
return cls(ctx.host, ctx.port, ctx.baudrate)

def MimasCustomUpload(self, boot_dir: str, image: str, vid: hex, pid: hex):
# using usb.core to fully reset device responsible for phoenixd
usb.core.find(idVendor=vid, idProduct=pid).reset()

self.rebooter()

# parsing passed hex values as string for find_port
port = str(hex(vid))[2:] + ":" + str(hex(pid))[2:]

subprocess.Popen(
f"phoenixd -p {find_port(port)} -b 115200 -s {str(boot_dir)}/.",
shell=True,
cwd=".",
start_new_session=True,
stdin=subprocess.PIPE,
stdout=subprocess.DEVNULL,
stderr=subprocess.STDOUT,
text=True,
)

while True:
inChar = self.dut.read()
inChar += inChar

if "Bootloader" in inChar:
with open(f"{boot_dir}/{image}", "rb") as fd:
filebuff = fd.read()
time.sleep(1)
self.dut.serial.write(filebuff)

try:
self.dut.expect_exact("(psh)%", timeout=80)
fd.close()
break

except pexpect.TIMEOUT as e:
fd.close()
raise FlashError(
msg=str(e),
output=e.stdout.decode("ascii") if e.stdout else None,
) from e
Comment on lines +74 to +94
Copy link
Member

@mateusz-bloch mateusz-bloch Mar 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can simplify this by knowing that dut is a wrapper around pexpect. For example, by expecting the appearance of the Bootloader instead of catching each character.

Example of simplified code that should work:

        with open(f"{boot_dir}/{image}", "rb") as fd:
            try:
                self.dut.expect_exact("Bootloader", timeout=60)
                time.sleep(1)
                self.dut.serial.write(fd.read())
                self.dut.expect_exact("(psh)%", timeout=80)
            except pexpect.TIMEOUT as e:
                raise FlashError(
                    msg="Timeout waiting for boatloader prompt or psh prompt.",
                    output=e.stdout.decode("ascii") if e.stdout else None,
                ) from e

Remember also that when you use a context manager in Python, it automatically handles the closing of resources opened within it, so you don't need to manually close them with fd.close()


def flash_dut(self):
self.MimasCustomUpload(
boot_dir=self.boot_dir(), image="plo.img", vid=0x067B, pid=0x2303
)

def build_test(self, test: TestOptions) -> Callable[[TestResult], TestResult]:
builder = HarnessBuilder()

if test.should_reboot:
# TODO implement soft restarts after implementing flash memory
self.dut.send("\r\n")

if test.bootloader is not None:
app_loader = None

if test.bootloader.apps:
app_loader = PloPhoenixdAppLoader(
dut=self.dut,
apps=test.bootloader.apps,
phoenixd=Phoenixd(directory=self.root_dir() / test.shell.path),
)

builder.add(PloHarness(self.dut, app_loader=app_loader))

if test.shell is not None:
builder.add(ShellHarness(self.dut, self.shell_prompt, test.shell.cmd))
else:
builder.add(TestStartRunningHarness())

builder.add(test.harness)

return builder.get_harness()


class MimasSparcV8EvkTarget(GR716Target):
Copy link
Member

@mateusz-bloch mateusz-bloch Mar 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, if I understand correctly, the target is not Sparcv8Leon3, but GR716, which is based on the Sparcv8Leon3 architecture. So, shouldn't it be the other way around, something like GR716-mimas-EvkTarget(SparcV8Target)

name = "sparcv8leon3-gr716-mimas"
rootfs = False
experimental = True

def __init__(self, host: Host, port: Optional[str] = None, baudrate: int = 115200):
if not port:
port = find_port("10c4:ea60") # vid:pid for communication (PLO usb/uart)

super().__init__(host, port, baudrate)