From 8fbfa79ea981d2fa943b5071f4d692836fb63e6a Mon Sep 17 00:00:00 2001 From: Alice Ziuziakowska Date: Tue, 16 Jun 2026 15:33:20 +0100 Subject: [PATCH 1/5] flash: fix clang format nit Signed-off-by: Alice Ziuziakowska --- lib/flash/flash.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/flash/flash.hh b/lib/flash/flash.hh index 8693599..0e0f9fa 100644 --- a/lib/flash/flash.hh +++ b/lib/flash/flash.hh @@ -264,7 +264,7 @@ class Generic { op = Opcode::PageProgram4b; } - auto total_size = 1 + ADDR_SIZE + data.size(); + auto total_size = 1 + ADDR_SIZE + data.size(); std::array cmd = {op}; for (size_t i = 0; i < ADDR_SIZE; ++i) { // This calculates the correct shift (24, 16, 8, 0 for 4-byte; 16, 8, 0 for 3-byte) From 79eb53dd17f08e225b64dacf5ae434f6b0725b57 Mon Sep 17 00:00:00 2001 From: Alice Ziuziakowska Date: Tue, 16 Jun 2026 14:58:55 +0100 Subject: [PATCH 2/5] app: add `flash-reset` command Signed-off-by: Alice Ziuziakowska --- app/commands.hh | 9 +++++++++ app/main.cc | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/app/commands.hh b/app/commands.hh index 7ca67b2..ad0c5ad 100644 --- a/app/commands.hh +++ b/app/commands.hh @@ -448,7 +448,16 @@ struct LoadFileElf : public Commands { if (bootstrap) { this->flash.reset(); } + return 1; + } +}; +template +struct ResetFlash : public Commands { + ResetFlash(flash::Generic f) : Commands(f) {} + + int run() override { + this->flash.reset(); return 1; } }; diff --git a/app/main.cc b/app/main.cc index 0d4f6d7..2ba919f 100644 --- a/app/main.cc +++ b/app/main.cc @@ -279,6 +279,16 @@ int main(int argc, char* argv[]) { return 0; }; + auto flash_reset_cmd = new_flash_command("flash-reset", "Reset flash."); + program.add_subparser(*flash_reset_cmd); + commands["flash-reset"] = [&]() -> int { + auto pid = program.get("--pid"); + auto spih = handle_flash_command(flash_reset_cmd, pid); + commands::ResetFlash(flash::Generic(*spih)).run(); + spih->close(); + return 0; + }; + if (argc == 1) { std::cout << program; // This prints the auto-generated help return 0; From b02173107509dff6706116dd116dc4f3e32b5c8d Mon Sep 17 00:00:00 2001 From: Alice Ziuziakowska Date: Tue, 16 Jun 2026 15:10:36 +0100 Subject: [PATCH 3/5] app: remove `bootstrap` flag from file and ELF loading Signed-off-by: Alice Ziuziakowska --- app/commands.hh | 33 +++++---------------------------- app/main.cc | 6 +++--- 2 files changed, 8 insertions(+), 31 deletions(-) diff --git a/app/commands.hh b/app/commands.hh index ad0c5ad..571a071 100644 --- a/app/commands.hh +++ b/app/commands.hh @@ -188,16 +188,10 @@ struct LoadFile : public Commands { std::size_t start_addr; std::string& filename; bool quad; - bool bootstrap; bool skip_erase; - LoadFile(flash::Generic f, std::string& filename, std::size_t addr = 0, bool bootstrap = false, + LoadFile(flash::Generic f, std::string& filename, std::size_t addr = 0, bool skip_erase = false, bool quad = false) - : Commands(f), - filename(filename), - start_addr(addr), - quad(quad), - bootstrap(bootstrap), - skip_erase(skip_erase) {} + : Commands(f), filename(filename), start_addr(addr), quad(quad), skip_erase(skip_erase) {} int run() override { if ((this->start_addr % flash::SectorSize) != 0) { @@ -227,9 +221,6 @@ struct LoadFile : public Commands { bool addr4b = this->start_addr > 0xFFFFFF; - if (!bootstrap) { - this->flash.reset(); - } if (addr4b && !this->flash.enter_4b_addr()) { std::println("Enter 4-byte address mode failed"); return 0; @@ -276,9 +267,6 @@ struct LoadFile : public Commands { this->flash.wait_not_busy(); this->flash.write_enable(false); - if (bootstrap) { - this->flash.reset(); - } return 1; } }; @@ -287,15 +275,10 @@ template struct LoadFileElf : public Commands { std::string& filename; bool quad; - bool bootstrap; bool skip_erase; - LoadFileElf(flash::Generic f, std::string& filename, bool bootstrap = false, - bool skip_erase = false, bool quad = false) - : Commands(f), - filename(filename), - quad(quad), - bootstrap(bootstrap), - skip_erase(skip_erase) {} + LoadFileElf(flash::Generic f, std::string& filename, bool skip_erase = false, + bool quad = false) + : Commands(f), filename(filename), quad(quad), skip_erase(skip_erase) {} int run() override { ELFIO::elfio reader; @@ -333,9 +316,6 @@ struct LoadFileElf : public Commands { } } - if (!bootstrap) { - this->flash.reset(); - } if (addr4b && !this->flash.enter_4b_addr()) { std::println("Enter 4-byte address mode failed"); return 0; @@ -445,9 +425,6 @@ struct LoadFileElf : public Commands { this->flash.wait_not_busy(); this->flash.write_enable(false); - if (bootstrap) { - this->flash.reset(); - } return 1; } }; diff --git a/app/main.cc b/app/main.cc index 2ba919f..283f1b6 100644 --- a/app/main.cc +++ b/app/main.cc @@ -185,7 +185,7 @@ int main(int argc, char* argv[]) { auto addr = load_file_cmd->get("--addr"); auto quad = load_file_cmd->get("--quad"); auto spih = handle_flash_command(load_file_cmd, pid); - commands::LoadFile(flash::Generic(*spih), filename, addr, false, quad).run(); + commands::LoadFile(flash::Generic(*spih), filename, addr, quad).run(); spih->close(); return 0; @@ -235,7 +235,7 @@ int main(int argc, char* argv[]) { auto quad = bootstrap_cmd->get("--quad"); auto skip_erase = bootstrap_cmd->get("--skip-erase"); auto spih = handle_flash_command(bootstrap_cmd, pid); - commands::LoadFile(flash::Generic(*spih), filename, addr, true, skip_erase, quad).run(); + commands::LoadFile(flash::Generic(*spih), filename, addr, skip_erase, quad).run(); spih->close(); return 0; @@ -259,7 +259,7 @@ int main(int argc, char* argv[]) { auto quad = bootstrap_elf_cmd->get("--quad"); auto skip_erase = bootstrap_elf_cmd->get("--skip-erase"); auto spih = handle_flash_command(bootstrap_elf_cmd, pid); - commands::LoadFileElf(flash::Generic(*spih), filename, true, skip_erase, quad).run(); + commands::LoadFileElf(flash::Generic(*spih), filename, skip_erase, quad).run(); spih->close(); return 0; From 5d408351429775d469378622c92e79842d73f2e2 Mon Sep 17 00:00:00 2001 From: Alice Ziuziakowska Date: Tue, 16 Jun 2026 15:22:42 +0100 Subject: [PATCH 4/5] app: replace bootstrap commands with `load-file`, `load-elf` The bootstrap and load-file commands are now identical, so replace the latter. Rename bootstrap-elf to load-elf to match. Change help strings and remove default value on load address. Signed-off-by: Alice Ziuziakowska --- app/main.cc | 74 +++++++++++++++++------------------------------------ 1 file changed, 23 insertions(+), 51 deletions(-) diff --git a/app/main.cc b/app/main.cc index 283f1b6..8a9ca93 100644 --- a/app/main.cc +++ b/app/main.cc @@ -170,27 +170,6 @@ int main(int argc, char* argv[]) { return 0; }; - auto load_file_cmd = - new_flash_command("load-file", "Write the content of a file to the address and verify it."); - load_file_cmd->add_argument("filename").help("The file path."); - load_file_cmd->add_argument("--addr") - .help("The address to be loaded") - .default_value(std::size_t{0}) - .scan<'x', std::size_t>(); - load_file_cmd->add_argument("--quad").help("Use qSPI").default_value(false).implicit_value(true); - program.add_subparser(*load_file_cmd); - commands["load-file"] = [&]() -> int { - auto pid = program.get("--pid"); - auto filename = load_file_cmd->get("filename"); - auto addr = load_file_cmd->get("--addr"); - auto quad = load_file_cmd->get("--quad"); - auto spih = handle_flash_command(load_file_cmd, pid); - commands::LoadFile(flash::Generic(*spih), filename, addr, quad).run(); - - spih->close(); - return 0; - }; - auto verify_file_cmd = new_flash_command( "verify-file", "Compare the hash of a file to the hash of the flash content at the address."); verify_file_cmd->add_argument("filename").help("The file path."); @@ -215,50 +194,43 @@ int main(int argc, char* argv[]) { return 0; }; - auto bootstrap_cmd = new_flash_command( - "bootstrap", "Write the content of a binary file to an address and reset the target."); - bootstrap_cmd->add_argument("filename").help("The file path."); - bootstrap_cmd->add_argument("--addr") - .help("The address to be loaded") - .default_value(std::size_t{0}) - .scan<'x', std::size_t>(); - bootstrap_cmd->add_argument("--quad").help("Use qSPI").default_value(false).implicit_value(true); - bootstrap_cmd->add_argument("--skip-erase") + auto load_file_cmd = new_flash_command( + "load-file", "Write the content of a binary file to a destination address."); + load_file_cmd->add_argument("filename").help("The file path."); + load_file_cmd->add_argument("--addr").help("The address to be loaded").scan<'x', std::size_t>(); + load_file_cmd->add_argument("--quad").help("Use qSPI").default_value(false).implicit_value(true); + load_file_cmd->add_argument("--skip-erase") .help("Don't issue erase commands") .default_value(false) .implicit_value(true); - program.add_subparser(*bootstrap_cmd); - commands["bootstrap"] = [&]() -> int { + program.add_subparser(*load_file_cmd); + commands["load-file"] = [&]() -> int { auto pid = program.get("--pid"); - auto filename = bootstrap_cmd->get("filename"); - auto addr = bootstrap_cmd->get("--addr"); - auto quad = bootstrap_cmd->get("--quad"); - auto skip_erase = bootstrap_cmd->get("--skip-erase"); - auto spih = handle_flash_command(bootstrap_cmd, pid); + auto filename = load_file_cmd->get("filename"); + auto addr = load_file_cmd->get("--addr"); + auto quad = load_file_cmd->get("--quad"); + auto skip_erase = load_file_cmd->get("--skip-erase"); + auto spih = handle_flash_command(load_file_cmd, pid); commands::LoadFile(flash::Generic(*spih), filename, addr, skip_erase, quad).run(); spih->close(); return 0; }; - auto bootstrap_elf_cmd = new_flash_command( - "bootstrap-elf", "Write the loadable contents of an ELF file and reset the target."); - bootstrap_elf_cmd->add_argument("filename").help("The file path."); - bootstrap_elf_cmd->add_argument("--quad") - .help("Use qSPI") - .default_value(false) - .implicit_value(true); - bootstrap_elf_cmd->add_argument("--skip-erase") + auto load_elf_cmd = new_flash_command("load-elf", "Write the loadable contents of an ELF file."); + load_elf_cmd->add_argument("filename").help("The file path."); + load_elf_cmd->add_argument("--quad").help("Use qSPI").default_value(false).implicit_value(true); + load_elf_cmd->add_argument("--skip-erase") .help("Don't issue erase commands") .default_value(false) .implicit_value(true); - program.add_subparser(*bootstrap_elf_cmd); - commands["bootstrap-elf"] = [&]() -> int { + program.add_subparser(*load_elf_cmd); + commands["load-elf"] = [&]() -> int { auto pid = program.get("--pid"); - auto filename = bootstrap_elf_cmd->get("filename"); - auto quad = bootstrap_elf_cmd->get("--quad"); - auto skip_erase = bootstrap_elf_cmd->get("--skip-erase"); - auto spih = handle_flash_command(bootstrap_elf_cmd, pid); + auto filename = load_elf_cmd->get("filename"); + auto quad = load_elf_cmd->get("--quad"); + auto skip_erase = load_elf_cmd->get("--skip-erase"); + auto spih = handle_flash_command(load_elf_cmd, pid); commands::LoadFileElf(flash::Generic(*spih), filename, skip_erase, quad).run(); spih->close(); From 8af9f81a0aee7f4685cd0fb8520a309e67e2ade9 Mon Sep 17 00:00:00 2001 From: Alice Ziuziakowska Date: Tue, 16 Jun 2026 15:34:33 +0100 Subject: [PATCH 5/5] nix: bump to version 0.5.0 Signed-off-by: Alice Ziuziakowska --- nix/ftditool.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/ftditool.nix b/nix/ftditool.nix index facadee..072cf04 100644 --- a/nix/ftditool.nix +++ b/nix/ftditool.nix @@ -19,7 +19,7 @@ }: stdenv.mkDerivation rec { pname = "ftditool"; - version = "0.4.0"; + version = "0.5.0"; src = ../.; nativeBuildInputs = [