Pins move the image for exactly one reason — a bit-banged link on a USART's own
pins has to release that USART — and the matrix said outright that they were no
axis, so the tightest configuration in the space was one nothing built. Not
subtly, either: the 1284's slot ends at flash end, so that build does not merely
exceed the size test's limit, it fails to link. pureboot_{sw,autobaud}_on_usart
{0,1} are gate points in both matrix modes now, and the exhaustive sweep carries
the pins across its whole cross product. The hand-measured table is the gate's
output: 506 B of 512 for the 1284 autobaud on USART0's pins, 504 on USART1's.
pureboot.mute drives the defect itself — an application hands over with USART0
still enabled and the loader on those pins must still answer. Reaching that
needed the runner to know an enabled USART owns its TxD, which simavr does not
model at all: it wires a USART through IRQs and never takes the pin from the
port. It also brings UCSRnB up with TXEN already set where silicon clears the
register, so the runner restores the reset value for the USART it models — the
mute must come from the application, not from power-on. The fixture stays
silent, since nothing is listening on the USART it brings up.
test_handshake.py, written where no gate could run it, is pureboot.handshake.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
74 lines
2.8 KiB
Python
74 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Hand-over with a USART left enabled on the loader's own pins.
|
|
|
|
A software or autobaud link deployed on a USART's TxD is mute if an
|
|
application hands over with that USART still enabled: TXEN keeps the USART
|
|
owning the pin, so the bit-banged transmitter's port writes go nowhere and the
|
|
loader receives and obeys while answering nothing. The link's init releases it.
|
|
|
|
The state is reached the way silicon reaches it — an application that sets up
|
|
its USART and jumps in with no reset between, so nothing clears UCSRnB for it.
|
|
The pin ownership itself is modelled by the device runner: simavr wires a
|
|
USART through IRQs alone and never takes the pin from the port, so without
|
|
that the mute could not happen here at all (test/pureboot_device.c).
|
|
|
|
Usage: pbmute.py <device_bin> <pureboot_elf> <mcu> <hz> <base_hex> <page>
|
|
<baud> <app_bin> <tool_py> <workdir> <link>
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
|
|
|
|
def fail(message):
|
|
print(f"FAIL: {message}")
|
|
sys.exit(1)
|
|
|
|
|
|
def main():
|
|
device_bin, elf, mcu, hz, base_hex, page, baud, app_bin, tool, workdir, link = sys.argv[1:]
|
|
page, baud = int(page), int(baud)
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(tool)))
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
import pbsim
|
|
import pureboot as pb
|
|
|
|
if "@" not in link:
|
|
fail(f"the link {link} names no owning USART — nothing would be under test")
|
|
|
|
os.makedirs(workdir, exist_ok=True)
|
|
dump = os.path.join(workdir, "dump.bin")
|
|
|
|
device = pbsim.Device(device_bin, elf, mcu, hz, base_hex, page, baud, dump, link=link)
|
|
try:
|
|
port = pb.Port(device.pty, baud)
|
|
loader = pb.Loader(port)
|
|
loader.connect(25)
|
|
resident = loader.info.version
|
|
|
|
# Install the fixture and let it take over. It brings up the USART
|
|
# that owns these pins and jumps straight back in.
|
|
pb.op_flash(loader, app_bin, erase=False, verify=True)
|
|
loader.run_application()
|
|
|
|
# The loader is running again with that USART enabled behind it. Only
|
|
# the release makes it audible; without it the connect times out.
|
|
loader = pb.Loader(port)
|
|
try:
|
|
loader.connect(25)
|
|
except pb.Error as error:
|
|
fail(f"the loader never answered after the hand-over — the USART still owns its TX pin ({error})")
|
|
if loader.info.version != resident:
|
|
fail(f"identity changed across the hand-over: {resident} then {loader.info.version}")
|
|
|
|
# Answering is not enough: it has to still be a working loader.
|
|
pb.verify_pages(loader, pb.plan_flash(open(app_bin, "rb").read(), loader.info))
|
|
port.close()
|
|
finally:
|
|
device.stop()
|
|
print("pbmute: a loader on a USART's own pins answers after a hand-over that left it enabled")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|