diff --git a/common.mk b/common.mk index 13a0c86..a6d4100 100644 --- a/common.mk +++ b/common.mk @@ -2,7 +2,7 @@ MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(dir $(MAKEFILE_PATH)) LIB ?= . -OPT ?= -O2 +OPT ?= -Og GENERATED ?= AARCH = --isa=sh4 --little diff --git a/example/serial_transfer.cpp b/example/serial_transfer.cpp index 481ac6e..96c173d 100644 --- a/example/serial_transfer.cpp +++ b/example/serial_transfer.cpp @@ -16,6 +16,8 @@ #include "crc32.h" +static struct serial_load::maple_poll_state poll_state __attribute__((aligned(32))); + extern uint32_t _binary_font_portfolio_6x8 __asm("_binary_font_portfolio_6x8_portfolio_6x8_data_start"); template @@ -43,22 +45,7 @@ struct serial_error_counter { struct serial_error_counter error_counter; -enum struct step { - IDLE = 0, - DEVICE_STATUS, - EXTENSION_DEVICE_STATUS, - EXTENSION_DEVICE_REPLY, -}; - -struct maple_display_poll_state { - bool want_start; - enum step step; - struct { - uint8_t ap__lm; - } port[4]; -}; - -void send_vmu_framebuffer(maple::host_command_writer& writer, uint8_t port, uint8_t lm) +void send_vmu_framebuffer(maple::host_command_writer<>& writer, uint8_t port, uint8_t lm) { using command_type = maple::block_write; using response_type = maple::device_reply; @@ -88,9 +75,9 @@ void send_vmu_framebuffer(maple::host_command_writer& writer, uint8_t port, uint copy(data_fields.written_data, fb, maple::display::vmu::framebuffer_size); } -void recv_extension_device_status(struct maple_display_poll_state &state) +void recv_extension_device_status(struct serial_load::maple_poll_state &state) { - auto writer = maple::host_command_writer(send_buf, recv_buf); + auto writer = maple::host_command_writer<>(send_buf, recv_buf); using response_type = maple::host_response; auto host_response = reinterpret_cast(recv_buf); @@ -112,20 +99,25 @@ void recv_extension_device_status(struct maple_display_poll_state &state) auto& bus_data = host_response[response_index++].bus_data; auto& data_fields = bus_data.data_fields; - if ((bus_data.command_code == maple::device_status::command_code) && - (std::byteswap(data_fields.device_id.ft) & function_type::bw_lcd)) { - - last_send_offset = writer.send_offset; - send_vmu_framebuffer(writer, port, bit); + if (bus_data.command_code != maple::device_status::command_code) { + state.port[port].lm[i].device_id.ft = 0; } else { - // this extension device is not a bw_lcd; remove it - state.port[port].ap__lm &= ~bit; + state.port[port].lm[i].device_id.ft = std::byteswap(data_fields.device_id.ft); + state.port[port].lm[i].device_id.fd[0] = std::byteswap(data_fields.device_id.fd[0]); + state.port[port].lm[i].device_id.fd[1] = std::byteswap(data_fields.device_id.fd[1]); + state.port[port].lm[i].device_id.fd[2] = std::byteswap(data_fields.device_id.fd[2]); + + if (state.port[port].lm[i].device_id.ft & function_type::bw_lcd) { + last_send_offset = writer.send_offset; + send_vmu_framebuffer(writer, port, bit); + } } bit <<= 1; } } { + // change the last command from using command_type = maple::host_command::data_fields>; auto host_command = reinterpret_cast(&send_buf[last_send_offset / 4]); host_command->host_instruction |= host_instruction::end_flag; @@ -135,7 +127,7 @@ void recv_extension_device_status(struct maple_display_poll_state &state) } } -void send_extension_device_request(maple::host_command_writer& writer, uint8_t port, uint8_t lm) +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; @@ -148,20 +140,19 @@ void send_extension_device_request(maple::host_command_writer& writer, uint8_t p false); // end_flag } -typedef void (* func_t)(maple::host_command_writer& writer, uint8_t port, uint8_t lm); -void do_lm_requests(maple::host_command_writer& writer, uint8_t port, uint8_t lm, func_t func) +typedef void (* func_t)(maple::host_command_writer<>& writer, uint8_t port, uint8_t lm); +void do_lm_requests(maple::host_command_writer<>& writer, uint8_t port, uint8_t lm, func_t func) { uint32_t bit = ap::lm_bus::_0; for (int i = 0; i < 5; i++) { if (lm & bit) { - lm &= ~bit; func(writer, port, bit); } bit <<= 1; } } -void recv_device_status(struct maple_display_poll_state &state) +void recv_device_status(struct serial_load::maple_poll_state &state) { auto writer = maple::host_command_writer(send_buf, recv_buf); @@ -170,13 +161,17 @@ void recv_device_status(struct maple_display_poll_state &state) for (int port = 0; port < 4; port++) { auto& bus_data = host_response[port].bus_data; + auto& data_fields = bus_data.data_fields; if (bus_data.command_code != maple::device_status::command_code) { state.port[port].ap__lm = 0; + state.port[port].device_id.ft = 0; } else { - //auto& data_fields = bus_data.data_fields; - uint8_t lm = bus_data.source_ap & ap::lm_bus::bit_mask; state.port[port].ap__lm = lm; + state.port[port].device_id.ft = std::byteswap(data_fields.device_id.ft); + state.port[port].device_id.fd[0] = std::byteswap(data_fields.device_id.fd[0]); + state.port[port].device_id.fd[1] = std::byteswap(data_fields.device_id.fd[1]); + state.port[port].device_id.fd[2] = std::byteswap(data_fields.device_id.fd[2]); do_lm_requests(writer, port, lm, &send_extension_device_request); } } @@ -198,11 +193,26 @@ void send_device_request() recv_buf, writer.recv_offset); } -void handle_maple(struct maple_display_poll_state& state) +void send_raw(struct serial_load::maple_poll_state& state) { + 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); + */ +} + +void handle_maple(struct serial_load::maple_poll_state& state) +{ + using namespace serial_load; + switch (state.step) { case step::IDLE: - if (state.want_start) { + if (state.want_raw) { + send_raw(state); + state.step = step::RAW; + } else if (state.want_start) { // always send to all ports send_device_request(); state.step = step::DEVICE_STATUS; @@ -212,20 +222,25 @@ void handle_maple(struct maple_display_poll_state& state) case step::DEVICE_STATUS: if (maple::dma_poll_complete()) { recv_device_status(state); - state.step = step::EXTENSION_DEVICE_STATUS; + state.step = step::EXTENSION__DEVICE_STATUS; } break; - case step::EXTENSION_DEVICE_STATUS: + case step::EXTENSION__DEVICE_STATUS: if (maple::dma_poll_complete()) { recv_extension_device_status(state); - state.step = step::EXTENSION_DEVICE_REPLY; + state.step = step::EXTENSION__DEVICE_STATUS__DEVICE_REPLY; } break; - case step::EXTENSION_DEVICE_REPLY: + case step::EXTENSION__DEVICE_STATUS__DEVICE_REPLY: if (maple::dma_poll_complete()) { state.step = step::IDLE; } break; + case step::RAW: + if (maple::dma_poll_complete()) { + state.want_raw = 0; + state.step = step::IDLE; + } } } @@ -281,13 +296,16 @@ void render_u8(uint32_t src, char * dst) for (int i = 0; i < 2; i++) dst[i] = num_buf[i]; } +static int count = 0; + void render_idle_state(char * dst) { - render_line("idle", &dst[0]); + render_line("idle3", &dst[0]); + render_u32(serial_load::state.buf.u32[0], &dst[8]); - render_u32(serial_load::state.buf.u32[1], &dst[16]); - render_u8(serial_load::state.len, &dst[24]); - render_clear(&dst[26], 6); + render_u8(serial_load::state.len, &dst[16]); + render_clear(&dst[18], 6); + render_u32(count++, &dst[24]); } void render_write_state(char * dst) @@ -295,7 +313,7 @@ void render_write_state(char * dst) render_line("write", &dst[0]); render_u32(sh7091.DMAC.DMATCR1, &dst[8]); render_u32(sh7091.DMAC.DAR1, &dst[16]); - render_u32(serial_load::state.write_crc.value, &dst[24]); + render_u32(serial_load::state.reply_crc.value, &dst[24]); } void render_read_state(char * dst) @@ -303,7 +321,7 @@ void render_read_state(char * dst) render_line("read", &dst[0]); render_u32(sh7091.DMAC.DMATCR1, &dst[8]); render_u32(sh7091.DMAC.SAR1, &dst[16]); - render_u32(serial_load::state.read_crc.value, &dst[24]); + render_u32(serial_load::state.reply_crc.value, &dst[24]); } void render_fsm_state(char * dst) @@ -327,8 +345,25 @@ void render_fsm_state(char * dst) render_line("speed", &dst[0]); render_clear(&dst[8], 24); break; + case fsm_state::maple_raw__command: + render_line("mr__cmd", &dst[0]); + render_u32(sh7091.DMAC.DAR1, &dst[8]); + render_u32(sh7091.DMAC.SAR1, &dst[16]); + render_clear(&dst[24], 8); + break; + case fsm_state::maple_raw__maple_dma: + render_line("mr__dma", &dst[0]); + render_u32(poll_state.send_length, &dst[8]); + render_u32(poll_state.recv_length, &dst[16]); + render_u8(poll_state.want_raw, &dst[24]); + render_clear(&dst[26], 6); + break; + case fsm_state::maple_raw__response: + render_line("mr__resp", &dst[0]); + render_clear(&dst[8], 24); + break; default: - render_line("invalid", &dst[0]); + render_line("unknown", &dst[0]); render_clear(&dst[8], 24); break; } @@ -362,10 +397,13 @@ void main() __attribute__((section(".text.main"))); void main() { + poll_state.want_start = 0; + poll_state.want_raw = 0; + poll_state.step = serial_load::step::IDLE; + constexpr uint32_t serial_speed = 0; serial_load::init(serial_speed); - struct maple_display_poll_state state = {0}; const uint8_t * font = reinterpret_cast(&_binary_font_portfolio_6x8); auto renderer0 = maple::display::font_renderer(font); framebuffer[0] = renderer0.fb; @@ -384,6 +422,13 @@ void main() error_counter.dr = 0; error_counter.orer = 0; + /* + const uint8_t m[] = {0xe0, 0x22, 0x24, 0xb6, 0x30, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xa5, 0xce, 0x18, 0xda}; + for (uint32_t i = 0; i < (sizeof (m)); i++) { + serial_load::recv(state, m[i]); + } + */ + while (1) { using namespace scif; @@ -411,16 +456,16 @@ void main() if (serial_load::state.fsm_state == serial_load::fsm_state::idle) { while (sh7091.SCIF.SCFSR2 & scfsr2::rdf::bit_mask) { const uint8_t c = sh7091.SCIF.SCFRDR2; - serial_load::recv(c); + serial_load::recv(poll_state, c); sh7091.SCIF.SCFSR2 = scfsr2 & ~scfsr2::rdf::bit_mask; } } } - serial_load::tick(); + serial_load::tick(poll_state); render(renderer0, renderer1); - state.want_start = 1; - handle_maple(state); + poll_state.want_start = 1; + handle_maple(poll_state); } } diff --git a/ip.lds b/ip.lds index 01c8d10..ab523e2 100644 --- a/ip.lds +++ b/ip.lds @@ -71,8 +71,8 @@ SECTIONS INCLUDE "debug.lds" } -__stack_reservation = 0x1000; -__stack_end = ORIGIN(p1ram) + LENGTH(p1ram) - __stack_reservation; + +__stack_end = ORIGIN(p1ram) + LENGTH(p1ram); __text_link_start = 0; __text_link_end = 0; @@ -97,3 +97,6 @@ __vbr_link_end = 0; __vbr_load_end = 0; INCLUDE "addresses.lds" + +__send_buf = 0xac000020; +__recv_buf = 0xac002020; diff --git a/loader.lds b/loader.lds index bef7081..cbe0cc1 100644 --- a/loader.lds +++ b/loader.lds @@ -3,7 +3,7 @@ MEMORY { p1ram : ORIGIN = 0xac005000, LENGTH = 0x0000 p2ram : ORIGIN = 0xac010000, LENGTH = 0xff0000 - ldram : ORIGIN = 0xacffd000, LENGTH = 0x3000 + ldram : ORIGIN = 0xacffd000, LENGTH = 0x4000 } SECTIONS { @@ -72,4 +72,7 @@ SECTIONS INCLUDE "symbols.lds" INCLUDE "addresses.lds" -__stack_end = 0x8c008000; +__stack_end = 0x8c00f000; + +__send_buf = 0xac000020; +__recv_buf = 0xac002020; diff --git a/main.lds b/main.lds index 9b33867..3583424 100644 --- a/main.lds +++ b/main.lds @@ -7,4 +7,4 @@ MEMORY INCLUDE "common.lds" -__stack_end = ORIGIN(p1ram) + LENGTH(p1ram) - 0x3000; +__stack_end = ORIGIN(p1ram) + LENGTH(p1ram) - 0x4000; diff --git a/maple/maple_host_command_writer.hpp b/maple/maple_host_command_writer.hpp index b3e9c09..d82b17c 100644 --- a/maple/maple_host_command_writer.hpp +++ b/maple/maple_host_command_writer.hpp @@ -1,6 +1,7 @@ #pragma once -#include +#include +#include #include #include "maple/maple.hpp" @@ -9,6 +10,7 @@ namespace maple { +template struct host_command_writer { uint32_t * const send_buf; uint32_t * const recv_buf; @@ -43,7 +45,13 @@ struct host_command_writer { | (host_port_select & host_instruction::port_select::bit_mask) | host_instruction::transfer_length(data_size / 4); - host_command->receive_data_storage_address = receive_data_storage_address::address(reinterpret_cast(host_response)); + uint32_t host_response_address; + if constexpr (base_address != 0) { + host_response_address = base_address + recv_offset; + } else { + host_response_address = reinterpret_cast(host_response); + } + host_command->receive_data_storage_address = receive_data_storage_address::address(host_response_address); host_command->bus_data.command_code = C::command_code; host_command->bus_data.destination_ap = destination_ap; diff --git a/maple/maple_port.hpp b/maple/maple_port.hpp index dfe2246..f9a1b58 100644 --- a/maple/maple_port.hpp +++ b/maple/maple_port.hpp @@ -23,3 +23,15 @@ constexpr inline uint32_t host_instruction_port_select(const uint32_t port) case 3: return host_instruction::port_select::d; } } + +constexpr inline uint32_t ap_lm_bus(const uint32_t lm) +{ + switch (lm) { + default: [[fallthrough]]; + case 0: return ap::lm_bus::_0; + case 1: return ap::lm_bus::_1; + case 2: return ap::lm_bus::_2; + case 3: return ap::lm_bus::_3; + case 4: return ap::lm_bus::_4; + } +} diff --git a/serial_load.cpp b/serial_load.cpp index f27c5ea..c0849c1 100644 --- a/serial_load.cpp +++ b/serial_load.cpp @@ -51,33 +51,106 @@ void jump_to_func(const uint32_t addr) // restore our stack } -static inline void prestart_write() +static void prestart_write() { uint32_t dest = state.buf.arg[0]; uint32_t size = state.buf.arg[1]; serial::recv_dma(dest - 1, size + 1); - state.write_crc.value = 0xffffffff; - state.write_crc.offset = dest; + state.reply_crc.value = 0xffffffff; + state.reply_crc.offset = dest; } -static inline void prestart_read() +static void poststart_read() { uint32_t src = state.buf.arg[0]; uint32_t size = state.buf.arg[1]; serial::send_dma(src, size); - state.read_crc.value = 0xffffffff; - state.read_crc.offset = src; + state.reply_crc.value = 0xffffffff; + state.reply_crc.offset = src; } +static void prestart_maple_raw__command() +{ + uint32_t dest = reinterpret_cast(&__send_buf); + //uint32_t dest = 0xac000020; + uint32_t size = state.buf.arg[0]; + serial::recv_dma(dest - 1, size + 1); + state.reply_crc.value = 0xffffffff; + state.reply_crc.offset = dest; +} + +static void prestart_maple_raw__response() +{ + uint32_t src = reinterpret_cast(&__recv_buf); + //uint32_t src = 0xac002020; + uint32_t size = state.buf.arg[1]; + serial::send_dma(src, size); + state.reply_crc.value = 0xffffffff; + state.reply_crc.offset = src; +} + + /* +static reply::maple_list_entry maple_list[4 + 4 * 5]; + +static void prestart_maple_list(struct maple_port * port) +{ + uint32_t function_type = state.buf.arg[0]; + uint32_t list_ix = 0; + + for (int port_ix = 0; port_ix < 4; port_ix++) { + + if ((port[port_ix].device_id.ft & function_type) == 0) { + continue; + } + + maple_list[list_ix].port = port_ix; + maple_list[list_ix].lm = 0; + maple_list[list_ix]._res = 0; + maple_list[list_ix].device_id.ft = port[port_ix].device_id.ft; + maple_list[list_ix].device_id.fd[0] = port[port_ix].device_id.fd[0]; + maple_list[list_ix].device_id.fd[1] = port[port_ix].device_id.fd[1]; + maple_list[list_ix].device_id.fd[2] = port[port_ix].device_id.fd[2]; + list_ix++; + + int bit = 1; + for (int lm_ix = 0; lm_ix < 5; lm_ix++) { + if ((port[port_ix].ap__lm & bit) != 0) { + maple_list[list_ix].port = port_ix; + maple_list[list_ix].lm = bit; + maple_list[list_ix]._res = 0; + maple_list[list_ix].device_id.ft = port[port_ix].lm[lm_ix].device_id.ft; + maple_list[list_ix].device_id.fd[0] = port[port_ix].lm[lm_ix].device_id.fd[0]; + maple_list[list_ix].device_id.fd[1] = port[port_ix].lm[lm_ix].device_id.fd[1]; + maple_list[list_ix].device_id.fd[2] = port[port_ix].lm[lm_ix].device_id.fd[2]; + list_ix++; + } + bit <<= 1; + } + } + + state.buf.arg[1] = list_ix * (sizeof (struct reply::maple_list_entry)); +} + +static void poststart_maple_list() +{ + uint32_t src = reinterpret_cast(maple_list); + uint32_t size = state.buf.arg[1]; + serial::send_dma(src, size); + state.reply_crc.value = 0xffffffff; + state.reply_crc.offset = src; +} + */ + struct state_arglen_reply command_list[] = { - {command::_write, reply::_write, fsm_state::write}, - {command::_read , reply::_read , fsm_state::read }, - {command::_jump , reply::_jump , fsm_state::jump }, - {command::_speed, reply::_speed, fsm_state::speed}, + {command::_write , reply::_write , fsm_state::write }, + {command::_read , reply::_read , fsm_state::read }, + {command::_jump , reply::_jump , fsm_state::jump }, + {command::_speed , reply::_speed , fsm_state::speed }, + {command::_maple_raw , reply::_maple_raw , fsm_state::maple_raw__command }, }; constexpr uint32_t command_list_length = (sizeof (command_list)) / (sizeof (command_list[0])); -void recv(uint8_t c) +void recv(struct maple_poll_state& poll_state, uint8_t c) { state.buf.u8[state.len++] = c; switch (state.fsm_state) { @@ -90,12 +163,13 @@ void recv(uint8_t c) if (crc == state.buf.crc) { // valid command, do the transition if (state.buf.cmd == command::_write) prestart_write(); + if (state.buf.cmd == command::_maple_raw) prestart_maple_raw__command(); state.fsm_state = sar.fsm_state; state.len = 0; - union command_reply reply = command_reply(sar.reply, state.buf.arg[0], state.buf.arg[1]); + union command_reply reply = command_reply(sar.reply, state.buf.arg[0], state.buf.arg[1]); serial::string(reply.u8, 16); - if (state.buf.cmd == command::_read) prestart_read(); + if (state.buf.cmd == command::_read) poststart_read(); return; } else { // do nothing @@ -112,25 +186,66 @@ void recv(uint8_t c) } } -void tick() +void tick(struct maple_poll_state& poll_state) { switch (state.fsm_state) { case fsm_state::idle: break; + case fsm_state::maple_raw__command: [[fallthrough]]; case fsm_state::write: { // read chcr1 before dar1 to avoid race uint32_t chcr1 = sh7091.DMAC.CHCR1; uint32_t dar1 = sh7091.DMAC.DAR1; - if (dar1 > state.write_crc.offset) { - uint32_t len = dar1 - state.write_crc.offset; - const uint8_t * buf = reinterpret_cast(state.write_crc.offset); - state.write_crc.value = crc32_update(state.write_crc.value, buf, len); - state.write_crc.offset += len; + if (dar1 > state.reply_crc.offset) { + uint32_t len = dar1 - state.reply_crc.offset; + const uint8_t * buf = reinterpret_cast(state.reply_crc.offset); + state.reply_crc.value = crc32_update(state.reply_crc.value, buf, len); + state.reply_crc.offset += len; } if (chcr1 & dmac::chcr::te::transfers_completed) { - state.write_crc.value ^= 0xffffffff; - union command_reply reply = reply::write_crc(state.write_crc.value); + state.reply_crc.value ^= 0xffffffff; + union command_reply reply = reply::crc(state.reply_crc.value); + serial::string(reply.u8, 16); + + sh7091.DMAC.CHCR1 = 0; + + // transition to next state + if (state.fsm_state == fsm_state::maple_raw__command) { + poll_state.send_length = state.buf.arg[0]; + poll_state.recv_length = state.buf.arg[1]; + poll_state.want_raw = 1; + state.fsm_state = fsm_state::maple_raw__maple_dma; + } else + state.fsm_state = fsm_state::idle; + } + } + break; + case fsm_state::maple_raw__maple_dma: + { + // transition to next state + if (poll_state.want_raw == 0) { + prestart_maple_raw__response(); + state.fsm_state = fsm_state::maple_raw__response; + } + } + break; + case fsm_state::maple_raw__response: [[fallthrough]]; + case fsm_state::read: + { + // read chcr1 before sar1 to avoid race + uint32_t chcr1 = sh7091.DMAC.CHCR1; + uint32_t sar1 = sh7091.DMAC.SAR1; + if (sar1 > state.reply_crc.offset) { + uint32_t len = sar1 - state.reply_crc.offset; + const uint8_t * buf = reinterpret_cast(state.reply_crc.offset); + state.reply_crc.value = crc32_update(state.reply_crc.value, buf, len); + state.reply_crc.offset += len; + } + + if (chcr1 & dmac::chcr::te::transfers_completed) { + state.reply_crc.value ^= 0xffffffff; + union command_reply reply = reply::crc(state.reply_crc.value); serial::string(reply.u8, 16); sh7091.DMAC.CHCR1 = 0; @@ -140,29 +255,6 @@ void tick() } } break; - case fsm_state::read: - { - uint32_t chcr1 = sh7091.DMAC.CHCR1; - uint32_t sar1 = sh7091.DMAC.SAR1; - if (sar1 > state.read_crc.offset) { - uint32_t len = sar1 - state.read_crc.offset; - const uint8_t * buf = reinterpret_cast(state.read_crc.offset); - state.read_crc.value = crc32_update(state.read_crc.value, buf, len); - state.read_crc.offset += len; - } - - if (chcr1 & dmac::chcr::te::transfers_completed) { - state.read_crc.value ^= 0xffffffff; - union command_reply reply = reply::read_crc(state.read_crc.value); - serial::string(reply.u8, 16); - - sh7091.DMAC.CHCR1 = 0; - - // transition to next state - //state.fsm_state = fsm_state::idle; - } - } - break; case fsm_state::jump: { using namespace scif; diff --git a/serial_load.hpp b/serial_load.hpp index dd7bd85..9657c0a 100644 --- a/serial_load.hpp +++ b/serial_load.hpp @@ -2,13 +2,14 @@ #include +#include "maple/maple_bus_commands.hpp" #include "serial_protocol.hpp" namespace serial_load { void init(uint32_t speed); -void recv(uint8_t c); -void tick(); +void recv(struct maple_poll_state& poll_state, uint8_t c); +void tick(struct maple_poll_state& poll_state); enum struct fsm_state { idle, @@ -16,6 +17,9 @@ enum struct fsm_state { read, jump, speed, + maple_raw__command, + maple_raw__maple_dma, + maple_raw__response, }; struct state_arglen_reply { @@ -33,11 +37,47 @@ struct state { union command_reply buf; uint32_t len; enum fsm_state fsm_state; - struct incremental_crc write_crc; - struct incremental_crc read_crc; + struct incremental_crc reply_crc; uint32_t speed; }; extern struct state state; +struct lm { + struct maple::device_id device_id; +}; + +struct maple_port { + struct maple::device_id device_id; + uint8_t ap__lm; + struct lm lm[5]; +}; + +enum struct step { + IDLE = 0, + DEVICE_STATUS, + EXTENSION__DEVICE_STATUS, + EXTENSION__DEVICE_STATUS__DEVICE_REPLY, + RAW, +}; + +struct maple_command_parameters { + uint8_t port; + uint8_t lm; +}; + +struct maple_poll_state { + uint32_t send_length; + uint32_t recv_length; + + bool want_start; + bool want_raw; + enum step step; + struct serial_load::maple_port port[4]; + struct maple_command_parameters command_parameters; +}; + } + +extern "C" uint32_t __send_buf __asm("__send_buf"); +extern "C" uint32_t __recv_buf __asm("__recv_buf"); diff --git a/serial_protocol.hpp b/serial_protocol.hpp index a7fa451..4352ed5 100644 --- a/serial_protocol.hpp +++ b/serial_protocol.hpp @@ -2,6 +2,8 @@ #include +#include "maple/maple_bus_commands.hpp" + #include "crc32.h" namespace serial_load { @@ -56,13 +58,15 @@ namespace command { constexpr uint32_t _jump = gen_cmd("JUMP"); constexpr uint32_t _speed = gen_cmd("SPED"); - constexpr uint32_t _maple_list = gen_cmd("MPLS"); + constexpr uint32_t _maple_raw = gen_cmd("MPRW"); static_assert(_write == 0x2cc46ed8); - static_assert(_read == 0xf18d57c7); - static_assert(_jump == 0xa6696f38); + static_assert(_read == 0xf18d57c7); + static_assert(_jump == 0xa6696f38); static_assert(_speed == 0x27a7a9f4); + static_assert(_maple_raw == 0xb62422e0); + constexpr union command_reply write(uint32_t dest, uint32_t size) { return command_reply(_write, dest, size); @@ -83,9 +87,9 @@ namespace command { return command_reply(_speed, speed, 0); } - constexpr union command_reply maple_list(uint32_t function_type) + constexpr union command_reply maple_raw(uint32_t send_size, uint32_t recv_size) { - return command_reply(_maple_list, function_type, 0); + return command_reply(_maple_raw, send_size, recv_size); } } @@ -94,18 +98,19 @@ namespace reply { constexpr uint32_t _read = gen_cmd("read"); constexpr uint32_t _jump = gen_cmd("jump"); constexpr uint32_t _speed = gen_cmd("sped"); - constexpr uint32_t _write_crc = gen_cmd("crcw"); - constexpr uint32_t _read_crc = gen_cmd("crcr"); - constexpr uint32_t _maple_list = gen_cmd("mpls"); - constexpr uint32_t _maple_list_crc = gen_cmd("mlcs"); + constexpr uint32_t _maple_raw = gen_cmd("mprw"); + + constexpr uint32_t _crc = gen_cmd("rcrc"); static_assert(_write == 0x8c661aaa); static_assert(_read == 0x512f23b5); static_assert(_jump == 0x06cb1b4a); static_assert(_speed == 0x8705dd86); - static_assert(_write_crc == 0x3cccc074); - static_assert(_read_crc == 0x99cc92f4); + + static_assert(_maple_raw == 0x16865692); + + static_assert(_crc == 0xcc9aab7c); constexpr union command_reply write(uint32_t dest, uint32_t size) { @@ -127,14 +132,14 @@ namespace reply { return command_reply(_speed, speed, 0); } - constexpr union command_reply write_crc(uint32_t crc) + constexpr union command_reply crc(uint32_t crc) { - return command_reply(_write_crc, crc, 0); + return command_reply(_crc, crc, 0); } - constexpr union command_reply read_crc(uint32_t crc) + constexpr union command_reply maple_raw(uint32_t send_size, uint32_t recv_size) { - return command_reply(_read_crc, crc, 0); + return command_reply(_maple_raw, send_size, recv_size); } } diff --git a/sh7091/serial.cpp b/sh7091/serial.cpp index a4a9cc1..9d2f721 100644 --- a/sh7091/serial.cpp +++ b/sh7091/serial.cpp @@ -99,6 +99,8 @@ void string(const char * s) void string(const uint8_t * s, uint32_t len) { while (len > 0) { + //hexlify(*s++); + //character(' '); character(*s++); len--; } diff --git a/tools/command_gen.py b/tools/command_gen.py index c6e2dde..01c756a 100644 --- a/tools/command_gen.py +++ b/tools/command_gen.py @@ -19,6 +19,7 @@ commands = [ "SPED", "MPLS", + "MPRW", ] replies = [ @@ -26,11 +27,11 @@ replies = [ "read", "jump", "sped", - "crcw", - "crcr", "mpls", - "mlcs", + "mprw", + + "rcrc" ] seen = set() diff --git a/tools/ftdi_transfer.cpp b/tools/ftdi_transfer.cpp index 64351ad..03be420 100644 --- a/tools/ftdi_transfer.cpp +++ b/tools/ftdi_transfer.cpp @@ -15,6 +15,11 @@ #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" + extern "C" int convert_baudrate_UT_export(int baudrate, struct ftdi_context *ftdi, unsigned short *value, unsigned short *index); @@ -190,6 +195,10 @@ void dump_command_reply(union serial_load::command_reply& cr) for (uint32_t i = 0; i < (sizeof (union serial_load::command_reply)) / (sizeof (uint32_t)); i++) { fprintf(stderr, " %08x\n", serial_load::le_bswap(cr.u32[i])); } + for (uint32_t i = 0; i < (sizeof (union serial_load::command_reply)); i++) { + fprintf(stderr, "%02x ", cr.u8[i]); + } + fprintf(stderr, "\n"); } int read_reply(struct ftdi_context * ftdi, uint32_t expected_cmd, union serial_load::command_reply& reply) @@ -200,7 +209,7 @@ int read_reply(struct ftdi_context * ftdi, uint32_t expected_cmd, union serial_l long length = read_with_timeout(ftdi, reply.u8, read_length); if (length != read_length) { - fprintf(stderr, "short read; want %ld bytes; received: %ld\n", read_length, length); + fprintf(stderr, "read_reply: short read; want %ld bytes; received: %ld\n", read_length, length); return -1; } @@ -273,7 +282,7 @@ int do_write(struct ftdi_context * ftdi, const uint32_t dest, const uint8_t * bu uint32_t buf_crc = crc32(buf, size); union serial_load::command_reply crc_reply; - res = read_reply(ftdi, serial_load::reply::_write_crc, crc_reply); + res = read_reply(ftdi, serial_load::reply::_crc, crc_reply); clock_res = clock_gettime(CLOCK_MONOTONIC, &end2); assert(clock_res == 0); if (res != 0) { @@ -300,6 +309,10 @@ int do_write(struct ftdi_context * ftdi, const uint32_t dest, const uint8_t * bu fprintf(stderr, " idealized write time : %.03f seconds\n", idealized_time); fprintf(stderr, " measured write time : %.03f seconds\n", measured_time2); + if (crc_reply.arg[0] != buf_crc) { + return -1; + } + return 0; } @@ -471,22 +484,25 @@ int do_read(struct ftdi_context * ftdi, const uint32_t src, uint8_t * buf, const uint32_t read_length = 0; while (read_length < size) { - res = ftdi_read_data(ftdi, (uint8_t *)buf, size - read_length); + res = ftdi_read_data(ftdi, (uint8_t *)&buf[read_length], size - read_length); assert(res >= 0); read_length += res; if (read_length < size) - fprintf(stderr, "short read; want %x out of %x\n", size - read_length, size); + fprintf(stderr, "read: short read; want %x out of %x\n", size - read_length, size); } uint32_t buf_crc = crc32((uint8_t*)buf, size); union serial_load::command_reply crc_reply; - res = read_reply(ftdi, serial_load::reply::_read_crc, crc_reply); + res = read_reply(ftdi, serial_load::reply::_crc, crc_reply); if (res != 0) { return -1; } - fprintf(stderr, "remote crc: %08x; local crc %08x\n", crc_reply.arg[0], buf_crc); + fprintf(stderr, "remote crc: %08x; local crc %08x\n", crc_reply.arg[0], buf_crc); + if (crc_reply.arg[0] != buf_crc) { + return -1; + } return 0; } @@ -562,6 +578,214 @@ void do_console(struct ftdi_context * ftdi) } } +int lm_bit_to_int(uint8_t bit) +{ + switch (bit) { + case 0b00001: + return 0; + case 0b00010: + return 1; + case 0b00100: + return 2; + case 0b01000: + return 3; + case 0b10000: + return 4; + default: + return -1; + } +} + +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); +} + +void print_device_id(struct maple::device_id& device_id) +{ + fprintf(stderr, " ft: %08x\n", device_id.ft); + fprintf(stderr, " fd[0]: %08x\n", device_id.fd[0]); + fprintf(stderr, " fd[1]: %08x\n", device_id.fd[1]); + fprintf(stderr, " fd[2]: %08x\n", device_id.fd[2]); + + if (device_id.ft & function_type::storage) { + int fd_ix = count_left_set_bits(device_id.ft, count_trailing_zeros(function_type::storage)); + print_storage_function_definition(device_id.fd[fd_ix]); + } +} + +int do_maple_raw(struct ftdi_context * ftdi, + uint8_t * send_buf, + uint32_t send_size, + uint8_t * recv_buf, + uint32_t recv_size) +{ + int res; + + union serial_load::command_reply command = serial_load::command::maple_raw(send_size, recv_size); + dump_command_reply(command); + res = ftdi_write_data(ftdi, command.u8, (sizeof (command))); + assert(res == (sizeof (command))); + union serial_load::command_reply reply; + fprintf(stderr, "maple_raw: wait maple_raw reply\n"); + res = read_reply(ftdi, serial_load::reply::_maple_raw, reply); + if (res != 0) { + return -2; + } + if (reply.arg[0] != command.arg[0] || reply.arg[1] != command.arg[1]) { + fprintf(stderr, "maple_raw: argument mismatch: (%08x, %08x) != (%08x, %08x)\n", + reply.arg[0], reply.arg[1], + command.arg[0], command.arg[1]); + return -1; + } + + res = ftdi_write_data(ftdi, send_buf, send_size); + assert(res >= 0); + assert((uint32_t)res == send_size); + + uint32_t send_buf_crc = crc32(send_buf, send_size); + fprintf(stderr, "send_size: %d\n", send_size); + for (uint32_t i = 0; i < send_size; i++) { + fprintf(stderr, "%02x ", send_buf[i]); + if (i % 4 == 3) + fprintf(stderr, "\n"); + } + fprintf(stderr, "\n"); + + union serial_load::command_reply send_crc_reply; + fprintf(stderr, "maple_raw: send: wait crc reply\n"); + res = read_reply(ftdi, serial_load::reply::_crc, send_crc_reply); + if (res != 0) { + 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) { + dump_command_reply(send_crc_reply); + return -1; + } + + uint32_t read_length = 0; + while (read_length < recv_size) { + res = ftdi_read_data(ftdi, &recv_buf[read_length], recv_size - read_length); + assert(res >= 0); + read_length += res; + if (read_length < recv_size) + fprintf(stderr, "maple raw: short read; want %x out of %x\n", recv_size - read_length, recv_size); + } + + uint32_t recv_buf_crc = crc32(recv_buf, recv_size); + + union serial_load::command_reply recv_crc_reply; + fprintf(stderr, "maple_raw: recv: wait crc reply\n"); + res = read_reply(ftdi, serial_load::reply::_crc, recv_crc_reply); + if (res != 0) { + 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) { + return -1; + } + + return 0; +} + +int do_maple_list(struct ftdi_context * ftdi) +{ + uint8_t send_buf[1024] = {0}; + uint8_t recv_buf[1024] = {0}; + + using command_type = maple::device_request; + using response_type = maple::device_status; + + auto writer = maple::host_command_writer<0xac002020>(reinterpret_cast(send_buf), reinterpret_cast(recv_buf)); + auto [host_command, host_response] + = writer.append_command_all_ports(); + + for (uint32_t i = 0; i < writer.send_offset; i++) { + fprintf(stderr, "%02x ", send_buf[i]); + } + fprintf(stderr, "\n"); + + int res = do_maple_raw(ftdi, + send_buf, writer.send_offset, + recv_buf, writer.recv_offset); + if (res != 0) { + return -1; + } + + for (uint32_t i = 0; i < writer.recv_offset; i++) { + fprintf(stderr, "%02x ", recv_buf[i]); + if (i % 4 == 3) + fprintf(stderr, "\n"); + } + fprintf(stderr, "\n"); + fprintf(stderr, "%d\n", response_type::command_code); + fprintf(stderr, "%p\n", host_response); + fprintf(stderr, "%p\n", recv_buf); + + 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, "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 { + fprintf(stderr, " ft: %08x\n", std::byteswap(data_fields.device_id.ft)); + fprintf(stderr, " fd[0]: %08x\n", std::byteswap(data_fields.device_id.fd[0])); + fprintf(stderr, " fd[1]: %08x\n", std::byteswap(data_fields.device_id.fd[1])); + fprintf(stderr, " fd[2]: %08x\n", std::byteswap(data_fields.device_id.fd[2])); + fprintf(stderr, " source_ap.lm_bus: %d\n", bus_data.source_ap & ap::lm_bus::bit_mask); + } + } + + return 0; +} + enum struct argument_type { string, integer @@ -581,6 +805,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 }, }; constexpr int commands_length = (sizeof (commands)) / (sizeof (commands[0])); diff --git a/tools/ftdi_transfer.sh b/tools/ftdi_transfer.sh index b328f6b..827915e 100644 --- a/tools/ftdi_transfer.sh +++ b/tools/ftdi_transfer.sh @@ -1,5 +1,7 @@ #!/bin/sh +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + filename="$1" if [ -z "$filename" ]; then @@ -9,7 +11,7 @@ fi set -ex -./ftdi_transfer \ +${SCRIPT_DIR}/ftdi_transfer \ write 0xac010000 "$filename" \ - jump 0xac010000 \ - console + jump 0xac010000 +# console