From 1d25d54bb194fa57aa8f51597d4ac7bca99e71bc Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Tue, 12 Nov 2024 20:37:02 -0600 Subject: [PATCH] ftdi_transfer: move maple code to separate ftdi_maple source file --- example/serial_transfer.cpp | 15 +- tools/Makefile | 7 +- tools/ftdi_maple.cpp | 480 +++++++++++++++++++++++++++++++++++ tools/ftdi_maple.hpp | 3 + tools/ftdi_transfer.cpp | 490 +----------------------------------- tools/ftdi_transfer.hpp | 10 + tools/ftdi_transfer.sh | 4 +- 7 files changed, 514 insertions(+), 495 deletions(-) create mode 100644 tools/ftdi_maple.cpp create mode 100644 tools/ftdi_maple.hpp create mode 100644 tools/ftdi_transfer.hpp diff --git a/example/serial_transfer.cpp b/example/serial_transfer.cpp index 0c9103c..406d739 100644 --- a/example/serial_transfer.cpp +++ b/example/serial_transfer.cpp @@ -33,8 +33,8 @@ inline void copy(T * dst, const T * src, const int32_t n) noexcept static uint8_t * framebuffer[2]; static char textbuffer[2][4 * 8]; -static uint32_t send_buf[1024 / 4] __attribute__((aligned(32))); -static uint32_t recv_buf[1024 / 4] __attribute__((aligned(32))); +static uint8_t send_buf[1024] __attribute__((aligned(32))); +static uint8_t recv_buf[1024] __attribute__((aligned(32))); struct serial_error_counter { uint32_t brk; @@ -200,15 +200,8 @@ void send_device_request() void send_raw(struct serial_load::maple_poll_state& state) { - for (int i = 0; i < 1024; i++) { - ((uint8_t*)&__recv_buf)[i] = 0xee; - } - maple::dma_start(&__send_buf, state.send_length, - &__recv_buf, state.recv_length); - /* - maple::dma_start((uint32_t*)0xac000020, state.send_length, - (uint32_t*)0xac002020, state.recv_length); - */ + maple::dma_start(reinterpret_cast(&__send_buf), state.send_length, + reinterpret_cast(&__recv_buf), state.recv_length); } void handle_maple(struct serial_load::maple_poll_state& state) diff --git a/tools/Makefile b/tools/Makefile index cf8f5ee..52c8cea 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -24,7 +24,12 @@ ttf_%: ttf_%.o ftdi_%.o: ftdi_%.cpp $(CXX) $(CFLAGS) $(CXXFLAGS) $(FTDI_CFLAGS) -c $< -o $@ -ftdi_%: ftdi_%.o crc32.o +FTDI_OBJ = \ + ftdi_transfer.o \ + ftdi_maple.o \ + crc32.o + +ftdi_transfer: $(FTDI_OBJ) $(CXX) $^ -o $@ $(FTDI_LDFLAGS) ttf_outline: ttf_outline.o 2d_pack.o diff --git a/tools/ftdi_maple.cpp b/tools/ftdi_maple.cpp new file mode 100644 index 0000000..f920d30 --- /dev/null +++ b/tools/ftdi_maple.cpp @@ -0,0 +1,480 @@ +#include +#include +#include + +#include "maple/maple_bus_bits.hpp" +#include "maple/maple.hpp" +#include "maple/maple_host_command_writer.hpp" +#include "maple/maple_bus_commands.hpp" +#include "maple/maple_port.hpp" +#include "maple/maple_bus_ft1.hpp" + +#include "ftdi_transfer.hpp" +#include "ftdi_maple.hpp" + +constexpr uint32_t base_address = 0x0c004020; +constexpr uint32_t maple_buffer_size = 16384; + +struct storage_fd { + uint32_t fd; + + uint32_t partitions() { + return ((fd >> 24) & 0xff) + 1; + } + uint32_t bytes_per_block() { + return (((fd >> 16) & 0xff) + 1) * 32; + } + uint32_t write_accesses() { + return (fd >> 12) & 0xf; + } + uint32_t read_accesses() { + return (fd >> 8) & 0xf; + } + + uint32_t bytes_per_read_access() + { + // divide rounding up + return (bytes_per_block() + (read_accesses() - 1)) / read_accesses(); + } + + uint32_t bytes_per_write_access() + { + // divide rounding up + return (bytes_per_block() + (write_accesses() - 1)) / write_accesses(); + } +}; + +constexpr int count_left_set_bits(uint32_t n, int stop_bit) +{ + int bit_ix = 31; + int count = 0; + while (bit_ix != stop_bit) { + if (n & (1 << 31)) { + count += 1; + } + n <<= 1; + bit_ix -= 1; + } + + return count; +} +static_assert(count_left_set_bits(0xe, 1) == 2); +static_assert(count_left_set_bits(0x2, 1) == 0); + +consteval int count_trailing_zeros(uint32_t n) +{ + int count = 0; + for (int i = 0; i < 32; i++) { + if ((n & 1) != 0) + break; + count += 1; + n >>= 1; + } + return count; +} +static_assert(count_trailing_zeros(0x80) == 7); +static_assert(count_trailing_zeros(0x2) == 1); + +void print_storage_function_definition(const uint32_t fd) +{ + int partitions = ((fd >> 24) & 0xff) + 1; + int bytes_per_block = (((fd >> 16) & 0xff) + 1) * 32; + int write_accesses = (fd >> 12) & 0xf; + int read_accesses = (fd >> 8) & 0xf; + + fprintf(stderr, " storage function definition:\n"); + fprintf(stderr, " partitions: %d\n", partitions); + fprintf(stderr, " bytes_per_block: %d\n", bytes_per_block); + fprintf(stderr, " write_accesses: %d\n", write_accesses); + fprintf(stderr, " read_accesses: %d\n", read_accesses); +} + +template +static inline T be_bswap(const T n) +{ + if constexpr (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + return n; + else + return std::byteswap(n); +} + +void print_device_id(struct maple::device_id& device_id) +{ + fprintf(stderr, " ft: %08x\n", be_bswap(device_id.ft)); + fprintf(stderr, " fd[0]: %08x\n", be_bswap(device_id.fd[0])); + fprintf(stderr, " fd[1]: %08x\n", be_bswap(device_id.fd[1])); + fprintf(stderr, " fd[2]: %08x\n", be_bswap(device_id.fd[2])); +} + +void print_media_info(struct ft1::get_media_info_data_transfer::data_format& data) +{ + fprintf(stderr, " media_info:\n"); + fprintf(stderr, " total_size: %04x\n", data.total_size); + fprintf(stderr, " partition_number: %04x\n", data.partition_number); + fprintf(stderr, " system_area_block_number: %04x\n", data.system_area_block_number); + fprintf(stderr, " fat_area_block_number: %04x\n", data.fat_area_block_number); + fprintf(stderr, " number_of_fat_area_blocks: %04x\n", data.number_of_fat_area_blocks); + fprintf(stderr, " file_information_block_number: %04x\n", data.file_information_block_number); + fprintf(stderr, " number_of_file_information_blocks: %04x\n", data.number_of_file_information_blocks); + fprintf(stderr, " volume_icon: %04x\n", data.volume_icon); + fprintf(stderr, " save_area_block_number: %04x\n", data.save_area_block_number); + fprintf(stderr, " number_of_save_area_blocks: %04x\n", data.number_of_save_area_blocks); + fprintf(stderr, " reserved_for_execution_file: %08x\n", data.reserved_for_execution_file); +} + + +void send_device_request_all_ports(maple::host_command_writer& writer) +{ + using command_type = maple::device_request; + using response_type = maple::device_status; + + writer.template append_command_all_ports(); +} + + +void send_extension_device_request(maple::host_command_writer& writer, uint8_t port, uint8_t lm) +{ + uint32_t host_port_select = host_instruction_port_select(port); + uint32_t destination_ap = ap_port_select(port) | ap::de::expansion_device | lm; + + using command_type = maple::device_request; + using response_type = maple::device_status; + + writer.template append_command(host_port_select, + destination_ap, + false); // end_flag +} + + +void send_get_media_info(maple::host_command_writer& writer, uint8_t port, uint8_t lm) +{ + uint32_t host_port_select = host_instruction_port_select(port); + uint32_t destination_ap = ap_port_select(port) | ap::de::expansion_device | lm; + + using command_type = maple::get_media_info; + using response_type = maple::data_transfer; + + auto [host_command, host_response] = + writer.template append_command(host_port_select, + destination_ap, + false); // end_flag + + host_command->bus_data.data_fields.function_type = be_bswap(function_type::storage); + host_command->bus_data.data_fields.pt = 0; +} + +struct block_read_response { + union responses { + struct maple::file_error::data_fields file_error; + struct maple::data_transfer::data_fields data_transfer; + }; + + using data_fields = union responses; +}; + + +void send_block_read(maple::host_command_writer& writer, uint8_t port, uint8_t lm, uint32_t recv_trailing, int partition, int phase, int block_number) +{ + uint32_t host_port_select = host_instruction_port_select(port); + uint32_t destination_ap = ap_port_select(port) | ap::de::expansion_device | lm; + + using command_type = maple::block_read; + using response_type = block_read_response; + + auto [host_command, host_response] = + writer.template append_command(host_port_select, + destination_ap, + false, // end_flag + 0, // send_trailing + recv_trailing // recv_trailing + ); + + auto& data_fields = host_command->bus_data.data_fields; + data_fields.function_type = be_bswap(function_type::storage); + data_fields.pt = partition; + data_fields.phase = phase; + data_fields.block_number = be_bswap(block_number); +} + + +void do_lm_requests(maple::host_command_writer& writer, uint8_t port, uint8_t lm, + void (* func)(maple::host_command_writer& writer, uint8_t port, uint8_t lm)) +{ + uint32_t bit = ap::lm_bus::_0; + for (int i = 0; i < 5; i++) { + if (lm & bit) { + func(writer, port, bit); + } + bit <<= 1; + } +} + +int handle_block_read_dump(struct ftdi_context * ftdi, + maple::host_command_writer& writer, + struct storage_fd& storage_fd, + FILE * dump) +{ + writer.set_end_flag(); + int res = do_maple_raw(ftdi, + writer.send_buf, writer.send_offset, + writer.recv_buf, writer.recv_offset); + if (res != 0) { + return -1; + } + + using response_type = block_read_response; + using host_response_type = maple::host_response; + const uint32_t recv_trailing = storage_fd.bytes_per_read_access(); + const uint32_t host_response_size = (sizeof (host_response_type)) + recv_trailing; + + uint8_t * recv_buf = reinterpret_cast(writer.recv_buf); + + for (uint32_t offset = 0; offset < writer.recv_offset; offset += host_response_size) { + auto host_response = reinterpret_cast(&recv_buf[offset]); + auto& bus_data = host_response->bus_data; + if (bus_data.command_code != maple::data_transfer::command_code) { + fprintf(stderr, "lm did not reply to block read: %d\n", bus_data.command_code); + auto& file_error = bus_data.data_fields.file_error; + if (bus_data.command_code == maple::file_error::command_code) { + fprintf(stderr, "function error code: %d\n", file_error.function_error_code); + } + return -1; + } + + fwrite(bus_data.data_fields.data_transfer.data.block_data, + 1, + storage_fd.bytes_per_read_access(), + dump); + } + + writer.reset(); + + return 0; +} + + +int do_maple_block_read_dump(struct ftdi_context * ftdi, + int port, + int lm, + struct storage_fd& storage_fd, + struct ft1::get_media_info_data_transfer::data_format& media_info) // copy of media_info on the stack +{ + uint8_t send_buf[maple_buffer_size]; + uint8_t recv_buf[maple_buffer_size]; + + char filename[256]; + snprintf(filename, (sizeof (filename)), "dump_p%dl%d.bin", port, ap_lm_bus_int(lm)); + + FILE * dump = fopen(filename, "wb"); + + auto writer = maple::host_command_writer(send_buf, + recv_buf); + constexpr int partition = 0; + + using response_type = maple::data_transfer; + using host_response_type = maple::host_response; + const uint32_t recv_trailing = storage_fd.bytes_per_read_access(); + const uint32_t host_response_size = (sizeof (host_response_type)) + recv_trailing; + + for (uint16_t block_number = 0; block_number < (media_info.total_size + 1); block_number++) { + for (uint32_t phase = 0; phase < storage_fd.read_accesses(); phase++) { + fprintf(stderr, "maple_block_read: block %d,%d\n", block_number, phase); + send_block_read(writer, port, lm, recv_trailing, partition, phase, block_number); + } + + if (writer.recv_offset + host_response_size > maple_buffer_size) { + int res = handle_block_read_dump(ftdi, + writer, + storage_fd, + dump); + if (res != 0) { + return -1; + } + } + } + + if (writer.send_offset != 0) { + int res = handle_block_read_dump(ftdi, + writer, + storage_fd, + dump); + if (res != 0) { + return -1; + } + } + + fclose(dump); + + return 0; +} + + +int handle_get_media_info_data_transfer_response(struct ftdi_context * ftdi, + maple::host_command_writer& writer, + struct storage_fd storage_fd[4][5]) +{ + writer.set_end_flag(); + int res = do_maple_raw(ftdi, + writer.send_buf, writer.send_offset, + writer.recv_buf, writer.recv_offset); + if (res != 0) { + return -1; + } + + const uint32_t recv_offset = writer.reset(); + + using response_type = maple::data_transfer; + using host_response_type = maple::host_response; + + for (uint32_t offset = 0; offset < recv_offset; offset += (sizeof (host_response_type))) { + auto host_response = reinterpret_cast(&writer.recv_buf[offset]); + + auto& bus_data = host_response->bus_data; + auto& data_fields = bus_data.data_fields; + auto& data = data_fields.data; + + if (bus_data.command_code != response_type::command_code) { + fprintf(stderr, " disconnected %02x %02x %02x %02x\n", + bus_data.command_code, + bus_data.destination_ap, + bus_data.source_ap, + bus_data.data_size); + continue; + } + + uint32_t port = (bus_data.source_ap & ap::port_select::bit_mask) >> 6; + uint32_t lm_bus = (bus_data.source_ap & ap::lm_bus::bit_mask) >> 0; + fprintf(stderr, "[extension] port: %d ; lm: %05b\n", port, lm_bus); + print_media_info(data); + + do_maple_block_read_dump(ftdi, + port, + lm_bus, + storage_fd[port][ap_lm_bus_int(lm_bus)], + data); + } + + return 0; +} + + +int handle_device_status_response_extension(struct ftdi_context * ftdi, + maple::host_command_writer& writer, + struct storage_fd storage_fd[4][5]) +{ + writer.set_end_flag(); + int res = do_maple_raw(ftdi, + writer.send_buf, writer.send_offset, + writer.recv_buf, writer.recv_offset); + if (res != 0) { + return -1; + } + + const uint32_t recv_offset = writer.reset(); + + using response_type = maple::device_status; + using host_response_type = maple::host_response; + for (uint32_t offset = 0; offset < recv_offset; offset += (sizeof (host_response_type))) { + auto host_response = reinterpret_cast(&writer.recv_buf[offset]); + + auto& bus_data = host_response->bus_data; + auto& data_fields = bus_data.data_fields; + + if (bus_data.command_code != response_type::command_code) { + fprintf(stderr, " disconnected %02x %02x %02x %02x\n", + bus_data.command_code, + bus_data.destination_ap, + bus_data.source_ap, + bus_data.data_size); + continue; + } + + uint32_t port = (bus_data.source_ap & ap::port_select::bit_mask) >> 6; + uint32_t lm_bus = (bus_data.source_ap & ap::lm_bus::bit_mask) >> 0; + fprintf(stderr, "[extension] port: %d ; lm: %05b\n", port, lm_bus); + print_device_id(data_fields.device_id); + + uint32_t ft = be_bswap(data_fields.device_id.ft); + if (ft & function_type::storage) { + int fd_ix = count_left_set_bits(ft, count_trailing_zeros(function_type::storage)); + uint32_t fd = be_bswap(data_fields.device_id.fd[fd_ix]); + print_storage_function_definition(fd); + + storage_fd[port][ap_lm_bus_int(lm_bus)].fd = fd; + send_get_media_info(writer, port, lm_bus); + } + } + + return 0; +} + + +int handle_device_status_response(struct ftdi_context * ftdi, + maple::host_command_writer& writer) +{ + int res = do_maple_raw(ftdi, + writer.send_buf, writer.send_offset, + writer.recv_buf, writer.recv_offset); + if (res != 0) { + return -1; + } + writer.reset(); + + using response_type = maple::device_status; + using host_response_type = maple::host_response; + + for (uint8_t port = 0; port < 4; port++) { + auto host_response = reinterpret_cast(writer.recv_buf); + auto& bus_data = host_response[port].bus_data; + auto& data_fields = bus_data.data_fields; + fprintf(stderr, "[device] port: %d\n", port); + if (bus_data.command_code != response_type::command_code) { + fprintf(stderr, " disconnected %02x %02x %02x %02x\n", + bus_data.command_code, + bus_data.destination_ap, + bus_data.source_ap, + bus_data.data_size); + } else { + print_device_id(data_fields.device_id); + uint8_t source_ap__lm_bus = bus_data.source_ap & ap::lm_bus::bit_mask; + do_lm_requests(writer, port, source_ap__lm_bus, &send_extension_device_request); + } + } + + return 0; +} + +int do_maple_storage_dump(struct ftdi_context * ftdi) +{ + uint8_t send_buf[maple_buffer_size]; + uint8_t recv_buf[maple_buffer_size]; + + auto writer = maple::host_command_writer(send_buf, + recv_buf); + + int res; + + send_device_request_all_ports(writer); + + res = handle_device_status_response(ftdi, writer); + if (res != 0) + return -1; + if (writer.send_offset == 0) + return 0; + + struct storage_fd storage_fd[4][5]; + + res = handle_device_status_response_extension(ftdi, writer, storage_fd); + if (res != 0) + return -1; + if (writer.send_offset == 0) + return 0; + + res = handle_get_media_info_data_transfer_response(ftdi, writer, storage_fd); + if (res != 0) + return -1; + if (writer.send_offset == 0) + return 0; + + return 0; +} diff --git a/tools/ftdi_maple.hpp b/tools/ftdi_maple.hpp new file mode 100644 index 0000000..14f4764 --- /dev/null +++ b/tools/ftdi_maple.hpp @@ -0,0 +1,3 @@ +#pragma once + +int do_maple_storage_dump(struct ftdi_context * ftdi); diff --git a/tools/ftdi_transfer.cpp b/tools/ftdi_transfer.cpp index 59effa8..844071a 100644 --- a/tools/ftdi_transfer.cpp +++ b/tools/ftdi_transfer.cpp @@ -14,13 +14,8 @@ #include "crc32.h" #include "serial_protocol.hpp" - -#include "maple/maple_bus_bits.hpp" -#include "maple/maple.hpp" -#include "maple/maple_host_command_writer.hpp" -#include "maple/maple_bus_commands.hpp" -#include "maple/maple_port.hpp" -#include "maple/maple_bus_ft1.hpp" +#include "ftdi_transfer.hpp" +#include "ftdi_maple.hpp" extern "C" int convert_baudrate_UT_export(int baudrate, struct ftdi_context *ftdi, unsigned short *value, unsigned short *index); @@ -569,12 +564,14 @@ void do_console(struct ftdi_context * ftdi) { int res; - ftdi->usb_read_timeout = 1; - uint8_t read_buf[ftdi->readbuffer_chunksize]; while (1) { res = ftdi_read_data(ftdi, read_buf, ftdi->readbuffer_chunksize); + if (res < 0) { + fprintf(stderr, "ftdi_read_data: %s\n", ftdi_get_error_string(ftdi)); + } + assert(res >= 0); if (res > 0) { fwrite(read_buf, 1, res, stdout); fflush(stdout); @@ -582,84 +579,6 @@ void do_console(struct ftdi_context * ftdi) } } -constexpr int count_left_set_bits(uint32_t n, int stop_bit) -{ - int bit_ix = 31; - int count = 0; - while (bit_ix != stop_bit) { - if (n & (1 << 31)) { - count += 1; - } - n <<= 1; - bit_ix -= 1; - } - - return count; -} -static_assert(count_left_set_bits(0xe, 1) == 2); -static_assert(count_left_set_bits(0x2, 1) == 0); - -consteval int count_trailing_zeros(uint32_t n) -{ - int count = 0; - for (int i = 0; i < 32; i++) { - if ((n & 1) != 0) - break; - count += 1; - n >>= 1; - } - return count; -} -static_assert(count_trailing_zeros(0x80) == 7); -static_assert(count_trailing_zeros(0x2) == 1); - -void print_storage_function_definition(const uint32_t fd) -{ - int partitions = ((fd >> 24) & 0xff) + 1; - int bytes_per_block = (((fd >> 16) & 0xff) + 1) * 32; - int write_accesses = (fd >> 12) & 0xf; - int read_accesses = (fd >> 8) & 0xf; - - fprintf(stderr, " storage function definition:\n"); - fprintf(stderr, " partitions: %d\n", partitions); - fprintf(stderr, " bytes_per_block: %d\n", bytes_per_block); - fprintf(stderr, " write_accesses: %d\n", write_accesses); - fprintf(stderr, " read_accesses: %d\n", read_accesses); -} - -template -static inline T be_bswap(const T n) -{ - if constexpr (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) - return n; - else - return std::byteswap(n); -} - -void print_device_id(struct maple::device_id& device_id) -{ - fprintf(stderr, " ft: %08x\n", be_bswap(device_id.ft)); - fprintf(stderr, " fd[0]: %08x\n", be_bswap(device_id.fd[0])); - fprintf(stderr, " fd[1]: %08x\n", be_bswap(device_id.fd[1])); - fprintf(stderr, " fd[2]: %08x\n", be_bswap(device_id.fd[2])); -} - -void print_media_info(struct ft1::get_media_info_data_transfer::data_format& data) -{ - fprintf(stderr, " media_info:\n"); - fprintf(stderr, " total_size: %04x\n", data.total_size); - fprintf(stderr, " partition_number: %04x\n", data.partition_number); - fprintf(stderr, " system_area_block_number: %04x\n", data.system_area_block_number); - fprintf(stderr, " fat_area_block_number: %04x\n", data.fat_area_block_number); - fprintf(stderr, " number_of_fat_area_blocks: %04x\n", data.number_of_fat_area_blocks); - fprintf(stderr, " file_information_block_number: %04x\n", data.file_information_block_number); - fprintf(stderr, " number_of_file_information_blocks: %04x\n", data.number_of_file_information_blocks); - fprintf(stderr, " volume_icon: %04x\n", data.volume_icon); - fprintf(stderr, " save_area_block_number: %04x\n", data.save_area_block_number); - fprintf(stderr, " number_of_save_area_blocks: %04x\n", data.number_of_save_area_blocks); - fprintf(stderr, " reserved_for_execution_file: %08x\n", data.reserved_for_execution_file); -} - int do_maple_raw(struct ftdi_context * ftdi, uint8_t * send_buf, uint32_t send_size, @@ -738,399 +657,6 @@ int do_maple_raw(struct ftdi_context * ftdi, return 0; } -template -void send_extension_device_request(maple::host_command_writer& writer, uint8_t port, uint8_t lm) -{ - uint32_t host_port_select = host_instruction_port_select(port); - uint32_t destination_ap = ap_port_select(port) | ap::de::expansion_device | lm; - - using command_type = maple::device_request; - using response_type = maple::device_status; - - writer.template append_command(host_port_select, - destination_ap, - false); // end_flag -} - -template -void send_get_media_info(maple::host_command_writer& writer, uint8_t port, uint8_t lm) -{ - uint32_t host_port_select = host_instruction_port_select(port); - uint32_t destination_ap = ap_port_select(port) | ap::de::expansion_device | lm; - - using command_type = maple::get_media_info; - using response_type = maple::data_transfer; - - auto [host_command, host_response] = - writer.template append_command(host_port_select, - destination_ap, - false); // end_flag - - host_command->bus_data.data_fields.function_type = be_bswap(function_type::storage); - host_command->bus_data.data_fields.pt = 0; -} - -struct block_read_response { - union responses { - struct maple::file_error::data_fields file_error; - struct maple::data_transfer::data_fields data_transfer; - }; - - using data_fields = union responses; -}; - -template -void send_block_read(maple::host_command_writer& writer, uint8_t port, uint8_t lm, uint32_t recv_trailing, int partition, int phase, int block_number) -{ - uint32_t host_port_select = host_instruction_port_select(port); - uint32_t destination_ap = ap_port_select(port) | ap::de::expansion_device | lm; - - using command_type = maple::block_read; - using response_type = block_read_response; - - auto [host_command, host_response] = - writer.template append_command(host_port_select, - destination_ap, - false, // end_flag - 0, // send_trailing - recv_trailing // recv_trailing - ); - - auto& data_fields = host_command->bus_data.data_fields; - data_fields.function_type = be_bswap(function_type::storage); - data_fields.pt = partition; - data_fields.phase = phase; - data_fields.block_number = be_bswap(block_number); -} - -template -void do_lm_requests(maple::host_command_writer& writer, uint8_t port, uint8_t lm, uint32_t& last_send_offset, - void (* func)(maple::host_command_writer& writer, uint8_t port, uint8_t lm)) -{ - uint32_t bit = ap::lm_bus::_0; - for (int i = 0; i < 5; i++) { - if (lm & bit) { - last_send_offset = writer.send_offset; - func(writer, port, bit); - } - bit <<= 1; - } -} - -struct storage_state { - uint32_t fd; - - uint32_t partitions() { - return ((fd >> 24) & 0xff) + 1; - } - uint32_t bytes_per_block() { - return (((fd >> 16) & 0xff) + 1) * 32; - } - uint32_t write_accesses() { - return (fd >> 12) & 0xf; - } - uint32_t read_accesses() { - return (fd >> 8) & 0xf; - } - - uint32_t bytes_per_read_access() - { - // divide rounding up - return (bytes_per_block() + (read_accesses() - 1)) / read_accesses(); - } - - uint32_t bytes_per_write_access() - { - // divide rounding up - return (bytes_per_block() + (write_accesses() - 1)) / write_accesses(); - } - -}; - -template -int handle_block_read_dump(struct ftdi_context * ftdi, - maple::host_command_writer& writer, - struct storage_state& storage_state, - uint32_t last_send_offset, - FILE * dump) -{ - using command_type = maple::block_read; - using host_command_type = maple::host_command; - - uint8_t * send_buf = reinterpret_cast(writer.send_buf); - auto host_command = reinterpret_cast(&send_buf[last_send_offset]); - host_command->host_instruction |= host_instruction::end_flag; - - int res = do_maple_raw(ftdi, - reinterpret_cast(writer.send_buf), writer.send_offset, - reinterpret_cast(writer.recv_buf), writer.recv_offset); - if (res != 0) { - return -1; - } - - using response_type = block_read_response; - using host_response_type = maple::host_response; - const uint32_t recv_trailing = storage_state.bytes_per_read_access(); - const uint32_t host_response_size = (sizeof (host_response_type)) + recv_trailing; - - uint8_t * recv_buf = reinterpret_cast(writer.recv_buf); - - for (uint32_t offset = 0; offset < writer.recv_offset; offset += host_response_size) { - auto host_response = reinterpret_cast(&recv_buf[offset]); - auto& bus_data = host_response->bus_data; - if (bus_data.command_code != maple::data_transfer::command_code) { - fprintf(stderr, "lm did not reply to block read: %d\n", bus_data.command_code); - auto& file_error = bus_data.data_fields.file_error; - if (bus_data.command_code == maple::file_error::command_code) { - fprintf(stderr, "function error code: %d\n", file_error.function_error_code); - } - return -1; - } - - fwrite(bus_data.data_fields.data_transfer.data.block_data, - 1, - storage_state.bytes_per_read_access(), - dump); - } - - writer.send_offset = 0; - writer.recv_offset = 0; - - return 0; -} - -template -int do_maple_block_read_dump(struct ftdi_context * ftdi, - int port, - int lm, - struct storage_state& storage_state, - struct ft1::get_media_info_data_transfer::data_format& media_info) // copy of media_info on the stack -{ - uint8_t send_buf[8192]; - uint8_t recv_buf[8192]; - - char filename[256]; - snprintf(filename, (sizeof (filename)), "dump_p%dl%d.bin", port, ap_lm_bus_int(lm)); - - FILE * dump = fopen(filename, "wb"); - - auto writer = maple::host_command_writer(reinterpret_cast(send_buf), - reinterpret_cast(recv_buf)); - uint32_t last_send_offset = 0; - - constexpr int partition = 0; - - using response_type = maple::data_transfer; - using host_response_type = maple::host_response; - const uint32_t recv_trailing = storage_state.bytes_per_read_access(); - const uint32_t host_response_size = (sizeof (host_response_type)) + recv_trailing; - - for (uint16_t block_number = 0; block_number < (media_info.total_size + 1); block_number++) { - for (uint32_t phase = 0; phase < storage_state.read_accesses(); phase++) { - fprintf(stderr, "maple_block_read: block %d,%d\n", block_number, phase); - last_send_offset = writer.send_offset; - send_block_read(writer, port, lm, recv_trailing, partition, phase, block_number); - } - - constexpr uint32_t maple_buffer_size = 8192; - if (writer.recv_offset + host_response_size > maple_buffer_size) { - int res = handle_block_read_dump(ftdi, - writer, - storage_state, - last_send_offset, - dump); - if (res != 0) { - return -1; - } - } - } - - if (writer.send_offset != 0) { - int res = handle_block_read_dump(ftdi, - writer, - storage_state, - last_send_offset, - dump); - if (res != 0) { - return -1; - } - } - - fclose(dump); - - return 0; -} - -int do_maple_list(struct ftdi_context * ftdi) -{ - constexpr uint32_t base_address = 0xac002020; - - uint8_t send_buf[8192]; - uint8_t recv_buf[8192]; - - using command_type = maple::device_request; - using response_type = maple::device_status; - - auto writer = maple::host_command_writer(reinterpret_cast(send_buf), - reinterpret_cast(recv_buf)); - auto [host_command, host_response] - = writer.append_command_all_ports(); - - int res = do_maple_raw(ftdi, - send_buf, writer.send_offset, - recv_buf, writer.recv_offset); - if (res != 0) { - return -1; - } - - // reset writer - writer.send_offset = 0; - writer.recv_offset = 0; - uint32_t last_send_offset = 0; - - for (uint8_t port = 0; port < 4; port++) { - auto& bus_data = host_response[port].bus_data; - auto& data_fields = bus_data.data_fields; - fprintf(stderr, "[device] port: %d\n", port); - if (bus_data.command_code != response_type::command_code) { - fprintf(stderr, " disconnected %02x %02x %02x %02x\n", - bus_data.command_code, - bus_data.destination_ap, - bus_data.source_ap, - bus_data.data_size); - } else { - print_device_id(data_fields.device_id); - uint8_t source_ap__lm_bus = bus_data.source_ap & ap::lm_bus::bit_mask; - do_lm_requests(writer, port, source_ap__lm_bus, last_send_offset, &send_extension_device_request); - } - } - - if (writer.send_offset == 0) { - return 0; - } - - struct storage_state storage_state[4][5]; - - { - // rewrite the end flag of the last request - using host_command_type = maple::host_command; - auto host_command = reinterpret_cast(&send_buf[last_send_offset]); - host_command->host_instruction |= host_instruction::end_flag; - - int res = do_maple_raw(ftdi, - send_buf, writer.send_offset, - recv_buf, writer.recv_offset); - if (res != 0) { - return -1; - } - - const uint32_t recv_offset = writer.recv_offset; - - // reset writer - writer.send_offset = 0; - writer.recv_offset = 0; - last_send_offset = 0; - - using response_type = maple::device_status; - using host_response_type = maple::host_response; - for (uint32_t offset = 0; offset < recv_offset; offset += (sizeof (host_response_type))) { - auto host_response = reinterpret_cast(&recv_buf[offset]); - - auto& bus_data = host_response->bus_data; - auto& data_fields = bus_data.data_fields; - - if (bus_data.command_code != response_type::command_code) { - fprintf(stderr, " disconnected %02x %02x %02x %02x\n", - bus_data.command_code, - bus_data.destination_ap, - bus_data.source_ap, - bus_data.data_size); - continue; - } - - uint32_t port = (bus_data.source_ap & ap::port_select::bit_mask) >> 6; - uint32_t lm_bus = (bus_data.source_ap & ap::lm_bus::bit_mask) >> 0; - fprintf(stderr, "[extension] port: %d ; lm: %05b\n", port, lm_bus); - print_device_id(data_fields.device_id); - - uint32_t ft = be_bswap(data_fields.device_id.ft); - if (ft & function_type::storage) { - int fd_ix = count_left_set_bits(ft, count_trailing_zeros(function_type::storage)); - uint32_t fd = be_bswap(data_fields.device_id.fd[fd_ix]); - print_storage_function_definition(fd); - - storage_state[port][ap_lm_bus_int(lm_bus)].fd = fd; - last_send_offset = writer.send_offset; - send_get_media_info(writer, port, lm_bus); - } - } - } - - if (writer.send_offset == 0) { - return 0; - } - - { - // rewrite the end flag of the last request - using host_command_type = maple::host_command; - auto host_command = reinterpret_cast(&send_buf[last_send_offset]); - host_command->host_instruction |= host_instruction::end_flag; - - int res = do_maple_raw(ftdi, - send_buf, writer.send_offset, - recv_buf, writer.recv_offset); - if (res != 0) { - return -1; - } - - const uint32_t recv_offset = writer.recv_offset; - // reset writer - writer.send_offset = 0; - writer.recv_offset = 0; - last_send_offset = 0; - - using response_type = maple::data_transfer; - using host_response_type = maple::host_response; - - for (uint32_t offset = 0; offset < recv_offset; offset += (sizeof (host_response_type))) { - auto host_response = reinterpret_cast(&recv_buf[offset]); - - auto& bus_data = host_response->bus_data; - auto& data_fields = bus_data.data_fields; - auto& data = data_fields.data; - - if (bus_data.command_code != response_type::command_code) { - fprintf(stderr, " disconnected %02x %02x %02x %02x\n", - bus_data.command_code, - bus_data.destination_ap, - bus_data.source_ap, - bus_data.data_size); - continue; - } - - uint32_t port = (bus_data.source_ap & ap::port_select::bit_mask) >> 6; - uint32_t lm_bus = (bus_data.source_ap & ap::lm_bus::bit_mask) >> 0; - fprintf(stderr, "[extension] port: %d ; lm: %05b\n", port, lm_bus); - print_media_info(data); - - using command_type = maple::block_read; - using host_command_type = maple::host_command; - using response_type = block_read_response; - using host_response_type = maple::host_response; - fprintf(stderr, "block read command size %ld\n", (sizeof (host_command_type))); - fprintf(stderr, "block read response size %ld\n", (sizeof (host_response_type))); - - do_maple_block_read_dump(ftdi, - port, - lm_bus, - storage_state[port][ap_lm_bus_int(lm_bus)], - data); - } - } - - return 0; -} - enum struct argument_type { string, integer @@ -1150,7 +676,7 @@ struct cli_command commands[] = { { "list_baudrates" , 1, (void *)&do_list_baudrates }, { "show_baudrate_error", 1, (void *)&do_show_baudrate_error }, { "console" , 0, (void *)&do_console }, - { "maple_list" , 0, (void *)&do_maple_list }, + { "maple_storage_dump" , 0, (void *)&do_maple_storage_dump }, }; constexpr int commands_length = (sizeof (commands)) / (sizeof (commands[0])); @@ -1236,6 +762,8 @@ int handle_command(int argc, const char * argv[], struct ftdi_context * ftdi) { fprintf(stderr, "handle command: %s ()\n", commands[i].name); func_0_arg func = (func_0_arg)commands[i].func; + fprintf(stderr, "%p\n", &do_console); + fprintf(stderr, "%p\n", func); func_ret = func(ftdi); } break; diff --git a/tools/ftdi_transfer.hpp b/tools/ftdi_transfer.hpp new file mode 100644 index 0000000..b45a2fb --- /dev/null +++ b/tools/ftdi_transfer.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +int do_maple_raw(struct ftdi_context * ftdi, + uint8_t * send_buf, + uint32_t send_size, + uint8_t * recv_buf, + uint32_t recv_size); diff --git a/tools/ftdi_transfer.sh b/tools/ftdi_transfer.sh index 827915e..923da19 100644 --- a/tools/ftdi_transfer.sh +++ b/tools/ftdi_transfer.sh @@ -13,5 +13,5 @@ set -ex ${SCRIPT_DIR}/ftdi_transfer \ write 0xac010000 "$filename" \ - jump 0xac010000 -# console + jump 0xac010000 \ + console