ftdi_transfer: add maple_storage_load

This commit is contained in:
Zack Buhman 2025-12-13 17:32:47 -06:00
parent 0b8f4a3923
commit d222a2dc9f
3 changed files with 210 additions and 13 deletions

View File

@ -1,5 +1,8 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <bit> #include <bit>
#include "maple/maple_bus_bits.hpp" #include "maple/maple_bus_bits.hpp"
@ -311,7 +314,8 @@ int do_maple_block_read_dump(struct ftdi_context * ftdi,
int handle_get_media_info_data_transfer_response(struct ftdi_context * ftdi, int handle_get_media_info_data_transfer_response(struct ftdi_context * ftdi,
maple::host_command_writer<base_address>& writer, maple::host_command_writer<base_address>& writer,
struct storage_fd storage_fd[4][5]) struct storage_fd storage_fd[4][5],
int (* func)(struct ftdi_context * ftdi, int port, int lm, struct storage_fd& storage_fd, struct ft1::get_media_info_data_transfer::data_format& media_info))
{ {
writer.set_end_flag(); writer.set_end_flag();
int res = do_maple_raw(ftdi, int res = do_maple_raw(ftdi,
@ -347,11 +351,11 @@ int handle_get_media_info_data_transfer_response(struct ftdi_context * ftdi,
fprintf(stderr, "[extension] port: %d ; lm: %05b\n", port, lm_bus); fprintf(stderr, "[extension] port: %d ; lm: %05b\n", port, lm_bus);
print_media_info(data); print_media_info(data);
do_maple_block_read_dump(ftdi, func(ftdi,
port, port,
lm_bus, lm_bus,
storage_fd[port][ap_lm_bus_int(lm_bus)], storage_fd[port][ap_lm_bus_int(lm_bus)],
data); data);
} }
return 0; return 0;
@ -412,6 +416,12 @@ int handle_device_status_response_extension(struct ftdi_context * ftdi,
int handle_device_status_response(struct ftdi_context * ftdi, int handle_device_status_response(struct ftdi_context * ftdi,
maple::host_command_writer<base_address>& writer) maple::host_command_writer<base_address>& writer)
{ {
fprintf(stderr, "handle device status response:\n");
fprintf(stderr, " send_offset: %d\n", writer.send_offset);
fprintf(stderr, " recv_offset: %d\n", writer.recv_offset);
for (uint32_t i = 0; i < writer.send_offset / 4; i++) {
fprintf(stderr, " send_buf: %08x\n", ((uint32_t*)writer.send_buf)[i]);
}
int res = do_maple_raw(ftdi, int res = do_maple_raw(ftdi,
writer.send_buf, writer.send_offset, writer.send_buf, writer.send_offset,
writer.recv_buf, writer.recv_offset); writer.recv_buf, writer.recv_offset);
@ -470,7 +480,188 @@ int do_maple_storage_dump(struct ftdi_context * ftdi)
if (writer.send_offset == 0) if (writer.send_offset == 0)
return 0; return 0;
res = handle_get_media_info_data_transfer_response(ftdi, writer, storage_fd); res = handle_get_media_info_data_transfer_response(ftdi, writer, storage_fd, &do_maple_block_read_dump);
if (res != 0)
return -1;
if (writer.send_offset == 0)
return 0;
return 0;
}
int send_block_write(maple::host_command_writer<base_address>& writer, uint8_t port, uint8_t lm, int partition, int phase, int block_number, const uint8_t * src, uint32_t send_trailing)
{
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_write<uint8_t[0]>;
using response_type = maple::device_reply;
auto [host_command, host_response] =
writer.template append_command<command_type, response_type>(host_port_select,
destination_ap,
false, // end_flag
send_trailing, // send_trailing
0 // recv_trailing
);
auto& data_fields = host_command->bus_data.data_fields;
data_fields.function_type = be_bswap<uint32_t>(function_type::storage);
data_fields.pt = partition;
data_fields.phase = phase;
data_fields.block_number = be_bswap<uint32_t>(block_number);
memcpy(data_fields.written_data, src, send_trailing);
//printf("sizeof host_command %ld %d\n", (sizeof (*host_command)), send_trailing);
return (sizeof (*host_command)) + send_trailing;
}
struct get_last_error_response {
union responses {
struct maple::device_reply device_reply;
struct maple::file_error file_error;
};
using data_fields = union responses;
};
int send_get_last_error(maple::host_command_writer<base_address>& writer, uint8_t port, uint8_t lm, 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::get_last_error;
using response_type = get_last_error_response;
auto [host_command, host_response]
= writer.append_command<command_type, response_type>(host_port_select,
destination_ap,
true); // end_flag
auto& data_fields = host_command->bus_data.data_fields;
data_fields.function_type = be_bswap<uint32_t>(function_type::storage);
data_fields.pt = partition;
data_fields.phase = phase;
data_fields.block_number = be_bswap<uint16_t>(block_number);
printf("write phase: %d\n", phase);
return (sizeof (*host_command));
}
int handle_block_write(struct ftdi_context * ftdi,
maple::host_command_writer<base_address>& writer)
{
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 = maple::device_reply;
using host_response_type = maple::host_response<response_type::data_fields>;
auto host_response = reinterpret_cast<host_response_type *>(writer.recv_buf);
auto& bus_data = host_response->bus_data;
printf("handle_block_write: command_code: %d\n", host_response->bus_data.command_code);
if (bus_data.command_code != response_type::command_code) {
printf("lm did not reply to block write: command code: %d\n", bus_data.command_code);
return -1;
}
writer.reset();
return 0;
}
int do_maple_block_load(struct ftdi_context * ftdi,
int port,
int lm,
struct storage_fd& storage_fd,
struct ft1::get_media_info_data_transfer::data_format& media_info)
{
printf("do maple block load\n");
printf(" port: %d\n", port);
printf(" lm: %d\n", lm);
uint8_t send_buf[maple_buffer_size];
uint8_t recv_buf[maple_buffer_size];
FILE * img = fopen("/home/bilbo/dreamcast/img.vmu.data", "rb");
assert(img != NULL);
uint8_t buf[128 * 1024];
size_t ret = fread(buf, 1, (sizeof (buf)), img);
assert(ret == (sizeof (buf)));
fclose(img);
auto writer = maple::host_command_writer<base_address>(send_buf,
recv_buf);
constexpr int partition = 0;
const uint32_t send_trailing = storage_fd.bytes_per_write_access();
int offset = 0;
for (uint16_t block_number = 0; block_number < (media_info.total_size + 1); block_number++) {
uint32_t phase;
fprintf(stderr, "maple_block_load: block_write: block_number %d\n", block_number);
for (phase = 0; phase < storage_fd.write_accesses(); phase++) {
send_block_write(writer, port, lm, partition, phase, block_number,
&buf[offset], send_trailing);
int res = handle_block_write(ftdi, writer);
if (res != 0) {
return -1;
}
usleep(16000); // sleep 16 ms
offset += send_trailing;
}
send_get_last_error(writer, port, lm, partition, phase, block_number);
int res = handle_block_write(ftdi, writer);
if (res != 0) {
return -1;
}
usleep(16000); // sleep 16 ms
}
assert(writer.send_offset == 0);
return 0;
}
int do_maple_storage_load(struct ftdi_context * ftdi)
{
uint8_t send_buf[maple_buffer_size];
uint8_t recv_buf[maple_buffer_size];
auto writer = maple::host_command_writer<base_address>(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, &do_maple_block_load);
if (res != 0) if (res != 0)
return -1; return -1;
if (writer.send_offset == 0) if (writer.send_offset == 0)

View File

@ -1,3 +1,4 @@
#pragma once #pragma once
int do_maple_storage_dump(struct ftdi_context * ftdi); int do_maple_storage_dump(struct ftdi_context * ftdi);
int do_maple_storage_load(struct ftdi_context * ftdi);

View File

@ -396,7 +396,7 @@ int do_reset(struct ftdi_context * ftdi)
int res; int res;
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
timespec t = {.tv_sec = 0, .tv_nsec = 33000 * 2 }; timespec t = {.tv_sec = 0, .tv_nsec = (int)(33000.0 * 2) };
// toggle ACBUS5 low (g reset asserted) // toggle ACBUS5 low (g reset asserted)
uint8_t bitmask1 = (0b0001 << 4) | (0b0001 << 0); uint8_t bitmask1 = (0b0001 << 4) | (0b0001 << 0);
@ -655,12 +655,15 @@ int do_maple_raw(struct ftdi_context * ftdi,
{ {
int res; int res;
assert(send_size <= 1024);
assert(recv_size <= 1024);
union serial_load::command_reply command = serial_load::command::maple_raw(send_size, recv_size); union serial_load::command_reply command = serial_load::command::maple_raw(send_size, recv_size);
//dump_command_reply(command); //dump_command_reply(command);
res = ftdi_write_data(ftdi, command.u8, (sizeof (command))); res = ftdi_write_data(ftdi, command.u8, (sizeof (command)));
assert(res == (sizeof (command))); assert(res == (sizeof (command)));
union serial_load::command_reply reply; union serial_load::command_reply reply;
fprintf(stderr, "maple_raw: wait maple_raw reply\n"); //fprintf(stderr, "maple_raw: wait maple_raw reply\n");
res = read_reply(ftdi, serial_load::reply::_maple_raw, reply); res = read_reply(ftdi, serial_load::reply::_maple_raw, reply);
if (res != 0) { if (res != 0) {
return -2; return -2;
@ -688,13 +691,14 @@ int do_maple_raw(struct ftdi_context * ftdi,
*/ */
union serial_load::command_reply send_crc_reply; union serial_load::command_reply send_crc_reply;
fprintf(stderr, "maple_raw: send: wait crc reply\n"); //fprintf(stderr, "maple_raw: send: wait crc reply\n");
res = read_reply(ftdi, serial_load::reply::_crc, send_crc_reply); res = read_reply(ftdi, serial_load::reply::_crc, send_crc_reply);
if (res != 0) { if (res != 0) {
return -1; return -1;
} }
fprintf(stderr, "maple_raw: send: remote crc: %08x; local crc %08x\n", send_crc_reply.arg[0], send_buf_crc);
if (send_crc_reply.arg[0] != send_buf_crc) { if (send_crc_reply.arg[0] != send_buf_crc) {
fprintf(stderr, "maple_raw: send: remote crc: %08x; local crc %08x\n", send_crc_reply.arg[0], send_buf_crc);
dump_command_reply(send_crc_reply); dump_command_reply(send_crc_reply);
return -1; return -1;
} }
@ -711,14 +715,14 @@ int do_maple_raw(struct ftdi_context * ftdi,
uint32_t recv_buf_crc = crc32(recv_buf, recv_size); uint32_t recv_buf_crc = crc32(recv_buf, recv_size);
union serial_load::command_reply recv_crc_reply; union serial_load::command_reply recv_crc_reply;
fprintf(stderr, "maple_raw: recv: wait crc reply\n"); //fprintf(stderr, "maple_raw: recv: wait crc reply\n");
res = read_reply(ftdi, serial_load::reply::_crc, recv_crc_reply); res = read_reply(ftdi, serial_load::reply::_crc, recv_crc_reply);
if (res != 0) { if (res != 0) {
return -1; return -1;
} }
fprintf(stderr, "maple_raw: recv: remote crc: %08x; local crc %08x\n", recv_crc_reply.arg[0], recv_buf_crc);
if (recv_crc_reply.arg[0] != recv_buf_crc) { if (recv_crc_reply.arg[0] != recv_buf_crc) {
fprintf(stderr, "maple_raw: recv: remote crc: %08x; local crc %08x\n", recv_crc_reply.arg[0], recv_buf_crc);
return -1; return -1;
} }
@ -772,6 +776,7 @@ const struct cli_command commands[] = {
{ "speed" , 1, (void *)&do_speed , true, &speed_help}, { "speed" , 1, (void *)&do_speed , true, &speed_help},
{ "console" , 0, (void *)&do_console , true, NULL}, { "console" , 0, (void *)&do_console , true, NULL},
{ "maple_storage_dump" , 0, (void *)&do_maple_storage_dump , true, NULL}, { "maple_storage_dump" , 0, (void *)&do_maple_storage_dump , true, NULL},
{ "maple_storage_load" , 0, (void *)&do_maple_storage_load , true, NULL},
{ "list_baudrates" , 0, (void *)&do_list_baudrates , false, NULL}, { "list_baudrates" , 0, (void *)&do_list_baudrates , false, NULL},
{ "show_baudrate_error", 0, (void *)&do_show_baudrate_error , true, NULL}, { "show_baudrate_error", 0, (void *)&do_show_baudrate_error , true, NULL},
{ "help" , 0, (void *)&do_help , false, NULL}, { "help" , 0, (void *)&do_help , false, NULL},