example/maple_storage: upload vmu image from fixed address

This commit is contained in:
Zack Buhman 2025-12-13 18:00:58 -06:00
parent 9a69cbe1a7
commit 25cf6b5394
2 changed files with 122 additions and 78 deletions

View File

@ -15,6 +15,8 @@
#include "systembus.hpp" #include "systembus.hpp"
const uint32_t maple_image_address = 0xac100000;
struct storage_state { struct storage_state {
uint8_t * send_buf; uint8_t * send_buf;
uint8_t * recv_buf; uint8_t * recv_buf;
@ -172,21 +174,36 @@ bool do_block_read(storage_state& state, uint16_t block_number, uint8_t * dest)
struct get_last_error_response { struct get_last_error_response {
union responses { union responses {
struct maple::device_reply device_reply; struct maple::device_reply::data_fields device_reply;
struct maple::file_error file_error; struct maple::file_error::data_fields file_error;
}; };
using data_fields = union responses; using data_fields = union responses;
}; };
bool do_block_write(storage_state& state, uint16_t block_number, uint8_t * src) extern "C"
void *memcpy(void *dest, const void * src, size_t n)
{
unsigned char *d = (unsigned char *)dest;
const unsigned char *s = (const unsigned char *)src;
for (; n; n--) *d++ = *s++;
return dest;
}
bool do_block_write(storage_state& state, uint16_t block_number, uint8_t * src, int retry)
{ {
auto writer = maple::host_command_writer(state.send_buf, state.recv_buf); auto writer = maple::host_command_writer(state.send_buf, state.recv_buf);
uint8_t * src_orig = src;
using command_type = maple::block_write<uint8_t[0]>;
using response_type = maple::device_reply;
using host_response_type = maple::host_response<response_type::data_fields>;
host_response_type responses[4];
uint32_t phase; uint32_t phase;
for (phase = 0; phase < state.device_status.write_accesses; phase++) { for (phase = 0; phase < state.device_status.write_accesses; phase++) {
using command_type = maple::block_write<uint8_t[0]>; writer.reset();
using response_type = maple::device_reply;
auto [host_command, host_response] auto [host_command, host_response]
= writer.append_command<command_type, response_type>(state.host_port_select, = writer.append_command<command_type, response_type>(state.host_port_select,
@ -204,11 +221,45 @@ bool do_block_write(storage_state& state, uint16_t block_number, uint8_t * src)
copy<uint8_t>(data_fields.written_data, src, state.bytes_per_write_access()); copy<uint8_t>(data_fields.written_data, src, state.bytes_per_write_access());
src += state.bytes_per_write_access(); src += state.bytes_per_write_access();
//serial::string("write phase: ");
//serial::integer<uint8_t>(phase); /*
//serial::integer(writer.send_offset); serial::string("block write:\n");
serial::integer<uint32_t>(writer.send_offset);
serial::string(" command code: ");
serial::integer<uint8_t>(host_command->bus_data.command_code);
serial::string(" destination ap: ");
serial::integer<uint8_t>(host_command->bus_data.destination_ap);
serial::string(" source ap: ");
serial::integer<uint8_t>(host_command->bus_data.source_ap);
serial::string(" data size: ");
serial::integer<uint8_t>(host_command->bus_data.data_size);
serial::string(" function type: ");
serial::integer<uint32_t>(std::byteswap<uint32_t>(host_command->bus_data.data_fields.function_type));
serial::string(" pt: ");
serial::integer<uint8_t>(host_command->bus_data.data_fields.pt);
serial::string(" phase: ");
serial::integer<uint8_t>(host_command->bus_data.data_fields.phase);
serial::string(" block number: ");
serial::integer<uint16_t>(std::byteswap<uint16_t>(host_command->bus_data.data_fields.block_number));
*/
maple::dma_start(state.send_buf, writer.send_offset,
state.recv_buf, writer.recv_offset);
maple::dma_wait_complete();
responses[phase] = *host_response;
for (int i = 0; i < 1; i++) {
while (!spg_status::vsync(holly.SPG_STATUS));
while (spg_status::vsync(holly.SPG_STATUS));
} }
asm volatile ("" ::: "memory");
writer.reset();
}
{
using command_type = maple::get_last_error; using command_type = maple::get_last_error;
using response_type = get_last_error_response; using response_type = get_last_error_response;
@ -222,16 +273,28 @@ bool do_block_write(storage_state& state, uint16_t block_number, uint8_t * src)
data_fields.pt = 0; data_fields.pt = 0;
data_fields.phase = phase; data_fields.phase = phase;
data_fields.block_number = std::byteswap<uint16_t>(block_number); data_fields.block_number = std::byteswap<uint16_t>(block_number);
//serial::string("write phase: "); serial::string("get last error: phase: ");
//serial::integer<uint8_t>(phase); serial::integer<uint8_t>(phase);
//serial::integer(writer.send_offset); serial::integer(writer.send_offset);
maple::dma_start(state.send_buf, writer.send_offset, maple::dma_start(state.send_buf, writer.send_offset,
state.recv_buf, writer.recv_offset); state.recv_buf, writer.recv_offset);
maple::dma_wait_complete(); maple::dma_wait_complete();
serial::string("block write status: "); for (int i = 0; i < 4; i++) {
serial::string("phase reponse command code: ");
serial::integer(responses[i].bus_data.command_code);
}
serial::string("do_block_write get_last_error command_code: ");
serial::integer(host_response->bus_data.command_code); serial::integer(host_response->bus_data.command_code);
if (host_response->bus_data.command_code >= 0xf0) {
serial::integer(std::byteswap(host_response->bus_data.data_fields.file_error.function_error_code));
serial::string("retry\n");
if (retry < 3)
do_block_write(state, block_number, src_orig, retry + 1);
}
}
return true; return true;
} }
@ -477,57 +540,14 @@ void do_lm_request(uint8_t port, uint8_t lm)
} }
{ {
uint16_t block_size = 3; int block_count = 128 * 1024 / 512;
uint16_t start_fat = allocate_fat_chain(state, block_size); for (int block_ix = 0; block_ix < block_count; block_ix++) {
char const * file_name = "HELLOANA.SUP"; uint8_t * buf = (uint8_t * )((maple_image_address) + block_ix * 512);
allocate_file_information_data(state, start_fat,
reinterpret_cast<uint8_t const *>(file_name),
block_size);
{ do_block_write(state, block_ix, buf, 0);
uint16_t chain = state.media_info.fat_area.block_number; serial::string("block: ");
uint8_t * buf = reinterpret_cast<uint8_t *>(state.fat_area); serial::integer<uint32_t>(block_ix);
do {
do_block_write(state, chain, buf);
buf += state.device_status.bytes_per_block;
chain = state.fat_area->fat_number[chain];
} while (chain != storage::fat_area::data::data_end);
} }
{
uint16_t chain = state.media_info.file_information.block_number;
uint8_t * buf = reinterpret_cast<uint8_t *>(state.file_information);
do {
do_block_write(state, chain, buf);
buf += state.device_status.bytes_per_block;
chain = state.fat_area->fat_number[chain];
} while (chain != storage::fat_area::data::data_end);
}
}
{
uint8_t * bufi = fat_area_data;
uint16_t chain = state.media_info.fat_area.block_number;
state.fat_area = reinterpret_cast<storage::fat_area *>(fat_area_data);
do {
do_block_read(state, chain, bufi);
bufi += state.device_status.bytes_per_block;
chain = state.fat_area->fat_number[chain];
} while (chain != storage::fat_area::data::data_end);
serial::string(" read fat_area bytes: ");
serial::integer((uint32_t)(bufi - fat_area_data));
uint32_t count = 0;
for (uint32_t i = 0; i < (bufi - fat_area_data) / (sizeof (uint16_t)); i++) {
if (state.fat_area->fat_number[i] == 0xfffc) {
count += 1;
}
serial::integer<uint16_t>(i, ' ');
serial::integer(state.fat_area->fat_number[i]);
}
serial::string(" free blocks: ");
serial::integer(count);
allocate_fat_chain(state, 98);
} }
} }
@ -591,9 +611,8 @@ void do_device_request()
void main() void main()
{ {
serial::init(4); //serial::init(4);
do_device_request(); do_device_request();
while (1);
} }

View File

@ -0,0 +1,25 @@
#!/bin/sh
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
filename="$1"
if [ -z "$filename" ]; then
echo "usage: ./$0 [vmu_image.vms]"
exit 1
fi
maple_storage="${SCRIPT_DIR}/../example/maple_storage.bin"
image="${filename}_image.bin"
set -ex
make -C "${SCRIPT_DIR}/.." example/maple_storage.bin
python tools/maple_build_image.py "$filename" "$image"
"${SCRIPT_DIR}/ftdi_transfer" \
write 0xac100000 "$image" \
write 0xac010000 "$maple_storage" \
jump 0xac010000 \
console