example/maple_storage: initial example
This commit is contained in:
parent
be8f06e486
commit
ea51bca518
1
base.mk
1
base.mk
@ -7,6 +7,7 @@ CFLAGS += -Wall -Werror -Wfatal-errors
|
||||
CFLAGS += -Wno-array-bounds
|
||||
#CFLAGS += -Wno-error=narrowing -Wno-error=unused-variable -Wno-error=array-bounds=
|
||||
CFLAGS += -Wno-error=maybe-uninitialized
|
||||
CFLAGS += -Wno-error=unused-but-set-variable
|
||||
|
||||
CXXFLAGS += -fno-exceptions -fno-non-call-exceptions -fno-rtti -fno-threadsafe-statics
|
||||
|
||||
|
@ -2,7 +2,7 @@ MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
DIR := $(dir $(MAKEFILE_PATH))
|
||||
|
||||
LIB ?= .
|
||||
OPT ?= -Os
|
||||
OPT ?= -O3
|
||||
GENERATED ?=
|
||||
|
||||
AARCH = --isa=sh4 --little
|
||||
|
@ -290,7 +290,8 @@ MAPLE_STORAGE_OBJ = \
|
||||
example/maple_storage.o \
|
||||
holly/video_output.o \
|
||||
sh7091/serial.o \
|
||||
maple/maple.o
|
||||
maple/maple.o \
|
||||
$(LIBGCC)
|
||||
|
||||
example/maple_storage.elf: LDSCRIPT = $(LIB)/main.lds
|
||||
example/maple_storage.elf: $(START_OBJ) $(MAPLE_STORAGE_OBJ)
|
||||
|
@ -10,10 +10,281 @@
|
||||
#include "maple/maple_bus_commands.hpp"
|
||||
#include "maple/maple_bus_ft1.hpp"
|
||||
#include "maple/maple_host_command_writer.hpp"
|
||||
#include "maple/storage.hpp"
|
||||
#include "sh7091/serial.hpp"
|
||||
|
||||
#include "systembus.hpp"
|
||||
|
||||
struct storage_state {
|
||||
uint32_t * send_buf;
|
||||
uint32_t * recv_buf;
|
||||
uint32_t host_port_select;
|
||||
uint32_t destination_ap;
|
||||
struct {
|
||||
uint8_t partitions;
|
||||
uint16_t bytes_per_block;
|
||||
uint8_t write_accesses;
|
||||
uint8_t read_accesses;
|
||||
} device_status;
|
||||
struct {
|
||||
struct {
|
||||
uint16_t block_number;
|
||||
} system_area;
|
||||
struct {
|
||||
uint16_t block_number;
|
||||
uint16_t number_of_blocks;
|
||||
} fat_area;
|
||||
struct {
|
||||
uint16_t block_number;
|
||||
uint16_t number_of_blocks;
|
||||
} file_information;
|
||||
} media_info;
|
||||
storage::system_area system_area;
|
||||
storage::fat_area * fat_area;
|
||||
storage::file_information * file_information; // array
|
||||
|
||||
uint32_t bytes_per_read_access()
|
||||
{
|
||||
// divide rounding up
|
||||
return (device_status.bytes_per_block + (device_status.read_accesses - 1)) / device_status.read_accesses;
|
||||
}
|
||||
|
||||
uint32_t bytes_per_write_access()
|
||||
{
|
||||
// divide rounding up
|
||||
return (device_status.bytes_per_block + (device_status.write_accesses - 1)) / device_status.write_accesses;
|
||||
}
|
||||
|
||||
uint32_t system_area_size()
|
||||
{
|
||||
return device_status.bytes_per_block * 1;
|
||||
}
|
||||
|
||||
uint32_t fat_area_size()
|
||||
{
|
||||
return device_status.bytes_per_block * media_info.fat_area.number_of_blocks;
|
||||
}
|
||||
|
||||
uint32_t file_information_size()
|
||||
{
|
||||
return device_status.bytes_per_block * media_info.file_information.number_of_blocks;
|
||||
}
|
||||
|
||||
uint32_t file_information_entries()
|
||||
{
|
||||
return file_information_size() / (sizeof (struct storage::file_information));
|
||||
}
|
||||
};
|
||||
|
||||
void parse_storage_function_definition(const uint32_t fd, storage_state& state)
|
||||
{
|
||||
state.device_status.partitions = ((fd >> 24) & 0xff) + 1;
|
||||
state.device_status.bytes_per_block = (((fd >> 16) & 0xff) + 1) * 32;
|
||||
state.device_status.write_accesses = (fd >> 12) & 0xf;
|
||||
state.device_status.read_accesses = (fd >> 8) & 0xf;
|
||||
|
||||
serial::string(" function_definition:\n");
|
||||
serial::string(" partitions: ");
|
||||
serial::integer(state.device_status.partitions);
|
||||
serial::string(" bytes_per_block: ");
|
||||
serial::integer(state.device_status.bytes_per_block);
|
||||
serial::string(" write_accesses: ");
|
||||
serial::integer(state.device_status.write_accesses);
|
||||
serial::string(" read_accesses: ");
|
||||
serial::integer(state.device_status.read_accesses);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void copy(T * dst, const T * src, const int32_t n) noexcept
|
||||
{
|
||||
int32_t n_t = n / (sizeof (T));
|
||||
while (n_t > 0) {
|
||||
*dst++ = *src++;
|
||||
n_t--;
|
||||
}
|
||||
}
|
||||
|
||||
struct block_read_response {
|
||||
union responses {
|
||||
struct maple::file_error::data_fields file_error;
|
||||
struct maple::data_transfer<ft1::block_read_data_transfer::data_format>::data_fields data_transfer;
|
||||
};
|
||||
|
||||
using data_fields = union responses;
|
||||
};
|
||||
|
||||
bool do_block_read(storage_state& state, uint16_t block_number, uint8_t * dest)
|
||||
{
|
||||
using command_type = maple::block_read;
|
||||
using response_type = block_read_response;
|
||||
|
||||
auto writer = maple::host_command_writer(state.send_buf, state.recv_buf);
|
||||
|
||||
maple::host_response<response_type::data_fields> * host_responses[state.device_status.read_accesses];
|
||||
for (int32_t phase = 0; phase < state.device_status.read_accesses; phase++) {
|
||||
bool end_flag = phase == (state.device_status.read_accesses - 1);
|
||||
auto [host_command, host_response]
|
||||
= writer.append_command<command_type, response_type>(state.host_port_select,
|
||||
state.destination_ap,
|
||||
end_flag,
|
||||
0, // send_trailing
|
||||
state.bytes_per_read_access() // recv_trailing
|
||||
);
|
||||
|
||||
auto& data_fields = host_command->bus_data.data_fields;
|
||||
data_fields.function_type = std::byteswap(function_type::storage);
|
||||
data_fields.pt = 0;
|
||||
data_fields.phase = phase;
|
||||
data_fields.block_number = std::byteswap<uint16_t>(block_number);
|
||||
|
||||
host_responses[phase] = host_response;
|
||||
|
||||
//serial::string("read phase: ");
|
||||
//serial::integer<uint8_t>(phase);
|
||||
//serial::integer(writer.recv_offset);
|
||||
}
|
||||
|
||||
maple::dma_start(state.send_buf, writer.send_offset,
|
||||
state.recv_buf, writer.recv_offset);
|
||||
|
||||
for (uint32_t phase = 0; phase < state.device_status.read_accesses; phase++) {
|
||||
auto& bus_data = host_responses[phase]->bus_data;
|
||||
if (bus_data.command_code != maple::data_transfer<uint8_t[0]>::command_code) {
|
||||
auto& file_error = bus_data.data_fields.file_error;
|
||||
serial::string("lm did not reply block_read: ");
|
||||
serial::integer<uint8_t>(bus_data.command_code);
|
||||
if (bus_data.command_code == maple::file_error::command_code) {
|
||||
serial::string("error: ");
|
||||
serial::hexlify(&file_error.function_error_code, 4);
|
||||
serial::character('\n');
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
auto& data_transfer = bus_data.data_fields.data_transfer;
|
||||
copy<uint8_t>(dest, data_transfer.data.block_data, state.bytes_per_read_access());
|
||||
dest += state.bytes_per_read_access();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct get_last_error_response {
|
||||
union responses {
|
||||
struct maple::device_reply device_reply;
|
||||
struct maple::file_error file_error;
|
||||
};
|
||||
|
||||
using data_fields = union responses;
|
||||
};
|
||||
|
||||
bool do_block_write(storage_state& state, uint16_t block_number, uint8_t * src)
|
||||
{
|
||||
auto writer = maple::host_command_writer(state.send_buf, state.recv_buf);
|
||||
|
||||
uint32_t phase;
|
||||
for (phase = 0; phase < state.device_status.write_accesses; phase++) {
|
||||
using command_type = maple::block_write<uint8_t[0]>;
|
||||
using response_type = maple::device_reply;
|
||||
|
||||
auto [host_command, host_response]
|
||||
= writer.append_command<command_type, response_type>(state.host_port_select,
|
||||
state.destination_ap,
|
||||
false, // end_flag
|
||||
state.bytes_per_write_access(), // send_trailing
|
||||
0 // recv_trailing
|
||||
);
|
||||
|
||||
auto& data_fields = host_command->bus_data.data_fields;
|
||||
data_fields.function_type = std::byteswap(function_type::storage);
|
||||
data_fields.pt = 0;
|
||||
data_fields.phase = phase;
|
||||
data_fields.block_number = std::byteswap<uint16_t>(block_number);
|
||||
|
||||
copy<uint8_t>(data_fields.written_data, 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);
|
||||
}
|
||||
|
||||
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>(state.host_port_select,
|
||||
state.destination_ap,
|
||||
true); // end_flag
|
||||
|
||||
auto& data_fields = host_command->bus_data.data_fields;
|
||||
data_fields.function_type = std::byteswap(function_type::storage);
|
||||
data_fields.pt = 0;
|
||||
data_fields.phase = phase;
|
||||
data_fields.block_number = std::byteswap<uint16_t>(block_number);
|
||||
//serial::string("write phase: ");
|
||||
//serial::integer<uint8_t>(phase);
|
||||
//serial::integer(writer.send_offset);
|
||||
|
||||
maple::dma_start(state.send_buf, writer.send_offset,
|
||||
state.recv_buf, writer.recv_offset);
|
||||
|
||||
serial::string("block write status: ");
|
||||
serial::integer(host_response->bus_data.command_code);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t allocate_fat_chain(storage_state& state, uint16_t blocks)
|
||||
{
|
||||
int32_t first_block = -1;
|
||||
int32_t last_block;
|
||||
//
|
||||
for (int32_t i = (state.fat_area_size() / (sizeof (uint16_t))) - 1; i >= 0; i--) {
|
||||
if (state.fat_area->fat_number[i] == storage::fat_area::data::unused) {
|
||||
if (first_block == -1) {
|
||||
first_block = i;
|
||||
} else {
|
||||
state.fat_area->fat_number[last_block] = i;
|
||||
}
|
||||
last_block = i;
|
||||
blocks -= 1;
|
||||
}
|
||||
|
||||
if (blocks == 0) {
|
||||
state.fat_area->fat_number[last_block] = storage::fat_area::data::data_end;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < (state.fat_area_size() / (sizeof (uint16_t))); i++) {
|
||||
//serial::integer<uint16_t>(i, ' ');
|
||||
//serial::integer(state.fat_area->fat_number[i]);
|
||||
}
|
||||
|
||||
return first_block;
|
||||
}
|
||||
|
||||
bool allocate_file_information_data(storage_state& state,
|
||||
uint16_t start_fat,
|
||||
uint8_t const * const file_name,
|
||||
uint16_t block_size)
|
||||
{
|
||||
for (uint32_t i = 0; i < state.file_information_entries(); i++) {
|
||||
if (state.file_information[i].status == storage::file_information::status::no_data_file) {
|
||||
|
||||
state.file_information[i].status = storage::file_information::status::data_file;
|
||||
state.file_information[i].copy = 0;
|
||||
state.file_information[i].start_fat = start_fat;
|
||||
copy<uint8_t>(state.file_information[i].file_name, file_name, 12);
|
||||
state.file_information[i].block_size = block_size;
|
||||
state.file_information[i].header = 0;
|
||||
state.file_information[i]._reserved = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void do_lm_request(uint8_t port, uint8_t lm)
|
||||
{
|
||||
uint32_t send_buf[1024] __attribute__((aligned(32)));
|
||||
@ -22,9 +293,15 @@ void do_lm_request(uint8_t port, uint8_t lm)
|
||||
const uint32_t host_port_select = host_instruction_port_select(port);
|
||||
const uint32_t destination_ap = ap_port_select(port) | ap::de::expansion_device | lm;
|
||||
|
||||
storage_state state;
|
||||
state.send_buf = send_buf;
|
||||
state.recv_buf = recv_buf;
|
||||
state.host_port_select = host_port_select;
|
||||
state.destination_ap = destination_ap;
|
||||
|
||||
{
|
||||
using command_type = device_request;
|
||||
using response_type = device_status;
|
||||
using command_type = maple::device_request;
|
||||
using response_type = maple::device_status;
|
||||
|
||||
auto writer = maple::host_command_writer(send_buf, recv_buf);
|
||||
|
||||
@ -60,11 +337,13 @@ void do_lm_request(uint8_t port, uint8_t lm)
|
||||
if ((std::byteswap(data_fields.device_id.ft) & function_type::storage) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
parse_storage_function_definition(std::byteswap(data_fields.device_id.fd[2]), state);
|
||||
}
|
||||
|
||||
{
|
||||
using command_type = get_media_info;
|
||||
using response_type = data_transfer<ft1::get_media_info_data_transfer::data_format>;
|
||||
using command_type = maple::get_media_info;
|
||||
using response_type = maple::data_transfer<ft1::get_media_info_data_transfer::data_format>;
|
||||
|
||||
auto writer = maple::host_command_writer(send_buf, recv_buf);
|
||||
|
||||
@ -87,6 +366,7 @@ void do_lm_request(uint8_t port, uint8_t lm)
|
||||
serial::integer<uint8_t>(port, ' ');
|
||||
serial::integer<uint8_t>(lm);
|
||||
} else {
|
||||
serial::string(" media_info:\n");
|
||||
serial::string(" total_size: ");
|
||||
serial::integer<uint32_t>(data.total_size);
|
||||
serial::string(" partition_number: ");
|
||||
@ -110,61 +390,150 @@ void do_lm_request(uint8_t port, uint8_t lm)
|
||||
serial::string(" reserved_for_execution_file: ");
|
||||
serial::integer<uint32_t>(data.reserved_for_execution_file);
|
||||
}
|
||||
|
||||
state.media_info.system_area.block_number = data.system_area_block_number;
|
||||
state.media_info.fat_area.block_number = data.fat_area_block_number;
|
||||
state.media_info.fat_area.number_of_blocks = data.number_of_fat_area_blocks;
|
||||
state.media_info.file_information.block_number = data.file_information_block_number;
|
||||
state.media_info.file_information.number_of_blocks = data.number_of_file_information_blocks;
|
||||
}
|
||||
|
||||
uint8_t fat_area_data[state.fat_area_size()];
|
||||
uint8_t file_information_data[state.file_information_size()];
|
||||
|
||||
{
|
||||
do_block_read(state, state.media_info.system_area.block_number,
|
||||
reinterpret_cast<uint8_t *>(&state.system_area));
|
||||
serial::string(" system_area:\n");
|
||||
serial::string(" format_information: ");
|
||||
serial::hexlify(state.system_area.format_information, 16);
|
||||
serial::string(" volume_label: ");
|
||||
serial::hexlify(state.system_area.volume_label, 32);
|
||||
serial::string(" date_and_time_created: ");
|
||||
serial::hexlify(state.system_area.date_and_time_created, 8);
|
||||
serial::string(" total_size: ");
|
||||
serial::integer(state.system_area.total_size);
|
||||
}
|
||||
|
||||
{
|
||||
using command_type = block_read;
|
||||
using response_type = data_transfer<ft1::block_read_data_transfer::data_format<512>>;
|
||||
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));
|
||||
|
||||
auto writer = maple::host_command_writer(send_buf, recv_buf);
|
||||
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);
|
||||
}
|
||||
|
||||
auto [host_command, host_response]
|
||||
= writer.append_command<command_type, response_type>(host_port_select,
|
||||
destination_ap,
|
||||
true); // end_flag
|
||||
host_command->bus_data.data_fields.function_type = std::byteswap(function_type::storage);
|
||||
host_command->bus_data.data_fields.pt = 0;
|
||||
host_command->bus_data.data_fields.phase = 0;
|
||||
host_command->bus_data.data_fields.block_number = std::byteswap<uint16_t>(0xff);
|
||||
{
|
||||
uint8_t * bufi = file_information_data;
|
||||
uint16_t chain = state.media_info.file_information.block_number;
|
||||
state.file_information = reinterpret_cast<storage::file_information *>(file_information_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 file_information bytes: ");
|
||||
serial::integer((uint32_t)(bufi - file_information_data));
|
||||
|
||||
maple::dma_start(send_buf, writer.send_offset,
|
||||
recv_buf, writer.recv_offset);
|
||||
|
||||
auto& bus_data = host_response->bus_data;
|
||||
auto& data_fields = bus_data.data_fields;
|
||||
auto& data = data_fields.data;
|
||||
serial::integer(std::byteswap(host_command->bus_data.data_fields.block_number));
|
||||
if (bus_data.command_code != response_type::command_code) {
|
||||
serial::string("lm did not reply block_read: ");
|
||||
serial::integer<uint8_t>(port, ' ');
|
||||
serial::integer<uint8_t>(lm, ' ');
|
||||
serial::integer<uint8_t>(bus_data.command_code);
|
||||
auto error = reinterpret_cast<file_error::data_fields *>(&data_fields);
|
||||
serial::hexlify(&error->function_error_code, 4);
|
||||
} else {
|
||||
for (int i = 0; i < 512; i++) {
|
||||
serial::hexlify(data.block_data[i]);
|
||||
serial::character(' ');
|
||||
if (i % 16 == 15) {
|
||||
for (uint32_t i = 0; i < state.file_information_entries(); i++) {
|
||||
if (state.file_information[i].status == storage::file_information::status::data_file
|
||||
|| state.file_information[i].status == storage::file_information::status::execution_file) {
|
||||
serial::string(" file_name: ");
|
||||
serial::string(state.file_information[i].file_name, 12);
|
||||
serial::character('\n');
|
||||
serial::string(" status: ");
|
||||
serial::integer<uint16_t>(state.file_information[i].status);
|
||||
serial::string(" start_fat: ");
|
||||
serial::integer<uint16_t>(state.file_information[i].start_fat);
|
||||
serial::string(" block_size: ");
|
||||
serial::integer<uint16_t>(state.file_information[i].block_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
uint16_t block_size = 3;
|
||||
uint16_t start_fat = allocate_fat_chain(state, block_size);
|
||||
char const * file_name = "HELLOANA.SUP";
|
||||
allocate_file_information_data(state, start_fat,
|
||||
reinterpret_cast<uint8_t const *>(file_name),
|
||||
block_size);
|
||||
|
||||
{
|
||||
uint16_t chain = state.media_info.fat_area.block_number;
|
||||
uint8_t * buf = reinterpret_cast<uint8_t *>(state.fat_area);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void do_lm_requests(uint8_t port, uint8_t lm)
|
||||
{
|
||||
if (lm & ap::lm_bus::_0)
|
||||
do_lm_request(port, lm & ap::lm_bus::_0);
|
||||
do_lm_request(port, ap::lm_bus::_0);
|
||||
if (lm & ap::lm_bus::_1)
|
||||
do_lm_request(port, lm & ap::lm_bus::_1);
|
||||
do_lm_request(port, ap::lm_bus::_1);
|
||||
if (lm & ap::lm_bus::_2)
|
||||
do_lm_request(port, lm & ap::lm_bus::_2);
|
||||
do_lm_request(port, ap::lm_bus::_2);
|
||||
if (lm & ap::lm_bus::_3)
|
||||
do_lm_request(port, lm & ap::lm_bus::_3);
|
||||
do_lm_request(port, ap::lm_bus::_3);
|
||||
if (lm & ap::lm_bus::_4)
|
||||
do_lm_request(port, lm & ap::lm_bus::_4);
|
||||
do_lm_request(port, ap::lm_bus::_4);
|
||||
}
|
||||
|
||||
void do_device_request()
|
||||
@ -174,8 +543,8 @@ void do_device_request()
|
||||
|
||||
auto writer = maple::host_command_writer(send_buf, recv_buf);
|
||||
|
||||
using command_type = device_request;
|
||||
using response_type = device_status;
|
||||
using command_type = maple::device_request;
|
||||
using response_type = maple::device_status;
|
||||
|
||||
auto [host_command, host_response]
|
||||
= writer.append_command_all_ports<command_type, response_type>();
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace maple {
|
||||
|
||||
struct device_id {
|
||||
uint32_t ft;
|
||||
uint32_t fd[3];
|
||||
@ -276,3 +278,4 @@ struct ar_error {
|
||||
|
||||
static_assert((sizeof (struct ar_error::data_fields)) == 4);
|
||||
|
||||
}
|
||||
|
@ -20,15 +20,14 @@ namespace ft1 {
|
||||
}
|
||||
|
||||
namespace block_read_data_transfer {
|
||||
template <int n>
|
||||
struct data_format {
|
||||
uint8_t pt;
|
||||
uint8_t phase;
|
||||
uint16_t block_number;
|
||||
uint8_t block_data[n];
|
||||
uint8_t block_data[0];
|
||||
};
|
||||
static_assert((sizeof (struct data_format<0>)) % 4 == 0);
|
||||
static_assert((sizeof (struct data_format<0>)) == 4);
|
||||
static_assert((sizeof (struct data_format)) % 4 == 0);
|
||||
static_assert((sizeof (struct data_format)) == 4);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,20 +20,21 @@ struct host_command_writer {
|
||||
: send_buf(send_buf), recv_buf(recv_buf), send_offset(0), recv_offset(0)
|
||||
{ }
|
||||
|
||||
template <typename C, typename R, int data_fields_trailing = 0>
|
||||
template <typename C, typename R>
|
||||
constexpr inline std::tuple<maple::host_command<typename C::data_fields> *,
|
||||
maple::host_response<typename R::data_fields> *>
|
||||
append_command(uint32_t host_port_select,
|
||||
uint32_t destination_ap,
|
||||
bool end_flag)
|
||||
bool end_flag,
|
||||
uint32_t send_trailing = 0,
|
||||
uint32_t recv_trailing = 0)
|
||||
{
|
||||
using command_type = maple::host_command<typename C::data_fields>;
|
||||
using response_type = maple::host_response<typename R::data_fields>;
|
||||
constexpr uint32_t data_size = (sizeof (typename C::data_fields)) + data_fields_trailing;
|
||||
const uint32_t data_size = (sizeof (typename C::data_fields)) + send_trailing;
|
||||
|
||||
static_assert((sizeof (command_type)) % 4 == 0);
|
||||
static_assert((sizeof (response_type)) % 4 == 0);
|
||||
static_assert(data_size % 4 == 0);
|
||||
|
||||
auto host_command = reinterpret_cast<command_type *>(&send_buf[send_offset / 4]);
|
||||
auto host_response = reinterpret_cast<response_type *>(&recv_buf[recv_offset / 4]);
|
||||
@ -50,8 +51,8 @@ struct host_command_writer {
|
||||
host_command->bus_data.source_ap = destination_ap & ap::port_select::bit_mask;
|
||||
host_command->bus_data.data_size = data_size / 4;
|
||||
|
||||
send_offset += (sizeof (command_type)) + data_fields_trailing;
|
||||
recv_offset += (sizeof (response_type));
|
||||
send_offset += (sizeof (command_type)) + send_trailing;
|
||||
recv_offset += (sizeof (response_type)) + recv_trailing;
|
||||
|
||||
return {host_command, host_response};
|
||||
}
|
||||
@ -61,10 +62,10 @@ struct host_command_writer {
|
||||
maple::host_response<typename R::data_fields> *>
|
||||
append_command_all_ports()
|
||||
{
|
||||
auto ret = append_command<C, R, 0>(host_instruction::port_select::a, ap::de::device | ap::port_select::a, false);
|
||||
append_command<C, R, 0>(host_instruction::port_select::b, ap::de::device | ap::port_select::b, false);
|
||||
append_command<C, R, 0>(host_instruction::port_select::c, ap::de::device | ap::port_select::c, false);
|
||||
append_command<C, R, 0>(host_instruction::port_select::d, ap::de::device | ap::port_select::d, true);
|
||||
auto ret = append_command<C, R>(host_instruction::port_select::a, ap::de::device | ap::port_select::a, false);
|
||||
append_command<C, R>(host_instruction::port_select::b, ap::de::device | ap::port_select::b, false);
|
||||
append_command<C, R>(host_instruction::port_select::c, ap::de::device | ap::port_select::c, false);
|
||||
append_command<C, R>(host_instruction::port_select::d, ap::de::device | ap::port_select::d, true);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
66
maple/storage.hpp
Normal file
66
maple/storage.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
namespace storage {
|
||||
|
||||
struct system_area {
|
||||
uint8_t format_information[16];
|
||||
uint8_t volume_label[32];
|
||||
uint8_t date_and_time_created[8];
|
||||
uint8_t _reserved0[8];
|
||||
uint16_t total_size;
|
||||
uint16_t partition_number;
|
||||
uint16_t system_area_block_number;
|
||||
uint16_t fat_area_block_number;
|
||||
uint16_t number_of_fat_area_blocks;
|
||||
uint16_t file_information_block_number;
|
||||
uint16_t number_of_file_information_blocks;
|
||||
uint8_t volume_icon;
|
||||
uint8_t reserved;
|
||||
uint16_t save_area_block_number;
|
||||
uint16_t number_of_save_area_blocks;
|
||||
uint8_t reserved_for_execution_file[4];
|
||||
uint8_t _reserved1[8];
|
||||
uint8_t _reserved2[416];
|
||||
};
|
||||
|
||||
static_assert((sizeof (struct system_area)) == 0x200);
|
||||
static_assert((offsetof (struct system_area, format_information)) == 0x000);
|
||||
static_assert((offsetof (struct system_area, volume_label)) == 0x010);
|
||||
static_assert((offsetof (struct system_area, date_and_time_created)) == 0x030);
|
||||
static_assert((offsetof (struct system_area, total_size)) == 0x040);
|
||||
static_assert((offsetof (struct system_area, save_area_block_number)) == 0x050);
|
||||
static_assert((offsetof (struct system_area, _reserved2)) == 0x060);
|
||||
|
||||
struct fat_area {
|
||||
uint16_t fat_number[0];
|
||||
|
||||
struct data {
|
||||
static constexpr uint16_t data_end = 0xfffa;
|
||||
static constexpr uint16_t unused = 0xfffc;
|
||||
static constexpr uint16_t block_damaged = 0xffff;
|
||||
};
|
||||
};
|
||||
|
||||
static_assert((sizeof (struct fat_area)) == 0);
|
||||
|
||||
struct file_information {
|
||||
uint8_t status;
|
||||
uint8_t copy;
|
||||
uint16_t start_fat;
|
||||
uint8_t file_name[12];
|
||||
uint8_t date[8];
|
||||
uint16_t block_size;
|
||||
uint16_t header;
|
||||
uint32_t _reserved;
|
||||
|
||||
struct status {
|
||||
static constexpr uint16_t no_data_file = 0x00;
|
||||
static constexpr uint16_t data_file = 0x33;
|
||||
static constexpr uint16_t execution_file = 0xcc;
|
||||
};
|
||||
};
|
||||
|
||||
static_assert((sizeof (struct file_information)) == 32);
|
||||
|
||||
}
|
403
notes/storage-notes.txt
Normal file
403
notes/storage-notes.txt
Normal file
@ -0,0 +1,403 @@
|
||||
ft: 0x0000000e
|
||||
fd[0]: 0x7e7e3f40 timer
|
||||
fd[1]: 0x00051000 lcd
|
||||
fd[2]: 0x000f4100 storage
|
||||
|
||||
storage:
|
||||
pt: 0x00 → 1 partition
|
||||
bb: 0x0f → (0x0f + 1) * 32 = 512 bytes per block
|
||||
wa: 0x4 → 1 block = 4 accesses, 128 bytes per access
|
||||
ra: 0x1 → 1 block = 1 accesss, 512 bytes per access
|
||||
rm: 0 → fixed
|
||||
crc: 0 → CRC not needed
|
||||
fd: 0 → reserved
|
||||
|
||||
---- block ff (system area)
|
||||
|
||||
format information: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55
|
||||
volume label: 01 8f af ff ff 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
date and time: 19 98 11 26 01 37 59 03
|
||||
reserved: 00 00 00 00 00 00 00 00
|
||||
total size: ff 00
|
||||
partition number: 00 00
|
||||
system area block number: ff 00
|
||||
fat area block number: fe 00
|
||||
number of fat area blocks: 01 00
|
||||
file information block number: fd 00
|
||||
number of file information blocks: 0d 00
|
||||
volume icon: 74
|
||||
reserved: 00
|
||||
save area block number: c8 00
|
||||
number of save area blocks: 1f 00
|
||||
reserved: 00 00 80 00
|
||||
|
||||
00 00 00 00 00 00 00 00
|
||||
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
|
||||
----- block fe (fat area)
|
||||
|
||||
00: fc ff
|
||||
01: fc ff
|
||||
02: fc ff
|
||||
03: fc ff
|
||||
04: fc ff
|
||||
05: fc ff
|
||||
06: fc ff
|
||||
07: fc ff
|
||||
08: fc ff
|
||||
09: fc ff
|
||||
0a: fc ff
|
||||
0b: fc ff
|
||||
0c: fc ff
|
||||
0d: fc ff
|
||||
0e: fc ff
|
||||
0f: fc ff
|
||||
10: fc ff
|
||||
11: fc ff
|
||||
12: fc ff
|
||||
13: fc ff
|
||||
14: fc ff
|
||||
15: fc ff
|
||||
16: fc ff
|
||||
17: fc ff
|
||||
18: fc ff
|
||||
19: fc ff
|
||||
1a: fc ff
|
||||
1b: fc ff
|
||||
1c: fc ff
|
||||
1d: fc ff
|
||||
1e: fc ff
|
||||
1f: fc ff
|
||||
20: fc ff
|
||||
21: fc ff
|
||||
22: fc ff
|
||||
23: fc ff
|
||||
24: fc ff
|
||||
25: fc ff
|
||||
26: fc ff
|
||||
27: fc ff
|
||||
28: fc ff
|
||||
29: fc ff
|
||||
2a: fc ff
|
||||
2b: fc ff
|
||||
2c: fc ff
|
||||
2d: fc ff
|
||||
2e: fc ff
|
||||
2f: fc ff
|
||||
30: fc ff
|
||||
31: fc ff
|
||||
32: fc ff
|
||||
33: fc ff
|
||||
34: fc ff
|
||||
35: fc ff
|
||||
36: fc ff
|
||||
37: fc ff
|
||||
38: fc ff
|
||||
39: fc ff
|
||||
3a: fc ff
|
||||
3b: fc ff
|
||||
3c: fc ff
|
||||
3d: fc ff
|
||||
3e: fc ff
|
||||
3f: fc ff
|
||||
40: fc ff
|
||||
41: fc ff
|
||||
42: fc ff
|
||||
43: fc ff
|
||||
44: fc ff
|
||||
45: fc ff
|
||||
46: fc ff
|
||||
47: fc ff
|
||||
48: fc ff
|
||||
49: fc ff
|
||||
4a: fc ff
|
||||
4b: fc ff
|
||||
4c: fc ff
|
||||
4d: fc ff
|
||||
4e: fc ff
|
||||
4f: fc ff
|
||||
50: fc ff
|
||||
51: fc ff
|
||||
52: fc ff
|
||||
53: fc ff
|
||||
54: fc ff
|
||||
55: fc ff
|
||||
56: fc ff
|
||||
57: fc ff
|
||||
58: fc ff
|
||||
59: fc ff
|
||||
5a: fc ff
|
||||
5b: fc ff
|
||||
5c: fc ff
|
||||
5d: fa ff
|
||||
5e: 5d 00
|
||||
5f: 5e 00
|
||||
60: fa ff
|
||||
61: 60 00
|
||||
62: 61 00
|
||||
63: 62 00
|
||||
64: 63 00
|
||||
65: 64 00
|
||||
66: 65 00
|
||||
67: 66 00
|
||||
68: 67 00
|
||||
69: 68 00
|
||||
6a: 69 00
|
||||
6b: 6a 00
|
||||
6c: 6b 00
|
||||
6d: fa ff
|
||||
6e: 6d 00
|
||||
6f: fa ff
|
||||
70: 6f 00
|
||||
71: 70 00
|
||||
72: 71 00
|
||||
73: 72 00
|
||||
74: 73 00
|
||||
75: 74 00
|
||||
76: 75 00
|
||||
77: 76 00
|
||||
78: 77 00
|
||||
79: 78 00
|
||||
7a: 79 00
|
||||
7b: 7a 00
|
||||
7c: 7b 00
|
||||
7d: 7c 00
|
||||
7e: 7d 00
|
||||
7f: 7e 00
|
||||
80: 7f 00
|
||||
81: 80 00
|
||||
82: 81 00
|
||||
83: 82 00
|
||||
84: 83 00
|
||||
85: 84 00
|
||||
86: 85 00
|
||||
87: 86 00
|
||||
88: 87 00
|
||||
89: 88 00
|
||||
8a: 89 00
|
||||
8b: 8a 00
|
||||
8c: 8b 00
|
||||
8d: 8c 00
|
||||
8e: 8d 00
|
||||
8f: 8e 00
|
||||
90: fa ff
|
||||
91: 90 00
|
||||
92: 91 00
|
||||
93: 92 00
|
||||
94: fa ff
|
||||
95: 94 00
|
||||
96: 95 00
|
||||
97: 96 00
|
||||
98: 97 00
|
||||
99: 98 00
|
||||
9a: 99 00
|
||||
9b: 9a 00
|
||||
9c: 9b 00
|
||||
9d: 9c 00
|
||||
9e: 9d 00
|
||||
9f: 9e 00
|
||||
a0: 9f 00
|
||||
a1: a0 00
|
||||
a2: a1 00
|
||||
a3: a2 00
|
||||
a4: a3 00
|
||||
a5: a4 00
|
||||
a6: a5 00
|
||||
a7: fa ff
|
||||
a8: a7 00
|
||||
a9: a8 00
|
||||
aa: a9 00
|
||||
ab: aa 00
|
||||
ac: ab 00
|
||||
ad: ac 00
|
||||
ae: ad 00
|
||||
af: ae 00
|
||||
b0: af 00
|
||||
b1: b0 00
|
||||
b2: b1 00
|
||||
b3: b2 00
|
||||
b4: b3 00
|
||||
b5: b4 00
|
||||
b6: b5 00
|
||||
b7: b6 00
|
||||
b8: b7 00
|
||||
b9: fa ff
|
||||
ba: b9 00
|
||||
bb: ba 00
|
||||
bc: bb 00
|
||||
bd: fa ff
|
||||
be: bd 00
|
||||
bf: be 00
|
||||
c0: bf 00
|
||||
c1: c0 00
|
||||
c2: c1 00
|
||||
c3: fa ff
|
||||
c4: c3 00
|
||||
c5: fa ff
|
||||
c6: c5 00
|
||||
c7: c6 00
|
||||
c8: fc ff
|
||||
c9: fc ff
|
||||
ca: fc ff
|
||||
cb: fc ff
|
||||
cc: fc ff
|
||||
cd: fc ff
|
||||
ce: fc ff
|
||||
cf: fc ff
|
||||
d0: fc ff
|
||||
d1: fc ff
|
||||
d2: fc ff
|
||||
d3: fc ff
|
||||
d4: fc ff
|
||||
d5: fc ff
|
||||
d6: fc ff
|
||||
d7: fc ff
|
||||
d8: fc ff
|
||||
d9: fc ff
|
||||
da: fc ff
|
||||
db: fc ff
|
||||
dc: fc ff
|
||||
dd: fc ff
|
||||
de: fc ff
|
||||
df: fc ff
|
||||
e0: fc ff
|
||||
e1: fc ff
|
||||
e2: fc ff
|
||||
e3: fc ff
|
||||
e4: fc ff
|
||||
e5: fc ff
|
||||
e6: fc ff
|
||||
e7: fc ff
|
||||
e8: fc ff
|
||||
e9: fc ff
|
||||
ea: fc ff
|
||||
eb: fc ff
|
||||
ec: fc ff
|
||||
ed: fc ff
|
||||
ee: fc ff
|
||||
ef: fc ff
|
||||
f0: fc ff
|
||||
f1: fa ff
|
||||
f2: f1 00
|
||||
f3: f2 00
|
||||
f4: f3 00
|
||||
f5: f4 00
|
||||
f6: f5 00
|
||||
f7: f6 00
|
||||
f8: f7 00
|
||||
f9: f8 00
|
||||
fa: f9 00
|
||||
fb: fa 00
|
||||
fc: fb 00
|
||||
fd: fc 00
|
||||
fe: fa ff
|
||||
ff: fa ff
|
||||
|
||||
----- block fd (file information)
|
||||
|
||||
status: 33
|
||||
copy: 00
|
||||
start fat: c7 00
|
||||
file name: 47 41 55 4e 54 4c 45 54 2e 30 30 31 "GAUNTLET.001"
|
||||
date: 19 98 11 26 00 10 12 03
|
||||
block size: 03 00
|
||||
header: 00 00
|
||||
reserved: 00 00 00 00
|
||||
|
||||
status: 33
|
||||
copy: 00
|
||||
start fat: c4 00
|
||||
file name: 45 43 43 4f 44 4f 54 46 2e 5a 41 43 "ECCODOTF.ZAC"
|
||||
date: 19 98 11 26 00 15 17 03
|
||||
block size: 02 00
|
||||
header: 00 00
|
||||
reserved: 00 00 00 00
|
||||
|
||||
status: 33
|
||||
copy: 00
|
||||
start fat: c2 00
|
||||
file name: 45 43 43 4f 44 4f 54 46 2e 5f 5f 5f "ECCODOTF.___"
|
||||
date: 19 98 11 26 00 12 35 03
|
||||
block size: 06 00
|
||||
header: 00 00
|
||||
reserved: 00 00 00 00
|
||||
|
||||
status: 33
|
||||
copy: 00
|
||||
start fat: bc 00
|
||||
file name: 53 48 45 4e 4d 55 45 32 5f 53 59 53 "SHENMUE2_SYS"
|
||||
date: 19 98 11 27 07 41 15 04
|
||||
block size: 04 00
|
||||
header: 00 00
|
||||
reserved: 00 00 00 00
|
||||
|
||||
status: 33
|
||||
copy: 00
|
||||
start fat: b8 00
|
||||
file name: 53 48 45 4e 4d 55 45 32 5f 30 30 31 "SHENMUE2_001"
|
||||
date: 19 98 11 27 07 41 16 04
|
||||
block size: 12 00
|
||||
header: 00 00
|
||||
reserved: 00 00 00 00
|
||||
|
||||
status: 33
|
||||
copy: 00
|
||||
start fat: a6 00
|
||||
file name: 54 4f 4d 42 43 48 52 4e 2e 30 30 30 "TOMBCHRN.000"
|
||||
date: 20 23 09 30 18 29 06 00
|
||||
block size: 13 00
|
||||
header: 00 00
|
||||
reserved: 00 00 00 00
|
||||
|
||||
status: 33
|
||||
copy: 00
|
||||
start fat: 93 00
|
||||
file name: 54 4f 4d 42 43 48 52 4e 2e 53 59 53 "TOMBCHRN.SYS"
|
||||
date: 20 23 09 30 18 29 06 00
|
||||
block size: 04 00
|
||||
header: 00 00
|
||||
reserved: 00 00 00 00
|
||||
|
||||
status: 33
|
||||
copy: 00
|
||||
start fat: 8f 00
|
||||
file name: 54 4f 4d 42 52 41 49 44 2e 30 30 30 "TOMBRAID.000"
|
||||
date: 20 23 09 30 22 09 06 00
|
||||
block size: 21 00
|
||||
header: 00 00
|
||||
reserved: 00 00 00 00
|
||||
|
||||
status: 33
|
||||
copy: 00
|
||||
start fat: 6e 00
|
||||
file name: 54 4f 4d 42 52 41 49 44 2e 53 59 53 "TOMBRAID.SYS"
|
||||
date: 20 23 09 30 22 09 06 00
|
||||
block size: 02 00
|
||||
header: 00 00
|
||||
reserved: 00 00 00 00
|
||||
|
||||
status: 33
|
||||
copy: 00
|
||||
start fat: 6c 00
|
||||
file name: 4c 45 4d 41 4e 53 32 34 2e 4f 50 54 "LEMANS24.OPT"
|
||||
date: 20 23 10 11 19 30 14 02
|
||||
block size: 0d 00
|
||||
header: 00 00
|
||||
reserved: 00 00 00 00
|
||||
|
||||
status: 33
|
||||
copy: ff
|
||||
start fat: 5f 00
|
||||
file name: 43 48 55 5f 43 48 55 5f 5f 52 43 54 "CHU_CHU__RCT"
|
||||
date: 20 23 10 11 16 59 43 02
|
||||
block size: 03 00
|
||||
header: 00 00
|
||||
reserved: 00 00 00 00
|
||||
|
||||
|
@ -35,6 +35,14 @@ def parse_bits(bits: list[str]):
|
||||
position=min(indicies),
|
||||
)
|
||||
|
||||
def parse_format_name(name):
|
||||
if '<' in name:
|
||||
head, middle, tail = re.split('[<>]', name)
|
||||
assert tail == "", name
|
||||
return head, middle
|
||||
else:
|
||||
return name, None
|
||||
|
||||
def parse_data_format(ix, rows):
|
||||
if ix >= len(rows):
|
||||
return None
|
||||
@ -61,6 +69,8 @@ def parse_data_format(ix, rows):
|
||||
assert len(bits) in {0, 8}, bits
|
||||
fields[field_name].append(Field(field_name,
|
||||
list(parse_bits(bits))))
|
||||
_, variable = parse_format_name(field_name)
|
||||
if not variable:
|
||||
size += 1
|
||||
if field_name not in field_order:
|
||||
field_order.append(field_name)
|
||||
@ -81,17 +91,8 @@ def parse(rows):
|
||||
assert len(formats) > 0
|
||||
return formats
|
||||
|
||||
def parse_format_name(name):
|
||||
if '<' in name:
|
||||
head, middle, tail = re.split('[<>]', name)
|
||||
assert tail == "", name
|
||||
return head, middle
|
||||
else:
|
||||
return name, None
|
||||
|
||||
def render_format(format):
|
||||
format_name, variable = parse_format_name(format.name)
|
||||
yield f"namespace {format_name} {{"
|
||||
yield f"namespace {format.name} {{"
|
||||
for field_name in format.field_order:
|
||||
subfields = format.fields[field_name]
|
||||
if not any(field.bits != [] for field in subfields):
|
||||
@ -110,8 +111,6 @@ def render_format(format):
|
||||
yield "}"
|
||||
yield ""
|
||||
|
||||
if variable is not None:
|
||||
yield f"template <int {variable}>"
|
||||
yield f"struct data_format {{"
|
||||
|
||||
for _field_name in format.field_order:
|
||||
@ -133,11 +132,6 @@ def render_format(format):
|
||||
assert False, (len(subfields), field_name)
|
||||
|
||||
yield "};"
|
||||
format_name, variable = parse_format_name(format.name)
|
||||
if variable is not None:
|
||||
yield f"static_assert((sizeof (struct data_format<0>)) % 4 == 0);"
|
||||
yield f"static_assert((sizeof (struct data_format<0>)) == {format.size - 1});"
|
||||
else:
|
||||
yield f"static_assert((sizeof (struct data_format)) % 4 == 0);"
|
||||
yield f"static_assert((sizeof (struct data_format)) == {format.size});"
|
||||
yield "}"
|
||||
|
@ -24,9 +24,9 @@
|
||||
"reserved_for_execution_file",,,,,,,,
|
||||
"reserved_for_execution_file",,,,,,,,
|
||||
,,,,,,,,
|
||||
"block_read_data_transfer<n>",7,6,5,4,3,2,1,0
|
||||
"block_read_data_transfer",7,6,5,4,3,2,1,0
|
||||
"pt",,,,,,,,
|
||||
"phase",,,,,,,,
|
||||
"block_number",,,,,,,,
|
||||
"block_number",,,,,,,,
|
||||
"block_data<n>",,,,,,,,
|
||||
"block_data<0>",,,,,,,,
|
||||
|
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user