From 39aa6b75a692c98d2c15efbfe2332dca967e9b94 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Fri, 15 Dec 2023 22:08:23 +0800 Subject: [PATCH] example: new maple "get_condition" demo This is very barebones, and uses the serial interface to communicate the status of the "a" controller button being pressed. I'd like to make this a more interactive/graphical demo. --- example/example.mk | 9 +++ example/maple_controller.cpp | 127 +++++++++++++++++++++++++------ example/maple_device_request.cpp | 37 +++++++++ maple/maple.cpp | 5 +- maple/maple.hpp | 3 +- maple/maple_bus_commands.hpp | 83 +++++++++++--------- regs/gen/maple_commands.py | 7 ++ 7 files changed, 206 insertions(+), 65 deletions(-) create mode 100644 example/maple_device_request.cpp diff --git a/example/example.mk b/example/example.mk index e7f774b..5f92511 100644 --- a/example/example.mk +++ b/example/example.mk @@ -54,6 +54,15 @@ CUBE_OBJ = \ example/cube.elf: LDSCRIPT = $(LIB)/alt.lds example/cube.elf: $(START_OBJ) $(CUBE_OBJ) +MAPLE_DEVICE_REQUEST_OBJ = \ + example/maple_device_request.o \ + vga.o \ + serial.o \ + maple/maple.o + +example/maple_device_request.elf: LDSCRIPT = $(LIB)/alt.lds +example/maple_device_request.elf: $(START_OBJ) $(MAPLE_DEVICE_REQUEST_OBJ) + MAPLE_CONTROLLER_OBJ = \ example/maple_controller.o \ vga.o \ diff --git a/example/maple_controller.cpp b/example/maple_controller.cpp index 7af9004..5ccc3cc 100644 --- a/example/maple_controller.cpp +++ b/example/maple_controller.cpp @@ -1,37 +1,116 @@ +#include + +#include "vga.hpp" #include "align.hpp" #include "maple/maple.hpp" +#include "maple/maple_bus_bits.hpp" #include "maple/maple_bus_commands.hpp" +#include "maple/maple_bus_ft0.hpp" #include "serial.hpp" -constexpr uint32_t command_data_size = (sizeof (device_request::data_fields)); -constexpr uint32_t response_data_size = (sizeof (device_status::data_fields)); +uint32_t _command_buf[1024 / 4 + 32] = {0}; +uint32_t _receive_buf[1024 / 4 + 32] = {0}; -constexpr uint32_t host_command_size = (sizeof (struct maple::host_command)); -constexpr uint32_t command_response_size = align_32byte((sizeof (struct maple::command_response))); +static uint32_t * command_buf; +static uint32_t * receive_buf; -uint32_t _command_buf[host_command_size * 4 + 32] = {0}; -uint32_t _receive_buf[command_response_size * 4 + 32] = {0}; +struct port_state { + bool controller_connected; +}; + +static port_state state[4] = {0}; + +void do_get_condition(uint32_t port) +{ + uint32_t destination_port; + uint32_t destination_ap; + + switch (port) { + case 0: + destination_port = host_instruction::port_select::a; + destination_ap = ap::de::device | ap::port_select::a; + break; + case 1: + destination_port = host_instruction::port_select::b; + destination_ap = ap::de::device | ap::port_select::b; + break; + case 2: + destination_port = host_instruction::port_select::c; + destination_ap = ap::de::device | ap::port_select::c; + break; + case 3: + destination_port = host_instruction::port_select::d; + destination_ap = ap::de::device | ap::port_select::d; + break; + default: + return; + } + + maple::init_get_condition(command_buf, receive_buf, + destination_port, + destination_ap, + std::byteswap(function_type::controller)); + maple::dma_start(command_buf); + + using response_type = struct maple::command_response>; + auto response = reinterpret_cast(receive_buf); + auto& bus_data = response->bus_data; + auto& data_fields = response->bus_data.data_fields; + if (bus_data.command_code != data_transfer::command_code) { + return; + } + if ((data_fields.function_type & std::byteswap(function_type::controller)) == 0) { + return; + } + + state[port].controller_connected = 1; + bool a = data_fields.data.digital_button & ft0::data_transfer::digital_button::a; + if (a == 0) { + serial::string("port "); + serial::integer(port); + serial::string(" `a` press "); + serial::integer(a); + } +} + +void do_device_request() +{ + using response_type = struct maple::command_response; + constexpr uint32_t response_size = align_32byte(sizeof (response_type)); + + maple::init_host_command_all_ports(command_buf, receive_buf, + device_request::command_code, + (sizeof (device_request::data_fields)), // command_data_size + (sizeof (device_status::data_fields))); // response_data_size + maple::dma_start(command_buf); + + for (uint8_t port = 0; port < 4; port++) { + auto response = reinterpret_cast(&receive_buf[response_size * port / 4]); + + auto& bus_data = response->bus_data; + auto& data_fields = response->bus_data.data_fields; + if (bus_data.command_code != device_status::command_code) { + // the controller is disconnected + state[port].controller_connected = 0; + } else { + if ((data_fields.device_id.ft & std::byteswap(function_type::controller)) != 0) { + //serial::string("is controller: "); + //serial::integer(port); + do_get_condition(port); + } + } + } +} void main() { - uint32_t * command_buf = align_32byte(_command_buf); - uint32_t * receive_buf = align_32byte(_receive_buf); + command_buf = align_32byte(_command_buf); + receive_buf = align_32byte(_receive_buf); - maple::init_host_command_all_ports(command_buf, receive_buf, - device_request::command_code, command_data_size, response_data_size); - - maple::dma_start(command_buf); - - uint8_t * buf = reinterpret_cast(receive_buf); - for (uint8_t port = 0; port < 4; port++) { - serial::string("port "); - serial::integer(port); - for (uint32_t i = 0; i < command_response_size; i++) { - serial::integer(buf[port * command_response_size + i]); - } - serial::character('\n'); - } - - while (1); + while (1) { + v_sync_out(); + v_sync_in(); + do_device_request(); + }; } diff --git a/example/maple_device_request.cpp b/example/maple_device_request.cpp new file mode 100644 index 0000000..7af9004 --- /dev/null +++ b/example/maple_device_request.cpp @@ -0,0 +1,37 @@ +#include "align.hpp" + +#include "maple/maple.hpp" +#include "maple/maple_bus_commands.hpp" +#include "serial.hpp" + +constexpr uint32_t command_data_size = (sizeof (device_request::data_fields)); +constexpr uint32_t response_data_size = (sizeof (device_status::data_fields)); + +constexpr uint32_t host_command_size = (sizeof (struct maple::host_command)); +constexpr uint32_t command_response_size = align_32byte((sizeof (struct maple::command_response))); + +uint32_t _command_buf[host_command_size * 4 + 32] = {0}; +uint32_t _receive_buf[command_response_size * 4 + 32] = {0}; + +void main() +{ + uint32_t * command_buf = align_32byte(_command_buf); + uint32_t * receive_buf = align_32byte(_receive_buf); + + maple::init_host_command_all_ports(command_buf, receive_buf, + device_request::command_code, command_data_size, response_data_size); + + maple::dma_start(command_buf); + + uint8_t * buf = reinterpret_cast(receive_buf); + for (uint8_t port = 0; port < 4; port++) { + serial::string("port "); + serial::integer(port); + for (uint32_t i = 0; i < command_response_size; i++) { + serial::integer(buf[port * command_response_size + i]); + } + serial::character('\n'); + } + + while (1); +} diff --git a/maple/maple.cpp b/maple/maple.cpp index 3e01ebd..69536f1 100644 --- a/maple/maple.cpp +++ b/maple/maple.cpp @@ -76,7 +76,8 @@ void init_device_request(uint32_t * buf, uint32_t * receive_buf, void init_get_condition(uint32_t * buf, uint32_t * receive_buf, uint32_t destination_port, - uint8_t destination_ap) + uint8_t destination_ap, + uint32_t function_type) { init_host_command(buf, receive_buf, destination_port, @@ -87,7 +88,7 @@ void init_get_condition(uint32_t * buf, uint32_t * receive_buf, auto& fields = host_command->bus_data.data_fields; // controller function type - fields.function_type = std::byteswap(function_type::controller); + fields.function_type = function_type; } void init_block_write(uint32_t * command_buf, uint32_t * receive_buf, diff --git a/maple/maple.hpp b/maple/maple.hpp index 6900633..c9e9850 100644 --- a/maple/maple.hpp +++ b/maple/maple.hpp @@ -42,7 +42,8 @@ void init_device_request(uint32_t * buf, uint32_t * receive_buf, void init_get_condition(uint32_t * buf, uint32_t * receive_buf, uint32_t destination_port, - uint8_t destination_ap); + uint8_t destination_ap, + uint32_t function_type); void init_block_write(uint32_t * buf, uint32_t * receive_buf, uint32_t destination_port, diff --git a/maple/maple_bus_commands.hpp b/maple/maple_bus_commands.hpp index 97a0977..a229f80 100644 --- a/maple/maple_bus_commands.hpp +++ b/maple/maple_bus_commands.hpp @@ -1,38 +1,44 @@ #include +struct device_id { + uint32_t ft; + uint32_t fd[3]; +}; + +static_assert((sizeof (struct device_id)) == 16); namespace device_request { constexpr uint32_t command_code = 0x1; - + struct data_fields { }; } namespace all_status_request { constexpr uint32_t command_code = 0x2; - + struct data_fields { }; } namespace device_reset { constexpr uint32_t command_code = 0x3; - + struct data_fields { }; } namespace device_kill { constexpr uint32_t command_code = 0x4; - + struct data_fields { }; } namespace device_status { constexpr uint32_t command_code = 0x5; - + struct data_fields { - uint8_t device_id[16]; + struct device_id device_id; uint8_t destination_code; uint8_t connection_direction; uint8_t product_name[30]; @@ -40,16 +46,16 @@ namespace device_status { uint16_t low_consumption_standby_current; uint16_t maximum_current_consumption; }; - + static_assert((sizeof (struct data_fields)) == 112); } namespace device_all_status { constexpr uint32_t command_code = 0x6; - + template struct data_fields { - uint8_t device_id[16]; + struct device_id device_id; uint8_t destination_code; uint8_t connection_direction; uint8_t product_name[30]; @@ -58,66 +64,66 @@ namespace device_all_status { uint16_t maximum_current_consumption; T free_device_status; }; - + static_assert((sizeof (struct data_fields)) == 112); } namespace device_reply { constexpr uint32_t command_code = 0x7; - + struct data_fields { }; } namespace data_transfer { constexpr uint32_t command_code = 0x8; - + template struct data_fields { uint32_t function_type; T data; }; - + static_assert((sizeof (struct data_fields)) == 4); } namespace get_condition { constexpr uint32_t command_code = 0x9; - + struct data_fields { uint32_t function_type; }; - + static_assert((sizeof (struct data_fields)) == 4); } namespace get_media_info { constexpr uint32_t command_code = 0xa; - + struct data_fields { uint32_t function_type; uint32_t pt; }; - + static_assert((sizeof (struct data_fields)) == 8); } namespace block_read { constexpr uint32_t command_code = 0xb; - + struct data_fields { uint32_t function_type; uint8_t pt; uint8_t phase; uint16_t block_no; }; - + static_assert((sizeof (struct data_fields)) == 8); } namespace block_write { constexpr uint32_t command_code = 0xc; - + template struct data_fields { uint32_t function_type; @@ -126,106 +132,107 @@ namespace block_write { uint16_t block_no; T written_data; }; - + static_assert((sizeof (struct data_fields)) == 8); } namespace get_last_error { constexpr uint32_t command_code = 0xd; - + struct data_fields { uint32_t function_type; uint8_t pt; uint8_t phase; uint16_t block_no; }; - + static_assert((sizeof (struct data_fields)) == 8); } namespace set_condition { constexpr uint32_t command_code = 0xe; - + template struct data_fields { uint32_t function_type; T write_in_data; }; - + static_assert((sizeof (struct data_fields)) == 4); } namespace ft4_control { constexpr uint32_t command_code = 0xf; - + template struct data_fields { uint32_t function_type; T ft4_data; }; - + static_assert((sizeof (struct data_fields)) == 4); } namespace ar_control { constexpr uint32_t command_code = 0x10; - + template struct data_fields { uint32_t function_type; T data; }; - + static_assert((sizeof (struct data_fields)) == 4); } namespace function_type_unknown { constexpr uint32_t command_code = 0xfe; - + struct data_fields { }; } namespace command_unknown { constexpr uint32_t command_code = 0xfd; - + struct data_fields { }; } namespace transmit_again { constexpr uint32_t command_code = 0xfc; - + struct data_fields { }; } namespace file_error { constexpr uint32_t command_code = 0xfb; - + struct data_fields { uint32_t function_error_code; }; - + static_assert((sizeof (struct data_fields)) == 4); } namespace lcd_error { constexpr uint32_t command_code = 0xfa; - + struct data_fields { uint32_t function_error_code; }; - + static_assert((sizeof (struct data_fields)) == 4); } namespace ar_error { constexpr uint32_t command_code = 0xf9; - + struct data_fields { uint32_t function_error_code; }; - + static_assert((sizeof (struct data_fields)) == 4); } + diff --git a/regs/gen/maple_commands.py b/regs/gen/maple_commands.py index e31e634..7b5330e 100644 --- a/regs/gen/maple_commands.py +++ b/regs/gen/maple_commands.py @@ -37,6 +37,8 @@ def command_namespace(namespace: CommandNamespace, if const in {1, 2, 4}: bits = const * 8 yield f"uint{bits}_t {field_name};" + elif field_name == "device_id": + yield f"struct device_id {field_name};" else: yield f"uint8_t {field_name}[{const}];" elif const == 0: @@ -155,6 +157,11 @@ def new_aggregator(): def headers(): yield "#include " yield "" + yield "struct device_id {" + yield "uint32_t ft;" + yield "uint32_t fd[3];" + yield "};" + yield "static_assert((sizeof (struct device_id)) == 16);" input_file = sys.argv[1] rows = read_input(input_file)